TeleStern/telegps/TeleGPSDisplayThread.java

213 lines
5.1 KiB
Java

/*
* 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 org.altusmetrum.telegps;
import java.awt.*;
import javax.swing.*;
import java.io.*;
import java.text.*;
import org.altusmetrum.altoslib_14.*;
import org.altusmetrum.altosuilib_14.*;
public class TeleGPSDisplayThread extends Thread {
Frame parent;
IdleThread idle_thread;
AltosVoice voice;
AltosFlightReader reader;
AltosState state;
int old_state = AltosLib.ao_flight_invalid;
boolean old_gps_ready = false;
AltosListenerState listener_state;
AltosFlightDisplay display;
synchronized void show_safely() {
final AltosState my_state = state;
final AltosListenerState my_listener_state = listener_state;
Runnable r = new Runnable() {
public void run() {
try {
display.show(my_state, my_listener_state);
} catch (Exception ex) {
}
}
};
SwingUtilities.invokeLater(r);
}
void reading_error_internal() {
JOptionPane.showMessageDialog(parent,
String.format("Error reading from \"%s\"", reader.name),
"Telemetry Read Error",
JOptionPane.ERROR_MESSAGE);
}
void reading_error_safely() {
Runnable r = new Runnable() {
public void run() {
try {
reading_error_internal();
} catch (Exception ex) {
}
}
};
SwingUtilities.invokeLater(r);
}
class IdleThread extends Thread {
boolean started;
int report_interval;
long report_time;
public synchronized void report(boolean last) {
if (state == null)
return;
if (state.height() != AltosLib.MISSING) {
if (state.from_pad != null) {
voice.speak("Height %s, bearing %s %d, elevation %d, range %s, .\n",
AltosConvert.height.say(state.gps_height()),
state.from_pad.bearing_words(
AltosGreatCircle.BEARING_VOICE),
(int) (state.from_pad.bearing + 0.5),
(int) (state.elevation + 0.5),
AltosConvert.distance.say(state.range));
} else {
voice.speak("Height %s.\n",
AltosConvert.height.say(state.height()));
}
}
}
long now () {
return System.currentTimeMillis();
}
void set_report_time() {
report_time = now() + report_interval;
}
public void run () {
try {
for (;;) {
if (reader.has_monitor_battery()) {
listener_state.battery = reader.monitor_battery();
show_safely();
}
set_report_time();
for (;;) {
voice.drain();
synchronized (this) {
long sleep_time = report_time - now();
if (sleep_time <= 0)
break;
wait(sleep_time);
}
}
report(false);
}
} catch (InterruptedException ie) {
try {
voice.drain();
} catch (InterruptedException iie) { }
}
}
public synchronized void notice(boolean spoken) {
if (old_state != state.state()) {
report_time = now();
this.notify();
} else if (spoken)
set_report_time();
old_state = state.state();
}
public IdleThread() {
report_interval = 10000;
}
}
synchronized boolean tell() {
boolean ret = false;
if (old_gps_ready != state.gps_ready) {
if (state.gps_ready) {
voice.speak("GPS ready");
ret = true;
}
else if (old_gps_ready) {
voice.speak("GPS lost");
ret = true;
}
old_gps_ready = state.gps_ready;
}
return ret;
}
public void run() {
boolean interrupted = false;
boolean told;
idle_thread = new IdleThread();
idle_thread.start();
try {
for (;;) {
try {
state = reader.read();
if (state == null) {
listener_state.running = false;
break;
}
show_safely();
told = tell();
idle_thread.notice(told);
} catch (ParseException pp) {
System.out.printf("Parse error: %d \"%s\"\n", pp.getErrorOffset(), pp.getMessage());
} catch (AltosCRCException ce) {
++listener_state.crc_errors;
show_safely();
}
}
} catch (InterruptedException ee) {
interrupted = true;
} catch (IOException ie) {
reading_error_safely();
} finally {
if (!interrupted)
idle_thread.report(true);
reader.close(interrupted);
idle_thread.interrupt();
try {
idle_thread.join();
} catch (InterruptedException ie) {}
}
}
public TeleGPSDisplayThread(Frame in_parent, AltosVoice in_voice, AltosFlightDisplay in_display, AltosFlightReader in_reader) {
listener_state = new AltosListenerState();
parent = in_parent;
voice = in_voice;
display = in_display;
reader = in_reader;
display.reset();
}
}