Initial Commit - Copy from Altus Metrum AltOS

This commit is contained in:
2024-06-25 19:03:04 +02:00
commit 13fc49c923
2048 changed files with 1206748 additions and 0 deletions

26
altosui/.gitignore vendored Normal file
View File

@@ -0,0 +1,26 @@
windows/
linux/
macosx/
fat/
Manifest.txt
Manifest-fat.txt
AltosVersion.java
Info.plist
libaltosJNI
classes
altosui
altosui-test
altosui-jdb
classaltosui.stamp
altos-windows.nsi
Altos-Linux-*.tar.bz2
Altos-Linux-*.sh
Altos-Mac-*.zip
Altos-Windows-*.exe
*.desktop
*.dll
*.dylib
*.so
*.jar
*.class
*.dmg

View File

@@ -0,0 +1 @@
<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>

View File

@@ -0,0 +1 @@
<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>

View File

@@ -0,0 +1 @@
<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>

29
altosui/Altos.java Normal file
View File

@@ -0,0 +1,29 @@
/*
* 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; 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.
*/
package altosui;
import java.awt.*;
import libaltosJNI.*;
import org.altusmetrum.altoslib_14.*;
import org.altusmetrum.altosuilib_14.*;
public class Altos extends AltosUILib {
}

195
altosui/AltosAscent.java Normal file
View File

@@ -0,0 +1,195 @@
/*
* 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; 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.
*/
package altosui;
import java.util.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import org.altusmetrum.altoslib_14.*;
import org.altusmetrum.altosuilib_14.*;
public class AltosAscent extends AltosUIFlightTab {
JLabel cur, max;
class Height extends AltosUIUnitsIndicator {
public double value(AltosState state, int i) {
if (i == 0)
return state.height();
else
return state.max_height();
}
public Height(Container container, int y) {
super(container, y, AltosConvert.height, "Height", 2, false, 1);
}
}
class Speed extends AltosUIUnitsIndicator {
public double value(AltosState state, int i) {
if (i == 0)
return state.speed();
else
return state.max_speed();
}
public Speed(Container container, int y) {
super(container, y, AltosConvert.speed, "Speed", 2, false, 1);
}
}
class Accel extends AltosUIUnitsIndicator {
public boolean hide(double v) { return v == AltosLib.MISSING; }
public double value(AltosState state, int i) {
if (i == 0)
return state.acceleration();
else
return state.max_acceleration();
}
public Accel(Container container, int y) {
super(container, y, AltosConvert.accel, "Acceleration", 2, false, 1);
}
}
class Orient extends AltosUIUnitsIndicator {
public boolean hide(double v) { return v == AltosLib.MISSING; }
public double value(AltosState state, int i) {
if (i == 0)
return state.orient();
else
return state.max_orient();
}
public Orient(Container container, int y) {
super(container, y, AltosConvert.orient, "Tilt Angle", 2, false, 1);
}
}
class Apogee extends AltosUIUnitsIndicator {
public double value(AltosState state, int i) {
return state.apogee_voltage;
}
public boolean good(double v) { return v >= AltosLib.ao_igniter_good; }
public boolean hide(double v) { return v == AltosLib.MISSING; }
public Apogee (Container container, int y) {
super(container, y, AltosConvert.voltage, "Apogee Igniter Voltage", 1, true, 2);
}
}
class Main extends AltosUIUnitsIndicator {
public double value(AltosState state, int i) {
return state.main_voltage;
}
public boolean good(double v) { return v >= AltosLib.ao_igniter_good; }
public boolean hide(double v) { return v == AltosLib.MISSING; }
public Main (Container container, int y) {
super(container, y, AltosConvert.voltage, "Main Igniter Voltage", 1, true, 2);
}
}
class Lat extends AltosUIUnitsIndicator {
public boolean hide(AltosState state, int i) {
return state.gps == null || !state.gps.connected;
}
public double value(AltosState state, int i) {
if (state.gps == null)
return AltosLib.MISSING;
if (!state.gps.connected)
return AltosLib.MISSING;
return state.gps.lat;
}
Lat (Container container, int y) {
super (container, y, AltosConvert.latitude, "Latitude", 1, false, 2);
}
}
class Lon extends AltosUIUnitsIndicator {
public boolean hide(AltosState state, int i) {
return state.gps == null || !state.gps.connected;
}
public double value(AltosState state, int i) {
if (state.gps == null)
return AltosLib.MISSING;
if (!state.gps.connected)
return AltosLib.MISSING;
return state.gps.lon;
}
Lon (Container container, int y) {
super (container, y, AltosConvert.longitude, "Longitude", 1, false, 2);
}
}
public void font_size_changed(int font_size) {
super.font_size_changed(font_size);
cur.setFont(AltosUILib.label_font);
max.setFont(AltosUILib.label_font);
}
public void labels(GridBagLayout layout, int y) {
GridBagConstraints c;
cur = new JLabel("Current");
cur.setFont(AltosUILib.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(AltosUILib.label_font);
c.gridx = 3; c.gridy = y;
layout.setConstraints(max, c);
add(max);
}
public String getName() {
return "Ascent";
}
public AltosAscent() {
int y = 0;
labels(layout, y++);
add(new Height(this, y++));
add(new Speed(this, y++));
add(new Accel(this, y++));
add(new Orient(this, y++));
add(new Lat(this, y++));
add(new Lon(this, y++));
add(new Apogee(this, y++));
add(new Main(this, y++));
}
}

View File

@@ -0,0 +1,37 @@
/*
* 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; 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.
*/
package altosui;
import java.awt.event.*;
import javax.swing.*;
public class AltosChannelMenu extends JComboBox<String> 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);
}
}

View File

@@ -0,0 +1,112 @@
/*
* 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; 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.
*/
package altosui;
import java.awt.*;
import javax.swing.*;
import org.altusmetrum.altoslib_14.*;
import org.altusmetrum.altosuilib_14.*;
public class AltosCompanionInfo extends JTable implements AltosFlightDisplay {
private AltosFlightInfoTableModel model;
static final int info_columns = 2;
static final int info_rows = 17;
int desired_row_height() {
FontMetrics infoValueMetrics = getFontMetrics(Altos.table_value_font);
return (infoValueMetrics.getHeight() + infoValueMetrics.getLeading()) * 18 / 10;
}
public void font_size_changed(int font_size) {
setFont(Altos.table_value_font);
setRowHeight(desired_row_height());
doLayout();
}
public void units_changed(boolean imperial_units) {
}
public AltosCompanionInfo() {
super(new AltosFlightInfoTableModel(info_rows, info_columns));
model = (AltosFlightInfoTableModel) getModel();
setAutoResizeMode(AUTO_RESIZE_ALL_COLUMNS);
setShowGrid(true);
font_size_changed(AltosUIPreferences.font_size());
}
public Dimension getPreferredScrollableViewportSize() {
return getPreferredSize();
}
public void 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_finish() {
model.finish();
}
public void clear() {
model.clear();
}
AltosCompanion companion;
public String board_name() {
if (companion == null)
return "None";
switch (companion.board_id) {
case AltosCompanion.board_id_telescience:
return "TeleScience";
default:
return String.format("%02x\n", companion.board_id);
}
}
public String getName() { return "Companion"; }
public void show(AltosState state, AltosListenerState listener_state) {
if (state == null)
return;
if (state.companion != null)
companion = state.companion;
reset();
info_add_row(0, "Companion board", "%s", board_name());
if (companion != null) {
info_add_row(0, "Last Data", "%5d", companion.tick);
info_add_row(0, "Update period", "%5.2f s",
companion.update_period / 100.0);
info_add_row(0, "Channels", "%3d", companion.channels);
for (int i = 0; i < companion.channels; i++)
info_add_row(1, String.format("Channel %2d", i),
"%6d", companion.companion_data[i]);
}
info_finish();
}
}

317
altosui/AltosConfigFC.java Normal file
View File

@@ -0,0 +1,317 @@
/*
* 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; 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.
*/
package altosui;
import java.awt.event.*;
import javax.swing.*;
import java.io.*;
import java.util.concurrent.*;
import java.text.*;
import org.altusmetrum.altoslib_14.*;
import org.altusmetrum.altosuilib_14.*;
public class AltosConfigFC implements 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;
AltosConfigData data;
AltosConfigFCUI config_ui;
boolean serial_started;
boolean made_visible;
void start_serial() throws InterruptedException, TimeoutException {
serial_started = true;
if (remote)
serial_line.start_remote();
}
void stop_serial() throws InterruptedException {
if (!serial_started)
return;
serial_started = false;
if (remote)
serial_line.stop_remote();
}
void update_ui() {
data.set_values(config_ui);
config_ui.set_clean();
if (!made_visible) {
made_visible = true;
config_ui.make_visible();
}
}
int pyro;
final static int serial_mode_read = 0;
final static int serial_mode_save = 1;
final static int serial_mode_reboot = 2;
class SerialData implements Runnable {
AltosConfigFC config;
int serial_mode;
void callback(String in_cmd) {
final String cmd = in_cmd;
Runnable r = new Runnable() {
public void run() {
if (cmd.equals("abort")) {
abort();
} else if (cmd.equals("all finished")) {
if (serial_line != null)
update_ui();
}
}
};
SwingUtilities.invokeLater(r);
}
void get_data() {
data = null;
try {
start_serial();
data = new AltosConfigData(config.serial_line);
} catch (InterruptedException ie) {
} catch (TimeoutException te) {
try {
stop_serial();
callback("abort");
} catch (InterruptedException ie) {
}
} finally {
try {
stop_serial();
} catch (InterruptedException ie) {
}
}
callback("all finished");
}
void save_data() {
try {
start_serial();
data.save(serial_line, remote);
if (remote)
AltosUIPreferences.set_frequency(device.getSerial(),
data.frequency());
} catch (InterruptedException ie) {
} catch (TimeoutException te) {
} finally {
try {
stop_serial();
} catch (InterruptedException ie) {
}
}
}
void reboot() {
try {
start_serial();
serial_line.printf("r eboot\n");
serial_line.flush_output();
} catch (InterruptedException ie) {
} catch (TimeoutException te) {
} finally {
try {
stop_serial();
serial_line.close();
} catch (InterruptedException ie) {
}
}
}
public void run () {
switch (serial_mode) {
case serial_mode_save:
save_data();
/* fall through ... */
case serial_mode_read:
get_data();
break;
case serial_mode_reboot:
reboot();
break;
}
}
public SerialData(AltosConfigFC in_config, int in_serial_mode) {
config = in_config;
serial_mode = in_serial_mode;
}
}
void run_serial_thread(int serial_mode) {
SerialData sd = new SerialData(this, serial_mode);
Thread st = new Thread(sd);
st.start();
}
void init_ui () throws InterruptedException, TimeoutException {
config_ui = new AltosConfigFCUI(owner, remote);
config_ui.addActionListener(this);
serial_line.set_frame(owner);
set_ui();
}
void abort() {
if (serial_line != null) {
serial_line.close();
serial_line = null;
}
JOptionPane.showMessageDialog(owner,
String.format("Connection to \"%s\" failed",
device.toShortString()),
"Connection Failed",
JOptionPane.ERROR_MESSAGE);
config_ui.setVisible(false);
}
void set_ui() throws InterruptedException, TimeoutException {
if (serial_line != null)
run_serial_thread(serial_mode_read);
else
update_ui();
}
double frequency() {
return AltosConvert.radio_to_frequency(data.radio_frequency,
data.radio_setting,
data.radio_calibration,
data.radio_channel);
}
void save_data() {
try {
/* bounds check stuff */
if (config_ui.flight_log_max() != AltosLib.MISSING &&
config_ui.flight_log_max() > data.log_space() / 1024)
{
JOptionPane.showMessageDialog(owner,
String.format("Requested flight log, %dk, is larger than the available space, %dk.\n",
config_ui.flight_log_max(),
data.log_space() / 1024),
"Maximum Flight Log Too Large",
JOptionPane.ERROR_MESSAGE);
return;
}
/* Pull data out of the UI and stuff back into our local data record */
data.get_values(config_ui);
run_serial_thread(serial_mode_save);
} catch (AltosConfigDataException ae) {
JOptionPane.showMessageDialog(owner,
ae.getMessage(),
"Configuration Data Error",
JOptionPane.ERROR_MESSAGE);
}
}
public void actionPerformed(ActionEvent e) {
String cmd = e.getActionCommand();
try {
if (cmd.equals("Save")) {
save_data();
} else if (cmd.equals("Reset")) {
set_ui();
} else if (cmd.equals("Reboot")) {
if (serial_line != null)
run_serial_thread(serial_mode_reboot);
} else if (cmd.equals("Close")) {
if (serial_line != null)
serial_line.close();
}
else if (cmd.equals("Accel")) {
if (data.pad_orientation != AltosLib.MISSING) {
AltosUIAccelCal accel_ui = new AltosUIAccelCal(owner, serial_line, config_ui);
if (accel_ui != null)
accel_ui.doit();
}
}
} catch (InterruptedException ie) {
abort();
} catch (TimeoutException te) {
abort();
}
}
public AltosConfigFC(JFrame given_owner) {
owner = given_owner;
device = AltosDeviceUIDialog.show(owner, Altos.product_any);
if (device != null) {
try {
serial_line = new AltosSerial(device);
try {
if (device.matchProduct(Altos.product_basestation))
remote = true;
init_ui();
} catch (InterruptedException ie) {
abort();
} catch (TimeoutException te) {
abort();
}
} catch (FileNotFoundException ee) {
JOptionPane.showMessageDialog(owner,
ee.getMessage(),
"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);
}
}
}
}

1777
altosui/AltosConfigFCUI.java Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,477 @@
/*
* Copyright © 2012 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; 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.
*/
package altosui;
import java.text.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import org.altusmetrum.altoslib_14.*;
import org.altusmetrum.altosuilib_14.*;
public class AltosConfigPyroUI
extends AltosUIDialog
implements ItemListener, DocumentListener, AltosUnitsListener, ActionListener
{
AltosConfigFCUI owner;
Container pane;
static Insets il = new Insets(4,4,4,4);
static Insets ir = new Insets(4,4,4,4);
static String[] state_names;
static void make_state_names() {
if (state_names == null) {
state_names = new String[AltosLib.ao_flight_landed - AltosLib.ao_flight_boost + 1];
for (int state = AltosLib.ao_flight_boost; state <= AltosLib.ao_flight_landed; state++)
state_names[state - AltosLib.ao_flight_boost] = AltosLib.state_name_capital(state);
}
}
class PyroItem implements ItemListener, DocumentListener, AltosUnitsListener
{
public int flag;
public JCheckBox enable;
public JTextField value;
public JComboBox<String> combo;
AltosConfigPyroUI ui;
boolean setting;
public void set_enable(boolean enable) {
if (value != null)
value.setEnabled(enable);
if (combo != null)
combo.setEnabled(enable);
}
public void itemStateChanged(ItemEvent e) {
set_enable(enable.isSelected());
if (!setting)
ui.set_dirty();
}
public void changedUpdate(DocumentEvent e) {
if (!setting)
ui.set_dirty();
}
public void insertUpdate(DocumentEvent e) {
if (!setting)
ui.set_dirty();
}
public void removeUpdate(DocumentEvent e) {
if (!setting)
ui.set_dirty();
}
public void units_changed(boolean imperial_units) {
AltosUnits units = AltosPyro.pyro_to_units(flag);
if (units != null) {
try {
double v = units.parse_locale(value.getText(), !imperial_units);
set(enabled(), v);
} catch (ParseException pe) {
set(enabled(), 0.0);
}
}
}
public void set(boolean new_enable, double new_value) {
setting = true;
enable.setSelected(new_enable);
set_enable(new_enable);
if (value != null) {
double scale = AltosPyro.pyro_to_scale(flag);
double unit_value = new_value;
AltosUnits units = AltosPyro.pyro_to_units(flag);
if (units != null)
unit_value = units.parse_value(new_value);
String format;
if (scale >= 100)
format = "%6.2f";
else if (scale >= 10)
format = "%6.1f";
else
format = "%6.0f";
value.setText(String.format(format, unit_value));
}
if (combo != null)
if (new_value >= AltosLib.ao_flight_boost && new_value <= AltosLib.ao_flight_landed)
combo.setSelectedIndex((int) new_value - AltosLib.ao_flight_boost);
setting = false;
}
public boolean enabled() {
return enable.isSelected();
}
public double value() throws AltosConfigDataException {
if (value != null) {
AltosUnits units = AltosPyro.pyro_to_units(flag);
try {
if (units != null)
return units.parse_locale(value.getText());
return AltosParse.parse_double_locale(value.getText());
} catch (ParseException e) {
throw new AltosConfigDataException("\"%s\": %s\n", value.getText(), e.getMessage());
}
}
if (combo != null)
return combo.getSelectedIndex() + AltosLib.ao_flight_boost;
return 0;
}
public PyroItem(AltosConfigPyroUI in_ui, int in_flag, int x, int y) {
ui = in_ui;
flag = in_flag;
GridBagConstraints c;
c = new GridBagConstraints();
c.gridx = x; c.gridy = y;
c.gridwidth = 1;
c.fill = GridBagConstraints.NONE;
c.anchor = GridBagConstraints.LINE_START;
c.insets = il;
enable = new JCheckBox();
enable.addItemListener(this);
pane.add(enable, c);
if ((flag & AltosPyro.pyro_no_value) == 0) {
c = new GridBagConstraints();
c.gridx = x+1; c.gridy = y;
c.gridwidth = 1;
c.fill = GridBagConstraints.NONE;
c.anchor = GridBagConstraints.LINE_START;
c.insets = il;
if ((flag & AltosPyro.pyro_state_value) != 0) {
make_state_names();
combo = new JComboBox<String>(state_names);
combo.addItemListener(this);
pane.add(combo, c);
} else {
value = new JTextField(10);
value.getDocument().addDocumentListener(this);
pane.add(value, c);
}
}
}
}
class PyroColumn implements AltosUnitsListener {
public PyroItem[] items;
public JLabel label;
int channel;
public void set(AltosPyro pyro) {
int row = 0;
if ((pyro.flags & AltosPyro.pyro_deprecate) != 0) {
JOptionPane.showMessageDialog(owner,
String.format("Pyro settings “Ascending” and “Descending” are deprecated.\n" +
"Clearing %s configuration.", AltosLib.igniter_name(pyro.channel)),
"Deprecated Pyro Settings",
JOptionPane.ERROR_MESSAGE);
pyro.flags = 0;
owner.set_dirty();
}
for (int flag = 1; flag < AltosPyro.pyro_all; flag <<= 1) {
if ((AltosPyro.pyro_all_useful & flag) != 0) {
items[row].set((pyro.flags & flag) != 0,
pyro.get_value(flag));
row++;
}
}
}
public AltosPyro get() throws AltosConfigDataException {
AltosPyro p = new AltosPyro(channel);
int row = 0;
for (int flag = 1; flag < AltosPyro.pyro_all; flag <<= 1) {
if ((AltosPyro.pyro_all_useful & flag) != 0) {
if (items[row].enabled()) {
try {
p.flags |= flag;
p.set_value(flag, items[row].value());
} catch (AltosConfigDataException ae) {
throw new AltosConfigDataException("%s, %s",
AltosPyro.pyro_to_name(flag),
ae.getMessage());
}
}
row++;
}
}
return p;
}
public void units_changed(boolean imperial_units) {
int row = 0;
for (int flag = 1; flag < AltosPyro.pyro_all; flag <<= 1) {
if ((AltosPyro.pyro_all_useful & flag) != 0) {
items[row].units_changed(imperial_units);
row++;
}
}
}
public PyroColumn(AltosConfigPyroUI ui, int x, int y, int in_channel) {
channel = in_channel;
int nrow = 0;
for (int flag = 1; flag < AltosPyro.pyro_all; flag <<= 1)
if ((flag & AltosPyro.pyro_all_useful) != 0)
nrow++;
items = new PyroItem[nrow];
int row = 0;
GridBagConstraints c;
c = new GridBagConstraints();
c.gridx = x; c.gridy = y;
c.gridwidth = 2;
c.fill = GridBagConstraints.NONE;
c.anchor = GridBagConstraints.CENTER;
c.insets = il;
label = new JLabel(String.format("Pyro Channel %c", 'A' + channel));
pane.add(label, c);
y++;
for (int flag = 1; flag < AltosPyro.pyro_all; flag <<= 1)
if ((flag & AltosPyro.pyro_all_useful) != 0) {
items[row] = new PyroItem(ui, flag, x, y + row);
row++;
}
}
}
PyroColumn[] columns;
JLabel[] labels;
public void set_pyros(AltosPyro[] pyros) {
for (int i = 0; i < pyros.length; i++) {
if (pyros[i].channel < columns.length)
columns[pyros[i].channel].set(pyros[i]);
}
}
public AltosPyro[] get_pyros() throws AltosConfigDataException {
AltosPyro[] pyros = new AltosPyro[columns.length];
for (int c = 0; c < columns.length; c++) {
try {
pyros[c] = columns[c].get();
} catch (AltosConfigDataException ae) {
throw new AltosConfigDataException ("Channel %c, %s", c + 'A', ae.getMessage());
}
}
return pyros;
}
JLabel pyro_firing_time_label;
JComboBox<String> pyro_firing_time_value;
static String[] pyro_firing_time_values = {
"0.050", "0.100", "0.250", "0.500", "1.0", "2.0"
};
boolean initializing;
public void set_pyro_firing_time(double new_pyro_firing_time) {
initializing = true;
pyro_firing_time_value.setSelectedItem(Double.toString(new_pyro_firing_time));
pyro_firing_time_value.setEnabled(new_pyro_firing_time >= 0);
initializing = false;
}
public double get_pyro_firing_time() throws AltosConfigDataException {
String v = pyro_firing_time_value.getSelectedItem().toString();
try {
return AltosParse.parse_double_locale(v);
} catch (ParseException e) {
throw new AltosConfigDataException("Invalid pyro firing time \"%s\"", v);
}
}
public void set_dirty() {
if (!initializing)
owner.set_dirty();
}
public void itemStateChanged(ItemEvent e) {
if (!initializing)
owner.set_dirty();
}
public void changedUpdate(DocumentEvent e) {
if (!initializing)
owner.set_dirty();
}
public void insertUpdate(DocumentEvent e) {
if (!initializing)
owner.set_dirty();
}
public void removeUpdate(DocumentEvent e) {
if (!initializing)
owner.set_dirty();
}
public void units_changed(boolean imperial_units) {
for (int c = 0; c < columns.length; c++)
columns[c].units_changed(imperial_units);
int r = 0;
for (int flag = 1; flag <= AltosPyro.pyro_all; flag <<= 1) {
if ((flag & AltosPyro.pyro_all_useful) != 0) {
String n = AltosPyro.pyro_to_name(flag);
if (n != null) {
labels[r].setText(n);
r++;
}
}
}
}
/* A window listener to catch closing events and tell the config code */
class ConfigListener extends WindowAdapter {
AltosConfigPyroUI ui;
AltosConfigFCUI owner;
public ConfigListener(AltosConfigPyroUI this_ui, AltosConfigFCUI this_owner) {
ui = this_ui;
owner = this_owner;
}
public void windowClosing(WindowEvent e) {
ui.setVisible(false);
}
}
/* Listen for events from our buttons */
public void actionPerformed(ActionEvent e) {
String cmd = e.getActionCommand();
if (cmd.equals("Close"))
setVisible(false);
}
public AltosConfigPyroUI(AltosConfigFCUI in_owner, AltosPyro[] pyros, double pyro_firing_time) {
super(in_owner, "Configure Pyro Channels", false);
owner = in_owner;
GridBagConstraints c;
pane = getScrollablePane();
pane.setLayout(new GridBagLayout());
int nrow = 0;
for (int flag = 1; flag < AltosPyro.pyro_all; flag <<= 1)
if ((flag & AltosPyro.pyro_all_useful) != 0)
nrow++;
labels = new JLabel[nrow];
int row = 1;
for (int flag = 1; flag <= AltosPyro.pyro_all; flag <<= 1) {
String n;
if ((flag & AltosPyro.pyro_all_useful) != 0) {
n = AltosPyro.pyro_to_name(flag);
if (n != null) {
c = new GridBagConstraints();
c.gridx = 0; c.gridy = row;
c.gridwidth = 1;
c.fill = GridBagConstraints.NONE;
c.anchor = GridBagConstraints.LINE_START;
c.insets = il;
JLabel label = new JLabel(n);
pane.add(label, c);
labels[row-1] = label;
row++;
}
}
}
columns = new PyroColumn[pyros.length];
for (int i = 0; i < pyros.length; i++) {
columns[i] = new PyroColumn(this, i*2 + 1, 0, i);
columns[i].set(pyros[i]);
}
/* Pyro firing time */
c = new GridBagConstraints();
c.gridx = 0; c.gridy = row;
c.gridwidth = 2;
c.fill = GridBagConstraints.NONE;
c.anchor = GridBagConstraints.LINE_START;
c.insets = il;
c.ipady = 5;
pyro_firing_time_label = new JLabel("Pyro Firing Time(s):");
pane.add(pyro_firing_time_label, c);
c = new GridBagConstraints();
c.gridx = 2; c.gridy = row;
c.gridwidth = 7;
c.fill = GridBagConstraints.HORIZONTAL;
c.weightx = 1;
c.anchor = GridBagConstraints.LINE_START;
c.insets = ir;
c.ipady = 5;
pyro_firing_time_value = new JComboBox<String>(pyro_firing_time_values);
pyro_firing_time_value.setEditable(true);
pyro_firing_time_value.addItemListener(this);
set_pyro_firing_time(pyro_firing_time);
pane.add(pyro_firing_time_value, c);
pyro_firing_time_value.setToolTipText("Length of extra pyro channel firing pulse");
c = new GridBagConstraints();
c.gridx = pyros.length*2-1;
c.fill = GridBagConstraints.HORIZONTAL;
c.gridwidth = 2;
c.gridy = 1000;
JButton close = new JButton("Close");
pane.add(close, c);
close.addActionListener(this);
close.setActionCommand("Close");
addWindowListener(new ConfigListener(this, owner));
AltosPreferences.register_units_listener(this);
}
public void dispose() {
AltosPreferences.unregister_units_listener(this);
super.dispose();
}
public void make_visible() {
pack();
setVisible(true);
}
}

380
altosui/AltosConfigTD.java Normal file
View File

@@ -0,0 +1,380 @@
/*
* 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; 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.
*/
package altosui;
import java.awt.event.*;
import javax.swing.*;
import java.io.*;
import java.util.concurrent.*;
import org.altusmetrum.altoslib_14.*;
import org.altusmetrum.altosuilib_14.*;
public class AltosConfigTD implements 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;
int_ref serial;
int_ref radio_channel;
int_ref radio_calibration;
int_ref radio_setting;
int_ref radio_frequency;
int_ref telemetry_rate;
string_ref config_version;
string_ref version;
string_ref product;
AltosConfigTDUI config_ui;
boolean made_visible;
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;
}
}
synchronized void update_ui() {
config_ui.set_serial(serial.get());
config_ui.set_product(product.get());
config_ui.set_version(version.get());
config_ui.set_radio_frequency(frequency());
config_ui.set_radio_calibration(radio_calibration.get());
config_ui.set_telemetry_rate(telemetry_rate.get());
config_ui.set_clean();
if (!made_visible) {
made_visible = true;
config_ui.make_visible();
}
}
void finish_input(String line) {
if (line == null) {
abort();
return;
}
if (line.equals("all finished")) {
if (serial_line != null)
update_ui();
return;
}
}
synchronized void process_line(String line) {
if (line == null || line.equals("all finished")) {
final String last_line = line;
Runnable r = new Runnable() {
public void run() {
finish_input(last_line);
}
};
SwingUtilities.invokeLater(r);
} else {
get_string(line, "Config version", config_version);
get_int(line, "serial-number", serial);
get_int(line, "Radio channel:", radio_channel);
get_int(line, "Radio cal:", radio_calibration);
get_int(line, "Frequency:", radio_frequency);
get_int(line, "Radio setting:", radio_setting);
get_int(line, "Telemetry rate:", telemetry_rate);
get_string(line,"software-version", version);
get_string(line,"product", product);
}
}
synchronized void reset_data() {
serial.set(0);
radio_channel.set(0);
radio_setting.set(0);
radio_frequency.set(0);
radio_calibration.set(1186611);
telemetry_rate.set(Altos.ao_telemetry_rate_38400);
config_version.set("0.0");
version.set("unknown");
product.set("unknown");
}
synchronized double frequency() {
return AltosConvert.radio_to_frequency(radio_frequency.get(),
radio_setting.get(),
radio_calibration.get(),
radio_channel.get());
}
synchronized void set_frequency(double freq) {
int frequency = radio_frequency.get();
int setting = radio_setting.get();
if (frequency > 0) {
radio_frequency.set((int) Math.floor (freq * 1000 + 0.5));
} else if (setting > 0) {
radio_setting.set(AltosConvert.radio_frequency_to_setting(freq,
radio_calibration.get()));
radio_channel.set(0);
} else {
radio_channel.set(AltosConvert.radio_frequency_to_channel(freq));
}
}
synchronized int telemetry_rate() {
return telemetry_rate.get();
}
synchronized void set_telemetry_rate(int new_telemetry_rate){
int rate = telemetry_rate.get();
if (rate >= 0)
telemetry_rate.set(new_telemetry_rate);
}
final static int serial_mode_read = 0;
final static int serial_mode_save = 1;
final static int serial_mode_reboot = 2;
SerialData serial_data;
Thread serial_thread;
class SerialData implements Runnable {
AltosConfigTD config;
int serial_mode;
void get_data() {
try {
boolean been_there = false;
config.reset_data();
while (config.serial_line != null) {
config.serial_line.printf("c s\nf\nv\n");
while (config.serial_line != null) {
try {
String line = config.serial_line.get_reply(5000);
config.process_line(line);
if (line != null && line.startsWith("software-version"))
break;
} catch (Exception e) {
break;
}
}
if (been_there)
break;
if (!config_version.get().equals("0.0"))
break;
been_there = true;
if (config != null && config.serial_line != null) {
config.serial_line.printf("C\n ");
config.serial_line.flush_input();
}
}
} catch (InterruptedException ie) {
}
/*
* This makes sure the displayed frequency respects the limits that the
* available firmware version might place on the actual frequency
*/
config.set_frequency(AltosPreferences.frequency(serial.get()));
config.set_telemetry_rate(AltosPreferences.telemetry_rate(serial.get()));
config.process_line("all finished");
}
void save_data() {
double frequency = frequency();
if (frequency != 0)
AltosPreferences.set_frequency(serial.get(),
frequency);
AltosPreferences.set_telemetry_rate(serial.get(),
telemetry_rate());
}
public void run () {
switch (serial_mode) {
case serial_mode_save:
save_data();
/* fall through ... */
case serial_mode_read:
get_data();
serial_thread = null;
break;
}
}
public SerialData(AltosConfigTD in_config, int in_serial_mode) {
config = in_config;
serial_mode = in_serial_mode;
}
}
void run_serial_thread(int serial_mode) {
serial_data = new SerialData(this, serial_mode);
serial_thread = new Thread(serial_data);
serial_thread.start();
}
void abort_serial_thread() {
if (serial_thread != null) {
serial_thread.interrupt();
serial_thread = null;
}
}
void init_ui () throws InterruptedException, TimeoutException {
config_ui = new AltosConfigTDUI(owner);
config_ui.addActionListener(this);
serial_line.set_frame(owner);
set_ui();
}
void abort() {
abort_serial_thread();
if (serial_line != null) {
serial_line.close();
serial_line = null;
}
JOptionPane.showMessageDialog(owner,
String.format("Connection to \"%s\" failed",
device.toShortString()),
"Connection Failed",
JOptionPane.ERROR_MESSAGE);
config_ui.setVisible(false);
}
void set_ui() throws InterruptedException, TimeoutException {
if (serial_line != null)
run_serial_thread(serial_mode_read);
else
update_ui();
}
void save_data() {
double freq = config_ui.radio_frequency();
set_frequency(freq);
int telemetry_rate = config_ui.telemetry_rate();
set_telemetry_rate(telemetry_rate);
run_serial_thread(serial_mode_save);
}
public void actionPerformed(ActionEvent e) {
String cmd = e.getActionCommand();
try {
if (cmd.equals("Save")) {
save_data();
} else if (cmd.equals("Reset")) {
set_ui();
} else if (cmd.equals("Reboot")) {
if (serial_line != null)
run_serial_thread(serial_mode_reboot);
} else if (cmd.equals("Close")) {
if (serial_line != null)
serial_line.close();
}
} catch (InterruptedException ie) {
abort();
} catch (TimeoutException te) {
abort();
}
}
public AltosConfigTD(JFrame given_owner) {
owner = given_owner;
serial = new int_ref(0);
radio_channel = new int_ref(0);
radio_setting = new int_ref(0);
radio_frequency = new int_ref(0);
radio_calibration = new int_ref(1186611);
telemetry_rate = new int_ref(AltosLib.ao_telemetry_rate_38400);
config_version = new string_ref("0.0");
version = new string_ref("unknown");
product = new string_ref("unknown");
device = AltosDeviceUIDialog.show(owner, Altos.product_basestation);
if (device != null) {
try {
serial_line = new AltosSerial(device);
try {
init_ui();
} catch (InterruptedException ie) {
abort();
} catch (TimeoutException te) {
abort();
}
} catch (FileNotFoundException ee) {
JOptionPane.showMessageDialog(owner,
ee.getMessage(),
"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);
}
}
}
}

View File

@@ -0,0 +1,378 @@
/*
* 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; 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.
*/
package altosui;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import org.altusmetrum.altoslib_14.*;
import org.altusmetrum.altosuilib_14.*;
public class AltosConfigTDUI
extends AltosUIDialog
implements ActionListener, ItemListener, DocumentListener
{
Container pane;
Box box;
JLabel product_label;
JLabel version_label;
JLabel serial_label;
JLabel frequency_label;
JLabel radio_calibration_label;
JLabel radio_frequency_label;
JLabel rate_label;
public boolean dirty;
JFrame owner;
JLabel product_value;
JLabel version_value;
JLabel serial_value;
AltosUIFreqList radio_frequency_value;
JLabel radio_calibration_value;
AltosUIRateList rate_value;
JButton save;
JButton reset;
JButton reboot;
JButton close;
ActionListener listener;
/* A window listener to catch closing events and tell the config code */
class ConfigListener extends WindowAdapter {
AltosConfigTDUI ui;
public ConfigListener(AltosConfigTDUI 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 AltosConfigTDUI(JFrame in_owner) {
super (in_owner, "Configure TeleDongle", false);
owner = in_owner;
GridBagConstraints c;
Insets il = new Insets(4,4,4,4);
Insets ir = new Insets(4,4,4,4);
pane = getScrollablePane();
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);
/* Frequency */
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_frequency_label = new JLabel("Frequency:");
pane.add(radio_frequency_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_frequency_value = new AltosUIFreqList();
radio_frequency_value.addItemListener(this);
pane.add(radio_frequency_value, c);
radio_frequency_value.setToolTipText("Telemetry, RDF and packet frequency");
/* 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 JLabel(String.format("%d", 1186611));
pane.add(radio_calibration_value, c);
/* Telemetry Rate */
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;
rate_label = new JLabel("Telemetry Rate:");
pane.add(rate_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;
rate_value = new AltosUIRateList();
pane.add(rate_value, c);
/* Buttons */
c = new GridBagConstraints();
c.gridx = 0; c.gridy = 12;
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 = 12;
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 = 6; c.gridy = 12;
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) {
radio_frequency_value.set_product(product);
product_value.setText(product);
}
public void set_version(String version) {
version_value.setText(version);
}
public void set_serial(int serial) {
radio_frequency_value.set_serial(serial);
serial_value.setText(String.format("%d", serial));
}
public void set_radio_frequency(double new_radio_frequency) {
int i;
for (i = 0; i < radio_frequency_value.getItemCount(); i++) {
AltosFrequency f = (AltosFrequency) radio_frequency_value.getItemAt(i);
if (f.close(new_radio_frequency)) {
radio_frequency_value.setSelectedIndex(i);
return;
}
}
for (i = 0; i < radio_frequency_value.getItemCount(); i++) {
AltosFrequency f = (AltosFrequency) radio_frequency_value.getItemAt(i);
if (new_radio_frequency < f.frequency)
break;
}
String description = String.format("%s serial %s",
product_value.getText(),
serial_value.getText());
AltosFrequency new_frequency = new AltosFrequency(new_radio_frequency, description);
AltosPreferences.add_common_frequency(new_frequency);
radio_frequency_value.insertItemAt(new_frequency, i);
radio_frequency_value.setSelectedIndex(i);
}
public double radio_frequency() {
return radio_frequency_value.frequency();
}
public void set_radio_calibration(int calibration) {
radio_calibration_value.setText(String.format("%d", calibration));
}
public int telemetry_rate() {
return rate_value.getSelectedIndex();
}
public void set_telemetry_rate(int rate) {
rate_value.setSelectedIndex(rate);
}
public void set_clean() {
dirty = false;
}
}

View File

@@ -0,0 +1,157 @@
/*
* 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; 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.
*/
package altosui;
import java.awt.*;
import java.awt.event.*;
import java.beans.*;
import javax.swing.*;
import javax.swing.event.*;
import org.altusmetrum.altosuilib_14.*;
public class AltosConfigureUI
extends AltosUIConfigure
implements DocumentListener
{
AltosVoice voice;
public JTextField callsign_value;
public JComboBox<String> position_value;
/* DocumentListener interface methods */
public void insertUpdate(DocumentEvent e) {
changedUpdate(e);
}
public void removeUpdate(DocumentEvent e) {
changedUpdate(e);
}
public void changedUpdate(DocumentEvent e) {
if (callsign_value != null)
AltosUIPreferences.set_callsign(callsign_value.getText());
}
public void add_voice() {
/* Voice settings */
pane.add(new JLabel("Voice"), constraints(0, 1));
JRadioButton enable_voice = new JRadioButton("Enable", AltosUIPreferences.voice());
enable_voice.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
JRadioButton item = (JRadioButton) e.getSource();
boolean enabled = item.isSelected();
AltosUIPreferences.set_voice(enabled);
if (enabled)
voice.speak_always("Enable voice.");
else
voice.speak_always("Disable voice.");
}
});
pane.add(enable_voice, constraints(1, 1));
enable_voice.setToolTipText("Enable/Disable all audio in-flight announcements");
JButton 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, constraints(2, 1));
test_voice.setToolTipText("Play a stock audio clip to check volume");
row++;
}
public void add_callsign() {
/* Callsign setting */
pane.add(new JLabel("Callsign"), constraints(0, 1));
callsign_value = new JTextField(AltosUIPreferences.callsign());
callsign_value.getDocument().addDocumentListener(this);
callsign_value.setToolTipText("Callsign sent in packet mode");
pane.add(callsign_value, constraints(1, 2, GridBagConstraints.BOTH));
row++;
}
boolean has_bluetooth;
public void add_bluetooth() {
JButton manage_bluetooth = new JButton("Manage Bluetooth");
manage_bluetooth.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
AltosBTManage.show(owner, AltosBTKnown.bt_known());
}
});
pane.add(manage_bluetooth, constraints(0, 2));
/* in the same row as add_frequencies, so don't bump row */
has_bluetooth = true;
}
public void add_frequencies() {
JButton manage_frequencies = new JButton("Manage Frequencies");
manage_frequencies.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
AltosConfigFreqUI.show(owner);
}
});
manage_frequencies.setToolTipText("Configure which values are shown in frequency menus");
if (has_bluetooth)
pane.add(manage_frequencies, constraints(2, 1));
else
pane.add(manage_frequencies, constraints(0, 3));
row++;
}
final static String[] position_names = {
"Top left",
"Top",
"Top right",
"Left",
"Center",
"Right",
"Bottom left",
"Bottom",
"Bottom right",
};
public void add_position() {
pane.add(new JLabel ("Menu position"), constraints(0, 1));
position_value = new JComboBox<String>(position_names);
position_value.setMaximumRowCount(position_names.length);
int position = AltosUIPreferences.position();
position_value.setSelectedIndex(position);
position_value.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
int position = position_value.getSelectedIndex();
AltosUIPreferences.set_position(position);
}
});
pane.add(position_value, constraints(1, 2, GridBagConstraints.BOTH));
position_value.setToolTipText("Position of main AltosUI window");
row++;
}
public AltosConfigureUI(JFrame owner, AltosVoice voice) {
super(owner);
this.voice = voice;
}
}

165
altosui/AltosDescent.java Normal file
View File

@@ -0,0 +1,165 @@
/*
* 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; 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.
*/
package altosui;
import java.util.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import org.altusmetrum.altoslib_14.*;
import org.altusmetrum.altosuilib_14.*;
public class AltosDescent extends AltosUIFlightTab {
class Height extends AltosUIUnitsIndicator {
public double value(AltosState state, int i) { return state.height(); }
public Height (Container container, int x, int y) {
super (container, x, y, AltosConvert.height, "Height");
}
}
class Speed extends AltosUIUnitsIndicator {
public double value(AltosState state, int i) { return state.speed(); }
public Speed (Container container, int x, int y) {
super (container, x, y, AltosConvert.speed, "Speed");
}
}
class Lat extends AltosUIUnitsIndicator {
public boolean hide (AltosState state, int i) { return state.gps == null || !state.gps.connected; }
public double value(AltosState state, int i) {
if (state.gps == null)
return AltosLib.MISSING;
if (!state.gps.connected)
return AltosLib.MISSING;
return state.gps.lat;
}
public Lat (Container container, int x, int y) {
super (container, x, y, AltosConvert.latitude, "Latitude");
}
}
class Lon extends AltosUIUnitsIndicator {
public boolean hide (AltosState state, int i) { return state.gps == null || !state.gps.connected; }
public double value(AltosState state, int i) {
if (state.gps == null)
return AltosLib.MISSING;
if (!state.gps.connected)
return AltosLib.MISSING;
return state.gps.lon;
}
public Lon (Container container, int x, int y) {
super (container, x, y, AltosConvert.longitude, "Longitude");
}
}
class Apogee extends AltosUIUnitsIndicator {
public boolean hide(double v) { return v == AltosLib.MISSING; }
public double value(AltosState state, int i) { return state.apogee_voltage; }
public double good() { return AltosLib.ao_igniter_good; }
public Apogee (Container container, int y) {
super(container, 0, y, 3, AltosConvert.voltage, "Apogee Igniter Voltage", 1, true, 3);
}
}
class Main extends AltosUIUnitsIndicator {
public boolean hide(double v) { return v == AltosLib.MISSING; }
public double value(AltosState state, int i) { return state.main_voltage; }
public double good() { return AltosLib.ao_igniter_good; }
public Main (Container container, int y) {
super(container, 0, y, 3, AltosConvert.voltage, "Main Igniter Voltage", 1, true, 3);
}
}
class Distance extends AltosUIUnitsIndicator {
public double value(AltosState state, int i) {
if (state.from_pad != null)
return state.from_pad.distance;
else
return AltosLib.MISSING;
}
public Distance(Container container, int x, int y) {
super(container, x, y, AltosConvert.distance, "Ground Distance");
}
}
class Range extends AltosUIUnitsIndicator {
public double value(AltosState state, int i) {
return state.range;
}
public Range (Container container, int x, int y) {
super (container, x, y, AltosConvert.distance, "Range");
}
}
class Bearing extends AltosUIIndicator {
public void show (AltosState state, AltosListenerState listener_state) {
if (state.from_pad != null && state.from_pad.bearing != AltosLib.MISSING) {
show( String.format("%3.0f°", state.from_pad.bearing),
state.from_pad.bearing_words(
AltosGreatCircle.BEARING_LONG));
} else {
show("Missing", "Missing");
}
}
public Bearing (Container container, int x, int y) {
super (container, x, y, 1, "Bearing", 2, false, 1, 2);
}
}
class Elevation extends AltosUIIndicator {
public void show (AltosState state, AltosListenerState listener_state) {
if (state.elevation == AltosLib.MISSING)
show("Missing");
else
show("%3.0f°", state.elevation);
}
public Elevation (Container container, int x, int y) {
super (container, x, y, "Elevation", 1, false, 1);
}
}
public String getName() {
return "Descent";
}
public AltosDescent() {
/* Elements in descent display */
add(new Speed(this, 0, 0));
add(new Height(this, 2, 0));
add(new Elevation(this, 0, 1));
add(new Range(this, 2, 1));
add(new Bearing(this, 0, 2));
add(new Distance(this, 0, 3));
add(new Lat(this, 0, 4));
add(new Lon(this, 2, 4));
add(new Apogee(this, 5));
add(new Main(this, 6));
}
}

30
altosui/AltosDevice.java Normal file
View File

@@ -0,0 +1,30 @@
/*
* Copyright © 2011 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; 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.
*/
package altosui;
import libaltosJNI.*;
public interface AltosDevice {
public abstract String toString();
public abstract String toShortString();
public abstract int getSerial();
public abstract String getPath();
public abstract boolean matchProduct(int product);
public abstract String getErrorString();
public SWIGTYPE_p_altos_file open();
}

View File

@@ -0,0 +1,325 @@
/*
* 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; 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.
*/
package altosui;
import java.awt.*;
import javax.swing.*;
import org.altusmetrum.altoslib_14.*;
import org.altusmetrum.altosuilib_14.*;
public class AltosFlightStatus extends JComponent implements AltosFlightDisplay {
GridBagLayout layout;
public abstract class FlightValue {
JLabel label;
JTextField value;
void show() {
label.setVisible(true);
value.setVisible(true);
}
void hide() {
label.setVisible(false);
value.setVisible(false);
}
abstract void show(AltosState state, AltosListenerState listener_state);
void reset() {
value.setText("");
}
void set_font() {
label.setFont(Altos.status_font);
value.setFont(Altos.status_font);
}
void setVisible(boolean visible) {
label.setVisible(visible);
value.setVisible(visible);
}
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.setEditable(false);
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 {
String last_call = "";
boolean same_call(String call) {
if (last_call == null)
return call == null;
else
return last_call.equals(call);
}
void show(AltosState state, AltosListenerState listener_state) {
if (!same_call(state.cal_data().callsign)) {
show();
value.setText(state.cal_data().callsign);
if (state.cal_data().callsign == null)
setVisible(false);
else
setVisible(true);
last_call = state.cal_data().callsign;
}
}
public void reset() {
super.reset();
last_call = "";
}
public Call (GridBagLayout layout, int x) {
super (layout, x, "Callsign");
}
}
Call call;
class Serial extends FlightValue {
int last_serial = -1;
void show(AltosState state, AltosListenerState listener_state) {
AltosCalData cal_data = state.cal_data();
if (cal_data.serial != last_serial) {
show();
if (cal_data.serial == AltosLib.MISSING)
value.setText("none");
else
value.setText(String.format("%d", cal_data.serial));
last_serial = cal_data.serial;
}
}
public void reset() {
super.reset();
last_serial = -1;
}
public Serial (GridBagLayout layout, int x) {
super (layout, x, "Serial");
}
}
Serial serial;
class Flight extends FlightValue {
int last_flight = -1;
void show(AltosState state, AltosListenerState listener_state) {
AltosCalData cal_data = state.cal_data();
if (cal_data.flight != last_flight) {
show();
if (cal_data.flight == AltosLib.MISSING)
value.setText("none");
else
value.setText(String.format("%d", cal_data.flight));
last_flight = cal_data.flight;
}
}
public void reset() {
super.reset();
last_flight = -1;
}
public Flight (GridBagLayout layout, int x) {
super (layout, x, "Flight");
}
}
Flight flight;
class FlightState extends FlightValue {
int last_state = -1;
void show(AltosState state, AltosListenerState listener_state) {
if (state.state() != last_state) {
if (state.state() == AltosLib.ao_flight_stateless)
hide();
else {
show();
value.setText(state.state_name());
}
last_state = state.state();
}
}
public void reset() {
super.reset();
last_state = -1;
}
public FlightState (GridBagLayout layout, int x) {
super (layout, x, "State");
}
}
FlightState flight_state;
class RSSI extends FlightValue {
int last_rssi = 10000;
void show(AltosState state, AltosListenerState listener_state) {
if (state.rssi() != last_rssi) {
show();
value.setText(String.format("%d", state.rssi()));
if (state.rssi == AltosLib.MISSING)
setVisible(false);
else
setVisible(true);
last_rssi = state.rssi();
}
}
public void reset() {
super.reset();
last_rssi = 10000;
}
public RSSI (GridBagLayout layout, int x) {
super (layout, x, "RSSI");
}
}
RSSI rssi;
class LastPacket extends FlightValue {
long last_secs = -1;
void show(AltosState state, AltosListenerState listener_state) {
if (listener_state.running) {
long secs = (System.currentTimeMillis() - state.received_time + 500) / 1000;
if (secs != last_secs) {
value.setText(String.format("%d", secs));
last_secs = secs;
}
} else {
value.setText("done");
}
}
public void reset() {
super.reset();
last_secs = -1;
}
public LastPacket(GridBagLayout layout, int x) {
super (layout, x, "Age");
}
}
LastPacket last_packet;
public void reset () {
call.reset();
serial.reset();
flight.reset();
flight_state.reset();
rssi.reset();
last_packet.reset();
}
public void font_size_changed(int font_size) {
call.set_font();
serial.set_font();
flight.set_font();
flight_state.set_font();
rssi.set_font();
last_packet.set_font();
}
public void units_changed(boolean imperial_units) {
}
public void show (AltosState state, AltosListenerState listener_state) {
call.show(state, listener_state);
serial.show(state, listener_state);
flight.show(state, listener_state);
flight_state.show(state, listener_state);
rssi.show(state, listener_state);
last_packet.show(state, listener_state);
if (!listener_state.running)
stop();
}
public int height() {
Dimension d = layout.preferredLayoutSize(this);
return d.height;
}
public String getName() { return "Flight Status"; }
AltosFlightStatusUpdate status_update;
javax.swing.Timer timer;
public void start(AltosFlightStatusUpdate status_update) {
this.status_update = status_update;
timer = new javax.swing.Timer(100, status_update);
timer.start();
}
public void stop() {
if (timer != null) {
timer.stop();
timer = null;
}
}
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);
last_packet = new LastPacket(layout, 5);
}
}

View File

@@ -0,0 +1,69 @@
/*
* 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; 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.
*/
/*
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 org.altusmetrum.altoslib_14.*;
public class AltosFlightStatusTableModel extends AbstractTableModel {
private String[] columnNames = {
String.format("Height (%s)", AltosConvert.show_distance_units()),
"State",
"RSSI (dBm)",
String.format("Speed (%s)", AltosConvert.show_speed_unit())
};
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", AltosConvert.distance(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", AltosConvert.speed(speed)), 3);
}
}
*/

View File

@@ -0,0 +1,42 @@
/*
* Copyright © 2012 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; 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.
*/
package altosui;
import java.awt.event.*;
import org.altusmetrum.altoslib_14.*;
public class AltosFlightStatusUpdate implements ActionListener {
public AltosState saved_state;
public AltosListenerState saved_listener_state;
AltosFlightStatus flightStatus;
public void actionPerformed (ActionEvent e) {
if (saved_state != null) {
if (saved_listener_state == null)
saved_listener_state = new AltosListenerState();
flightStatus.show(saved_state, saved_listener_state);
}
}
public AltosFlightStatusUpdate (AltosFlightStatus in_flightStatus) {
flightStatus = in_flightStatus;
}
}

333
altosui/AltosFlightUI.java Normal file
View File

@@ -0,0 +1,333 @@
/*
* 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; 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.
*/
package altosui;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.*;
import java.util.concurrent.*;
import org.altusmetrum.altoslib_14.*;
import org.altusmetrum.altosuilib_14.*;
public class AltosFlightUI extends AltosUIFrame implements AltosFlightDisplay {
AltosVoice voice;
AltosFlightReader reader;
AltosDisplayThread thread;
LinkedList<AltosFlightDisplay> displays;
JTabbedPane pane;
AltosPad pad;
AltosIgnitor igniter;
AltosAscent ascent;
AltosDescent descent;
AltosLanded landed;
AltosCompanionInfo companion;
AltosUIMap sitemap;
boolean has_map;
boolean has_companion;
boolean has_state;
boolean has_igniter;
private AltosFlightStatus flightStatus;
private AltosInfoTable flightInfo;
boolean exit_on_close = false;
JComponent cur_tab = null;
JComponent which_tab(AltosState state) {
if (state.state() < Altos.ao_flight_boost)
return pad;
if (state.state() <= Altos.ao_flight_coast)
return ascent;
if (state.state() <= Altos.ao_flight_main)
return descent;
if (state.state() == AltosLib.ao_flight_stateless)
return descent;
return 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() {
for (AltosFlightDisplay d : displays)
d.reset();
}
public void font_size_changed(int font_size) {
for (AltosFlightDisplay d : displays)
d.font_size_changed(font_size);
}
public void units_changed(boolean imperial_units) {
for (AltosFlightDisplay d : displays)
d.units_changed(imperial_units);
}
AltosFlightStatusUpdate status_update;
public void show(AltosState state, AltosListenerState listener_state) {
status_update.saved_state = state;
status_update.saved_listener_state = listener_state;
if (state == null)
state = new AltosState(new AltosCalData());
if (state.state() != Altos.ao_flight_startup) {
if (!has_state) {
pane.setTitleAt(0, "Launch Pad");
pane.add(ascent, 1);
pane.add(descent, 2);
pane.add(landed, 3);
has_state = true;
}
}
JComponent tab = which_tab(state);
if (tab != cur_tab) {
if (cur_tab == pane.getSelectedComponent())
pane.setSelectedComponent(tab);
cur_tab = tab;
}
if (igniter.should_show(state)) {
if (!has_igniter) {
pane.add("Ignitor", igniter);
has_igniter = true;
}
} else {
if (has_igniter) {
pane.remove(igniter);
has_igniter = false;
}
}
if (state.companion != null) {
if (!has_companion) {
pane.add("Companion", companion);
has_companion= true;
}
} else {
if (has_companion) {
pane.remove(companion);
has_companion = false;
}
}
if (state.gps != null) {
if (!has_map) {
pane.add("Site Map", sitemap);
has_map = true;
}
} else {
if (has_map) {
pane.remove(sitemap);
has_map = false;
}
}
for (AltosFlightDisplay d : displays) {
try {
d.show(state, listener_state);
} catch (Exception e) {
System.out.printf("Exception showing %s\n", d.getName());
e.printStackTrace();
}
}
}
public void set_exit_on_close() {
exit_on_close = true;
}
Container bag;
AltosUIFreqList frequencies;
AltosUIRateList rates;
AltosUITelemetryList telemetries;
JLabel telemetry;
ActionListener show_timer;
public AltosFlightUI(AltosVoice in_voice, AltosFlightReader in_reader, final int serial) {
AltosUIPreferences.set_component(this);
displays = new LinkedList<AltosFlightDisplay>();
voice = in_voice;
reader = in_reader;
bag = getScrollablePane();
bag.setLayout(new GridBagLayout());
setTitle(String.format("AltOS %s", reader.name));
/* Stick channel selector at top of table for telemetry monitoring */
if (serial >= 0) {
set_inset(3);
// Frequency menu
frequencies = new AltosUIFreqList(AltosUIPreferences.frequency(serial));
frequencies.set_product("Monitor");
frequencies.set_serial(serial);
frequencies.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
double frequency = frequencies.frequency();
try {
reader.set_frequency(frequency);
} catch (TimeoutException te) {
} catch (InterruptedException ie) {
}
reader.save_frequency();
}
});
bag.add (frequencies, constraints(0, 1));
// Telemetry rate list
rates = new AltosUIRateList(AltosUIPreferences.telemetry_rate(serial));
rates.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
int rate = rates.rate();
try {
reader.set_telemetry_rate(rate);
} catch (TimeoutException te) {
} catch (InterruptedException ie) {
}
reader.save_telemetry_rate();
}
});
rates.setEnabled(reader.supports_telemetry_rate(AltosLib.ao_telemetry_rate_2400));
bag.add (rates, constraints(1, 1));
// Telemetry format list
if (reader.supports_telemetry(Altos.ao_telemetry_standard)) {
telemetries = new AltosUITelemetryList(serial);
telemetries.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
int telemetry = telemetries.get_selected();
reader.set_telemetry(telemetry);
reader.save_telemetry();
}
});
bag.add (telemetries, constraints(2, 1));
} else {
String version;
if (reader.supports_telemetry(Altos.ao_telemetry_0_9))
version = "Telemetry: 0.9";
else if (reader.supports_telemetry(Altos.ao_telemetry_0_8))
version = "Telemetry: 0.8";
else
version = "Telemetry: None";
telemetry = new JLabel(version);
bag.add (telemetry, constraints(2, 1));
}
next_row();
}
set_inset(0);
/* Flight status is always visible */
flightStatus = new AltosFlightStatus();
displays.add(flightStatus);
bag.add(flightStatus, constraints(0, 4, GridBagConstraints.HORIZONTAL));
next_row();
/* The rest of the window uses a tabbed pane to
* show one of the alternate data views
*/
pane = new JTabbedPane();
pad = new AltosPad();
displays.add(pad);
pane.add("Status", pad);
igniter = new AltosIgnitor();
displays.add(igniter);
ascent = new AltosAscent();
displays.add(ascent);
descent = new AltosDescent();
displays.add(descent);
landed = new AltosLanded(reader);
displays.add(landed);
flightInfo = new AltosInfoTable();
displays.add(flightInfo);
pane.add("Table", new JScrollPane(flightInfo));
companion = new AltosCompanionInfo();
displays.add(companion);
has_companion = false;
has_state = false;
sitemap = new AltosUIMap();
displays.add(sitemap);
has_map = false;
/* Make the tabbed pane use the rest of the window space */
bag.add(pane, constraints(0, 4, GridBagConstraints.BOTH));
setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
AltosUIPreferences.register_font_listener(this);
AltosPreferences.register_units_listener(this);
status_update = new AltosFlightStatusUpdate(flightStatus);
flightStatus.start(status_update);
addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
flightStatus.stop();
disconnect();
setVisible(false);
dispose();
AltosUIPreferences.unregister_font_listener(AltosFlightUI.this);
AltosPreferences.unregister_units_listener(AltosFlightUI.this);
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);
}
}

154
altosui/AltosGraphUI.java Normal file
View File

@@ -0,0 +1,154 @@
/*
* Copyright © 2010 Anthony Towns
*
* 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.
*/
package altosui;
import java.io.*;
import java.util.ArrayList;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import org.altusmetrum.altoslib_14.*;
import org.altusmetrum.altosuilib_14.*;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.ui.RefineryUtilities;
public class AltosGraphUI extends AltosUIFrame implements AltosFontListener, AltosUnitsListener, AltosFilterListener
{
JTabbedPane pane;
AltosGraph graph;
AltosUIEnable enable;
AltosUIMap map;
AltosFlightStats stats;
AltosFlightStatsTable statsTable;
AltosGPS gps;
boolean has_gps;
void fill_map(AltosFlightSeries flight_series) {
boolean any_gps = false;
AltosGPSTimeValue gtv_last = null;
double gps_pad_altitude = flight_series.cal_data().gps_pad_altitude;;
if (flight_series.gps_series != null) {
for (AltosGPSTimeValue gtv : flight_series.gps_series) {
AltosGPS gps = gtv.gps;
if (gps != null &&
gps.locked &&
gps.nsat >= 4) {
if (map == null)
map = new AltosUIMap();
double gps_height = gps.alt - gps_pad_altitude;
int state = (int) flight_series.value_before(AltosFlightSeries.state_name, gtv.time);
map.show(gps, gtv.time, state, gps_height);
this.gps = gps;
gtv_last = gtv;
has_gps = true;
}
}
}
if (gtv_last != null) {
int state = (int) flight_series.value_after(AltosFlightSeries.state_name, gtv_last.time);
double gps_height = gps.alt - gps_pad_altitude;
if (state == AltosLib.ao_flight_landed)
map.show(gtv_last.gps, gtv_last.time, state,gps_height);
}
}
public void font_size_changed(int font_size) {
if (map != null)
map.font_size_changed(font_size);
if (statsTable != null)
statsTable.font_size_changed(font_size);
}
public void units_changed(boolean imperial_units) {
if (map != null)
map.units_changed(imperial_units);
if (enable != null)
enable.units_changed(imperial_units);
}
AltosUIFlightSeries flight_series;
public void filter_changed(double speed_filter, double accel_filter) {
flight_series.set_filter(speed_filter, accel_filter);
graph.filter_changed();
stats = new AltosFlightStats(flight_series);
statsTable.filter_changed(stats);
}
public double speed_filter() {
return flight_series.speed_filter_width;
}
public double accel_filter() {
return flight_series.accel_filter_width;
}
AltosGraphUI(AltosRecordSet set, File file) throws InterruptedException, IOException {
super(file.getName());
AltosCalData cal_data = set.cal_data();
pane = new JTabbedPane();
flight_series = new AltosUIFlightSeries(cal_data);
enable = new AltosUIEnable(this);
set.capture_series(flight_series);
flight_series.finish();
stats = new AltosFlightStats(flight_series);
graph = new AltosGraph(enable, stats, flight_series);
statsTable = new AltosFlightStatsTable(stats);
pane.add("Flight Graph", graph.panel);
pane.add("Configure Graph", enable);
pane.add("Flight Statistics", statsTable);
has_gps = false;
fill_map(flight_series);
if (has_gps)
pane.add("Map", map);
setContentPane (pane);
AltosUIPreferences.register_font_listener(this);
AltosPreferences.register_units_listener(this);
addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
AltosUIPreferences.unregister_font_listener(AltosGraphUI.this);
AltosPreferences.unregister_units_listener(AltosGraphUI.this);
}
});
pack();
setVisible(true);
if (gps != null)
map.centre(gps);
}
}

View File

@@ -0,0 +1,308 @@
/*
* 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; 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.
*/
package altosui;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import java.io.*;
import java.util.concurrent.*;
import java.util.Arrays;
import org.altusmetrum.altoslib_14.*;
import org.altusmetrum.altosuilib_14.*;
public class AltosIdleMonitorUI extends AltosUIFrame implements AltosFlightDisplay, AltosIdleMonitorListener, DocumentListener {
AltosDevice device;
JTabbedPane pane;
AltosPad pad;
AltosInfoTable flightInfo;
AltosFlightStatus flightStatus;
AltosIgnitor igniter;
AltosIdleMonitor thread;
AltosUIMap sitemap;
int serial;
boolean remote;
boolean has_igniter;
boolean has_map;
void stop_display() {
if (thread != null) {
try {
thread.abort();
} catch (InterruptedException ie) {
}
}
thread = null;
}
void disconnect() {
stop_display();
}
public void reset() {
pad.reset();
flightInfo.clear();
}
public void font_size_changed(int font_size) {
pad.font_size_changed(font_size);
flightInfo.font_size_changed(font_size);
}
public void units_changed(boolean imperial_units) {
pad.units_changed(imperial_units);
flightInfo.units_changed(imperial_units);
}
AltosFlightStatusUpdate status_update;
public void show(AltosState state, AltosListenerState listener_state) {
status_update.saved_state = state;
if (igniter.should_show(state)) {
if (!has_igniter) {
pane.add("Ignitor", igniter);
has_igniter = true;
}
} else {
if (has_igniter) {
pane.remove(igniter);
has_igniter = false;
}
}
if (state.gps != null && state.gps.connected) {
if (!has_map) {
pane.add("Site Map", sitemap);
has_map = true;
}
} else {
if (has_map) {
pane.remove(sitemap);
has_map = false;
}
}
// try {
pad.show(state, listener_state);
flightStatus.show(state, listener_state);
flightInfo.show(state, listener_state);
if (has_igniter)
igniter.show(state, listener_state);
if (has_map)
sitemap.show(state, listener_state);
// } catch (Exception e) {
// System.out.print("Show exception " + e);
// }
}
public void update(final AltosState state, final AltosListenerState listener_state) {
Runnable r = new Runnable() {
public void run() {
show(state, listener_state);
}
};
SwingUtilities.invokeLater(r);
}
public void failed() {
Runnable r = new Runnable() {
public void run() {
close();
}
};
SwingUtilities.invokeLater(r);
}
public void error(final String reason) {
Runnable r = new Runnable() {
public void run() {
disconnect();
JOptionPane.showMessageDialog(AltosIdleMonitorUI.this,
reason,
"Error fetching data",
JOptionPane.ERROR_MESSAGE);
}
};
SwingUtilities.invokeLater(r);
}
Container bag;
AltosUIFreqList frequencies;
JTextField callsign_value;
/* DocumentListener interface methods */
public void changedUpdate(DocumentEvent e) {
if (callsign_value != null) {
String callsign = callsign_value.getText();
System.out.printf("callsign set to %s\n", callsign);
thread.set_callsign(callsign);
AltosUIPreferences.set_callsign(callsign);
}
}
public void insertUpdate(DocumentEvent e) {
changedUpdate(e);
}
public void removeUpdate(DocumentEvent e) {
changedUpdate(e);
}
void idle_exception(JFrame owner, Exception e) {
if (e instanceof FileNotFoundException) {
JOptionPane.showMessageDialog(owner,
((FileNotFoundException) e).getMessage(),
"Cannot open target device",
JOptionPane.ERROR_MESSAGE);
} else if (e instanceof AltosSerialInUseException) {
JOptionPane.showMessageDialog(owner,
String.format("Device \"%s\" already in use",
device.toShortString()),
"Device in use",
JOptionPane.ERROR_MESSAGE);
} else if (e instanceof IOException) {
IOException ee = (IOException) e;
JOptionPane.showMessageDialog(owner,
device.toShortString(),
ee.getLocalizedMessage(),
JOptionPane.ERROR_MESSAGE);
} else {
JOptionPane.showMessageDialog(owner,
String.format("Connection to \"%s\" failed",
device.toShortString()),
"Connection Failed",
JOptionPane.ERROR_MESSAGE);
}
}
private void close() {
try {
disconnect();
} catch (Exception ex) {
System.out.printf("Exception %s\n", ex.toString());
for (StackTraceElement el : ex.getStackTrace())
System.out.printf("%s\n", el.toString());
}
setVisible(false);
dispose();
AltosUIPreferences.unregister_font_listener(AltosIdleMonitorUI.this);
}
public AltosIdleMonitorUI(JFrame in_owner)
throws FileNotFoundException, TimeoutException, InterruptedException {
device = AltosDeviceUIDialog.show(in_owner, Altos.product_any);
remote = false;
if (device.matchProduct(Altos.product_basestation))
remote = true;
serial = device.getSerial();
AltosSerial link;
try {
link = new AltosSerial(device);
} catch (Exception ex) {
idle_exception(in_owner, ex);
return;
}
link.set_frame(this);
/* We let the user set the freq/callsign, so don't bother with the cancel dialog */
link.set_cancel_enable(false);
bag = getScrollablePane();
bag.setLayout(new GridBagLayout());
setTitle(String.format("AltOS %s", device.toShortString()));
/* Stick frequency selector at top of table for telemetry monitoring */
if (remote && serial >= 0) {
set_inset(3);
// Frequency menu
frequencies = new AltosUIFreqList(AltosUIPreferences.frequency(serial));
frequencies.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
double frequency = frequencies.frequency();
thread.set_frequency(frequency);
AltosUIPreferences.set_frequency(device.getSerial(),
frequency);
}
});
bag.add (frequencies, constraints(0, 1));
bag.add (new JLabel("Callsign:"), constraints(1, 1));
/* Add callsign configuration */
callsign_value = new JTextField(AltosUIPreferences.callsign());
callsign_value.getDocument().addDocumentListener(this);
callsign_value.setToolTipText("Callsign sent in packet mode");
bag.add(callsign_value, constraints(2, 1, GridBagConstraints.HORIZONTAL));
next_row();
}
set_inset(0);
/* Flight status is always visible */
flightStatus = new AltosFlightStatus();
bag.add(flightStatus, constraints(0, 4, GridBagConstraints.HORIZONTAL));
next_row();
/* 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);
flightInfo = new AltosInfoTable();
pane.add("Table", new JScrollPane(flightInfo));
igniter = new AltosIgnitor();
sitemap = new AltosUIMap();
/* Make the tabbed pane use the rest of the window space */
bag.add(pane, constraints(0, 4, GridBagConstraints.BOTH));
setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
AltosUIPreferences.register_font_listener(this);
addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
close();
}
});
pack();
setVisible(true);
thread = new AltosIdleMonitor(this, link, (boolean) remote);
thread.set_frequency(AltosUIPreferences.frequency(serial));
status_update = new AltosFlightStatusUpdate(flightStatus);
new javax.swing.Timer(100, status_update).start();
thread.start();
}
}

486
altosui/AltosIgniteUI.java Normal file
View File

@@ -0,0 +1,486 @@
/*
* 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; 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.
*/
package altosui;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.io.*;
import java.text.*;
import java.util.*;
import java.util.concurrent.*;
import org.altusmetrum.altoslib_14.*;
import org.altusmetrum.altosuilib_14.*;
public class AltosIgniteUI
extends AltosUIDialog
implements ActionListener
{
AltosDevice device;
JFrame owner;
JLabel label;
JToggleButton arm;
JButton fire;
javax.swing.Timer timer;
JButton close;
ButtonGroup group;
Boolean opened;
boolean has_standard;
int npyro;
final static int timeout = 1 * 1000;
int time_remaining;
boolean timer_running;
int poll_remaining;
LinkedBlockingQueue<String> command_queue;
class Igniter {
JRadioButton button;
JLabel status_label;
String name;
int status;
void set_status (int status) {
this.status = status;
status_label.setText(String.format("\"%s\"", AltosIgnite.status_string(status)));
}
Igniter(AltosIgniteUI ui, String label, String name, int y) {
Container pane = getScrollablePane();
GridBagConstraints c = new GridBagConstraints();
Insets i = new Insets(4,4,4,4);
this.name = name;
this.status = AltosIgnite.Unknown;
c.gridx = 0;
c.gridy = y;
c.gridwidth = 1;
c.anchor = GridBagConstraints.WEST;
button = new JRadioButton (label);
pane.add(button, c);
button.addActionListener(ui);
button.setActionCommand(name);
group.add(button);
c.gridx = 1;
c.gridy = y;
c.gridwidth = 1;
c.anchor = GridBagConstraints.WEST;
status_label = new JLabel("plenty of text");
pane.add(status_label, c);
status = AltosIgnite.Unknown;
}
}
Igniter igniters[];
void set_status(String _name, int _status) {
final String name = _name;
final int status = _status;
Runnable r = new Runnable() {
public void run() {
for (int p = 0; p < igniters.length; p++)
if (name.equals(igniters[p].name))
igniters[p].set_status(status);
}
};
SwingUtilities.invokeLater(r);
}
class IgniteHandler implements Runnable {
AltosIgnite ignite;
JFrame owner;
AltosLink link;
void send_exception(Exception e) {
final Exception f_e = e;
Runnable r = new Runnable() {
public void run() {
ignite_exception(f_e);
}
};
SwingUtilities.invokeLater(r);
}
public void run () {
try {
ignite = new AltosIgnite(link,
device.matchProduct(Altos.product_basestation));
} catch (Exception e) {
send_exception(e);
return;
}
for (;;) {
Runnable r;
try {
String command = command_queue.take();
String reply = null;
if (command.equals("get_status")) {
HashMap<String,Integer> status_map = ignite.status();
for (int p = 0; p < igniters.length; p++) {
Integer i = status_map.get(igniters[p].name);
if (i != null)
set_status(igniters[p].name, i);
}
reply = "status";
} else if (command.equals("get_npyro")) {
reply = String.format("npyro %d %d", ignite.npyro(), ignite.has_standard() ? 1 : 0);
} else if (command.equals("quit")) {
ignite.close();
break;
} else {
ignite.fire(command);
reply = "fired";
}
final String f_reply = reply;
r = new Runnable() {
public void run() {
ignite_reply(f_reply);
}
};
SwingUtilities.invokeLater(r);
} catch (Exception e) {
send_exception(e);
}
}
}
public IgniteHandler(JFrame in_owner, AltosLink in_link) {
owner = in_owner;
link = in_link;
}
}
void ignite_exception(Exception e) {
if (e instanceof FileNotFoundException) {
JOptionPane.showMessageDialog(owner,
((FileNotFoundException) e).getMessage(),
"Cannot open target device",
JOptionPane.ERROR_MESSAGE);
} else if (e instanceof AltosSerialInUseException) {
JOptionPane.showMessageDialog(owner,
String.format("Device \"%s\" already in use",
device.toShortString()),
"Device in use",
JOptionPane.ERROR_MESSAGE);
} else if (e instanceof IOException) {
IOException ee = (IOException) e;
JOptionPane.showMessageDialog(owner,
device.toShortString(),
ee.getLocalizedMessage(),
JOptionPane.ERROR_MESSAGE);
} else {
JOptionPane.showMessageDialog(owner,
String.format("Connection to \"%s\" failed",
device.toShortString()),
"Connection Failed",
JOptionPane.ERROR_MESSAGE);
}
close();
}
void ignite_reply(String reply) {
if (reply.equals("status")) {
set_ignite_status();
} else if (reply.equals("fired")) {
fired();
} else if (reply.startsWith("npyro")) {
String items[] = reply.split("\\s+");
npyro = Integer.parseInt(items[1]);
if (npyro == AltosLib.MISSING)
npyro = 0;
has_standard = Integer.parseInt(items[2]) != 0;
make_ui();
}
}
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;
fire.setEnabled(false);
timer_running = false;
arm.setSelected(false);
arm.setEnabled(false);
set_arm_text();
}
void cancel () {
group.clearSelection();
fire.setEnabled(false);
stop_timer();
}
void send_command(String command) {
try {
command_queue.put(command);
} catch (Exception ex) {
ignite_exception(ex);
}
}
boolean getting_status = false;
void set_ignite_status() {
getting_status = false;
poll_remaining = 2;
if (!isVisible())
setVisible(true);
}
void poll_ignite_status() {
if (poll_remaining > 0) {
--poll_remaining;
return;
}
if (!getting_status) {
getting_status = true;
send_command("get_status");
}
}
boolean firing = false;
void start_fire(String which) {
if (!firing) {
firing = true;
send_command(which);
}
}
void fired() {
firing = false;
cancel();
}
void close() {
if (opened) {
send_command("quit");
}
if (timer != null)
timer.stop();
setVisible(false);
dispose();
}
void tick_timer() {
if (timer_running) {
--time_remaining;
if (time_remaining <= 0)
cancel();
else
set_arm_text();
}
poll_ignite_status();
}
void fire() {
if (arm.isEnabled() && arm.isSelected() && time_remaining > 0) {
String igniter = "none";
for (int p = 0; p < igniters.length; p++)
if (igniters[p].button.isSelected()) {
igniter = igniters[p].name;
break;
}
send_command(igniter);
cancel();
}
}
public void actionPerformed(ActionEvent e) {
String cmd = e.getActionCommand();
for (int p = 0; p < igniters.length; p++)
if (cmd.equals(igniters[p].name)) {
stop_timer();
arm.setEnabled(true);
break;
}
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() {
command_queue = new LinkedBlockingQueue<String>();
opened = false;
device = AltosDeviceUIDialog.show(owner, Altos.product_any);
if (device != null) {
try {
AltosSerial serial = new AltosSerial(device);
serial.set_frame(owner);
IgniteHandler handler = new IgniteHandler(owner, serial);
Thread t = new Thread(handler);
t.start();
opened = true;
return true;
} catch (Exception ex) {
ignite_exception(ex);
}
}
return false;
}
private void make_ui() {
group = new ButtonGroup();
Container pane = getScrollablePane();
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();
pane.setLayout(new GridBagLayout());
c.fill = GridBagConstraints.NONE;
c.anchor = GridBagConstraints.CENTER;
c.insets = i;
c.weightx = 0;
c.weighty = 0;
int y = 0;
c.gridx = 0;
c.gridy = y;
c.gridwidth = 2;
c.anchor = GridBagConstraints.CENTER;
label = new JLabel ("Fire Igniter");
pane.add(label, c);
y++;
int nstandard = 0;
if (has_standard)
nstandard = 2;
igniters = new Igniter[nstandard + npyro];
if (has_standard) {
igniters[0] = new Igniter(this, "Apogee", AltosIgnite.Apogee, y++);
igniters[1] = new Igniter(this, "Main", AltosIgnite.Main, y++);
}
for (int p = 0; p < npyro; p++) {
String name = String.format("%d", p);
String label = String.format("%c", 'A' + p);
igniters[nstandard+p] = new Igniter(this, label, name, y++);
}
c.gridx = 0;
c.gridy = y;
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 = y;
c.gridwidth = 1;
c.anchor = GridBagConstraints.CENTER;
fire = new JButton ("Fire");
fire.setEnabled(false);
pane.add(fire, c);
fire.addActionListener(this);
fire.setActionCommand("fire");
y++;
c.gridx = 0;
c.gridy = y;
c.gridwidth = 2;
c.anchor = GridBagConstraints.CENTER;
close = new JButton ("Close");
pane.add(close, c);
close.addActionListener(this);
close.setActionCommand("close");
pack();
setLocationRelativeTo(owner);
addWindowListener(new ConfigListener(this));
}
public AltosIgniteUI(JFrame in_owner) {
owner = in_owner;
if (!open())
return;
send_command("get_npyro");
}
}

92
altosui/AltosIgnitor.java Normal file
View File

@@ -0,0 +1,92 @@
/*
* Copyright © 2014 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; 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.
*/
package altosui;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import org.altusmetrum.altoslib_14.*;
import org.altusmetrum.altosuilib_14.*;
public class AltosIgnitor extends AltosUIFlightTab {
public class Ignitor extends AltosUIUnitsIndicator {
int igniter;
public double value(AltosState state, int i) {
if (state.igniter_voltage == null ||
state.igniter_voltage.length < igniter)
return AltosLib.MISSING;
return state.igniter_voltage[igniter];
}
public double good() { return AltosLib.ao_igniter_good; }
public Ignitor (AltosUIFlightTab container, int y) {
super(container, y, AltosConvert.voltage, String.format ("%s Voltage", AltosLib.igniter_name(y)), 1, true, 1);
igniter = y;
}
}
Ignitor[] igniters;
public void show(AltosState state, AltosListenerState listener_state) {
if (isShowing())
make_igniters(state);
super.show(state, listener_state);
}
public boolean should_show(AltosState state) {
if (state == null)
return false;
if (state.igniter_voltage == null)
return false;
return state.igniter_voltage.length > 0;
}
void make_igniters(AltosState state) {
int n = (state == null || state.igniter_voltage == null) ? 0 : state.igniter_voltage.length;
int old_n = igniters == null ? 0 : igniters.length;
if (n != old_n) {
if (igniters != null) {
for (int i = 0; i < igniters.length; i++) {
remove(igniters[i]);
igniters[i].remove(this);
igniters = null;
}
}
if (n > 0) {
setVisible(true);
igniters = new Ignitor[n];
for (int i = 0; i < n; i++) {
igniters[i] = new Ignitor(this, i);
add(igniters[i]);
}
} else
setVisible(false);
}
}
public String getName() {
return "Ignitors";
}
}

193
altosui/AltosLanded.java Normal file
View File

@@ -0,0 +1,193 @@
/*
* 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; 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.
*/
package altosui;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.io.*;
import org.altusmetrum.altoslib_14.*;
import org.altusmetrum.altosuilib_14.*;
public class AltosLanded extends AltosUIFlightTab implements ActionListener {
class Bearing extends AltosUIIndicator {
public void show (AltosState state, AltosListenerState listener_state) {
if (state.from_pad != null && state.from_pad.bearing != AltosLib.MISSING) {
show( String.format("%3.0f°", state.from_pad.bearing),
state.from_pad.bearing_words(
AltosGreatCircle.BEARING_LONG));
} else {
show("Missing", "Missing");
}
}
public Bearing (Container container, int y) {
super (container, y, "Bearing", 2);
}
}
class Distance extends AltosUIUnitsIndicator {
public double value(AltosState state, int i) {
if (state.from_pad != null)
return state.from_pad.distance;
else
return AltosLib.MISSING;
}
public Distance(Container container, int y) {
super(container, y, AltosConvert.distance, "Ground Distance", 2);
}
}
class Lat extends AltosUIUnitsIndicator {
public boolean hide (AltosState state, int i) { return state.gps == null || !state.gps.connected; }
public double value(AltosState state, int i) {
if (state.gps == null)
return AltosLib.MISSING;
if (!state.gps.connected)
return AltosLib.MISSING;
return state.gps.lat;
}
public Lat (Container container, int y) {
super (container, y, AltosConvert.latitude, "Latitude", 2);
}
}
class Lon extends AltosUIUnitsIndicator {
public boolean hide (AltosState state, int i) { return state.gps == null || !state.gps.connected; }
public double value(AltosState state, int i) {
if (state.gps == null)
return AltosLib.MISSING;
if (!state.gps.connected)
return AltosLib.MISSING;
return state.gps.lon;
}
public Lon (Container container, int y) {
super (container, y, AltosConvert.longitude, "Longitude", 2);
}
}
class MaxHeight extends AltosUIUnitsIndicator {
public double value(AltosState state, int i) { return state.max_height(); }
public MaxHeight (Container container, int y) {
super (container, y, AltosConvert.height, "Maximum Height", 2);
}
}
class MaxSpeed extends AltosUIUnitsIndicator {
public double value(AltosState state, int i) { return state.max_speed(); }
public MaxSpeed (Container container, int y) {
super (container, y, AltosConvert.speed, "Maximum Speed", 2);
}
}
class MaxAccel extends AltosUIUnitsIndicator {
public double value(AltosState state, int i) { return state.max_acceleration(); }
public MaxAccel (Container container, int y) {
super (container, y, AltosConvert.speed, "Maximum acceleration", 2);
}
}
JButton graph;
AltosFlightReader reader;
public void actionPerformed(ActionEvent e) {
String cmd = e.getActionCommand();
if (cmd.equals("graph")) {
File file = reader.backing_file();
if (file != null) {
String filename = file.getName();
try {
AltosRecordSet record_set = null;
FileInputStream in = new FileInputStream(file);
if (filename.endsWith("eeprom")) {
record_set = new AltosEepromRecordSet(in);
} else if (filename.endsWith("telem")) {
record_set = new AltosTelemetryFile(in);
} else {
throw new FileNotFoundException(filename);
}
try {
new AltosGraphUI(record_set, file);
} catch (InterruptedException ie) {
} catch (IOException ie) {
}
} catch (FileNotFoundException fe) {
JOptionPane.showMessageDialog(null,
fe.getMessage(),
"Cannot open file",
JOptionPane.ERROR_MESSAGE);
} catch (IOException ie) {
JOptionPane.showMessageDialog(null,
ie.getMessage(),
"Error reading file file",
JOptionPane.ERROR_MESSAGE);
}
}
}
}
public String getName() {
return "Landed";
}
public void show(AltosState state, AltosListenerState listener_state) {
super.show(state, listener_state);
if (reader.backing_file() != null)
graph.setEnabled(true);
}
public AltosLanded(AltosFlightReader in_reader) {
reader = in_reader;
/* Elements in descent display */
add(new Bearing(this, 0));
add(new Distance(this, 1));
add(new Lat(this, 2));
add(new Lon(this, 3));
add(new MaxHeight(this, 4));
add(new MaxSpeed(this, 5));
add(new MaxAccel(this, 6));
graph = new JButton ("Graph Flight");
graph.setActionCommand("graph");
graph.addActionListener(this);
graph.setEnabled(false);
GridBagConstraints c = new GridBagConstraints();
c.gridx = 1; c.gridy = 7;
c.insets = new Insets(10, 10, 10, 10);
c.anchor = GridBagConstraints.WEST;
c.weightx = 0;
c.weighty = 0;
c.fill = GridBagConstraints.VERTICAL;
add(graph, c);
addHierarchyListener(this);
}
}

198
altosui/AltosLaunch.java Normal file
View File

@@ -0,0 +1,198 @@
/*
* 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; 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.
*/
package altosui;
import java.io.*;
import java.util.concurrent.*;
import java.awt.*;
import org.altusmetrum.altosuilib_14.*;
public class AltosLaunch {
AltosDevice device;
AltosSerial serial;
boolean serial_started;
int launcher_serial;
int launcher_channel;
int rssi;
final static int Unknown = -1;
final static int Good = 0;
final static int Bad = 1;
int armed;
int igniter;
private void start_serial() throws InterruptedException {
serial_started = true;
}
private void stop_serial() throws InterruptedException {
if (!serial_started)
return;
serial_started = false;
if (serial == null)
return;
}
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;
}
}
public boolean status() throws InterruptedException, TimeoutException {
boolean ok = false;
if (serial == null)
return false;
string_ref status_name = new string_ref();
start_serial();
serial.printf("l %d %d\n", launcher_serial, launcher_channel);
for (;;) {
String line = serial.get_reply(20000);
if (line == null)
throw new TimeoutException();
if (get_string(line, "Rssi: ", status_name)) {
try {
rssi = (int) Altos.fromdec(status_name.get());
} catch (NumberFormatException ne) {
}
break;
} else if (get_string(line, "Armed: ", status_name)) {
armed = Good;
String status = status_name.get();
if (status.startsWith("igniter good"))
igniter = Good;
else if (status.startsWith("igniter bad"))
igniter = Bad;
else
igniter = Unknown;
ok = true;
} else if (get_string(line, "Disarmed: ", status_name)) {
armed = Bad;
if (status_name.get().startsWith("igniter good"))
igniter = Good;
else if (status_name.get().startsWith("igniter bad"))
igniter = Bad;
else
igniter = Unknown;
ok = true;
} else if (get_string(line, "Error ", status_name)) {
armed = Unknown;
igniter = Unknown;
ok = false;
break;
}
}
stop_serial();
if (!ok) {
armed = Unknown;
igniter = Unknown;
}
return ok;
}
public static String status_string(int status) {
switch (status) {
case Good:
return "good";
case Bad:
return "open";
}
return "unknown";
}
public void arm() {
if (serial == null)
return;
try {
start_serial();
serial.printf("a %d %d\n", launcher_serial, launcher_channel);
serial.flush_output();
} catch (InterruptedException ie) {
} finally {
try {
stop_serial();
} catch (InterruptedException ie) {
}
}
}
public void fire() {
if (serial == null)
return;
try {
start_serial();
serial.printf("i %d %d\n", launcher_serial, launcher_channel);
serial.flush_output();
} catch (InterruptedException ie) {
} finally {
try {
stop_serial();
} catch (InterruptedException ie) {
}
}
}
public void close() {
try {
stop_serial();
} catch (InterruptedException ie) {
}
serial.close();
serial = null;
}
public void set_frame(Frame frame) {
serial.set_frame(frame);
}
public void set_remote(int in_serial, int in_channel) {
launcher_serial = in_serial;
launcher_channel = in_channel;
}
public AltosLaunch(AltosDevice in_device) throws FileNotFoundException, AltosSerialInUseException {
device = in_device;
serial = new AltosSerial(device);
}
}

513
altosui/AltosLaunchUI.java Normal file
View File

@@ -0,0 +1,513 @@
/*
* 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; 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.
*/
package altosui;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.io.*;
import java.text.*;
import java.util.concurrent.*;
import org.altusmetrum.altosuilib_14.*;
class FireButton extends JButton {
protected void processMouseEvent(MouseEvent e) {
super.processMouseEvent(e);
switch (e.getID()) {
case MouseEvent.MOUSE_PRESSED:
if (actionListener != null)
actionListener.actionPerformed(new ActionEvent(this, e.getID(), "fire_down"));
break;
case MouseEvent.MOUSE_RELEASED:
if (actionListener != null)
actionListener.actionPerformed(new ActionEvent(this, e.getID(), "fire_up"));
break;
}
}
public FireButton(String s) {
super(s);
}
}
public class AltosLaunchUI
extends AltosUIDialog
implements ActionListener
{
AltosDevice device;
JFrame owner;
JLabel label;
int radio_channel;
JLabel radio_channel_label;
JTextField radio_channel_text;
int launcher_serial;
JLabel launcher_serial_label;
JTextField launcher_serial_text;
int launcher_channel;
JLabel launcher_channel_label;
JTextField launcher_channel_text;
JLabel armed_label;
JLabel armed_status_label;
JLabel igniter;
JLabel igniter_status_label;
JToggleButton arm;
FireButton fire;
javax.swing.Timer arm_timer;
javax.swing.Timer fire_timer;
boolean firing;
boolean armed;
int armed_status;
int igniter_status;
int rssi;
final static int arm_timeout = 1 * 1000;
final static int fire_timeout = 250;
int armed_count;
LinkedBlockingQueue<String> command_queue;
class LaunchHandler implements Runnable {
AltosLaunch launch;
JFrame owner;
void send_exception(Exception e) {
final Exception f_e = e;
Runnable r = new Runnable() {
public void run() {
launch_exception(f_e);
}
};
SwingUtilities.invokeLater(r);
}
public void run () {
try {
launch = new AltosLaunch(device);
} catch (Exception e) {
send_exception(e);
return;
}
launch.set_frame(owner);
launch.set_remote(launcher_serial, launcher_channel);
for (;;) {
Runnable r;
try {
String command = command_queue.take();
String reply = null;
if (command.equals("get_status")) {
launch.status();
reply = "status";
armed_status = launch.armed;
igniter_status = launch.igniter;
rssi = launch.rssi;
} else if (command.equals("set_remote")) {
launch.set_remote(launcher_serial, launcher_channel);
reply = "remote set";
} else if (command.equals("arm")) {
launch.arm();
reply = "armed";
} else if (command.equals("fire")) {
launch.fire();
reply = "fired";
} else if (command.equals("quit")) {
launch.close();
break;
} else {
throw new ParseException(String.format("invalid command %s", command), 0);
}
final String f_reply = reply;
r = new Runnable() {
public void run() {
launch_reply(f_reply);
}
};
SwingUtilities.invokeLater(r);
} catch (Exception e) {
send_exception(e);
}
}
}
public LaunchHandler(JFrame in_owner) {
owner = in_owner;
}
}
void launch_exception(Exception e) {
if (e instanceof FileNotFoundException) {
JOptionPane.showMessageDialog(owner,
((FileNotFoundException) e).getMessage(),
"Cannot open target device",
JOptionPane.ERROR_MESSAGE);
} else if (e instanceof AltosSerialInUseException) {
JOptionPane.showMessageDialog(owner,
String.format("Device \"%s\" already in use",
device.toShortString()),
"Device in use",
JOptionPane.ERROR_MESSAGE);
} else if (e instanceof IOException) {
IOException ee = (IOException) e;
JOptionPane.showMessageDialog(owner,
device.toShortString(),
ee.getLocalizedMessage(),
JOptionPane.ERROR_MESSAGE);
} else {
JOptionPane.showMessageDialog(owner,
String.format("Connection to \"%s\" failed",
device.toShortString()),
"Connection Failed",
JOptionPane.ERROR_MESSAGE);
}
close();
}
void launch_reply(String reply) {
if (reply == null)
return;
if (reply.equals("remote set"))
poll_launch_status();
if (reply.equals("status")) {
set_launch_status();
}
}
void set_arm_text() {
if (arm.isSelected())
arm.setText(String.format("%d", armed_count));
else
arm.setText("Arm");
}
void start_arm_timer() {
armed_count = 30;
set_arm_text();
}
void stop_arm_timer() {
armed_count = 0;
armed = false;
arm.setSelected(false);
fire.setEnabled(false);
set_arm_text();
}
void cancel () {
fire.setEnabled(false);
firing = false;
stop_arm_timer();
}
void send_command(String command) {
try {
command_queue.put(command);
} catch (Exception ex) {
launch_exception(ex);
}
}
boolean getting_status = false;
void set_launch_status() {
getting_status = false;
armed_status_label.setText(String.format("\"%s\"", AltosLaunch.status_string(armed_status)));
igniter_status_label.setText(String.format("\"%s\"", AltosLaunch.status_string(igniter_status)));
}
void poll_launch_status() {
if (!getting_status && !firing && !armed) {
getting_status = true;
send_command("get_status");
}
}
void fired() {
firing = false;
cancel();
}
void close() {
send_command("quit");
arm_timer.stop();
setVisible(false);
dispose();
}
void tick_arm_timer() {
if (armed_count > 0) {
--armed_count;
if (armed_count <= 0) {
armed_count = 0;
cancel();
} else {
if (!firing) {
send_command("arm");
set_arm_text();
}
}
}
poll_launch_status();
}
void arm() {
if (arm.isSelected()) {
fire.setEnabled(true);
start_arm_timer();
if (!firing)
send_command("arm");
armed = true;
} else
cancel();
}
void fire_more() {
if (firing)
send_command("fire");
}
void fire_down() {
if (arm.isEnabled() && arm.isSelected() && armed_count > 0) {
firing = true;
fire_more();
fire_timer.restart();
}
}
void fire_up() {
firing = false;
fire_timer.stop();
}
void set_radio() {
try {
radio_channel = Integer.parseInt(radio_channel_text.getText());
} catch (NumberFormatException ne) {
radio_channel_text.setText(String.format("%d", radio_channel));
}
}
void set_serial() {
try {
launcher_serial = Integer.parseInt(launcher_serial_text.getText());
AltosUIPreferences.set_launcher_serial(launcher_serial);
send_command("set_remote");
} catch (NumberFormatException ne) {
launcher_serial_text.setText(String.format("%d", launcher_serial));
}
}
void set_channel() {
try {
launcher_channel = Integer.parseInt(launcher_channel_text.getText());
AltosUIPreferences.set_launcher_serial(launcher_channel);
send_command("set_remote");
} catch (NumberFormatException ne) {
launcher_channel_text.setText(String.format("%d", launcher_channel));
}
}
public void actionPerformed(ActionEvent e) {
String cmd = e.getActionCommand();
if (cmd.equals("armed") || cmd.equals("igniter")) {
stop_arm_timer();
}
if (cmd.equals("arm"))
arm();
if (cmd.equals("tick_arm"))
tick_arm_timer();
if (cmd.equals("close"))
close();
if (cmd.equals("fire_down"))
fire_down();
if (cmd.equals("fire_up"))
fire_up();
if (cmd.equals("tick_fire"))
fire_more();
if (cmd.equals("new_serial"))
set_serial();
if (cmd.equals("new_channel"))
set_channel();
}
/* A window listener to catch closing events and tell the config code */
class ConfigListener extends WindowAdapter {
AltosLaunchUI ui;
public ConfigListener(AltosLaunchUI this_ui) {
ui = this_ui;
}
public void windowClosing(WindowEvent e) {
ui.actionPerformed(new ActionEvent(e.getSource(),
ActionEvent.ACTION_PERFORMED,
"close"));
}
}
private boolean open() {
command_queue = new LinkedBlockingQueue<String>();
device = AltosDeviceUIDialog.show(owner, Altos.product_any);
if (device != null) {
LaunchHandler handler = new LaunchHandler(owner);
Thread t = new Thread(handler);
t.start();
return true;
}
return false;
}
public AltosLaunchUI(JFrame in_owner) {
launcher_channel = AltosUIPreferences.launcher_channel();
launcher_serial = AltosUIPreferences.launcher_serial();
owner = in_owner;
armed_status = AltosLaunch.Unknown;
igniter_status = AltosLaunch.Unknown;
if (!open())
return;
Container pane = getScrollablePane();
GridBagConstraints c = new GridBagConstraints();
Insets i = new Insets(4,4,4,4);
arm_timer = new javax.swing.Timer(arm_timeout, this);
arm_timer.setActionCommand("tick_arm");
arm_timer.restart();
fire_timer = new javax.swing.Timer(fire_timeout, this);
fire_timer.setActionCommand("tick_fire");
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 ("Launch Controller");
pane.add(label, c);
c.gridx = 0;
c.gridy = 1;
c.gridwidth = 1;
c.anchor = GridBagConstraints.WEST;
launcher_serial_label = new JLabel("Launcher Serial");
pane.add(launcher_serial_label, c);
c.gridx = 1;
c.gridy = 1;
c.gridwidth = 1;
c.anchor = GridBagConstraints.WEST;
launcher_serial_text = new JTextField(7);
launcher_serial_text.setText(String.format("%d", launcher_serial));
launcher_serial_text.setActionCommand("new_serial");
launcher_serial_text.addActionListener(this);
pane.add(launcher_serial_text, c);
c.gridx = 0;
c.gridy = 2;
c.gridwidth = 1;
c.anchor = GridBagConstraints.WEST;
launcher_channel_label = new JLabel("Launcher Channel");
pane.add(launcher_channel_label, c);
c.gridx = 1;
c.gridy = 2;
c.gridwidth = 1;
c.anchor = GridBagConstraints.WEST;
launcher_channel_text = new JTextField(7);
launcher_channel_text.setText(String.format("%d", launcher_channel));
launcher_channel_text.setActionCommand("new_channel");
launcher_channel_text.addActionListener(this);
pane.add(launcher_channel_text, c);
c.gridx = 0;
c.gridy = 3;
c.gridwidth = 1;
c.anchor = GridBagConstraints.WEST;
armed_label = new JLabel ("Armed");
pane.add(armed_label, c);
c.gridx = 1;
c.gridy = 3;
c.gridwidth = 1;
c.anchor = GridBagConstraints.WEST;
armed_status_label = new JLabel();
pane.add(armed_status_label, c);
c.gridx = 0;
c.gridy = 4;
c.gridwidth = 1;
c.anchor = GridBagConstraints.WEST;
igniter = new JLabel ("Igniter");
pane.add(igniter, c);
c.gridx = 1;
c.gridy = 4;
c.gridwidth = 1;
c.anchor = GridBagConstraints.WEST;
igniter_status_label = new JLabel();
pane.add(igniter_status_label, c);
c.gridx = 0;
c.gridy = 5;
c.gridwidth = 1;
c.anchor = GridBagConstraints.CENTER;
arm = new JToggleButton ("Arm");
pane.add(arm, c);
arm.addActionListener(this);
arm.setActionCommand("arm");
arm.setEnabled(true);
c.gridx = 1;
c.gridy = 5;
c.gridwidth = 1;
c.anchor = GridBagConstraints.CENTER;
fire = new FireButton ("Fire");
fire.setEnabled(false);
pane.add(fire, c);
fire.addActionListener(this);
fire.setActionCommand("fire");
pack();
setLocationRelativeTo(owner);
addWindowListener(new ConfigListener(this));
setVisible(true);
}
}

257
altosui/AltosPad.java Normal file
View File

@@ -0,0 +1,257 @@
/*
* 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; 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.
*/
package altosui;
import java.util.*;
import org.altusmetrum.altoslib_14.*;
import org.altusmetrum.altosuilib_14.*;
public class AltosPad extends AltosUIFlightTab {
class Battery extends AltosUIVoltageIndicator {
public double voltage(AltosState state) { return state.battery_voltage; }
public double good() { return AltosLib.ao_battery_good; }
public Battery (AltosUIFlightTab container, int y) { super(container, y, "Battery Voltage", 2); }
}
class Apogee extends AltosUIVoltageIndicator {
public boolean hide(double v) { return v == AltosLib.MISSING; }
public double voltage(AltosState state) { return state.apogee_voltage; }
public double good() { return AltosLib.ao_igniter_good; }
public Apogee (AltosUIFlightTab container, int y) { super(container, y, "Apogee Igniter Voltage", 2); }
}
class Main extends AltosUIVoltageIndicator {
public boolean hide(double v) { return v == AltosLib.MISSING; }
public double voltage(AltosState state) { return state.main_voltage; }
public double good() { return AltosLib.ao_igniter_good; }
public Main (AltosUIFlightTab container, int y) { super(container, y, "Main Igniter Voltage", 2); }
}
class LoggingReady extends AltosUIIndicator {
public void show (AltosState state, AltosListenerState listener_state) {
AltosCalData cal_data = state.cal_data();
if (state == null || cal_data.flight == AltosLib.MISSING) {
hide();
} else {
if (cal_data.flight != 0) {
if (state.state() <= Altos.ao_flight_pad)
show("Ready to record");
else if (state.state() < Altos.ao_flight_landed ||
state.state() == AltosLib.ao_flight_stateless)
show("Recording data");
else
show("Recorded data");
} else
show("Storage full");
set_lights(cal_data.flight != 0);
}
}
public LoggingReady (AltosUIFlightTab container, int y) {
super(container, y, "On-board Data Logging", 1, true, 2);
}
}
class GPSLocked extends AltosUIIndicator {
public void show (AltosState state, AltosListenerState listener_state) {
if (state == null || state.gps == null)
hide();
else {
int sol = state.gps.nsat;
int sat = state.gps.cc_gps_sat == null ? 0 : state.gps.cc_gps_sat.length;
show("%d in solution", sol, "%d in view", sat);
set_lights(state.gps.locked && sol >= 4);
}
}
public GPSLocked (AltosUIFlightTab container, int y) {
super (container, y, "GPS Locked", 2, true, 1);
}
}
class GPSReady extends AltosUIIndicator {
public void show (AltosState state, AltosListenerState listener_state) {
if (state == null || state.gps == null)
hide();
else {
if (state.gps_ready)
show("Ready");
else
show("Waiting %d", state.gps_waiting);
set_lights(state.gps_ready);
}
}
public GPSReady (AltosUIFlightTab container, int y) {
super (container, y, "GPS Ready", 1, true, 2);
}
}
class ReceiverBattery extends AltosUIVoltageIndicator {
double last_voltage = AltosLib.MISSING;
public double voltage(AltosState state) {
return last_voltage;
}
public double good() { return AltosLib.ao_battery_good; }
public boolean hide(AltosState state, AltosListenerState listener_state, int i) {
return value(state, listener_state, i) == AltosLib.MISSING;
}
public double value(AltosState state, AltosListenerState listener_state, int i) {
if (listener_state == null)
last_voltage = AltosLib.MISSING;
else
last_voltage = listener_state.battery;
return last_voltage;
}
public ReceiverBattery (AltosUIFlightTab container, int y) {
super(container, y, "Receiver Battery", 2);
}
}
boolean report_pad(AltosState state) {
if (state.state() == AltosLib.ao_flight_stateless ||
state.state() < AltosLib.ao_flight_pad)
{
return false;
}
return true;
}
class PadLat extends AltosUIIndicator {
double last_lat = AltosLib.MISSING - 1;
public void show (AltosState state, AltosListenerState listener_state) {
double lat = AltosLib.MISSING;
String label = null;
if (state != null) {
if (report_pad(state)) {
lat = state.pad_lat;
label = "Pad Latitude";
} else if (state.gps != null) {
lat = state.gps.lat;
label = "Latitude";
}
}
if (lat != last_lat) {
if (lat != AltosLib.MISSING) {
show(AltosConvert.latitude.show(10, lat));
set_label(label);
} else
hide();
last_lat = lat;
}
}
public void reset() {
super.reset();
last_lat = AltosLib.MISSING - 1;
}
public PadLat (AltosUIFlightTab container, int y) {
super (container, y, "Pad Latitude", 1, false, 2);
}
}
class PadLon extends AltosUIIndicator {
double last_lon = AltosLib.MISSING - 1;
public void show (AltosState state, AltosListenerState listener_state) {
double lon = AltosLib.MISSING;
String label = null;
if (state != null) {
if (report_pad(state)) {
lon = state.pad_lon;
label = "Pad Longitude";
} else if (state.gps != null) {
lon = state.gps.lon;
label = "Longitude";
}
}
if (lon != last_lon) {
if (lon != AltosLib.MISSING) {
show(AltosConvert.longitude.show(10, lon));
set_label(label);
} else
hide();
last_lon = lon;
}
}
public void reset() {
super.reset();
last_lon = AltosLib.MISSING - 1;
}
public PadLon (AltosUIFlightTab container, int y) {
super (container, y, "Pad Longitude", 1, false, 2);
}
}
class PadAlt extends AltosUIUnitsIndicator {
public double value(AltosState state, int i) {
if (report_pad(state)) {
double alt = state.gps_ground_altitude();
if (alt == AltosLib.MISSING)
alt = state.ground_altitude();
return alt;
}
else if (state.gps != null && state.gps.alt != AltosLib.MISSING)
return state.gps.alt;
else
return state.altitude();
}
public void show (AltosState state, AltosListenerState listener_state) {
String label = "Altitude";
if (state != null && report_pad(state))
label = "Pad Altitude";
set_label(label);
super.show(state, listener_state);
}
public PadAlt (AltosUIFlightTab container, int y) {
super (container, y, AltosConvert.height, "Pad Altitude", 1, false, 2);
}
}
public String getName() { return "Pad"; }
public AltosPad() {
int y = 0;
add(new Battery(this, y++));
add(new ReceiverBattery(this, y++));
add(new Apogee(this, y++));
add(new Main(this, y++));
add(new LoggingReady(this, y++));
add(new GPSLocked(this, y++));
add(new GPSReady(this, y++));
add(new PadLat(this, y++));
add(new PadLon(this, y++));
add(new PadAlt(this, y++));
}
}

View File

@@ -0,0 +1,906 @@
#!/bin/bash
##################################################################################
# #
# universalJavaApplicationStub #
# #
# A BASH based JavaApplicationStub for Java Apps on Mac OS X #
# that works with both Apple's and Oracle's plist format. #
# #
# Inspired by Ian Roberts stackoverflow answer #
# at http://stackoverflow.com/a/17546508/1128689 #
# #
# @author Tobias Fischer #
# @url https://github.com/tofi86/universalJavaApplicationStub #
# @date 2021-02-21 #
# @version 3.2.0 #
# #
##################################################################################
# #
# The MIT License (MIT) #
# #
# Copyright (c) 2014-2021 Tobias Fischer #
# #
# Permission is hereby granted, free of charge, to any person obtaining a copy #
# of this software and associated documentation files (the "Software"), to deal #
# in the Software without restriction, including without limitation the rights #
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell #
# copies of the Software, and to permit persons to whom the Software is #
# furnished to do so, subject to the following conditions: #
# #
# The above copyright notice and this permission notice shall be included in all #
# copies or substantial portions of the Software. #
# #
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR #
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, #
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE #
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER #
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, #
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE #
# SOFTWARE. #
# #
##################################################################################
#
# Fix fonts. I don't know why the getting the
# basename of the app set to . matters, but it does
#
case "$0" in
/*)
cd `dirname "$0"`
./`basename "$0"` "$@"
exit $?
;;
esac
export FREETYPE_PROPERTIES=truetype:interpreter-version=35
# function 'stub_logger()'
#
# A logger which logs to the macOS Console.app using the 'syslog' command
#
# @param1 the log message
# @return void
################################################################################
function stub_logger() {
syslog -s -k \
Facility com.apple.console \
Level Notice \
Sender "$(basename "$0")" \
Message "[$$][${CFBundleName:-$(basename "$0")}] $1"
}
# set the directory abspath of the current
# shell script with symlinks being resolved
############################################
PRG=$0
while [ -h "$PRG" ]; do
ls=$(ls -ld "$PRG")
link=$(expr "$ls" : '^.*-> \(.*\)$' 2>/dev/null)
if expr "$link" : '^/' 2> /dev/null >/dev/null; then
PRG="$link"
else
PRG="$(dirname "$PRG")/$link"
fi
done
PROGDIR=$(dirname "$PRG")
stub_logger "[StubDir] $PROGDIR"
# set files and folders
############################################
# the absolute path of the app package
cd "$PROGDIR"/../../ || exit 11
AppPackageFolder=$(pwd)
# the base path of the app package
cd .. || exit 12
AppPackageRoot=$(pwd)
# set Apple's Java folder
AppleJavaFolder="${AppPackageFolder}"/Contents/Resources/Java
# set Apple's Resources folder
AppleResourcesFolder="${AppPackageFolder}"/Contents/Resources
# set Oracle's Java folder
OracleJavaFolder="${AppPackageFolder}"/Contents/Java
# set Oracle's Resources folder
OracleResourcesFolder="${AppPackageFolder}"/Contents/Resources
# set path to Info.plist in bundle
InfoPlistFile="${AppPackageFolder}"/Contents/Info.plist
# set the default JVM Version to a null string
JVMVersion=""
JVMMaxVersion=""
# function 'plist_get()'
#
# read a specific Plist key with 'PlistBuddy' utility
#
# @param1 the Plist key with leading colon ':'
# @return the value as String or Array
################################################################################
plist_get(){
/usr/libexec/PlistBuddy -c "print $1" "${InfoPlistFile}" 2> /dev/null
}
# function 'plist_get_java()'
#
# read a specific Plist key with 'PlistBuddy' utility
# in the 'Java' or 'JavaX' dictionary (<dict>)
#
# @param1 the Plist :Java(X):Key with leading colon ':'
# @return the value as String or Array
################################################################################
plist_get_java(){
plist_get ${JavaKey:-":Java"}$1
}
# read Info.plist and extract JVM options
############################################
# read the program name from CFBundleName
CFBundleName=$(plist_get ':CFBundleName')
# read the icon file name
CFBundleIconFile=$(plist_get ':CFBundleIconFile')
# check Info.plist for Apple style Java keys -> if key :Java is present, parse in apple mode
/usr/libexec/PlistBuddy -c "print :Java" "${InfoPlistFile}" > /dev/null 2>&1
exitcode=$?
JavaKey=":Java"
# if no :Java key is present, check Info.plist for universalJavaApplication style JavaX keys -> if key :JavaX is present, parse in apple mode
if [ $exitcode -ne 0 ]; then
/usr/libexec/PlistBuddy -c "print :JavaX" "${InfoPlistFile}" > /dev/null 2>&1
exitcode=$?
JavaKey=":JavaX"
fi
# read 'Info.plist' file in Apple style if exit code returns 0 (true, ':Java' key is present)
if [ $exitcode -eq 0 ]; then
stub_logger "[PlistStyle] Apple"
# set Java and Resources folder
JavaFolder="${AppleJavaFolder}"
ResourcesFolder="${AppleResourcesFolder}"
# set expandable variables
APP_ROOT="${AppPackageFolder}"
APP_PACKAGE="${AppPackageFolder}"
JAVAROOT="${AppleJavaFolder}"
USER_HOME="$HOME"
# read the Java WorkingDirectory
JVMWorkDir=$(plist_get_java ':WorkingDirectory' | xargs)
# set Working Directory based upon PList value
if [[ ! -z ${JVMWorkDir} ]]; then
WorkingDirectory="${JVMWorkDir}"
else
# AppPackageRoot is the standard WorkingDirectory when the script is started
WorkingDirectory="${AppPackageRoot}"
fi
# expand variables $APP_PACKAGE, $APP_ROOT, $JAVAROOT, $USER_HOME
WorkingDirectory=$(eval echo "${WorkingDirectory}")
# read the MainClass name
JVMMainClass="$(plist_get_java ':MainClass')"
# read the SplashFile name
JVMSplashFile=$(plist_get_java ':SplashFile')
# read the JVM Properties as an array and retain spaces
IFS=$'\t\n'
JVMOptions=($(xargs -n1 <<<$(plist_get_java ':Properties' | grep " =" | sed 's/^ */-D/g' | sed -E 's/ = (.*)$/="\1"/g')))
unset IFS
# post processing of the array follows further below...
# read the ClassPath in either Array or String style
JVMClassPath_RAW=$(plist_get_java ':ClassPath' | xargs)
if [[ $JVMClassPath_RAW == *Array* ]] ; then
JVMClassPath=.$(plist_get_java ':ClassPath' | grep " " | sed 's/^ */:/g' | tr -d '\n' | xargs)
else
JVMClassPath=${JVMClassPath_RAW}
fi
# expand variables $APP_PACKAGE, $APP_ROOT, $JAVAROOT, $USER_HOME
JVMClassPath=$(eval echo "${JVMClassPath}")
# read the JVM Options in either Array or String style
JVMDefaultOptions_RAW=$(plist_get_java ':VMOptions' | xargs)
if [[ $JVMDefaultOptions_RAW == *Array* ]] ; then
JVMDefaultOptions=$(plist_get_java ':VMOptions' | grep " " | sed 's/^ */ /g' | tr -d '\n' | xargs)
else
JVMDefaultOptions=${JVMDefaultOptions_RAW}
fi
# expand variables $APP_PACKAGE, $APP_ROOT, $JAVAROOT, $USER_HOME (#84)
JVMDefaultOptions=$(eval echo "${JVMDefaultOptions}")
# read StartOnMainThread and add as -XstartOnFirstThread
JVMStartOnMainThread=$(plist_get_java ':StartOnMainThread')
if [ "${JVMStartOnMainThread}" == "true" ]; then
JVMDefaultOptions+=" -XstartOnFirstThread"
fi
# read the JVM Arguments in either Array or String style (#76) and retain spaces
IFS=$'\t\n'
MainArgs_RAW=$(plist_get_java ':Arguments' | xargs)
if [[ $MainArgs_RAW == *Array* ]] ; then
MainArgs=($(xargs -n1 <<<$(plist_get_java ':Arguments' | tr -d '\n' | sed -E 's/Array \{ *(.*) *\}/\1/g' | sed 's/ */ /g')))
else
MainArgs=($(xargs -n1 <<<$(plist_get_java ':Arguments')))
fi
unset IFS
# post processing of the array follows further below...
# read the Java version we want to find
JVMVersion=$(plist_get_java ':JVMVersion' | xargs)
# post processing of the version string follows below...
# read 'Info.plist' file in Oracle style
else
stub_logger "[PlistStyle] Oracle"
# set Working Directory and Java and Resources folder
JavaFolder="${OracleJavaFolder}"
ResourcesFolder="${OracleResourcesFolder}"
WorkingDirectory="${OracleJavaFolder}"
# set expandable variables
APP_ROOT="${AppPackageFolder}"
APP_PACKAGE="${AppPackageFolder}"
JAVAROOT="${OracleJavaFolder}"
USER_HOME="$HOME"
# read the MainClass name
JVMMainClass="$(plist_get ':JVMMainClassName')"
# read the SplashFile name
JVMSplashFile=$(plist_get ':JVMSplashFile')
# read the JVM Options as an array and retain spaces
IFS=$'\t\n'
JVMOptions=($(plist_get ':JVMOptions' | grep " " | sed 's/^ *//g'))
unset IFS
# post processing of the array follows further below...
# read the ClassPath in either Array or String style
JVMClassPath_RAW=$(plist_get ':JVMClassPath')
if [[ $JVMClassPath_RAW == *Array* ]] ; then
JVMClassPath=.$(plist_get ':JVMClassPath' | grep " " | sed 's/^ */:/g' | tr -d '\n' | xargs)
# expand variables $APP_PACKAGE, $APP_ROOT, $JAVAROOT, $USER_HOME
JVMClassPath=$(eval echo "${JVMClassPath}")
elif [[ ! -z ${JVMClassPath_RAW} ]] ; then
JVMClassPath=${JVMClassPath_RAW}
# expand variables $APP_PACKAGE, $APP_ROOT, $JAVAROOT, $USER_HOME
JVMClassPath=$(eval echo "${JVMClassPath}")
else
#default: fallback to OracleJavaFolder
JVMClassPath="${JavaFolder}/*"
# Do NOT expand the default 'AppName.app/Contents/Java/*' classpath (#42)
fi
# read the JVM Default Options by parsing the :JVMDefaultOptions <dict>
# and pulling all <string> values starting with a dash (-)
JVMDefaultOptions=$(plist_get ':JVMDefaultOptions' | grep -o " \-.*" | tr -d '\n' | xargs)
# expand variables $APP_PACKAGE, $APP_ROOT, $JAVAROOT, $USER_HOME (#99)
JVMDefaultOptions=$(eval echo "${JVMDefaultOptions}")
# read the Main Arguments from JVMArguments key as an array and retain spaces (see #46 for naming details)
IFS=$'\t\n'
MainArgs=($(xargs -n1 <<<$(plist_get ':JVMArguments' | tr -d '\n' | sed -E 's/Array \{ *(.*) *\}/\1/g' | sed 's/ */ /g')))
unset IFS
# post processing of the array follows further below...
# read the Java version we want to find
JVMVersion=$(plist_get ':JVMVersion' | xargs)
# post processing of the version string follows below...
fi
# (#75) check for undefined icons or icon names without .icns extension and prepare
# an osascript statement for those cases when the icon can be shown in the dialog
DialogWithIcon=""
if [ ! -z ${CFBundleIconFile} ]; then
if [[ ${CFBundleIconFile} == *.icns ]] && [[ -f "${ResourcesFolder}/${CFBundleIconFile}" ]] ; then
DialogWithIcon=" with icon path to resource \"${CFBundleIconFile}\" in bundle (path to me)"
elif [[ ${CFBundleIconFile} != *.icns ]] && [[ -f "${ResourcesFolder}/${CFBundleIconFile}.icns" ]] ; then
CFBundleIconFile+=".icns"
DialogWithIcon=" with icon path to resource \"${CFBundleIconFile}\" in bundle (path to me)"
fi
fi
# JVMVersion: post processing and optional splitting
if [[ ${JVMVersion} == *";"* ]]; then
minMaxArray=(${JVMVersion//;/ })
JVMVersion=${minMaxArray[0]//+}
JVMMaxVersion=${minMaxArray[1]//+}
fi
stub_logger "[JavaRequirement] JVM minimum version: ${JVMVersion}"
stub_logger "[JavaRequirement] JVM maximum version: ${JVMMaxVersion}"
# MainArgs: expand variables $APP_PACKAGE, $APP_ROOT, $JAVAROOT, $USER_HOME
MainArgsArr=()
for i in "${MainArgs[@]}"
do
MainArgsArr+=("$(eval echo "$i")")
done
# JVMOptions: expand variables $APP_PACKAGE, $APP_ROOT, $JAVAROOT, $USER_HOME
JVMOptionsArr=()
for i in "${JVMOptions[@]}"
do
JVMOptionsArr+=("$(eval echo "$i")")
done
# internationalized messages
############################################
# supported languages / available translations
stubLanguages="^(fr|de|zh|es|en)-"
# read user preferred languages as defined in macOS System Preferences (#101)
stub_logger '[LanguageSearch] Checking preferred languages in macOS System Preferences...'
appleLanguages=($(defaults read -g AppleLanguages | grep '\s"' | tr -d ',' | xargs))
stub_logger "[LanguageSearch] ... found [${appleLanguages[*]}]"
language=""
for i in "${appleLanguages[@]}"
do
langValue="${i%-*}"
if [[ "$i" =~ $stubLanguages ]]; then
stub_logger "[LanguageSearch] ... selected '$i' ('$langValue') as the default language for the launcher stub"
language=${langValue}
break
fi
done
if [ -z "${language}" ]; then
language="en"
stub_logger "[LanguageSearch] ... selected fallback 'en' as the default language for the launcher stub"
fi
stub_logger "[Language] $language"
case "${language}" in
# French
fr)
MSG_ERROR_LAUNCHING="ERREUR au lancement de '${CFBundleName}'."
MSG_MISSING_MAINCLASS="'MainClass' n'est pas spécifié.\nL'application Java ne peut pas être lancée."
MSG_JVMVERSION_REQ_INVALID="La syntaxe de la version de Java demandée est invalide: %s\nVeuillez contacter le développeur de l'application."
MSG_NO_SUITABLE_JAVA="La version de Java installée sur votre système ne convient pas.\nCe programme nécessite Java %s"
MSG_JAVA_VERSION_OR_LATER="ou ultérieur"
MSG_JAVA_VERSION_LATEST="(dernière mise à jour)"
MSG_JAVA_VERSION_MAX="à %s"
MSG_NO_SUITABLE_JAVA_CHECK="Merci de bien vouloir installer la version de Java requise."
MSG_INSTALL_JAVA="Java doit être installé sur votre système.\nRendez-vous sur java.com et suivez les instructions d'installation..."
MSG_LATER="Plus tard"
MSG_VISIT_JAVA_DOT_COM="Java by Oracle"
MSG_VISIT_ADOPTIUM="Java by Adoptium"
;;
# German
de)
MSG_ERROR_LAUNCHING="FEHLER beim Starten von '${CFBundleName}'."
MSG_MISSING_MAINCLASS="Die 'MainClass' ist nicht spezifiziert!\nDie Java-Anwendung kann nicht gestartet werden!"
MSG_JVMVERSION_REQ_INVALID="Die Syntax der angeforderten Java-Version ist ungültig: %s\nBitte kontaktieren Sie den Entwickler der App."
MSG_NO_SUITABLE_JAVA="Es wurde keine passende Java-Version auf Ihrem System gefunden!\nDieses Programm benötigt Java %s"
MSG_JAVA_VERSION_OR_LATER="oder neuer"
MSG_JAVA_VERSION_LATEST="(neuste Unterversion)"
MSG_JAVA_VERSION_MAX="bis %s"
MSG_NO_SUITABLE_JAVA_CHECK="Stellen Sie sicher, dass die angeforderte Java-Version installiert ist."
MSG_INSTALL_JAVA="Auf Ihrem System muss die 'Java'-Software installiert sein.\nBesuchen Sie java.com für weitere Installationshinweise."
MSG_LATER="Später"
MSG_VISIT_JAVA_DOT_COM="Java von Oracle"
MSG_VISIT_ADOPTIUM="Java von Adoptium"
;;
# Simplified Chinese
zh)
MSG_ERROR_LAUNCHING="无法启动 '${CFBundleName}'."
MSG_MISSING_MAINCLASS="没有指定 'MainClass'\nJava程序无法启动!"
MSG_JVMVERSION_REQ_INVALID="Java版本参数语法错误: %s\n请联系该应用的开发者。"
MSG_NO_SUITABLE_JAVA="没有在系统中找到合适的Java版本\n必须安装Java %s才能够使用该程序"
MSG_JAVA_VERSION_OR_LATER="及以上版本"
MSG_JAVA_VERSION_LATEST="(最新版本)"
MSG_JAVA_VERSION_MAX="最高为 %s"
MSG_NO_SUITABLE_JAVA_CHECK="请确保系统中安装了所需的Java版本"
MSG_INSTALL_JAVA="你需要在Mac中安装Java运行环境\n访问 java.com 了解如何安装。"
MSG_LATER="稍后"
MSG_VISIT_JAVA_DOT_COM="Java by Oracle"
MSG_VISIT_ADOPTIUM="Java by Adoptium"
;;
# Spanish
es)
MSG_ERROR_LAUNCHING="ERROR iniciando '${CFBundleName}'."
MSG_MISSING_MAINCLASS="¡'MainClass' no especificada!\n¡La aplicación Java no puede iniciarse!"
MSG_JVMVERSION_REQ_INVALID="La sintaxis de la versión Java requerida no es válida: %s\nPor favor, contacte con el desarrollador de la aplicación."
MSG_NO_SUITABLE_JAVA="¡No se encontró una versión de Java adecuada en su sistema!\nEste programa requiere Java %s"
MSG_JAVA_VERSION_OR_LATER="o posterior"
MSG_JAVA_VERSION_LATEST="(ultima actualización)"
MSG_JAVA_VERSION_MAX="superior a %s"
MSG_NO_SUITABLE_JAVA_CHECK="Asegúrese de instalar la versión Java requerida."
MSG_INSTALL_JAVA="¡Necesita tener JAVA instalado en su Mac!\nVisite java.com para consultar las instrucciones para su instalación..."
MSG_LATER="Más tarde"
MSG_VISIT_JAVA_DOT_COM="Java de Oracle"
MSG_VISIT_ADOPTIUM="Java de Adoptium"
;;
# English | default
en|*)
MSG_ERROR_LAUNCHING="ERROR launching '${CFBundleName}'."
MSG_MISSING_MAINCLASS="'MainClass' isn't specified!\nJava application cannot be started!"
MSG_JVMVERSION_REQ_INVALID="The syntax of the required Java version is invalid: %s\nPlease contact the App developer."
MSG_NO_SUITABLE_JAVA="No suitable Java version found on your system!\nThis program requires Java %s"
MSG_JAVA_VERSION_OR_LATER="or later"
MSG_JAVA_VERSION_LATEST="(latest update)"
MSG_JAVA_VERSION_MAX="up to %s"
MSG_NO_SUITABLE_JAVA_CHECK="Make sure you install the required Java version."
MSG_INSTALL_JAVA="You need to have JAVA installed on your Mac!\nVisit java.com for installation instructions..."
MSG_LATER="Later"
MSG_VISIT_JAVA_DOT_COM="Java by Oracle"
MSG_VISIT_ADOPTIUM="Java by Adoptium"
;;
esac
# function 'get_java_version_from_cmd()'
#
# returns Java version string from 'java -version' command
# works for both old (1.8) and new (9) version schema
#
# @param1 path to a java JVM executable
# @return the Java version number as displayed in 'java -version' command
################################################################################
function get_java_version_from_cmd() {
# second sed command strips " and -ea from the version string
echo $("$1" -version 2>&1 | awk '/version/{print $3}' | sed -E 's/"//g;s/-ea//g')
}
# function 'extract_java_major_version()'
#
# extract Java major version from a version string
#
# @param1 a Java version number ('1.8.0_45') or requirement string ('1.8+')
# @return the major version (e.g. '7', '8' or '9', etc.)
################################################################################
function extract_java_major_version() {
echo $(echo "$1" | sed -E 's/^1\.//;s/^([0-9]+)(-ea|(\.[0-9_.]{1,7})?)(-b[0-9]+-[0-9]+)?[+*]?$/\1/')
}
# function 'get_comparable_java_version()'
#
# return comparable version for a Java version number or requirement string
#
# @param1 a Java version number ('1.8.0_45') or requirement string ('1.8+')
# @return an 8 digit numeral ('1.8.0_45'->'08000045'; '9.1.13'->'09001013')
################################################################################
function get_comparable_java_version() {
# cleaning: 1) remove leading '1.'; 2) remove build string (e.g. '-b14-468'); 3) remove 'a-Z' and '-*+' (e.g. '-ea'); 4) replace '_' with '.'
local cleaned=$(echo "$1" | sed -E 's/^1\.//g;s/-b[0-9]+-[0-9]+$//g;s/[a-zA-Z+*\-]//g;s/_/./g')
# splitting at '.' into an array
local arr=( ${cleaned//./ } )
# echo a string with left padded version numbers
echo "$(printf '%02s' ${arr[0]})$(printf '%03s' ${arr[1]})$(printf '%03s' ${arr[2]})"
}
# function 'is_valid_requirement_pattern()'
#
# check whether the Java requirement is a valid requirement pattern
#
# supported requirements are for example:
# - 1.6 requires Java 6 (any update) [1.6, 1.6.0_45, 1.6.0_88]
# - 1.6* requires Java 6 (any update) [1.6, 1.6.0_45, 1.6.0_88]
# - 1.6+ requires Java 6 or higher [1.6, 1.6.0_45, 1.8, 9, etc.]
# - 1.6.0 requires Java 6 (any update) [1.6, 1.6.0_45, 1.6.0_88]
# - 1.6.0_45 requires Java 6u45 [1.6.0_45]
# - 1.6.0_45+ requires Java 6u45 or higher [1.6.0_45, 1.6.0_88, 1.8, etc.]
# - 9 requires Java 9 (any update) [9.0.*, 9.1, 9.3, etc.]
# - 9* requires Java 9 (any update) [9.0.*, 9.1, 9.3, etc.]
# - 9+ requires Java 9 or higher [9.0, 9.1, 10, etc.]
# - 9.1 requires Java 9.1 (any update) [9.1.*, 9.1.2, 9.1.13, etc.]
# - 9.1* requires Java 9.1 (any update) [9.1.*, 9.1.2, 9.1.13, etc.]
# - 9.1+ requires Java 9.1 or higher [9.1, 9.2, 10, etc.]
# - 9.1.3 requires Java 9.1.3 [9.1.3]
# - 9.1.3* requires Java 9.1.3 (any update) [9.1.3]
# - 9.1.3+ requires Java 9.1.3 or higher [9.1.3, 9.1.4, 9.2.*, 10, etc.]
# - 10-ea requires Java 10 (early access release)
#
# unsupported requirement patterns are for example:
# - 1.2, 1.3, 1.9 Java 2, 3 are not supported
# - 1.9 Java 9 introduced a new versioning scheme
# - 6u45 known versioning syntax, but unsupported
# - 9-ea*, 9-ea+ early access releases paired with */+
# - 9., 9.*, 9.+ version ending with a .
# - 9.1., 9.1.*, 9.1.+ version ending with a .
# - 9.3.5.6 4 part version number is unsupported
#
# @param1 a Java requirement string ('1.8+')
# @return boolean exit code: 0 (is valid), 1 (is not valid)
################################################################################
function is_valid_requirement_pattern() {
local java_req=$1
java8pattern='1\.[4-8](\.[0-9]+)?(\.0_[0-9]+)?[*+]?'
java9pattern='(9|1[0-9])(-ea|[*+]|(\.[0-9]+){1,2}[*+]?)?'
# test matches either old Java versioning scheme (up to 1.8) or new scheme (starting with 9)
if [[ ${java_req} =~ ^(${java8pattern}|${java9pattern})$ ]]; then
return 0
else
return 1
fi
}
# determine which JVM to use
############################################
# default Apple JRE plugin path (< 1.6)
apple_jre_plugin="/Library/Java/Home/bin/java"
apple_jre_version=$(get_java_version_from_cmd "${apple_jre_plugin}")
# default Oracle JRE plugin path (>= 1.7)
oracle_jre_plugin="/Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home/bin/java"
oracle_jre_version=$(get_java_version_from_cmd "${oracle_jre_plugin}")
# first check system variable "$JAVA_HOME" -> has precedence over any other System JVM
stub_logger '[JavaSearch] Checking for $JAVA_HOME ...'
if [ -n "$JAVA_HOME" ] ; then
stub_logger "[JavaSearch] ... found JAVA_HOME with value $JAVA_HOME"
# PR 26: Allow specifying "$JAVA_HOME" relative to "$AppPackageFolder"
# which allows for bundling a custom version of Java inside your app!
if [[ $JAVA_HOME == /* ]] ; then
# if "$JAVA_HOME" starts with a Slash it's an absolute path
JAVACMD="$JAVA_HOME/bin/java"
stub_logger "[JavaSearch] ... parsing JAVA_HOME as absolute path to the executable '$JAVACMD'"
else
# otherwise it's a relative path to "$AppPackageFolder"
JAVACMD="$AppPackageFolder/$JAVA_HOME/bin/java"
stub_logger "[JavaSearch] ... parsing JAVA_HOME as relative path inside the App bundle to the executable '$JAVACMD'"
fi
JAVACMD_version=$(get_comparable_java_version $(get_java_version_from_cmd "${JAVACMD}"))
else
stub_logger "[JavaSearch] ... haven't found JAVA_HOME"
fi
# check for any other or a specific Java version
# also if $JAVA_HOME exists but isn't executable
if [ -z "${JAVACMD}" ] || [ ! -x "${JAVACMD}" ] ; then
# add a warning in the syslog if JAVA_HOME is not executable or not found (#100)
if [ -n "$JAVA_HOME" ] ; then
stub_logger "[JavaSearch] ... but no 'java' executable was found at the JAVA_HOME location!"
fi
stub_logger "[JavaSearch] Searching for JavaVirtualMachines on the system ..."
# reset variables
JAVACMD=""
JAVACMD_version=""
# first check whether JVMVersion string is a valid requirement string
if [ ! -z "${JVMVersion}" ] && ! is_valid_requirement_pattern ${JVMVersion} ; then
MSG_JVMVERSION_REQ_INVALID_EXPANDED=$(printf "${MSG_JVMVERSION_REQ_INVALID}" "${JVMVersion}")
# log exit cause
stub_logger "[EXIT 4] ${MSG_JVMVERSION_REQ_INVALID_EXPANDED}"
# display error message with AppleScript
osascript -e "tell application \"System Events\" to display dialog \"${MSG_ERROR_LAUNCHING}\n\n${MSG_JVMVERSION_REQ_INVALID_EXPANDED}\" with title \"${CFBundleName}\" buttons {\" OK \"} default button 1${DialogWithIcon}"
# exit with error
exit 4
fi
# then check whether JVMMaxVersion string is a valid requirement string
if [ ! -z "${JVMMaxVersion}" ] && ! is_valid_requirement_pattern ${JVMMaxVersion} ; then
MSG_JVMVERSION_REQ_INVALID_EXPANDED=$(printf "${MSG_JVMVERSION_REQ_INVALID}" "${JVMMaxVersion}")
# log exit cause
stub_logger "[EXIT 5] ${MSG_JVMVERSION_REQ_INVALID_EXPANDED}"
# display error message with AppleScript
osascript -e "tell application \"System Events\" to display dialog \"${MSG_ERROR_LAUNCHING}\n\n${MSG_JVMVERSION_REQ_INVALID_EXPANDED}\" with title \"${CFBundleName}\" buttons {\" OK \"} default button 1${DialogWithIcon}"
# exit with error
exit 5
fi
# find installed JavaVirtualMachines (JDK + JRE)
allJVMs=()
# read JDK's from '/usr/libexec/java_home --xml' command with PlistBuddy and a custom Dict iterator
# idea: https://stackoverflow.com/a/14085460/1128689 and https://scriptingosx.com/2018/07/parsing-dscl-output-in-scripts/
javaXml=$(/usr/libexec/java_home --xml)
javaCounter=$(/usr/libexec/PlistBuddy -c "Print" /dev/stdin <<< $javaXml | grep "Dict" | wc -l | tr -d ' ')
# iterate over all Dict entries
# but only if there are any JVMs at all (#93)
if [ "$javaCounter" -gt "0" ] ; then
for idx in $(seq 0 $((javaCounter - 1)))
do
version=$(/usr/libexec/PlistBuddy -c "print :$idx:JVMVersion" /dev/stdin <<< $javaXml)
path=$(/usr/libexec/PlistBuddy -c "print :$idx:JVMHomePath" /dev/stdin <<< $javaXml)
path+="/bin/java"
allJVMs+=("$version:$path")
done
# unset for loop variables
unset version path
fi
# add SDKMAN! java versions (#95)
if [ -d ~/.sdkman/candidates/java/ ] ; then
for sdkjdk in ~/.sdkman/candidates/java/*/
do
if [[ ${sdkjdk} =~ /current/$ ]] ; then
continue
fi
sdkjdkcmd="${sdkjdk}bin/java"
version=$(get_java_version_from_cmd "${sdkjdkcmd}")
allJVMs+=("$version:$sdkjdkcmd")
done
# unset for loop variables
unset version
fi
# add Apple JRE if available
if [ -x "${apple_jre_plugin}" ] ; then
allJVMs+=("$apple_jre_version:$apple_jre_plugin")
fi
# add Oracle JRE if available
if [ -x "${oracle_jre_plugin}" ] ; then
allJVMs+=("$oracle_jre_version:$oracle_jre_plugin")
fi
# debug output
for i in "${allJVMs[@]}"
do
stub_logger "[JavaSearch] ... found JVM: $i"
done
# determine JVMs matching the min/max version requirement
stub_logger "[JavaSearch] Filtering the result list for JVMs matching the min/max version requirement ..."
minC=$(get_comparable_java_version ${JVMVersion})
maxC=$(get_comparable_java_version ${JVMMaxVersion})
matchingJVMs=()
for i in "${allJVMs[@]}"
do
# split JVM string at ':' delimiter to retain spaces in $path substring
IFS=: arr=($i) ; unset IFS
# [0] JVM version number
ver=${arr[0]}
# comparable JVM version number
comp=$(get_comparable_java_version $ver)
# [1] JVM path
path="${arr[1]}"
# construct string item for adding to the "matchingJVMs" array
item="$comp:$ver:$path"
# pre-requisite: current version number needs to be greater than min version number
if [ "$comp" -ge "$minC" ] ; then
# perform max version checks if max version requirement is present
if [ ! -z ${JVMMaxVersion} ] ; then
# max version requirement ends with '*' modifier
if [[ ${JVMMaxVersion} == *\* ]] ; then
# use the '*' modifier from the max version string as wildcard for a 'starts with' comparison
# and check whether the current version number starts with the max version wildcard string
if [[ ${ver} == ${JVMMaxVersion} ]]; then
matchingJVMs+=("$item")
# or whether the current comparable version is lower than the comparable max version
elif [ "$comp" -le "$maxC" ] ; then
matchingJVMs+=("$item")
fi
# max version requirement ends with '+' modifier -> always add this version if it's greater than $min
# because a max requirement with + modifier doesn't make sense
elif [[ ${JVMMaxVersion} == *+ ]] ; then
matchingJVMs+=("$item")
# matches 6 zeros at the end of the max version string (e.g. for 1.8, 9)
# -> then the max version string should be treated like with a '*' modifier at the end
#elif [[ ${maxC} =~ ^[0-9]{2}0{6}$ ]] && [ "$comp" -le $(( ${maxC#0} + 999 )) ] ; then
# matchingJVMs+=("$item")
# matches 3 zeros at the end of the max version string (e.g. for 9.1, 10.3)
# -> then the max version string should be treated like with a '*' modifier at the end
#elif [[ ${maxC} =~ ^[0-9]{5}0{3}$ ]] && [ "$comp" -le "${maxC}" ] ; then
# matchingJVMs+=("$item")
# matches standard requirements without modifier
elif [ "$comp" -le "$maxC" ]; then
matchingJVMs+=("$item")
fi
# no max version requirement:
# min version requirement ends with '+' modifier
# -> always add the current version because it's greater than $min
elif [[ ${JVMVersion} == *+ ]] ; then
matchingJVMs+=("$item")
# min version requirement ends with '*' modifier
# -> use the '*' modifier from the min version string as wildcard for a 'starts with' comparison
# and check whether the current version number starts with the min version wildcard string
elif [[ ${JVMVersion} == *\* ]] ; then
if [[ ${ver} == ${JVMVersion} ]] ; then
matchingJVMs+=("$item")
fi
# compare the min version against the current version with an additional * wildcard for a 'starts with' comparison
# -> e.g. add 1.8.0_44 when the requirement is 1.8
elif [[ ${ver} == ${JVMVersion}* ]] ; then
matchingJVMs+=("$item")
fi
fi
done
# unset for loop variables
unset arr ver comp path item
# debug output
for i in "${matchingJVMs[@]}"
do
stub_logger "[JavaSearch] ... matches all requirements: $i"
done
# sort the matching JavaVirtualMachines by version number
# https://stackoverflow.com/a/11789688/1128689
IFS=$'\n' matchingJVMs=($(sort -nr <<<"${matchingJVMs[*]}"))
unset IFS
# get the highest matching JVM
for ((i = 0; i < ${#matchingJVMs[@]}; i++));
do
# split JVM string at ':' delimiter to retain spaces in $path substring
IFS=: arr=(${matchingJVMs[$i]}) ; unset IFS
# [0] comparable JVM version number
comp=${arr[0]}
# [1] JVM version number
ver=${arr[1]}
# [2] JVM path
path="${arr[2]}"
# use current value as JAVACMD if it's executable
if [ -x "$path" ] ; then
JAVACMD="$path"
JAVACMD_version=$comp
break
fi
done
# unset for loop variables
unset arr comp ver path
fi
# log the Java Command and the extracted version number
stub_logger "[JavaCommand] '$JAVACMD'"
stub_logger "[JavaVersion] $(get_java_version_from_cmd "${JAVACMD}")${JAVACMD_version:+ / $JAVACMD_version}"
# Make sure tabbing mode is disabled for the selected java version
CFBundleIdentifier=net.java.openjdk.$(get_java_version_from_cmd "${JAVACMD}").java
if [ x$(defaults read ${CFBundleIdentifier} AppleWindowTabbingMode) != "xnever" ]; then
defaults write ${CFBundleIdentifier} AppleWindowTabbingMode never
fi
if [ -z "${JAVACMD}" ] || [ ! -x "${JAVACMD}" ] ; then
# different error messages when a specific JVM was required
if [ ! -z "${JVMVersion}" ] ; then
# display human readable java version (#28)
java_version_hr=$(echo ${JVMVersion} | sed -E 's/^1\.([0-9+*]+)$/ \1/g' | sed "s/+/ ${MSG_JAVA_VERSION_OR_LATER}/;s/*/ ${MSG_JAVA_VERSION_LATEST}/")
MSG_NO_SUITABLE_JAVA_EXPANDED=$(printf "${MSG_NO_SUITABLE_JAVA}" "${java_version_hr}").
if [ ! -z "${JVMMaxVersion}" ] ; then
java_version_hr=$(extract_java_major_version ${JVMVersion})
java_version_max_hr=$(echo ${JVMMaxVersion} | sed -E 's/^1\.([0-9+*]+)$/ \1/g' | sed "s/+//;s/*/ ${MSG_JAVA_VERSION_LATEST}/")
MSG_NO_SUITABLE_JAVA_EXPANDED="$(printf "${MSG_NO_SUITABLE_JAVA}" "${java_version_hr}") $(printf "${MSG_JAVA_VERSION_MAX}" "${java_version_max_hr}")"
fi
# log exit cause
stub_logger "[EXIT 3] ${MSG_NO_SUITABLE_JAVA_EXPANDED}"
# display error message with AppleScript
osascript -e "tell application \"System Events\" to display dialog \"${MSG_ERROR_LAUNCHING}\n\n${MSG_NO_SUITABLE_JAVA_EXPANDED}\n${MSG_NO_SUITABLE_JAVA_CHECK}\" with title \"${CFBundleName}\" buttons {\" OK \", \"${MSG_VISIT_JAVA_DOT_COM}\", \"${MSG_VISIT_ADOPTIUM}\"} default button 1${DialogWithIcon}" \
-e "set response to button returned of the result" \
-e "if response is \"${MSG_VISIT_JAVA_DOT_COM}\" then open location \"https://www.java.com/download/\"" \
-e "if response is \"${MSG_VISIT_ADOPTIUM}\" then open location \"https://adoptium.net/releases.html\""
# exit with error
exit 3
else
# log exit cause
stub_logger "[EXIT 1] ${MSG_ERROR_LAUNCHING}"
# display error message with AppleScript
osascript -e "tell application \"System Events\" to display dialog \"${MSG_ERROR_LAUNCHING}\n\n${MSG_INSTALL_JAVA}\" with title \"${CFBundleName}\" buttons {\"${MSG_LATER}\", \"${MSG_VISIT_JAVA_DOT_COM}\", \"${MSG_VISIT_ADOPTIUM}\"} default button 1${DialogWithIcon}" \
-e "set response to button returned of the result" \
-e "if response is \"${MSG_VISIT_JAVA_DOT_COM}\" then open location \"https://www.java.com/download/\"" \
-e "if response is \"${MSG_VISIT_ADOPTIUM}\" then open location \"https://adoptium.net/releases.html\""
# exit with error
exit 1
fi
fi
# MainClass check
############################################
if [ -z "${JVMMainClass}" ]; then
# log exit cause
stub_logger "[EXIT 2] ${MSG_MISSING_MAINCLASS}"
# display error message with AppleScript
osascript -e "tell application \"System Events\" to display dialog \"${MSG_ERROR_LAUNCHING}\n\n${MSG_MISSING_MAINCLASS}\" with title \"${CFBundleName}\" buttons {\" OK \"} default button 1${DialogWithIcon}"
# exit with error
exit 2
fi
# execute $JAVACMD and do some preparation
############################################
# enable drag&drop to the dock icon
export CFProcessPath="$0"
# remove Apples ProcessSerialNumber from passthru arguments (#39)
if [[ "$*" == -psn* ]] ; then
ArgsPassthru=()
else
ArgsPassthru=("$@")
fi
# change to Working Directory based upon Apple/Oracle Plist info
cd "${WorkingDirectory}" || exit 13
stub_logger "[WorkingDirectory] ${WorkingDirectory}"
# execute Java and set
# - classpath
# - splash image
# - dock icon
# - app name
# - JVM options / properties (-D)
# - JVM default options (-X)
# - main class
# - main class arguments
# - passthrough arguments from Terminal or Drag'n'Drop to Finder icon
stub_logger "[Exec] \"$JAVACMD\" -cp \"${JVMClassPath}\" ${JVMSplashFile:+ -splash:\"${ResourcesFolder}/${JVMSplashFile}\"} -Xdock:icon=\"${ResourcesFolder}/${CFBundleIconFile}\" -Xdock:name=\"${CFBundleName}\" ${JVMOptionsArr:+$(printf "'%s' " "${JVMOptionsArr[@]}") }${JVMDefaultOptions:+$JVMDefaultOptions }${JVMMainClass}${MainArgsArr:+ $(printf "'%s' " "${MainArgsArr[@]}")}${ArgsPassthru:+ $(printf "'%s' " "${ArgsPassthru[@]}")}"
exec "${JAVACMD}" \
-Djava.library.path="${AppleJavaFolder}" \
-cp "${JVMClassPath}" \
${JVMSplashFile:+ -splash:"${ResourcesFolder}/${JVMSplashFile}"} \
-Xdock:icon="${ResourcesFolder}/${CFBundleIconFile}" \
-Xdock:name="${CFBundleName}" \
${JVMOptionsArr:+"${JVMOptionsArr[@]}" }\
${JVMDefaultOptions:+$JVMDefaultOptions }\
"${JVMMainClass}"\
${MainArgsArr:+ "${MainArgsArr[@]}"}\
${ArgsPassthru:+ "${ArgsPassthru[@]}"}

View File

@@ -0,0 +1 @@
APPLAM.O

651
altosui/AltosUI.java Normal file
View File

@@ -0,0 +1,651 @@
/*
* 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; 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.
*/
package altosui;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.io.*;
import java.util.concurrent.*;
import org.altusmetrum.altoslib_14.*;
import org.altusmetrum.altosuilib_14.*;
public class AltosUI extends AltosUIFrame implements AltosEepromGrapher {
public AltosVoice voice = new AltosVoice();
public static boolean load_library(Frame frame) {
if (!Altos.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(new AltosSerial(device));
if (reader != null)
new AltosFlightUI(voice, reader, device.getSerial());
} catch (FileNotFoundException ee) {
JOptionPane.showMessageDialog(AltosUI.this,
ee.getMessage(),
String.format ("Cannot open %s", device.toShortString()),
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,
String.format ("Unknown I/O error on %s", device.toShortString()),
"Unknown I/O error",
JOptionPane.ERROR_MESSAGE);
} catch (TimeoutException te) {
JOptionPane.showMessageDialog(this,
String.format ("Timeout on %s", device.toShortString()),
"Timeout error",
JOptionPane.ERROR_MESSAGE);
} catch (InterruptedException ie) {
JOptionPane.showMessageDialog(this,
String.format("Interrupted %s", device.toShortString()),
"Interrupted exception",
JOptionPane.ERROR_MESSAGE);
}
}
public void scan_device_selected(AltosDevice device) {
telemetry_window(device);
}
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;
}
/* OSXAdapter interfaces */
public void macosx_file_handler(String path) {
process_graph(null, new File(path));
}
public void macosx_quit_handler() {
System.exit(0);
}
public void macosx_preferences_handler() {
ConfigureAltosUI();
}
public AltosUI() {
load_library(null);
register_for_macosx_events();
AltosUIPreferences.set_component(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.setToolTipText("Connect to TeleDongle and monitor telemetry");
b = addButton(1, 0, "Save Flight Data");
b.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
SaveFlightData();
}
});
b.setToolTipText("Download and/or delete flight data from an altimeter");
b = addButton(2, 0, "Replay Flight");
b.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
Replay();
}
});
b.setToolTipText("Watch an old flight in real-time");
b = addButton(3, 0, "Graph Data");
b.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
GraphData();
}
});
b.setToolTipText("Present flight data in a graph and table of statistics");
b = addButton(4, 0, "Export Data");
b.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
ExportData();
}
});
b.setToolTipText("Convert flight data for a spreadsheet or GoogleEarth");
b = addButton(0, 1, "Configure Altimeter");
b.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
ConfigureTeleMetrum();
}
});
b.setToolTipText("Set flight, storage and communication parameters");
b = addButton(1, 1, "Configure AltosUI");
b.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
ConfigureAltosUI();
}
});
b.setToolTipText("Global AltosUI settings");
b = addButton(2, 1, "Configure Ground Station");
b.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
ConfigureTeleDongle();
}
});
b = addButton(3, 1, "Flash Image");
b.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
FlashImage();
}
});
b.setToolTipText("Replace the firmware in any AltusMetrum product");
b = addButton(4, 1, "Fire Igniter");
b.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
FireIgniter();
}
});
b.setToolTipText("Remote control of igniters for deployment testing");
b = addButton(0, 2, "Scan Channels");
b.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
ScanChannels();
}
});
b.setToolTipText("Find what channel an altimeter is sending telemetry on");
b = addButton(1, 2, "Load Maps");
b.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
LoadMaps();
}
});
b.setToolTipText("Download satellite images for off-line flight monitoring");
b = addButton(2, 2, "Monitor Idle");
b.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
IdleMonitor();
}
});
b.setToolTipText("Check flight readiness of altimeter in idle mode");
// b = addButton(3, 2, "Launch Controller");
// b.addActionListener(new ActionListener() {
// public void actionPerformed(ActionEvent e) {
// LaunchController();
// }
// });
b = addButton(4, 2, "Quit");
b.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
});
b.setToolTipText("Close all active windows and terminate AltosUI");
setTitle("AltOS");
pane.doLayout();
pane.validate();
doLayout();
validate();
setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
setLocationByPlatform(false);
/* Insets aren't set before the window is visible */
setVisible(true);
}
private void ConnectToDevice() {
AltosDevice device = AltosDeviceUIDialog.show(AltosUI.this,
Altos.product_basestation);
if (device != null)
telemetry_window(device);
}
void ConfigureCallsign() {
String result;
result = JOptionPane.showInputDialog(AltosUI.this,
"Configure Callsign",
AltosUIPreferences.callsign());
if (result != null)
AltosUIPreferences.set_callsign(result);
}
void ConfigureTeleMetrum() {
new AltosConfigFC(AltosUI.this);
}
void ConfigureTeleDongle() {
new AltosConfigTD(AltosUI.this);
}
void FlashImage() {
AltosFlashUI.show(AltosUI.this);
}
void FireIgniter() {
new AltosIgniteUI(AltosUI.this);
}
void ScanChannels() {
new AltosScanUI(AltosUI.this, true);
}
void LoadMaps() {
new AltosUIMapPreload(AltosUI.this);
}
void LaunchController() {
new AltosLaunchUI(AltosUI.this);
}
/*
* Replay a flight from telemetry data
*/
private void Replay() {
AltosDataChooser chooser = new AltosDataChooser(
AltosUI.this);
AltosRecordSet set = chooser.runDialog();
if (set != null) {
AltosReplayReader reader = new AltosReplayReader(set, chooser.file());
new AltosFlightUI(voice, reader);
}
}
/* Connect to TeleMetrum, either directly or through
* a TeleDongle over the packet link
*/
public void graph_flights(AltosEepromList flights) {
for (AltosEepromLog flight : flights) {
if (flight.graph_selected && flight.file != null) {
process_graph(this, flight.file);
}
}
}
private void SaveFlightData() {
new AltosEepromManage(this, this, AltosLib.product_any);
}
private static AltosFlightSeries make_series(AltosRecordSet set) {
AltosFlightSeries series = new AltosFlightSeries(set.cal_data());
set.capture_series(series);
series.finish();
return series;
}
/* 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);
AltosRecordSet set = chooser.runDialog();
if (set == null)
return;
AltosFlightSeries series = make_series(set);
new AltosCSVUI(AltosUI.this, series, chooser.file());
}
private static boolean graph_file(AltosUI altosui, AltosRecordSet set, File file) {
if (set == null)
return false;
if (!set.valid()) {
JOptionPane.showMessageDialog(altosui,
String.format("Failed to parse file %s", file),
"Graph Failed",
JOptionPane.ERROR_MESSAGE);
return false;
}
try {
new AltosGraphUI(set, file);
return true;
} catch (InterruptedException ie) {
} catch (IOException ie) {
}
return false;
}
/* Load a flight log CSV file and display a pretty graph.
*/
private void GraphData() {
AltosDataChooser chooser;
chooser = new AltosDataChooser(this);
AltosRecordSet set = chooser.runDialog();
graph_file(this, set, chooser.file());
}
private void ConfigureAltosUI() {
new AltosConfigureUI(AltosUI.this, voice);
}
private void IdleMonitor() {
try {
new AltosIdleMonitorUI(this);
} catch (Exception e) {
}
}
static AltosWriter open_csv(File file) {
try {
return new AltosCSV(file);
} catch (FileNotFoundException fe) {
System.out.printf("%s\n", fe.getMessage());
return null;
}
}
static AltosWriter open_kml(File file) {
try {
return new AltosKML(file);
} catch (FileNotFoundException fe) {
System.out.printf("%s\n", fe.getMessage());
return null;
}
}
static AltosRecordSet record_set(File input) {
try {
return AltosLib.record_set(input);
} catch (IOException ie) {
String message = ie.getMessage();
if (message == null)
message = String.format("%s (I/O error)", input.toString());
System.err.printf("%s: %s\n", input.toString(), message);
}
return null;
}
static final int process_none = 0;
static final int process_csv = 1;
static final int process_kml = 2;
static final int process_graph = 3;
static final int process_replay = 4;
static final int process_summary = 5;
static final int process_oneline = 6;
static boolean process_csv(File input) {
AltosRecordSet set = record_set(input);
if (set == null)
return false;
File 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);
return false;
} else {
AltosWriter writer = open_csv(output);
if (writer == null)
return false;
AltosFlightSeries series = make_series(set);
writer.write(series);
writer.close();
}
return true;
}
static boolean process_kml(File input) {
AltosRecordSet set = record_set(input);
if (set == null)
return false;
File 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);
return false;
} else {
AltosWriter writer = open_kml(output);
if (writer == null)
return false;
AltosFlightSeries series = make_series(set);
series.finish();
writer.write(series);
writer.close();
return true;
}
}
static AltosReplayReader replay_file(File file) {
AltosRecordSet set = record_set(file);
if (set == null)
return null;
return new AltosReplayReader(set, file);
}
static boolean process_replay(File file) {
AltosReplayReader reader = replay_file(file);
if (reader == null)
return false;
AltosFlightUI flight_ui = new AltosFlightUI(new AltosVoice(), reader);
return true;
}
static boolean process_graph(AltosUI altosui, File file) {
AltosRecordSet set = record_set(file);
return graph_file(altosui, set, file);
}
static boolean process_summary(File file) {
AltosRecordSet set = record_set(file);
if (set == null)
return false;
System.out.printf("%s:\n", file.toString());
AltosFlightSeries series = make_series(set);
AltosFlightStats stats = new AltosFlightStats(series);
if (stats.serial != AltosLib.MISSING)
System.out.printf("Serial: %5d\n", stats.serial);
if (stats.flight != AltosLib.MISSING)
System.out.printf("Flight: %5d\n", stats.flight);
if (stats.year != AltosLib.MISSING)
System.out.printf("Date: %04d-%02d-%02d\n",
stats.year, stats.month, stats.day);
if (stats.hour != AltosLib.MISSING)
System.out.printf("Time: %02d:%02d:%02d UTC\n",
stats.hour, stats.minute, stats.second);
if (stats.max_height != AltosLib.MISSING)
System.out.printf("Max height: %6.0f m %6.0f ft\n",
stats.max_height,
AltosConvert.meters_to_feet(stats.max_height));
if (stats.max_speed != AltosLib.MISSING)
System.out.printf("Max speed: %6.0f m/s %6.0f ft/s %6.4f Mach\n",
stats.max_speed,
AltosConvert.meters_to_feet(stats.max_speed),
AltosConvert.meters_to_mach(stats.max_speed));
if (stats.max_acceleration != AltosLib.MISSING) {
System.out.printf("Max accel: %6.0f m/s² %6.0f ft/s² %6.2f g\n",
stats.max_acceleration,
AltosConvert.meters_to_feet(stats.max_acceleration),
AltosConvert.meters_to_g(stats.max_acceleration));
}
if (stats.state_speed[Altos.ao_flight_drogue] != AltosLib.MISSING)
System.out.printf("Drogue rate: %6.0f m/s %6.0f ft/s\n",
stats.state_speed[Altos.ao_flight_drogue],
AltosConvert.meters_to_feet(stats.state_speed[Altos.ao_flight_drogue]));
if (stats.state_speed[Altos.ao_flight_main] != AltosLib.MISSING)
System.out.printf("Main rate: %6.0f m/s %6.0f ft/s\n",
stats.state_speed[Altos.ao_flight_main],
AltosConvert.meters_to_feet(stats.state_speed[Altos.ao_flight_main]));
if (stats.landed_time != AltosLib.MISSING &&
stats.boost_time != AltosLib.MISSING &&
stats.landed_time > stats.boost_time)
System.out.printf("Flight time: %6.0f s\n",
stats.landed_time -
stats.boost_time);
System.out.printf("\n");
return true;
}
static boolean process_oneline(File file) {
AltosRecordSet set = record_set(file);
if (set == null)
return false;
System.out.printf("%s", file.toString());
AltosFlightSeries series = make_series(set);
AltosFlightStats stats = new AltosFlightStats(series);
if (stats.max_height != AltosLib.MISSING)
System.out.printf(" height %6.0f m", stats.max_height);
if (stats.max_speed != AltosLib.MISSING)
System.out.printf(" speed %6.0f m/s", stats.max_speed);
if (stats.state_enter_speed[AltosLib.ao_flight_drogue] != AltosLib.MISSING)
System.out.printf(" drogue-deploy %6.0f m/s", stats.state_enter_speed[AltosLib.ao_flight_drogue]);
if (stats.max_acceleration != AltosLib.MISSING)
System.out.printf(" accel %6.0f m/s²", stats.max_acceleration);
System.out.printf("\n");
return true;
}
public static void help(int code) {
System.out.printf("Usage: altosui [OPTION]... [FILE]...\n");
System.out.printf(" Options:\n");
System.out.printf(" --replay <filename>\t\trelive the glory of past flights \n");
System.out.printf(" --graph <filename>\t\tgraph a flight\n");
System.out.printf(" --summary <filename>\t\tText summary of a flight\n");
System.out.printf(" --oneline <filename>\t\tOne line summary of a flight\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");
System.exit(code);
}
public static void main(final String[] args) {
int errors = 0;
load_library(null);
try {
UIManager.setLookAndFeel(AltosUIPreferences.look_and_feel());
} catch (Exception e) {
}
AltosUI altosui = null;
/* Handle batch-mode */
if (args.length == 0) {
altosui = new AltosUI();
java.util.List<AltosDevice> devices = AltosUSBDevice.list(Altos.product_basestation);
if (devices != null)
for (AltosDevice device : devices)
altosui.telemetry_window(device);
} else {
int process = process_none;
for (int i = 0; i < args.length; i++) {
if (args[i].equals("--help"))
help(0);
else if (args[i].equals("--replay"))
process = process_replay;
else if (args[i].equals("--kml"))
process = process_kml;
else if (args[i].equals("--csv"))
process = process_csv;
else if (args[i].equals("--graph"))
process = process_graph;
else if (args[i].equals("--summary"))
process = process_summary;
else if (args[i].equals("--oneline"))
process = process_oneline;
else if (args[i].startsWith("--"))
help(1);
else {
File file = new File(args[i]);
switch (process) {
case process_none:
if (altosui == null)
altosui = new AltosUI();
case process_graph:
if (!process_graph(null, file))
++errors;
break;
case process_replay:
if (!process_replay(file))
++errors;
break;
case process_kml:
if (!process_kml(file))
++errors;
break;
case process_csv:
if (!process_csv(file))
++errors;
break;
case process_summary:
if (!process_summary(file))
++errors;
break;
case process_oneline:
if (!process_oneline(file))
++errors;
break;
}
}
}
}
if (errors != 0)
System.exit(errors);
}
}

73
altosui/Info.plist.in Normal file
View File

@@ -0,0 +1,73 @@
<?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>@VERSION@</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>CFBundleIdentifier</key>
<string>org.altusmetrum.altosui</string>
<key>CFBundleSignature</key>
<string>Altu</string>
<key>CFBundleGetInfoString</key>
<string>AltOS UI version @VERSION@</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleIconFile</key>
<string>altusmetrum-altosui.icns</string>
<key>CFBundleDocumentTypes</key>
<array>
<dict>
<key>CFBundleTypeName</key>
<string>Telemetry</string>
<key>CFBundleTypeIconFile</key>
<string>application-vnd.altusmetrum.telemetry.icns</string>
<key>CFBundleTypeExtensions</key>
<array>
<string>telem</string>
</array>
<key>CFBundleTypeRole</key>
<string>Editor</string>
</dict>
<dict>
<key>CFBundleTypeName</key>
<string>Eeprom</string>
<key>CFBundleTypeIconFile</key>
<string>application-vnd.altusmetrum.eeprom.icns</string>
<key>CFBundleTypeExtensions</key>
<array>
<string>eeprom</string>
</array>
<key>CFBundleTypeRole</key>
<string>Editor</string>
</dict>
</array>
<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>
<key>VMOptions</key>
<array>
<string>-Xms512M</string>
<string>-Xmx512M</string>
<string>-Dosgi.clean=true</string>
</array>
</dict>
</dict>
</plist>

View File

@@ -0,0 +1,84 @@
#
# InstDrv Example, (c) 2003 Jan Kiszka (Jan Kiszka@web.de)
#
Name "InstDrv.dll test"
OutFile "InstDrv-Test.exe"
ShowInstDetails show
ComponentText "InstDrv Plugin Usage Example"
Page components
Page instfiles
Section "Install a Driver" InstDriver
InstDrv::InitDriverSetup /NOUNLOAD "{4d36e978-e325-11ce-bfc1-08002be10318}" "IrCOMM2k"
Pop $0
DetailPrint "InitDriverSetup: $0"
InstDrv::DeleteOemInfFiles /NOUNLOAD
Pop $0
DetailPrint "DeleteOemInfFiles: $0"
StrCmp $0 "00000000" PrintInfNames ContInst1
PrintInfNames:
Pop $0
DetailPrint "Deleted $0"
Pop $0
DetailPrint "Deleted $0"
ContInst1:
InstDrv::CreateDevice /NOUNLOAD
Pop $0
DetailPrint "CreateDevice: $0"
SetOutPath $TEMP
File "ircomm2k.inf"
File "ircomm2k.sys"
InstDrv::InstallDriver /NOUNLOAD "$TEMP\ircomm2k.inf"
Pop $0
DetailPrint "InstallDriver: $0"
StrCmp $0 "00000000" PrintReboot ContInst2
PrintReboot:
Pop $0
DetailPrint "Reboot: $0"
ContInst2:
InstDrv::CountDevices
Pop $0
DetailPrint "CountDevices: $0"
SectionEnd
Section "Uninstall the driver again" UninstDriver
InstDrv::InitDriverSetup /NOUNLOAD "{4d36e978-e325-11ce-bfc1-08002be10318}" "IrCOMM2k"
Pop $0
DetailPrint "InitDriverSetup: $0"
InstDrv::DeleteOemInfFiles /NOUNLOAD
Pop $0
DetailPrint "DeleteOemInfFiles: $0"
StrCmp $0 "00000000" PrintInfNames ContUninst1
PrintInfNames:
Pop $0
DetailPrint "Deleted $0"
Pop $0
DetailPrint "Deleted $0"
ContUninst1:
InstDrv::RemoveAllDevices
Pop $0
DetailPrint "RemoveAllDevices: $0"
StrCmp $0 "00000000" PrintReboot ContUninst2
PrintReboot:
Pop $0
DetailPrint "Reboot: $0"
ContUninst2:
Delete "$SYSDIR\system32\ircomm2k.sys"
SectionEnd

Binary file not shown.

View File

@@ -0,0 +1,704 @@
/*
InstDrv.dll - Installs or Removes Device Drivers
Copyright <20> 2003 Jan Kiszka (Jan.Kiszka@web.de)
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute
it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented;
you must not claim that you wrote the original software.
If you use this software in a product, an acknowledgment in the
product documentation would be appreciated but is not required.
2. Altered versions must be plainly marked as such,
and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any distribution.
*/
#include <windows.h>
#include <setupapi.h>
#include <newdev.h>
#include "../exdll/exdll.h"
char paramBuf[1024];
GUID devClass;
char hwIdBuf[1024];
int initialized = 0;
void* memset(void* dst, int val, unsigned int len)
{
while (len-- > 0)
*((char *)dst)++ = val;
return NULL;
}
void* memcpy(void* dst, const void* src, unsigned int len)
{
while (len-- > 0)
*((char *)dst)++ = *((char *)src)++;
return NULL;
}
int HexCharToInt(char c)
{
if ((c >= '0') && (c <= '9'))
return c - '0';
else if ((c >= 'a') && (c <= 'f'))
return c - 'a' + 10;
else if ((c >= 'A') && (c <= 'F'))
return c - 'A' + 10;
else
return -1;
}
BOOLEAN HexStringToUInt(char* str, int width, void* valBuf)
{
int i, val;
for (i = width - 4; i >= 0; i -= 4)
{
val = HexCharToInt(*str++);
if (val < 0)
return FALSE;
*(unsigned int *)valBuf += val << i;
}
return TRUE;
}
BOOLEAN StringToGUID(char* guidStr, GUID* pGuid)
{
int i;
memset(pGuid, 0, sizeof(GUID));
if (*guidStr++ != '{')
return FALSE;
if (!HexStringToUInt(guidStr, 32, &pGuid->Data1))
return FALSE;
guidStr += 8;
if (*guidStr++ != '-')
return FALSE;
if (!HexStringToUInt(guidStr, 16, &pGuid->Data2))
return FALSE;
guidStr += 4;
if (*guidStr++ != '-')
return FALSE;
if (!HexStringToUInt(guidStr, 16, &pGuid->Data3))
return FALSE;
guidStr += 4;
if (*guidStr++ != '-')
return FALSE;
for (i = 0; i < 2; i++)
{
if (!HexStringToUInt(guidStr, 8, &pGuid->Data4[i]))
return FALSE;
guidStr += 2;
}
if (*guidStr++ != '-')
return FALSE;
for (i = 2; i < 8; i++)
{
if (!HexStringToUInt(guidStr, 8, &pGuid->Data4[i]))
return FALSE;
guidStr += 2;
}
if (*guidStr++ != '}')
return FALSE;
return TRUE;
}
DWORD FindNextDevice(HDEVINFO devInfoSet, SP_DEVINFO_DATA* pDevInfoData, DWORD* pIndex)
{
DWORD buffersize = 0;
LPTSTR buffer = NULL;
DWORD dataType;
DWORD result;
while (1)
{
if (!SetupDiEnumDeviceInfo(devInfoSet, (*pIndex)++, pDevInfoData))
{
result = GetLastError();
break;
}
GetDeviceRegistryProperty:
if (!SetupDiGetDeviceRegistryProperty(devInfoSet, pDevInfoData, SPDRP_HARDWAREID,
&dataType, (PBYTE)buffer, buffersize,
&buffersize))
{
result = GetLastError();
if (result == ERROR_INSUFFICIENT_BUFFER)
{
if (buffer != NULL)
LocalFree(buffer);
buffer = (LPTSTR)LocalAlloc(LPTR, buffersize);
if (buffer == NULL)
break;
goto GetDeviceRegistryProperty;
}
else if (result == ERROR_INVALID_DATA)
continue; // ignore invalid entries
else
break; // break on other errors
}
if (lstrcmpi(buffer, hwIdBuf) == 0)
{
result = 0;
break;
}
}
if (buffer != NULL)
LocalFree(buffer);
return result;
}
DWORD FindFirstDevice(HWND hwndParent, const GUID* pDevClass, const LPTSTR hwId,
HDEVINFO* pDevInfoSet, SP_DEVINFO_DATA* pDevInfoData,
DWORD *pIndex, DWORD flags)
{
DWORD result;
*pDevInfoSet = SetupDiGetClassDevs((GUID*)pDevClass, NULL, hwndParent, flags);
if (*pDevInfoSet == INVALID_HANDLE_VALUE)
return GetLastError();
pDevInfoData->cbSize = sizeof(SP_DEVINFO_DATA);
*pIndex = 0;
result = FindNextDevice(*pDevInfoSet, pDevInfoData, pIndex);
if (result != 0)
SetupDiDestroyDeviceInfoList(*pDevInfoSet);
return result;
}
/*
* InstDrv::InitDriverSetup devClass drvHWID
*
* devClass - GUID of the driver's device setup class
* drvHWID - Hardware ID of the supported device
*
* Return:
* result - error message, empty on success
*/
void __declspec(dllexport) InitDriverSetup(HWND hwndParent, int string_size, char *variables, stack_t **stacktop)
{
EXDLL_INIT();
/* convert class GUID */
popstring(paramBuf);
if (!StringToGUID(paramBuf, &devClass))
{
popstring(paramBuf);
pushstring("Invalid GUID!");
return;
}
/* get hardware ID */
memset(hwIdBuf, 0, sizeof(hwIdBuf));
popstring(hwIdBuf);
initialized = 1;
pushstring("");
}
/*
* InstDrv::CountDevices
*
* Return:
* result - Number of installed devices the driver supports
*/
void __declspec(dllexport) CountDevices(HWND hwndParent, int string_size, char *variables, stack_t **stacktop)
{
HDEVINFO devInfoSet;
SP_DEVINFO_DATA devInfoData;
int count = 0;
char countBuf[16];
DWORD index;
DWORD result;
EXDLL_INIT();
if (!initialized)
{
pushstring("Fatal error!");
return;
}
result = FindFirstDevice(hwndParent, &devClass, hwIdBuf, &devInfoSet, &devInfoData,
&index, DIGCF_PRESENT);
if (result != 0)
{
pushstring("0");
return;
}
do
{
count++;
} while (FindNextDevice(devInfoSet, &devInfoData, &index) == 0);
SetupDiDestroyDeviceInfoList(devInfoSet);
wsprintf(countBuf, "%d", count);
pushstring(countBuf);
}
/*
* InstDrv::CreateDevice
*
* Return:
* result - Windows error code
*/
void __declspec(dllexport) CreateDevice(HWND hwndParent, int string_size, char *variables, stack_t **stacktop)
{
HDEVINFO devInfoSet;
SP_DEVINFO_DATA devInfoData;
DWORD result = 0;
char resultBuf[16];
EXDLL_INIT();
if (!initialized)
{
pushstring("Fatal error!");
return;
}
devInfoSet = SetupDiCreateDeviceInfoList(&devClass, hwndParent);
if (devInfoSet == INVALID_HANDLE_VALUE)
{
wsprintf(resultBuf, "%08X", GetLastError());
pushstring(resultBuf);
return;
}
devInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
if (!SetupDiCreateDeviceInfo(devInfoSet, hwIdBuf, &devClass, NULL,
hwndParent, DICD_GENERATE_ID, &devInfoData))
{
result = GetLastError();
goto InstallCleanup;
}
if (!SetupDiSetDeviceRegistryProperty(devInfoSet, &devInfoData, SPDRP_HARDWAREID,
hwIdBuf, (lstrlen(hwIdBuf)+2)*sizeof(TCHAR)))
{
result = GetLastError();
goto InstallCleanup;
}
if (!SetupDiCallClassInstaller(DIF_REGISTERDEVICE, devInfoSet, &devInfoData))
result = GetLastError();
InstallCleanup:
SetupDiDestroyDeviceInfoList(devInfoSet);
wsprintf(resultBuf, "%08X", result);
pushstring(resultBuf);
}
/*
* InstDrv::InstallDriver infPath
*
* Return:
* result - Windows error code
* reboot - non-zero if reboot is required
*/
void __declspec(dllexport) InstallDriver(HWND hwndParent, int string_size, char *variables, stack_t **stacktop)
{
char resultBuf[16];
BOOL reboot;
EXDLL_INIT();
popstring(paramBuf);
if (!initialized)
{
pushstring("Fatal error!");
return;
}
if (!UpdateDriverForPlugAndPlayDevices(hwndParent, hwIdBuf, paramBuf,
INSTALLFLAG_FORCE, &reboot))
{
wsprintf(resultBuf, "%08X", GetLastError());
pushstring(resultBuf);
}
else
{
wsprintf(resultBuf, "%d", reboot);
pushstring(resultBuf);
pushstring("00000000");
}
}
/*
* InstDrv::DeleteOemInfFiles
*
* Return:
* result - Windows error code
* oeminf - Path of the deleted devices setup file (oemXX.inf)
* oempnf - Path of the deleted devices setup file (oemXX.pnf)
*/
void __declspec(dllexport) DeleteOemInfFiles(HWND hwndParent, int string_size, char *variables, stack_t **stacktop)
{
HDEVINFO devInfo;
SP_DEVINFO_DATA devInfoData;
SP_DRVINFO_DATA drvInfoData;
SP_DRVINFO_DETAIL_DATA drvInfoDetail;
DWORD index;
DWORD result;
char resultBuf[16];
if (!initialized)
{
pushstring("Fatal error!");
return;
}
result = FindFirstDevice(NULL, &devClass, hwIdBuf, &devInfo, &devInfoData, &index, 0);
if (result != 0)
goto Cleanup1;
if (!SetupDiBuildDriverInfoList(devInfo, &devInfoData, SPDIT_COMPATDRIVER))
{
result = GetLastError();
goto Cleanup2;
}
drvInfoData.cbSize = sizeof(SP_DRVINFO_DATA);
drvInfoDetail.cbSize = sizeof(SP_DRVINFO_DETAIL_DATA);
if (!SetupDiEnumDriverInfo(devInfo, &devInfoData, SPDIT_COMPATDRIVER, 0, &drvInfoData))
{
result = GetLastError();
goto Cleanup3;
}
if (!SetupDiGetDriverInfoDetail(devInfo, &devInfoData, &drvInfoData,
&drvInfoDetail, sizeof(drvInfoDetail), NULL))
{
result = GetLastError();
if (result != ERROR_INSUFFICIENT_BUFFER)
goto Cleanup3;
result = 0;
}
pushstring(drvInfoDetail.InfFileName);
if (!DeleteFile(drvInfoDetail.InfFileName))
result = GetLastError();
else
{
index = lstrlen(drvInfoDetail.InfFileName);
if (index > 3)
{
lstrcpy(drvInfoDetail.InfFileName+index-3, "pnf");
pushstring(drvInfoDetail.InfFileName);
if (!DeleteFile(drvInfoDetail.InfFileName))
result = GetLastError();
}
}
Cleanup3:
SetupDiDestroyDriverInfoList(devInfo, &devInfoData, SPDIT_COMPATDRIVER);
Cleanup2:
SetupDiDestroyDeviceInfoList(devInfo);
Cleanup1:
wsprintf(resultBuf, "%08X", result);
pushstring(resultBuf);
}
/*
* InstDrv::RemoveAllDevices
*
* Return:
* result - Windows error code
* reboot - non-zero if reboot is required
*/
void __declspec(dllexport) RemoveAllDevices(HWND hwndParent, int string_size, char *variables, stack_t **stacktop)
{
HDEVINFO devInfo;
SP_DEVINFO_DATA devInfoData;
DWORD index;
DWORD result;
char resultBuf[16];
BOOL reboot = FALSE;
SP_DEVINSTALL_PARAMS instParams;
EXDLL_INIT();
if (!initialized)
{
pushstring("Fatal error!");
return;
}
result = FindFirstDevice(NULL, &devClass, hwIdBuf, &devInfo, &devInfoData, &index, 0);
if (result != 0)
goto Cleanup1;
do
{
if (!SetupDiCallClassInstaller(DIF_REMOVE, devInfo, &devInfoData))
{
result = GetLastError();
break;
}
instParams.cbSize = sizeof(instParams);
if (!reboot &&
SetupDiGetDeviceInstallParams(devInfo, &devInfoData, &instParams) &&
((instParams.Flags & (DI_NEEDRESTART|DI_NEEDREBOOT)) != 0))
{
reboot = TRUE;
}
result = FindNextDevice(devInfo, &devInfoData, &index);
} while (result == 0);
SetupDiDestroyDeviceInfoList(devInfo);
Cleanup1:
if ((result == 0) || (result == ERROR_NO_MORE_ITEMS))
{
wsprintf(resultBuf, "%d", reboot);
pushstring(resultBuf);
pushstring("00000000");
}
else
{
wsprintf(resultBuf, "%08X", result);
pushstring(resultBuf);
}
}
/*
* InstDrv::StartSystemService serviceName
*
* Return:
* result - Windows error code
*/
void __declspec(dllexport) StartSystemService(HWND hwndParent, int string_size, char *variables, stack_t **stacktop)
{
SC_HANDLE managerHndl;
SC_HANDLE svcHndl;
SERVICE_STATUS svcStatus;
DWORD oldCheckPoint;
DWORD result;
char resultBuf[16];
EXDLL_INIT();
popstring(paramBuf);
managerHndl = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (managerHndl == NULL)
{
result = GetLastError();
goto Cleanup1;
}
svcHndl = OpenService(managerHndl, paramBuf, SERVICE_START | SERVICE_QUERY_STATUS);
if (svcHndl == NULL)
{
result = GetLastError();
goto Cleanup2;
}
if (!StartService(svcHndl, 0, NULL) || !QueryServiceStatus(svcHndl, &svcStatus))
{
result = GetLastError();
goto Cleanup3;
}
while (svcStatus.dwCurrentState == SERVICE_START_PENDING)
{
oldCheckPoint = svcStatus.dwCheckPoint;
Sleep(svcStatus.dwWaitHint);
if (!QueryServiceStatus(svcHndl, &svcStatus))
{
result = GetLastError();
break;
}
if (oldCheckPoint >= svcStatus.dwCheckPoint)
{
if ((svcStatus.dwCurrentState == SERVICE_STOPPED) &&
(svcStatus.dwWin32ExitCode != 0))
result = svcStatus.dwWin32ExitCode;
else
result = ERROR_SERVICE_REQUEST_TIMEOUT;
}
}
if (svcStatus.dwCurrentState == SERVICE_RUNNING)
result = 0;
Cleanup3:
CloseServiceHandle(svcHndl);
Cleanup2:
CloseServiceHandle(managerHndl);
Cleanup1:
wsprintf(resultBuf, "%08X", result);
pushstring(resultBuf);
}
/*
* InstDrv::StopSystemService serviceName
*
* Return:
* result - Windows error code
*/
void __declspec(dllexport) StopSystemService(HWND hwndParent, int string_size, char *variables, stack_t **stacktop)
{
SC_HANDLE managerHndl;
SC_HANDLE svcHndl;
SERVICE_STATUS svcStatus;
DWORD oldCheckPoint;
DWORD result;
char resultBuf[16];
EXDLL_INIT();
popstring(paramBuf);
managerHndl = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (managerHndl == NULL)
{
result = GetLastError();
goto Cleanup1;
}
svcHndl = OpenService(managerHndl, paramBuf, SERVICE_STOP | SERVICE_QUERY_STATUS);
if (svcHndl == NULL)
{
result = GetLastError();
goto Cleanup2;
}
if (!ControlService(svcHndl, SERVICE_CONTROL_STOP, &svcStatus))
{
result = GetLastError();
goto Cleanup3;
}
while (svcStatus.dwCurrentState == SERVICE_STOP_PENDING)
{
oldCheckPoint = svcStatus.dwCheckPoint;
Sleep(svcStatus.dwWaitHint);
if (!QueryServiceStatus(svcHndl, &svcStatus))
{
result = GetLastError();
break;
}
if (oldCheckPoint >= svcStatus.dwCheckPoint)
{
result = ERROR_SERVICE_REQUEST_TIMEOUT;
break;
}
}
if (svcStatus.dwCurrentState == SERVICE_STOPPED)
result = 0;
Cleanup3:
CloseServiceHandle(svcHndl);
Cleanup2:
CloseServiceHandle(managerHndl);
Cleanup1:
wsprintf(resultBuf, "%08X", result);
pushstring(resultBuf);
}
BOOL WINAPI _DllMainCRTStartup(HANDLE hInst, ULONG ul_reason_for_call, LPVOID lpReserved)
{
return TRUE;
}

View File

@@ -0,0 +1,110 @@
# Microsoft Developer Studio Project File - Name="InstDrv" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** NICHT BEARBEITEN **
# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
CFG=InstDrv - Win32 Debug
!MESSAGE Dies ist kein g<>ltiges Makefile. Zum Erstellen dieses Projekts mit NMAKE
!MESSAGE verwenden Sie den Befehl "Makefile exportieren" und f<>hren Sie den Befehl
!MESSAGE
!MESSAGE NMAKE /f "InstDrv.mak".
!MESSAGE
!MESSAGE Sie k<>nnen beim Ausf<73>hren von NMAKE eine Konfiguration angeben
!MESSAGE durch Definieren des Makros CFG in der Befehlszeile. Zum Beispiel:
!MESSAGE
!MESSAGE NMAKE /f "InstDrv.mak" CFG="InstDrv - Win32 Debug"
!MESSAGE
!MESSAGE F<>r die Konfiguration stehen zur Auswahl:
!MESSAGE
!MESSAGE "InstDrv - Win32 Release" (basierend auf "Win32 (x86) Dynamic-Link Library")
!MESSAGE "InstDrv - Win32 Debug" (basierend auf "Win32 (x86) Dynamic-Link Library")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName ""
# PROP Scc_LocalPath ""
CPP=cl.exe
MTL=midl.exe
RSC=rc.exe
!IF "$(CFG)" == "InstDrv - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Ignore_Export_Lib 1
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "INSTDRV_EXPORTS" /YX /FD /c
# 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
# SUBTRACT CPP /YX
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x407 /d "NDEBUG"
# ADD RSC /l 0x407 /d "NDEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# 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
# 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
# SUBTRACT LINK32 /pdb:none
!ELSEIF "$(CFG)" == "InstDrv - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# 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
# 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
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x407 /d "_DEBUG"
# ADD RSC /l 0x407 /d "_DEBUG"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# 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
# 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
# SUBTRACT LINK32 /nodefaultlib
!ENDIF
# Begin Target
# Name "InstDrv - Win32 Release"
# Name "InstDrv - Win32 Debug"
# Begin Group "Quellcodedateien"
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
# Begin Source File
SOURCE=.\InstDrv.c
# End Source File
# End Group
# Begin Group "Header-Dateien"
# PROP Default_Filter "h;hpp;hxx;hm;inl"
# End Group
# Begin Group "Ressourcendateien"
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
# End Group
# End Target
# End Project

View File

@@ -0,0 +1,29 @@
Microsoft Developer Studio Workspace File, Format Version 6.00
# WARNUNG: DIESE ARBEITSBEREICHSDATEI DARF NICHT BEARBEITET ODER GEL<45>SCHT WERDEN!
###############################################################################
Project: "InstDrv"=.\InstDrv.dsp - Package Owner=<4>
Package=<5>
{{{
}}}
Package=<4>
{{{
}}}
###############################################################################
Global:
Package=<5>
{{{
}}}
Package=<3>
{{{
}}}
###############################################################################

View File

@@ -0,0 +1,141 @@
InstDrv.dll version 0.2 - Installs or Removes Device Drivers
------------------------------------------------------------
The plugin helps you to create NSIS scripts for installing device drivers or
removing them again. It can count installed device instances, create new ones
or delete all supported device. InstDrv works on Windows 2000 or later.
InstDrv::InitDriverSetup devClass drvHWID
Return: result
To start processing a driver, first call this function. devClass is the GUID
of the device class the driver supports, drvHWID is the device hardware ID. If
you don't know what these terms mean, you may want to take a look at the
Windows DDK. This function returns an empty string on success, otherwise an
error message.
InitDriverSetup has to be called every time after the plugin dll has been
(re-)loaded, or if you want to switch to a different driver.
InstDrv::CountDevices
Return: number
This call returns the number of installed and supported devices of the driver.
InstDrv::CreateDevice
Return: result
To create a new deviced node which the driver has to support, use this
function. You may even call it multiple times for more than one instance. The
return value is the Windows error code (in hex). Use CreateDevice before
installing or updating the driver itself.
InstDrv::InstallDriver infPath
Return: result
reboot
InstallDriver installs or updates a device driver as specified in the .inf
setup script. It returns a Windows error code (in hex) and, on success, a flag
signalling if a system reboot is required.
InstDrv::DeleteOemInfFiles
Return: result
oeminf
oempnf
DeleteOemInfFiles tries to clean up the Windows inf directory by deleting the
oemXX.inf and oemXX.pnf files associated with the drivers. It returns a
Windows error code (in hex) and, on success, the names of the deleted files.
This functions requires that at least one device instance is still present.
So, call it before you remove the devices itself. You should also call it
before updating a driver. This avoids that the inf directory gets slowly
messed up with useless old setup scripts (which does NOT really accelerate
Windows). The error code which comes up when no device is installed is
"00000103".
InstDrv::RemoveAllDevices
Return: result
reboot
This functions deletes all devices instances the driver supported. It returns
a Windows error code (in hex) and, on success, a flag signalling if the system
needs to be rebooted. You additionally have to remove the driver binaries from
the system paths.
InstDrv::StartSystemService serviceName
Return: result
Call this function to start the provided system service. The function blocks
until the service is started or the system reported a timeout. The return value
is the Windows error code (in hex).
InstDrv::StopSystemService serviceName
Return: result
This function tries to stop the provided system service. It blocks until the
service has been shut down or the system reported a timeout. The return value
is the Windows error code (in hex).
Example.nsi
The example script installs or removes the virtual COM port driver of IrCOMM2k
(2.0.0-alpha8, see www.ircomm2k.de/english). The driver and its setup script
are only included for demonstration purposes, they do not work without the
rest of IrCOMM2k (but they also do not cause any harm).
Building the Source Code
To build the plugin from the source code, some include files and libraries
which come with the Windows DDK are required.
History
0.2 - fixed bug when calling InitDriverSetup the second time
- added StartSystemService and StopSystemService
0.1 - first release
License
Copyright <20> 2003 Jan Kiszka (Jan.Kiszka@web.de)
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute
it freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented;
you must not claim that you wrote the original software.
If you use this software in a product, an acknowledgment in the
product documentation would be appreciated but is not required.
2. Altered versions must be plainly marked as such,
and must not be misrepresented as being the original software.
3. This notice may not be removed or altered from any distribution.

View File

@@ -0,0 +1,137 @@
; IrCOMM2k.inf
;
; Installation file for the Virtual Infrared-COM-Port
;
; (c) Copyright 2001, 2002 Jan Kiszka
;
[Version]
Signature="$Windows NT$"
Provider=%JK%
Class=Ports
ClassGUID={4d36e978-e325-11ce-bfc1-08002be10318}
;DriverVer=03/26/2002,1.2.1.0
[DestinationDirs]
IrCOMM2k.Copy2Drivers = 12
IrCOMM2k.Copy2Winnt = 10
IrCOMM2k.Copy2System32 = 11
IrCOMM2k.Copy2Help = 18
;
; Driver information
;
[Manufacturer]
%JK% = JK.Mfg
[JK.Mfg]
%JK.DeviceDescIrCOMM% = IrCOMM2k_inst,IrCOMM2k
;
; General installation section
;
[IrCOMM2k_inst]
CopyFiles = IrCOMM2k.Copy2Drivers ;,IrCOMM2k.Copy2System32,IrCOMM2k.Copy2Help,IrCOMM2k.Copy2Winnt
;AddReg = IrCOMM2k_inst_AddReg
;
; File sections
;
[IrCOMM2k.Copy2Drivers]
ircomm2k.sys,,,2
;[IrCOMM2k.Copy2System32]
;ircomm2k.exe,,,2
;ircomm2k.dll,,,2
;[IrCOMM2k.Copy2Help]
;ircomm2k.hlp,,,2
;[IrCOMM2k.Copy2Winnt]
;IrCOMM2k-Setup.exe,Setup.exe,,2
;
; Service Installation
;
[IrCOMM2k_inst.Services]
AddService = IrCOMM2k,0x00000002,IrCOMM2k_DriverService_Inst,IrCOMM2k_DriverEventLog_Inst
;AddService = IrCOMM2kSvc,,IrCOMM2k_Service_Inst
[IrCOMM2k_DriverService_Inst]
DisplayName = %IrCOMM2k.DrvName%
ServiceType = 1 ; SERVICE_KERNEL_DRIVER
StartType = 3 ; SERVICE_DEMAND_START
ErrorControl = 0 ; SERVICE_ERROR_IGNORE
ServiceBinary = %12%\ircomm2k.sys
;[IrCOMM2k_Service_Inst]
;DisplayName = %IrCOMM2k.SvcName%
;Description = %IrCOMM2k.SvcDesc%
;ServiceType = 0x00000120 ; SERVICE_WIN32_SHARE_PROCESS, SERVICE_INTERACTIVE_PROCESS
;StartType = 2 ; SERVICE_AUTO_START
;ErrorControl = 0 ; SERVICE_ERROR_IGNORE
;ServiceBinary = %11%\ircomm2k.exe
;Dependencies = IrCOMM2k
;AddReg = IrCOMM2kSvcAddReg
[IrCOMM2k_inst.nt.HW]
AddReg=IrCOMM2kHwAddReg
[IrCOMM2kHwAddReg]
HKR,,PortSubClass,REG_BINARY,0x00000001
;HKR,,TimeoutScaling,REG_DWORD,0x00000001
;HKR,,StatusLines,REG_DWORD,0x00000000
;[IrCOMM2k_inst_AddReg]
;HKR,,EnumPropPages32,,"ircomm2k.dll,IrCOMM2kPropPageProvider"
;HKLM,%UNINSTALL_KEY%,DisplayIcon,0x00020000,"%windir%\IrCOMM2k-Setup.exe"
;HKLM,%UNINSTALL_KEY%,DisplayName,,"IrCOMM2k 1.2.1 "
;HKLM,%UNINSTALL_KEY%,DisplayVersion,,"1.2.1"
;HKLM,%UNINSTALL_KEY%,HelpLink,,"http://www.ircomm2k.de"
;HKLM,%UNINSTALL_KEY%,Publisher,,%JK%
;HKLM,%UNINSTALL_KEY%,UninstallString,0x00020000,"%windir%\IrCOMM2k-Setup.exe"
;[IrCOMM2kSvcAddReg]
;HKR,Parameters,ActiveConnectOnly,REG_DWORD,0x00000000
[IrCOMM2k_DriverEventLog_Inst]
AddReg = IrCOMM2k_DriverEventLog_AddReg
[IrCOMM2k_DriverEventLog_AddReg]
HKR,,EventMessageFile,REG_EXPAND_SZ,"%SystemRoot%\System32\IoLogMsg.dll;%SystemRoot%\System32\drivers\ircomm2k.sys"
HKR,,TypesSupported,REG_DWORD,7
[Strings]
;
; Non-Localizable Strings
;
REG_SZ = 0x00000000
REG_MULTI_SZ = 0x00010000
REG_EXPAND_SZ = 0x00020000
REG_BINARY = 0x00000001
REG_DWORD = 0x00010001
SERVICEROOT = "System\CurrentControlSet\Services"
UNINSTALL_KEY = "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\IrCOMM2k"
;
; Localizable Strings
;
JK = "Jan Kiszka"
JK.DeviceDescIrCOMM = "Virtueller Infrarot-Kommunikationsanschluss"
IrCOMM2k.DrvName = "Virtueller Infrarot-Kommunikationsanschluss"
;IrCOMM2k.SvcName = "Virtueller Infrarot-Kommunikationsanschlu<6C>, Dienstprogramm"
;IrCOMM2k.SvcDesc = "Bildet <20>ber Infarot einen Kommunikationsanschlu<6C> nach."

Binary file not shown.

View File

@@ -0,0 +1,181 @@
!include WordFunc.nsh
; Definitions for Java Detection
!define JAVA_VERSION "6.0"
Function GetFileVersion
!define GetFileVersion `!insertmacro GetFileVersionCall`
!macro GetFileVersionCall _FILE _RESULT
Push `${_FILE}`
Call GetFileVersion
Pop ${_RESULT}
!macroend
Exch $0
Push $1
Push $2
Push $3
Push $4
Push $5
Push $6
ClearErrors
GetDllVersion '$0' $1 $2
IfErrors error
IntOp $3 $1 >> 16
IntOp $3 $3 & 0x0000FFFF
IntOp $4 $1 & 0x0000FFFF
IntOp $5 $2 >> 16
IntOp $5 $5 & 0x0000FFFF
IntOp $6 $2 & 0x0000FFFF
StrCpy $0 '$3.$4.$5.$6'
goto end
error:
SetErrors
StrCpy $0 ''
end:
Pop $6
Pop $5
Pop $4
Pop $3
Pop $2
Pop $1
Exch $0
FunctionEnd
Function openLinkNewWindow
Push $3
Exch
Push $2
Exch
Push $1
Exch
Push $0
Exch
ReadRegStr $1 HKCU "Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.html\UserChoice" "Progid"
IfErrors iexplore
Goto foundbrowser
iexplore:
StrCpy $1 "IE.AssocFile.HTM"
foundbrowser:
StrCpy $2 "\shell\open\command"
StrCpy $3 $1$2
ReadRegStr $0 HKCR $3 ""
# Get browser path
DetailPrint $0
StrCpy $2 '"'
StrCpy $1 $0 1
StrCmp $1 $2 +2 # if path is not enclosed in " look for space as final char
StrCpy $2 ' '
StrCpy $3 1
loop:
StrCpy $1 $0 1 $3
DetailPrint $1
StrCmp $1 $2 found
StrCmp $1 "" found
IntOp $3 $3 + 1
Goto loop
found:
StrCpy $1 $0 $3
StrCmp $2 " " +2
StrCpy $1 '$1"'
Pop $0
Exec '$1 $0'
Pop $0
Pop $1
Pop $2
Pop $3
FunctionEnd
!macro _OpenURL URL
Push "${URL}"
Call openLinkNewWindow
!macroend
!define OpenURL '!insertmacro "_OpenURL"'
Function DoDetectJRE
DetailPrint "Desired Java version ${JAVA_VERSION}"
SearchPath $0 javaw.exe
IfErrors no
DetailPrint "Detected java in $0"
${GetFileVersion} "$0" $1
IfErrors no
DetailPrint "Java version $1"
${VersionCompare} $1 ${JAVA_VERSION} $2
IntCmp $2 1 yes yes old
yes:
StrCpy $0 2
Goto done
old:
StrCpy $0 1
Goto done
no:
StrCpy $0 0
Goto done
done:
FunctionEnd
var dialog
var hwnd
var null
var install
var quit
var skip
Function GetJRE
${OpenURL} "adoptium.net"
MessageBox MB_OK "Click OK to continue after completing the Java Install."
FunctionEnd
Function DetectJRE
Call DoDetectJRE
IntCmp $0 1 ask_old ask_no yes
ask_no:
StrCpy $0 "Cannot find Java. Download and install?"
Goto ask
ask_old:
StrCpy $0 "Java version appears to be too old. Download and install?"
Goto ask
ask:
MessageBox MB_YESNOCANCEL $0 IDYES do_java IDNO skip_java
do_java:
Call GetJRE
skip_java:
yes:
FunctionEnd

View File

@@ -0,0 +1,14 @@
!define SHCNE_ASSOCCHANGED 0x08000000
!define SHCNF_IDLIST 0
Function RefreshShellIcons
; By jerome tremblay - april 2003
${DisableX64FSRedirection}
System::Call 'shell32.dll::SHChangeNotify(i, i, i, i) v (${SHCNE_ASSOCCHANGED}, ${SHCNF_IDLIST}, 0, 0)'
FunctionEnd
Function un.RefreshShellIcons
; By jerome tremblay - april 2003
${DisableX64FSRedirection}
System::Call 'shell32.dll::SHChangeNotify(i, i, i, i) v (${SHCNE_ASSOCCHANGED}, ${SHCNF_IDLIST}, 0, 0)'
FunctionEnd

191
altosui/Makefile-standalone Normal file
View File

@@ -0,0 +1,191 @@
.SUFFIXES: .java .class
CLASSPATH=classes:./*:/usr/share/java/*
CLASSFILES=\
Altos.class \
AltosChannelMenu.class \
AltosConfigFC.class \
AltosConfigFCUI.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_ICONS=\
../icon/altus-metrum-16.png \
../icon/altus-metrum-32.png \
../icon/altus-metrum-48.png \
../icon/altus-metrum-64.png \
../icon/altus-metrum-128.png \
../icon/altus-metrum-256.png
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_ICONS) 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_ICONS) 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_ICONS) 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 ../altusmetrum.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

423
altosui/Makefile.am Normal file
View File

@@ -0,0 +1,423 @@
# location of code signing key, et al
JAVAROOT=classes
AM_JAVACFLAGS=$(JAVAC_VERSION_FLAGS) -encoding UTF-8 -Xlint:deprecation -Xlint:unchecked
man_MANS=altosui.1
altoslibdir=$(libdir)/altos
CLASSPATH_ENV=mkdir -p $(JAVAROOT); CLASSPATH="$(JAVAROOT):../altoslib/*:../altosuilib/*:../libaltos:$(JCOMMON)/jcommon.jar:$(JFREECHART)/jfreechart.jar:$(FREETTS)/freetts.jar"
bin_SCRIPTS=altosui
altosui_JAVA = \
AltosAscent.java \
AltosChannelMenu.java \
AltosCompanionInfo.java \
AltosConfigFC.java \
AltosConfigFCUI.java \
AltosConfigPyroUI.java \
AltosConfigureUI.java \
AltosConfigTD.java \
AltosConfigTDUI.java \
AltosDescent.java \
AltosFlightStatus.java \
AltosFlightStatusUpdate.java \
AltosFlightUI.java \
Altos.java \
AltosIdleMonitorUI.java \
AltosIgniteUI.java \
AltosIgnitor.java \
AltosLaunch.java \
AltosLaunchUI.java \
AltosLanded.java \
AltosPad.java \
AltosUI.java \
AltosGraphUI.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
ALTOSLIB_CLASS=\
altoslib_$(ALTOSLIB_VERSION).jar
ALTOSUILIB_CLASS=\
altosuilib_$(ALTOSUILIB_VERSION).jar
if MULTI_ARCH
LIBALTOS_LINUX=libaltos_i686.so libaltos_amd64.so libaltos_aarch64.so libaltos_armel.so libaltos_armhf.so
else
LIBALTOS_LINUX=libaltos.so
endif
LIBALTOS= \
$(LIBALTOS_LINUX) \
libaltos.dylib \
altos.dll \
altos64.dll
desktopdir = $(datadir)/applications
desktop_file = altusmetrum-altosui.desktop
desktop_SCRIPTS = $(desktop_file)
JAR=altosui.jar
FATJAR=altosui-fat.jar
# Icons
ICONDIR=../icon
JAVA_ICONS=\
$(ICONDIR)/altusmetrum-altosui-16.png \
$(ICONDIR)/altusmetrum-altosui-32.png \
$(ICONDIR)/altusmetrum-altosui-48.png \
$(ICONDIR)/altusmetrum-altosui-64.png \
$(ICONDIR)/altusmetrum-altosui-128.png\
$(ICONDIR)/altusmetrum-altosui-256.png
# icon base names for jar
ICONJAR= \
-C $(ICONDIR) altusmetrum-altosui-16.png \
-C $(ICONDIR) altusmetrum-altosui-32.png \
-C $(ICONDIR) altusmetrum-altosui-48.png \
-C $(ICONDIR) altusmetrum-altosui-64.png \
-C $(ICONDIR) altusmetrum-altosui-128.png\
-C $(ICONDIR) altusmetrum-altosui-256.png
WINDOWS_ICONS =\
$(ICONDIR)/altusmetrum-altosui.ico \
$(ICONDIR)/altusmetrum-altosui.exe
$(ICONDIR)/application-vnd.altusmetrum.eeprom.ico \
$(ICONDIR)/application-vnd.altusmetrum.eeprom.exe \
$(ICONDIR)/application-vnd.altusmetrum.telemetry.ico \
$(ICONDIR)/application-vnd.altusmetrum.telemetry.exe
MACOSX_ICONS =\
$(ICONDIR)/altusmetrum-altosui.icns \
$(ICONDIR)/application-vnd.altusmetrum.eeprom.icns \
$(ICONDIR)/application-vnd.altusmetrum.telemetry.icns
LINUX_ICONS =\
$(ICONDIR)/altusmetrum-altosui.svg \
$(ICONDIR)/application-vnd.altusmetrum.eeprom.svg \
$(ICONDIR)/application-vnd.altusmetrum.telemetry.svg
LINUX_MIMETYPE =\
$(ICONDIR)/org-altusmetrum-mimetypes.xml
# Firmware
FIRMWARE_TD_3_0=$(top_srcdir)/src/teledongle-v3.0/teledongle-v3.0-$(VERSION).ihx
FIRMWARE_TD=$(FIRMWARE_TD_3_0)
FIRMWARE_TM_2_0=$(top_srcdir)/src/telemetrum-v2.0/telemetrum-v2.0-$(VERSION).ihx
FIRMWARE_TM_3_0=$(top_srcdir)/src/telemetrum-v3.0/telemetrum-v3.0-$(VERSION).ihx
FIRMWARE_TM_4_0=$(top_srcdir)/src/telemetrum-v4.0/telemetrum-v4.0-$(VERSION).ihx
FIRMWARE_TM=$(FIRMWARE_TM_2_0) $(FIRMWARE_TM_3_0) $(FIRMWARE_TM_4_0)
FIRMWARE_TELEMINI_3_0=$(top_srcdir)/src/telemini-v3.0/telemini-v3.0-$(VERSION).ihx
FIRMWARE_TELEMINI=$(FIRMWARE_TELEMINI_3_0)
FIRMWARE_TBT_3_0=$(top_srcdir)/src/telebt-v3.0/telebt-v3.0-$(VERSION).ihx
FIRMWARE_TBT_4_0=$(top_srcdir)/src/telebt-v4.0/telebt-v4.0-$(VERSION).ihx
FIRMWARE_TBT=$(FIRMWARE_TBT_3_0) $(FIRMWARE_TBT_4_0)
FIRMWARE_TMEGA_1_0=$(top_srcdir)/src/telemega-v1.0/telemega-v1.0-$(VERSION).ihx
FIRMWARE_TMEGA_2_0=$(top_srcdir)/src/telemega-v2.0/telemega-v2.0-$(VERSION).ihx
FIRMWARE_TMEGA_3_0=$(top_srcdir)/src/telemega-v3.0/telemega-v3.0-$(VERSION).ihx
FIRMWARE_TMEGA_4_0=$(top_srcdir)/src/telemega-v4.0/telemega-v4.0-$(VERSION).ihx
FIRMWARE_TMEGA_5_0=$(top_srcdir)/src/telemega-v5.0/telemega-v5.0-$(VERSION).ihx
FIRMWARE_TMEGA_6_0=$(top_srcdir)/src/telemega-v6.0/telemega-v6.0-$(VERSION).ihx
FIRMWARE_TMEGA=$(FIRMWARE_TMEGA_1_0) $(FIRMWARE_TMEGA_2_0) $(FIRMWARE_TMEGA_3_0) $(FIRMWARE_TMEGA_4_0) $(FIRMWARE_TMEGA_5_0) $(FIRMWARE_TMEGA_6_0)
FIRMWARE_EMINI_1_0=$(top_srcdir)/src/easymini-v1.0/easymini-v1.0-$(VERSION).ihx
FIRMWARE_EMINI_2_0=$(top_srcdir)/src/easymini-v2.0/easymini-v2.0-$(VERSION).ihx
FIRMWARE_EMINI_3_0=$(top_srcdir)/src/easymini-v3.0/easymini-v3.0-$(VERSION).ihx
FIRMWARE_EMINI=$(FIRMWARE_EMINI_1_0) $(FIRMWARE_EMINI_2_0) $(FIRMWARE_EMINI_3_0)
FIRMWARE_EMEGA_1_0=$(top_srcdir)/src/easymega-v1.0/easymega-v1.0-$(VERSION).ihx
FIRMWARE_EMEGA_2_0=$(top_srcdir)/src/easymega-v2.0/easymega-v2.0-$(VERSION).ihx
FIRMWARE_EMEGA=$(FIRMWARE_EMEGA_1_0) $(FIRMWARE_EMEGA_2_0)
FIRMWARE_EMOTOR_3=$(top_srcdir)/src/easymotor-v3/easymotor-v3-$(VERSION).ihx
FIRMWARE_EMOTOR=$(FIRMWARE_EMOTOR_3)
FIRMWARE_ETIMER_1=$(top_srcdir)/src/easytimer-v1/easytimer-v1-$(VERSION).ihx
FIRMWARE_ETIMER_2=$(top_srcdir)/src/easytimer-v2/easytimer-v2-$(VERSION).ihx
FIRMWARE_ETIMER=$(FIRMWARE_ETIMER_1) $(FIRMWARE_ETIMER_2)
FIRMWARE_TGPS_1_0=$(top_srcdir)/src/telegps-v1.0/telegps-v1.0-$(VERSION).ihx
FIRMWARE_TGPS_2_0=$(top_srcdir)/src/telegps-v2.0/telegps-v2.0-$(VERSION).ihx
FIRMWARE_TGPS_3_0=$(top_srcdir)/src/telegps-v3.0/telegps-v3.0-$(VERSION).ihx
FIRMWARE_TGPS=$(FIRMWARE_TGPS_1_0) $(FIRMWARE_TGPS_2_0) $(FIRMWARE_TGPS_3_0)
FIRMWARE_TLCO_2_0=$(top_srcdir)/src/telelco-v2.0/telelco-v2.0-$(VERSION).ihx
FIRMWARE_TLCO=$(FIRMWARE_TLCO_2_0)
FIRMWARE_TFIRE8_1_0=$(top_srcdir)/src/telefireeight-v1.0/telefireeight-v1.0-$(VERSION).ihx
FIRMWARE_TFIRE8_2_0=$(top_srcdir)/src/telefireeight-v2.0/telefireeight-v2.0-$(VERSION).ihx
FIRMWARE_TFIRE8=$(FIRMWARE_TFIRE8_1_0) $(FIRMWARE_TFIRE8_2_0)
FIRMWARE=$(FIRMWARE_TM) $(FIRMWARE_TELEMINI) $(FIRMWARE_TD) $(FIRMWARE_TBT) $(FIRMWARE_TMEGA) $(FIRMWARE_EMINI) $(FIRMWARE_TGPS) $(FIRMWARE_EMEGA) $(FIRMWARE_EMOTOR) $(FIRMWARE_ETIMER) $(FIRMWARE_TLCO) $(FIRMWARE_TFIRE8)
ALTUSMETRUM_DOC=$(top_srcdir)/doc/altusmetrum.pdf
ALTOS_DOC=$(top_srcdir)/doc/altos.pdf
TELEMETRY_DOC=$(top_srcdir)/doc/telemetry.pdf
MOTORTEST_DOC=$(top_srcdir)/doc/motortest.pdf
TEMPLATE_DOC=\
$(top_srcdir)/doc/telemetrum-outline.pdf \
$(top_srcdir)/doc/easymini-outline.pdf \
$(top_srcdir)/doc/telemega-outline.pdf \
$(top_srcdir)/doc/telemini-v1-outline.pdf \
$(top_srcdir)/doc/telemini-v3-outline.pdf
DOC=$(ALTUSMETRUM_DOC) $(ALTOS_DOC) $(TELEMETRY_DOC) $(MOTORTEST_DOC) $(TEMPLATE_DOC)
# Distribution targets
LINUX_DIST=Altos-Linux-$(VERSION).tar.bz2
LINUX_SH=Altos-Linux-$(VERSION).sh
MACOSX_DIST=Altos-Mac-$(VERSION).dmg
WINDOWS_DIST=Altos-Windows-$(VERSION_DASH).exe
MDWN=$(VERSION).mdwn
MDWNTMPL=mdwn.tmpl
FAT_FILES=$(FATJAR) $(ALTOSLIB_CLASS) $(ALTOSUILIB_CLASS) $(FREETTS_CLASS) $(JFREECHART_CLASS) $(JCOMMON_CLASS)
LINUX_LIBS=$(LIBALTOS_LINUX)
LINUX_FILES=$(FAT_FILES) $(LINUX_LIBS) $(FIRMWARE) $(DOC) $(desktop_file).in $(LINUX_ICONS) $(LINUX_MIMETYPE)
LINUX_EXTRA=altosui-fat
MACOSX_INFO_PLIST=Info.plist
MACOSX_INSTALL=install-macosx ask-pass
MACOSX_FILES=$(FAT_FILES) libaltos.dylib $(MACOSX_INFO_PLIST) $(DOC) ReadMe-Mac.rtf $(MACOSX_ICONS) $(MACOSX_INSTALL)
MACOSX_EXTRA=$(FIRMWARE)
WINDOWS_FILES=$(FAT_FILES) $(FIRMWARE) altos.dll altos64.dll $(top_srcdir)/altusmetrum.inf $(top_srcdir)/altusmetrum.cat $(WINDOWS_ICONS)
all-local: classes/altosui $(JAR) altosui altosui-test altosui-jdb $(MDWN)
clean-local:
-rm -rf classes $(JAR) $(FATJAR) \
Altos-Linux-*.tar.bz2 Altos-Linux-*.sh Altos-Mac-*.dmg Altos-Windows-*.exe \
windows altoslib_*.jar altosuilib_*.jar $(FREETTS_CLASS) \
$(JFREECHART_CLASS) $(JCOMMON_CLASS) $(LIBALTOS) Manifest.txt Manifest-fat.txt altos-windows.log altos-windows.nsi \
altosui altosui-test altosui-jdb macosx linux *.desktop *.mdwn
EXTRA_DIST = $(desktop_file).in
$(desktop_file): $(desktop_file).in
sed -e 's#%bindir%#@bindir@#' -e 's#%icondir%#$(datadir)/icons/hicolor/scalable/apps#' ${srcdir}/$(desktop_file).in > $@
chmod +x $@
if FATINSTALL
FATTARGET=$(FATDIR)/AltOS/releases/$(VERSION)
LINUX_SH_TARGET=$(FATTARGET)/$(LINUX_SH)
MACOSX_DIST_TARGET=$(FATTARGET)/$(MACOSX_DIST)
WINDOWS_DIST_TARGET=$(FATTARGET)/$(WINDOWS_DIST)
MDWN_TARGET=$(FATDIR)/AltOS/releases/$(MDWN)
RELNOTES=release-notes-$(VERSION).html
RELNOTES_SRC=$(top_builddir)/doc/$(RELNOTES)
RELNOTES_TARGET=$(FATTARGET)/$(RELNOTES)
fat-install: fat $(LINUX_SH_TARGET) $(MACOSX_DIST_TARGET) $(WINDOWS_DIST_TARGET) $(MDWN_TARGET) $(RELNOTES_TARGET)
$(LINUX_SH_TARGET): $(LINUX_SH)
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 $< $@
$(MDWN_TARGET): $(MDWN)
mkdir -p $(FATTARGET)
cp -p $< $@
$(RELNOTES_TARGET): $(RELNOTES_SRC)
mkdir -p $(FATTARGET)
sh $(top_srcdir)/doc/install-html -d $(FATTARGET) $(RELNOTES_SRC)
endif
$(MDWN): $(MDWNTMPL)
sed -e 's/%version%/$(VERSION)/g' -e 's/%version_dash%/$(VERSION_DASH)/g' $(MDWNTMPL) > $@
fat: $(LINUX_DIST) $(LINUX_SH) $(MACOSX_DIST) $(WINDOWS_DIST)
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_ICONS) $(ALTOSLIB_CLASS) $(ALTOSUILIB_CLASS) build-libaltos
jar cfm $@ Manifest.txt \
$(ICONJAR) \
-C classes altosui \
-C ../libaltos libaltosJNI
if STRIP_NONDETERMINISM
$(STRIP_NONDETERMINISM) $@
endif
$(FATJAR): classaltosui.stamp Manifest-fat.txt $(ALTOSLIB_CLASS) $(ALTOSUILIB_CLASS) $(FREETTS_CLASS) $(JFREECHART_CLASS) $(JCOMMON_CLASS) $(LIBALTOS) $(JAVA_ICONS)
jar cfm $@ Manifest-fat.txt \
$(ICONJAR) \
-C classes altosui \
-C ../libaltos libaltosJNI
if STRIP_NONDETERMINISM
$(STRIP_NONDETERMINISM) $@
endif
Manifest.txt: Makefile
echo 'Main-Class: altosui.AltosUI' > $@
echo "Class-Path: $(ALTOSLIB_CLASS) $(ALTOSUILIB_CLASS) $(FREETTS)/freetts.jar $(JCOMMON)/jcommon.jar $(JFREECHART)/jfreechart.jar" >> $@
Manifest-fat.txt:
echo 'Main-Class: altosui.AltosUI' > $@
echo "Class-Path: $(ALTOSLIB_CLASS) $(ALTOSUILIB_CLASS) freetts.jar jcommon.jar jfreechart.jar" >> $@
altosui: Makefile
echo "#!/bin/sh" > $@
echo 'exec java -Djava.library.path="$(altoslibdir)" -jar "$(altosuidir)/altosui.jar" "$$@"' >> $@
chmod +x $@
altosui-test: Makefile
echo '#!/bin/sh' > $@
echo 'dir="$$(dirname $$0)"' >> $@
echo 'cd "$$dir"' >> $@
echo 'altosui="$$(pwd -P)"' >> $@
echo 'altos="$$(dirname $$altosui)"' >> $@
echo 'exec java -Djava.library.path="$$altos/libaltos/.libs" -jar "$$altosui/altosui.jar" "$$@"' >> $@
chmod +x $@
altosui-jdb: Makefile
echo "#!/bin/sh" > $@
echo 'exec jdb -classpath "classes:./*:../libaltos:$(FREETTS)/freetts.jar:$(JCOMMON)/jcommon.jar:$(JFREECHART)/jfreechart.jar" -Djava.library.path="../libaltos/.libs" altosui/AltosUI "$$@"' >> $@
chmod +x $@
libaltos.so: build-libaltos
-rm -f "$@"
$(LN_S) ../libaltos/.libs/"$@" .
libaltos_i686.so: build-libaltos
-rm -f "$@"
$(LN_S) ../libaltos/.libs/"$@" .
libaltos_amd64.so: build-libaltos
-rm -f "$@"
$(LN_S) ../libaltos/.libs/"$@" .
libaltos_aarch64.so: build-libaltos
-rm -f "$@"
$(LN_S) ../libaltos/.libs/"$@" .
libaltos_armel.so: build-libaltos
-rm -f "$@"
$(LN_S) ../libaltos/.libs/"$@" .
libaltos_armhf.so: build-libaltos
-rm -f "$@"
$(LN_S) ../libaltos/.libs/"$@" .
libaltos.dylib:
-rm -f "$@"
$(LN_S) ../libaltos/"$@" .
altos.dll: build-libaltos
-rm -f "$@"
$(LN_S) ../libaltos/"$@" .
altos64.dll: build-libaltos
-rm -f "$@"
$(LN_S) ../libaltos/"$@" .
build-libaltos:
+cd ../libaltos && make
$(ALTOSLIB_CLASS):
-rm -f "$@"
$(LN_S) ../altoslib/"$@" .
$(ALTOSUILIB_CLASS):
-rm -f "$@"
$(LN_S) ../altosuilib/"$@" .
$(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
$(LINUX_SH): $(LINUX_DIST) linux-install.sh
cat linux-install.sh $(LINUX_DIST) > $@
chmod +x $@
$(MACOSX_DIST): $(MACOSX_FILES) $(MACOSX_EXTRA) Makefile
-rm -f $@
-rm -rf macosx
mkdir macosx
cp -a AltosUI.app macosx/
cp -a $(MACOSX_INSTALL) macosx
cp -a ReadMe-Mac.rtf macosx/ReadMe-AltosUI.rtf
mkdir -p macosx/Doc
cp -a $(DOC) macosx/Doc
cp -p Info.plist macosx/AltosUI.app/Contents
mkdir -p macosx/AltOS-$(VERSION) macosx/AltosUI.app/Contents/Resources/Java
cp -p $(MACOSX_ICONS) macosx/AltosUI.app/Contents/Resources
cp -p $(FATJAR) macosx/AltosUI.app/Contents/Resources/Java/altosui.jar
cp -p libaltos.dylib macosx/AltosUI.app/Contents/Resources/Java
cp -p $(ALTOSLIB_CLASS) macosx/AltosUI.app/Contents/Resources/Java
cp -p $(ALTOSUILIB_CLASS) macosx/AltosUI.app/Contents/Resources/Java
cp -p $(FREETTS_CLASS) macosx/AltosUI.app/Contents/Resources/Java
cp -p $(JFREECHART_CLASS) macosx/AltosUI.app/Contents/Resources/Java
cp -p $(JCOMMON_CLASS) macosx/AltosUI.app/Contents/Resources/Java
cp -p $(MACOSX_EXTRA) macosx/AltOS-$(VERSION)
genisoimage -D -V AltOS-$(VERSION) -no-pad -r -apple -o $@ macosx
$(WINDOWS_DIST): $(WINDOWS_FILES) altos-windows.nsi Instdrv/NSIS/Includes/java.nsh
-rm -f $@
makensis -Oaltos-windows.log "-XOutFile $@" "-DVERSION=$(VERSION)" altos-windows.nsi || (cat altos-windows.log && exit 1)
if [ "$(HAVE_WINDOWS_KEY)" = "yes" ]; then \
jsign --keystore "$(WINDOWSKEYFILE)" --alias 1 \
--storetype PKCS12 --storepass `cat "$(WINDOWSKEYPASSFILE)"` \
--tsaurl http://ts.ssl.com --tsmode RFC3161 $@ ; \
fi

59
altosui/ReadMe-Mac.rtf Normal file
View File

@@ -0,0 +1,59 @@
{\rtf1\ansi\deff3\adeflang1025
{\fonttbl{\f0\froman\fprq2\fcharset0 Times New Roman;}{\f1\froman\fprq2\fcharset2 Symbol;}{\f2\fswiss\fprq2\fcharset0 Arial;}{\f3\froman\fprq2\fcharset0 Liberation Serif{\*\falt Times New Roman};}{\f4\froman\fprq2\fcharset0 Arial;}{\f5\froman\fprq2\fcharset0 Helvetica LT Std;}{\f6\froman\fprq2\fcharset0 Helvetica{\*\falt Arial};}{\f7\fnil\fprq2\fcharset0 SimSun;}{\f8\fnil\fprq2\fcharset0 Helvetica LT Std;}{\f9\fnil\fprq2\fcharset0 Helvetica{\*\falt Arial};}{\f10\fnil\fprq2\fcharset0 Liberation Serif{\*\falt Times New Roman};}}
{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0;\red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0;\red255\green255\blue255;\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0;\red128\green0\blue128;\red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128;\red192\green192\blue192;}
{\stylesheet{\s0\snext0\ql\nowidctlpar\hyphpar0\ltrpar\cf0\kerning1\dbch\af7\langfe1081\dbch\af10\afs24\alang1081\loch\f3\fs24\lang1033 Normal;}
{\*\cs15\snext15 Numbering Symbols;}
{\s16\sbasedon0\snext17\ql\nowidctlpar\hyphpar0\sb240\sa120\keepn\ltrpar\cf0\kerning1\dbch\af7\langfe1081\dbch\af10\afs24\loch\f4\fs28\lang1033 Heading;}
{\s17\sbasedon0\snext17\sl276\slmult1\ql\nowidctlpar\hyphpar0\sb0\sa140\ltrpar\cf0\kerning1\dbch\af7\langfe1081\dbch\af10\afs24\loch\f3\fs24\lang1033 Text Body;}
{\s18\sbasedon17\snext18\sl276\slmult1\ql\nowidctlpar\hyphpar0\sb0\sa120\ltrpar\cf0\kerning1\dbch\af7\langfe1081\dbch\af10\afs24\loch\f3\fs24\lang1033 List;}
{\s19\sbasedon0\snext19\ql\nowidctlpar\hyphpar0\sb120\sa120\ltrpar\cf0\i\kerning1\dbch\af7\langfe1081\dbch\af10\afs24\loch\f3\fs24\lang1033 Caption;}
{\s20\sbasedon0\snext20\ql\nowidctlpar\hyphpar0\ltrpar\cf0\kerning1\dbch\af7\langfe1081\dbch\af10\afs24\loch\f3\fs24\lang1033 Index;}
{\s21\sbasedon0\snext21\ql\nowidctlpar\hyphpar0\sb0\sa120\ltrpar\cf0\kerning1\dbch\af7\langfe1081\dbch\af10\afs24\loch\f3\fs24\lang1033 Text body;}
}{\*\listtable{\list\listtemplateid1
{\listlevel\levelnfc0\leveljc0\levelstartat1\levelfollow0{\leveltext \'02\'00);}{\levelnumbers\'01;}\fi-360\li720}
{\listlevel\levelnfc0\leveljc0\levelstartat1\levelfollow0{\leveltext \'02\'01.;}{\levelnumbers\'01;}\fi-360\li1080}
{\listlevel\levelnfc0\leveljc0\levelstartat1\levelfollow0{\leveltext \'02\'02.;}{\levelnumbers\'01;}\fi-360\li1440}
{\listlevel\levelnfc0\leveljc0\levelstartat1\levelfollow0{\leveltext \'02\'03.;}{\levelnumbers\'01;}\fi-360\li1800}
{\listlevel\levelnfc0\leveljc0\levelstartat1\levelfollow0{\leveltext \'02\'04.;}{\levelnumbers\'01;}\fi-360\li2160}
{\listlevel\levelnfc0\leveljc0\levelstartat1\levelfollow0{\leveltext \'02\'05.;}{\levelnumbers\'01;}\fi-360\li2520}
{\listlevel\levelnfc0\leveljc0\levelstartat1\levelfollow0{\leveltext \'02\'06.;}{\levelnumbers\'01;}\fi-360\li2880}
{\listlevel\levelnfc0\leveljc0\levelstartat1\levelfollow0{\leveltext \'02\'07.;}{\levelnumbers\'01;}\fi-360\li3240}
{\listlevel\levelnfc0\leveljc0\levelstartat1\levelfollow0{\leveltext \'02\'08.;}{\levelnumbers\'01;}\fi-360\li3600}\listid1}
{\list\listtemplateid2
{\listlevel\levelnfc255\leveljc0\levelstartat1\levelfollow2{\leveltext \'00;}{\levelnumbers;}\fi0\li0}
{\listlevel\levelnfc255\leveljc0\levelstartat1\levelfollow2{\leveltext \'00;}{\levelnumbers;}\fi0\li0}
{\listlevel\levelnfc255\leveljc0\levelstartat1\levelfollow2{\leveltext \'00;}{\levelnumbers;}\fi0\li0}
{\listlevel\levelnfc255\leveljc0\levelstartat1\levelfollow2{\leveltext \'00;}{\levelnumbers;}\fi0\li0}
{\listlevel\levelnfc255\leveljc0\levelstartat1\levelfollow2{\leveltext \'00;}{\levelnumbers;}\fi0\li0}
{\listlevel\levelnfc255\leveljc0\levelstartat1\levelfollow2{\leveltext \'00;}{\levelnumbers;}\fi0\li0}
{\listlevel\levelnfc255\leveljc0\levelstartat1\levelfollow2{\leveltext \'00;}{\levelnumbers;}\fi0\li0}
{\listlevel\levelnfc255\leveljc0\levelstartat1\levelfollow2{\leveltext \'00;}{\levelnumbers;}\fi0\li0}
{\listlevel\levelnfc255\leveljc0\levelstartat1\levelfollow2{\leveltext \'00;}{\levelnumbers;}\fi0\li0}\listid2}
}{\listoverridetable{\listoverride\listid1\listoverridecount0\ls1}{\listoverride\listid2\listoverridecount0\ls2}}{\*\generator LibreOffice/6.1.2.1$Linux_X86_64 LibreOffice_project/10$Build-1}{\info{\creatim\yr2013\mo1\dy6\hr13\min7}{\revtim\yr2018\mo10\dy5\hr19\min22}{\printim\yr0\mo0\dy0\hr0\min0}}{\*\userprops}\deftab709
\hyphauto0\viewscale150
{\*\pgdsctbl
{\pgdsc0\pgdscuse451\pgwsxn12240\pghsxn15840\marglsxn1134\margrsxn1134\margtsxn1134\margbsxn1134\pgdscnxt0 Default Style;}}
\formshade{\*\pgdscno0}\paperh15840\paperw12240\margl1134\margr1134\margt1134\margb1134\sectd\sbknone\sectunlocked1\pgndec\pgwsxn12240\pghsxn15840\marglsxn1134\margrsxn1134\margtsxn1134\margbsxn1134\ftnbj\ftnstart1\ftnrstcont\ftnnar\aenddoc\aftnrstcont\aftnstart1\aftnnrlc
{\*\ftnsep\chftnsep}\pgndec\pard\plain \s0\ql\nowidctlpar\hyphpar0\ltrpar\cf0\kerning1\dbch\af7\langfe1081\dbch\af10\afs24\alang1081\loch\f3\fs24\lang1033{\cf0\kerning1\dbch\af7\langfe1081\dbch\af8\rtlch \ltrch\loch\fs24\lang1033\loch\f5\hich\af5
Installing AltOS software for Mac OS X Computers}
\par \pard\plain \s0\ql\nowidctlpar\hyphpar0\ltrpar\cf0\kerning1\dbch\af7\langfe1081\dbch\af10\afs24\alang1081\loch\f3\fs24\lang1033\cf0\kerning1\dbch\af7\langfe1081\dbch\af9\rtlch \ltrch\loch\fs24\lang1033\loch\f6\hich\af6
\par \pard\plain \s0\ql\nowidctlpar\hyphpar0\ltrpar\cf0\kerning1\dbch\af7\langfe1081\dbch\af10\afs24\alang1081\loch\f3\fs24\lang1033{\cf0\kerning1\dbch\af7\langfe1081\dbch\af8\rtlch \ltrch\loch\fs24\lang1033\loch\f5\hich\af5
The AltOS distribution for Mac OS X consists of:}
\par \pard\plain \s0\ql\nowidctlpar\hyphpar0\ltrpar\cf0\kerning1\dbch\af7\langfe1081\dbch\af10\afs24\alang1081\loch\f3\fs24\lang1033\cf0\kerning1\dbch\af7\langfe1081\dbch\af8\rtlch \ltrch\loch\fs24\lang1033\loch\f5\hich\af5
\par \pard\plain \s0\ql\nowidctlpar\hyphpar0\ltrpar\cf0\kerning1\dbch\af7\langfe1081\dbch\af10\afs24\alang1081\loch\f3\fs24\lang1033{\listtext\pard\plain 1)\tab}\ilvl0\ls1 \li1440\ri0\lin1440\rin0\fi-360\li720\ri0\lin720\rin0\fi-360{\cf0\kerning1\dbch\af7\langfe1081\dbch\af8\rtlch \ltrch\loch\fs24\lang1033\loch\f5\hich\af5
The AltosUI application}
\par \pard\plain \s0\ql\nowidctlpar\hyphpar0\ltrpar\cf0\kerning1\dbch\af7\langfe1081\dbch\af10\afs24\alang1081\loch\f3\fs24\lang1033{\listtext\pard\plain 2)\tab}\ilvl0\ls1 \li1440\ri0\lin1440\rin0\fi-360\li720\ri0\lin720\rin0\fi-360{\cf0\kerning1\dbch\af7\langfe1081\dbch\af8\rtlch \ltrch\loch\fs24\lang1033\loch\f5\hich\af5
Current AltOS firmware for Altus Metrum products}
\par \pard\plain \s0\ql\nowidctlpar\hyphpar0\ltrpar\cf0\kerning1\dbch\af7\langfe1081\dbch\af10\afs24\alang1081\loch\f3\fs24\lang1033\cf0\kerning1\dbch\af7\langfe1081\dbch\af8\rtlch \ltrch\loch\fs24\lang1033\loch\f5\hich\af5
\par \pard\plain \s0\ql\nowidctlpar\hyphpar0\ltrpar\cf0\kerning1\dbch\af7\langfe1081\dbch\af10\afs24\alang1081\loch\f3\fs24\lang1033{\cf0\kerning1\dbch\af7\langfe1081\dbch\af8\rtlch \ltrch\loch\fs24\lang1033\loch\f5\hich\af5
Install the AltosUI application by control-clicking the install-macosx script and selecting \u8220\'93Open\u8221\'94 from the menu. This will display a dialog asking if you are sure you want to open it. Select \u8220\'93Open\u8221\'94 from the dialog to execute the script. This will install the software, documentation and firmware in your home Applications/AltOS folder. You can move it afte}{\cf0\kerning1\dbch\af7\langfe1081\dbch\af8\rtlch \ltrch\loch\fs24\lang1033\loch\f5\hich\af5
r}{\cf0\kerning1\dbch\af7\langfe1081\dbch\af8\rtlch \ltrch\loch\fs24\lang1033\loch\f5\hich\af5
wards if you choose.}
\par \pard\plain \s0\ql\nowidctlpar\hyphpar0\ltrpar\cf0\kerning1\dbch\af7\langfe1081\dbch\af10\afs24\alang1081\loch\f3\fs24\lang1033\cf0\kerning1\dbch\af7\langfe1081\dbch\af8\rtlch \ltrch\loch\fs24\lang1033\loch\f5\hich\af5
\par \pard\plain \s0\ql\nowidctlpar\hyphpar0\ltrpar\cf0\kerning1\dbch\af7\langfe1081\dbch\af10\afs24\alang1081\loch\f3\fs24\lang1033\sl240\slmult1\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640{\cf0\kerning1\dbch\af7\langfe1081\dbch\af9\rtlch \ltrch\loch\fs24\lang1033\loch\f6\hich\af6
Thanks for choosing AltusMetrum products!}
\par }

View File

@@ -0,0 +1,268 @@
!addplugindir Instdrv/NSIS/Plugins
!addincludedir Instdrv/NSIS/Includes
!include x64.nsh
!include java.nsh
!include refresh-sh.nsh
!define REG_NAME "Altus Metrum"
!define PROG_ID_TELEM "altusmetrum.altosui.telem.1"
!define PROG_ID_EEPROM "altusmetrum.altosui.eeprom.1"
!define FAT_NAME "altosui-fat.jar"
!define WIN_APP_ICON "altusmetrum-altosui.ico"
!define WIN_APP_EXE "altusmetrum-altosui.exe"
!define WIN_TELEM_EXE "application-vnd.altusmetrum.telemetry.exe"
!define WIN_EEPROM_EXE "application-vnd.altusmetrum.eeprom.exe"
Name "${REG_NAME} Installer"
; Default install directory
InstallDir "$PROGRAMFILES\AltusMetrum"
; Tell the installer where to re-install a new version
InstallDirRegKey HKLM "Software\${REG_NAME}" "Install_Dir"
LicenseText "GNU General Public License Version 2"
LicenseData "../COPYING"
; Need admin privs for Vista or Win7
RequestExecutionLevel admin
ShowInstDetails Show
ComponentText "${REG_NAME} Software and Driver Installer"
Function .onInit
DetailPrint "Checking host operating system"
${If} ${RunningX64}
DetailPrint "Installer running on 64-bit host"
SetRegView 64
StrCpy $INSTDIR "$PROGRAMFILES64\AltusMetrum"
${DisableX64FSRedirection}
${EndIf}
FunctionEnd
Function un.onInit
DetailPrint "Checking host operating system"
${If} ${RunningX64}
DetailPrint "Installer running on 64-bit host"
SetRegView 64
StrCpy $INSTDIR "$PROGRAMFILES64\AltusMetrum"
${DisableX64FSRedirection}
${EndIf}
FunctionEnd
; 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} AltusMetrumSerial
Pop $0
DetailPrint "InitDriverSetup: $0"
InstDrv::DeleteOemInfFiles /NOUNLOAD
InstDrv::CreateDevice /NOUNLOAD
SetOutPath $INSTDIR
File "../altusmetrum.inf"
File "../altusmetrum.cat"
${DisableX64FSRedirection}
IfFileExists $WINDIR\System32\PnPutil.exe 0 nopnp
${DisableX64FSRedirection}
nsExec::ExecToLog '"$WINDIR\System32\PnPutil.exe" -i -a "$INSTDIR\altusmetrum.inf"'
Goto done
nopnp:
InstDrv::InstallDriver /NOUNLOAD "$INSTDIR\altusmetrum.inf"
done:
SectionEnd
Section "${REG_NAME} Application"
Call DetectJRE
SetOutPath $INSTDIR
File "${FAT_NAME}"
File "altoslib_@ALTOSLIB_VERSION@.jar"
File "altosuilib_@ALTOSUILIB_VERSION@.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 "jfreechart.jar"
File "jcommon.jar"
File "../icon/${WIN_APP_EXE}"
File "*.dll"
File "../icon/${WIN_APP_ICON}"
CreateShortCut "$SMPROGRAMS\${REG_NAME}.lnk" "$INSTDIR\${WIN_APP_EXE}" "" "$INSTDIR\${WIN_APP_ICON}"
SectionEnd
Section "${REG_NAME} Desktop Shortcut"
CreateShortCut "$DESKTOP\${REG_NAME}.lnk" "$INSTDIR\${WIN_APP_EXE}" "" "$INSTDIR\${WIN_APP_ICON}"
SectionEnd
Section "Firmware"
SetOutPath $INSTDIR
File "../src/telemetrum-v2.0/telemetrum-v2.0-${VERSION}.ihx"
File "../src/telemetrum-v3.0/telemetrum-v3.0-${VERSION}.ihx"
File "../src/telemetrum-v4.0/telemetrum-v4.0-${VERSION}.ihx"
File "../src/telemini-v3.0/telemini-v3.0-${VERSION}.ihx"
File "../src/telegps-v1.0/telegps-v1.0-${VERSION}.ihx"
File "../src/telegps-v2.0/telegps-v2.0-${VERSION}.ihx"
File "../src/telegps-v3.0/telegps-v3.0-${VERSION}.ihx"
File "../src/teledongle-v3.0/teledongle-v3.0-${VERSION}.ihx"
File "../src/telebt-v3.0/telebt-v3.0-${VERSION}.ihx"
File "../src/telebt-v4.0/telebt-v4.0-${VERSION}.ihx"
File "../src/telemega-v1.0/telemega-v1.0-${VERSION}.ihx"
File "../src/telemega-v2.0/telemega-v2.0-${VERSION}.ihx"
File "../src/telemega-v3.0/telemega-v3.0-${VERSION}.ihx"
File "../src/telemega-v4.0/telemega-v4.0-${VERSION}.ihx"
File "../src/telemega-v5.0/telemega-v5.0-${VERSION}.ihx"
File "../src/telemega-v6.0/telemega-v6.0-${VERSION}.ihx"
File "../src/easymini-v1.0/easymini-v1.0-${VERSION}.ihx"
File "../src/easymini-v2.0/easymini-v2.0-${VERSION}.ihx"
File "../src/easymini-v3.0/easymini-v3.0-${VERSION}.ihx"
File "../src/easymega-v1.0/easymega-v1.0-${VERSION}.ihx"
File "../src/easymega-v2.0/easymega-v2.0-${VERSION}.ihx"
File "../src/easymotor-v3/easymotor-v3-${VERSION}.ihx"
File "../src/easytimer-v1/easytimer-v1-${VERSION}.ihx"
File "../src/easytimer-v2/easytimer-v2-${VERSION}.ihx"
File "../src/telelco-v2.0/telelco-v2.0-${VERSION}.ihx"
File "../src/telefireeight-v1.0/telefireeight-v1.0-${VERSION}.ihx"
File "../src/telefireeight-v2.0/telefireeight-v2.0-${VERSION}.ihx"
SectionEnd
Section "Documentation"
SetOutPath $INSTDIR
File "../doc/altusmetrum.pdf"
File "../doc/altos.pdf"
File "../doc/telemetry.pdf"
File "../doc/motortest.pdf"
File "../doc/telemetrum-outline.pdf"
File "../doc/telemega-outline.pdf"
File "../doc/easymini-outline.pdf"
File "../doc/telemini-v1-outline.pdf"
File "../doc/telemini-v3-outline.pdf"
SectionEnd
Section "File Associations"
${DisableX64FSRedirection}
SetOutPath $INSTDIR
File "../icon/${WIN_TELEM_EXE}"
File "../icon/${WIN_EEPROM_EXE}"
DeleteRegKey HKCR "${PROG_ID_TELEM}"
DeleteRegKey HKCR "${PROG_ID_EEPROM}"
DeleteRegKey HKCR ".eeprom\${PROG_ID_EEPROM}"
DeleteRegValue HKCR ".eeprom\OpenWithProgids" "${PROG_ID_EEPROM}"
DeleteRegKey HKCR ".telem\${PROG_ID_EEPROM}"
DeleteRegValue HKCR ".telem\OpenWithProgids" "${PROG_ID_EEPROM}"
; .eeprom elements
WriteRegStr HKCR "${PROG_ID_EEPROM}" "" "Altus Metrum Log File"
WriteRegStr HKCR "${PROG_ID_EEPROM}" "FriendlyTypeName" "Altus Metrum Log File"
WriteRegStr HKCR "${PROG_ID_EEPROM}\CurVer" "" "${PROG_ID_EEPROM}"
WriteRegStr HKCR "${PROG_ID_EEPROM}\DefaultIcon" "" '"$INSTDIR\${WIN_EEPROM_EXE}",-101'
WriteRegExpandStr HKCR "${PROG_ID_EEPROM}\shell\open\command" "" '"$INSTDIR\${WIN_APP_EXE}" "%1"'
WriteRegStr HKCR ".eeprom" "" "${PROG_ID_EEPROM}"
WriteRegStr HKCR ".eeprom" "PerceivedType" "Altus Metrum Log File"
WriteRegStr HKCR ".eeprom" "Content Type" "application/vnd.altusmetrum.eeprom"
WriteRegStr HKCR ".eeprom\OpenWithProgids" "${PROG_ID_EEPROM}" ""
WriteRegStr HKCR ".eeprom\${PROG_ID_EEPROM}" "" "${REG_NAME}"
; .telem elements
WriteRegStr HKCR "${PROG_ID_TELEM}" "" "Altus Metrum Telemetry File"
WriteRegStr HKCR "${PROG_ID_TELEM}" "FriendlyTypeName" "Altus Metrum Telemetry File"
WriteRegStr HKCR "${PROG_ID_TELEM}\CurVer" "" "${PROG_ID_TELEM}"
WriteRegStr HKCR "${PROG_ID_TELEM}\DefaultIcon" "" '"$INSTDIR\${WIN_TELEM_EXE}",-101'
WriteRegExpandStr HKCR "${PROG_ID_TELEM}\shell\open\command" "" '"$INSTDIR\${WIN_APP_EXE}" "%1"'
WriteRegStr HKCR ".telem" "" "${PROG_ID_TELEM}"
WriteRegStr HKCR ".telem" "PerceivedType" "Altus Metrum Telemetry File"
WriteRegStr HKCR ".telem" "Content Type" "application/vnd.altusmetrum.telemetry"
WriteRegStr HKCR ".telem\OpenWithProgids" "${PROG_ID_TELEM}" ""
WriteRegStr HKCR ".telem\${PROG_ID_TELEM}" "" "${REG_NAME}"
Call RefreshShellIcons
SectionEnd
Section "Uninstaller"
; Deal with the uninstaller
${DisableX64FSRedirection}
SetOutPath $INSTDIR
; Write the install path to the registry
WriteRegStr HKLM "SOFTWARE\${REG_NAME}" "Install_Dir" "$INSTDIR"
; Write the uninstall keys for windows
WriteRegStr HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\${REG_NAME}" "DisplayName" "${REG_NAME}"
WriteRegStr HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\${REG_NAME}" "UninstallString" '"$INSTDIR\uninstall-${REG_NAME}.exe"'
WriteRegStr HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\${REG_NAME}" "NoModify" "1"
WriteRegStr HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\${REG_NAME}" "NoRepair" "1"
WriteUninstaller "uninstall-${REG_NAME}.exe"
SectionEnd
Section "Uninstall"
${DisableX64FSRedirection}
DeleteRegKey HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\${REG_NAME}"
DeleteRegKey HKLM "SOFTWARE\${REG_NAME}"
DetailPrint "Delete uninstall reg entries"
DeleteRegKey HKCR "${PROG_ID_EEPROM}"
DeleteRegKey HKCR "${PROG_ID_TELEM}"
DeleteRegKey HKCR ".eeprom\${PROG_ID_EEPROM}"
DeleteRegValue HKCR ".eeprom\OpenWithProgids" "${PROG_ID_EEPROM}"
DeleteRegKey HKCR ".telem\${PROG_ID_TELEM}"
DeleteRegValue HKCR ".telem\OpenWithProgids" "${PROG_ID_TELEM}"
DetailPrint "Delete file association reg entries"
Delete "$INSTDIR\${FAT_NAME}"
Delete "$INSTDIR\uninstall-${REG_NAME}.exe"
Delete "$INSTDIR\${WIN_APP_ICON}"
Delete "$INSTDIR\${WIN_APP_EXE}"
; Remove shortcuts, if any
Delete "$SMPROGRAMS\${REG_NAME}.lnk"
Delete "$DESKTOP\${REG_NAME}.lnk"
Call un.RefreshShellIcons
SectionEnd

4
altosui/altosui-fat Executable file
View File

@@ -0,0 +1,4 @@
#!/bin/sh
me=`which "$0"`
dir=`dirname "$me"`
exec java -cp "$dir/*" -Djava.library.path="$dir" -jar "$dir"/altosui-fat.jar "$@"

46
altosui/altosui.1 Normal file
View File

@@ -0,0 +1,46 @@
.\"
.\" 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

View File

@@ -0,0 +1,12 @@
[Desktop Entry]
Type=Application
Version=1.0
Name=AltOS UI
GenericName=Altus Metrum Ground Station
Comment=View and log downlink data from Altus Metrum products
Icon=%icondir%/altusmetrum-altosui.svg
Exec=%bindir%/altosui %F
Terminal=false
MimeType=application/vnd.altusmetrum.telemetry;application/vnd.altusmetrum.eeprom
Categories=Education;Electronics;Science;
Keywords=Rocket;Telemetry;GPS

BIN
altosui/altusmetrum.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

2
altosui/ask-pass Executable file
View File

@@ -0,0 +1,2 @@
#!/bin/bash
osascript -e 'display dialog "Password:" with hidden answer default answer "" with title "Password for '$USER'"' -e 'text returned of result'

55
altosui/install-macosx Executable file
View File

@@ -0,0 +1,55 @@
#!/bin/bash
JVM=/Library/Java/JavaVirtualMachines
dir=`dirname "$0"`
case `id -u` in
0)
;;
*)
SUDO_ASKPASS="${dir}/ask-pass" sudo -A "$0" "$@"
case $? in
0)
;;
*)
osascript -e 'display dialog "Installation failed. Incorrect password?" buttons {"OK"} default button 1 with title "Installation Status"' > /dev/null
;;
esac
exit 0
;;
esac
# Check for java
if ls "$JVM" | grep -q temurin; then
echo "Adoptium already present"
else
open https://adoptium.net/
osascript -e 'display dialog "Install Java from https://adoptium.net then click Continue" buttons {"Continue"} default button 1 with title "Install Java"' >/dev/null
fi
cd "$dir"
LIBRARY=/Library/AltusMetrum
APPLICATIONS=/Applications
INSTALLED=
for file in *; do
echo 'Installing' "$file"
case "$file" in
*.app)
mkdir -p "${APPLICATIONS}"
if [ -d "${APPLICATIONS}/${file}" ]; then
rm -rf "${APPLICATIONS}/${file}"
fi
cp -a "$file" "${APPLICATIONS}/${file}"
chmod -R +w "${APPLICATIONS}/${file}"
xattr -rc "${APPLICATIONS}/${file}"
APP=`basename "$file" .app`
INSTALLED="${INSTALLED} ${APP}"
;;
*)
mkdir -p "${LIBRARY}"
cp -a "$file" "${LIBRARY}"
;;
esac
done
open "${LIBRARY}"
osascript -e 'display dialog "Installation of'"${INSTALLED}"' complete" with title "Installation Complete" buttons {"OK"} default button 1' >/dev/null

244
altosui/linux-install.sh Normal file
View File

@@ -0,0 +1,244 @@
#!/bin/sh
can_ask=y
finish()
{
if [ "$can_ask" = "y" ]; then
echo ""
echo -n "Press enter to continue..."
read foo
fi
exit $1
}
#
# Make sure we have a terminal to talk to
#
if tty -s; then
:
else
case "$DISPLAY" in
"")
echo 'No user input available'
can_ask=n
;;
*)
GUESS_XTERMS="x-terminal-emulator xterm rxvt roxterm gnome-terminal dtterm eterm Eterm kvt konsole aterm"
for a in $GUESS_XTERMS; do
if type $a >/dev/null 2>&1; then
XTERM=$a
break
fi
done
case "$XTERM" in
"")
echo 'No terminal emulator available'
can_ask=n
;;
*)
exec "$XTERM" -e "sh '$0'"
;;
esac
;;
esac
fi
#
# Make sure we can run java
#
echo -n "Checking for java..."
if java -version > /dev/null 2>&1; then
echo " found it."
else
echo " java isn't working."
echo ""
echo "You'll need to install a java runtime system"
echo "on this computer before AltOS will work properly."
finish 1
fi
#
# Pick an installation target
#
if [ '(' -d /opt -a -w /opt ')' -o '(' -d /opt/AltOS -a -w /opt/AltOS ')' ]; then
target_default=/opt
else
target_default="$HOME"
fi
case "$#" in
0)
echo -n "Installation location [default: $target_default] "
if [ "$can_ask" = "y" ]; then
read target
else
echo ""
target=""
fi
case "$target" in
"")
target="$target_default"
;;
esac
;;
*)
target="$1"
;;
esac
target_altos="$target"/AltOS
echo -n "Installing to $target..."
#
# Make sure the target exists
#
mkdir -p "$target_altos"
if [ ! -d "$target_altos" ]; then
echo "$target_altos does not exist and cannot be created"
finish 1
fi
if [ ! -w "$target_altos" ]; then
echo "$target_altos cannot be written"
finish 1
fi
#
# Unpack the tar archive appended to the end of this script
#
archive_line=`awk '/^__ARCHIVE_BELOW__/ {print NR + 1; exit 0; }' "$0"`
tail -n+$archive_line "$0" | tar xjf - -C "$target"
case $? in
0)
echo " done."
;;
*)
echo "Install failed."
finish 1
;;
esac
#
# Create the .desktop file by editing the paths
#
case "$target" in
/*)
target_abs="$target"
;;
*)
target_abs=`pwd`/$target
;;
esac
BIN="$target_abs"/AltOS
for infile in "$target"/AltOS/*.desktop.in; do
desktop="$target"/AltOS/`basename "$infile" .in`
rm -f "$desktop"
sed -e "s;%bindir%;$BIN;" -e "s;%icondir%;$BIN;" "$infile" > "$desktop"
chmod +x "$desktop"
done
#
# Install the .desktop file
#
for desktop in "$target"/AltOS/*.desktop; do
case `id -u` in
0)
xdg-desktop-menu install --mode system "$desktop"
;;
*)
xdg-desktop-menu install --mode user "$desktop"
;;
esac
done
#
# Install mime type file
#
for mimetype in "$target"/AltOS/*-mimetypes.xml; do
case `id -u` in
0)
xdg-mime install --mode system "$mimetype"
;;
*)
xdg-mime install --mode user "$mimetype"
;;
esac
done
#
# Install icons
#
for icon_dir in /usr/share/icons/hicolor/scalable/mimetypes "$HOME/.icons" "$HOME/.kde/share/icons"; do
if [ -w "$icon_dir" ]; then
cp "$target"/AltOS/*.svg "$icon_dir"
update-icon-caches "$icon_dir"
fi
done
#
# Install icon to desktop if desired
#
if [ -d $HOME/Desktop ]; then
default_desktop=n
if [ "$can_ask" = "y" ]; then
:
else
default_desktop=y
fi
answered=n
while [ "$answered" = "n" ]; do
echo -n "Install icons to desktop? [default: $default_desktop] "
if [ "$can_ask" = "y" ]; then
read do_desktop
else
echo
do_desktop=""
fi
case "$do_desktop" in
"")
do_desktop=$default_desktop
;;
esac
case "$do_desktop" in
[yYnN]*)
answered=y
;;
esac
done
case "$do_desktop" in
[yY]*)
echo -n "Installing desktop icons..."
for d in "$target"/AltOS/*.desktop; do
base=`basename $d`
cp --remove-destination "$d" "$HOME/Desktop/"
done
;;
esac
echo " done."
fi
finish 0
__ARCHIVE_BELOW__

7
altosui/mdwn.tmpl Normal file
View File

@@ -0,0 +1,7 @@
[[!inline pages="./%version%/release-notes-%version%.html" rss="no" raw="yes" ]]
- Available Files:
- [Windows Installer](/AltOS/releases/%version%/Altos-Windows-%version_dash%.exe)
- [Mac OS X Package](/AltOS/releases/%version%/Altos-Mac-%version%.dmg)
- [Linux](/AltOS/releases/%version%/Altos-Linux-%version%.sh)
- [Source Snapshot](http://git.gag.com/?p=fw/altos;a=snapshot;h=refs/tags/%version%;sf=tgz)