From: Keith Packard Date: Fri, 2 Apr 2010 20:37:52 +0000 (-0700) Subject: Add telem parsing code X-Git-Tag: debian/0.6+163+g01e524f~27 X-Git-Url: https://git.gag.com/?p=fw%2Faltos;a=commitdiff_plain;h=02f2be90879b682b6e648cf2debc83223d127b9d Add telem parsing code --- diff --git a/ao-tools/altosui/AltosSerial.java b/ao-tools/altosui/AltosSerial.java index 82663eab..9537f190 100644 --- a/ao-tools/altosui/AltosSerial.java +++ b/ao-tools/altosui/AltosSerial.java @@ -21,18 +21,12 @@ package altosui; -import java.lang.String; -import java.lang.System; -import java.lang.Character; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.FileNotFoundException; +import java.lang.*; +import java.io.*; import java.util.concurrent.LinkedBlockingQueue; -import java.lang.InterruptedException; import java.util.LinkedList; -import altosui.AltosSerialMonitor; import java.util.Iterator; +import altosui.AltosSerialMonitor; /* * This class reads from the serial port and places each received @@ -43,6 +37,7 @@ class AltosSerialReader implements Runnable { FileInputStream serial_in; LinkedBlockingQueue monitor_queue; LinkedBlockingQueue reply_queue; + Thread input_thread; String line; public void run () { @@ -71,20 +66,12 @@ class AltosSerialReader implements Runnable { } } - public String get_telem() { - try { - return monitor_queue.take(); - } catch (InterruptedException e) { - return ""; - } + public String get_telem() throws InterruptedException { + return monitor_queue.take(); } - public String get_reply() { - try { - return reply_queue.take(); - } catch (InterruptedException e) { - return ""; - } + public String get_reply() throws InterruptedException { + return reply_queue.take(); } public void flush () { @@ -94,56 +81,131 @@ class AltosSerialReader implements Runnable { reply_queue.clear(); } } - public AltosSerialReader (FileInputStream in) { - serial_in = in; + + public boolean opened() { + return serial_in != null; + } + + public void close() { + if (serial_in != null) { + try { + serial_in.close(); + } catch (IOException e) { + } + serial_in = null; + } + if (input_thread != null) { + try { + input_thread.join(); + } catch (InterruptedException e) { + } + input_thread = null; + } + } + + public void open(File name) throws FileNotFoundException { + close(); + serial_in = new FileInputStream(name); + input_thread = new Thread(this); + input_thread.start(); + } + public AltosSerialReader () { + serial_in = null; + input_thread = null; + line = ""; monitor_queue = new LinkedBlockingQueue (); reply_queue = new LinkedBlockingQueue (); - line = ""; } } public class AltosSerial implements Runnable { - FileInputStream serial_in = null; FileOutputStream serial_out = null; - AltosSerialReader reader; + Thread monitor_thread = null; + AltosSerialReader reader = null; LinkedList callbacks; public void run() { - for (;;) { - String s = reader.get_reply(); - synchronized(callbacks) { - Iterator i = callbacks.iterator(); - while (i.hasNext()) { - i.next().data(s); + try { + for (;;) { + String s = reader.get_telem(); + synchronized(callbacks) { + Iterator i = callbacks.iterator(); + while (i.hasNext()) { + i.next().data(s); + } } } + } catch (InterruptedException e) { } } - public void start () { - try { - serial_out.write('?'); - serial_out.write('\r'); - } catch (IOException e) { + boolean need_monitor() { + return reader.opened() && !callbacks.isEmpty(); + } + + void maybe_stop_monitor() { + if (!need_monitor() && monitor_thread != null) { + monitor_thread.interrupt(); + try { + monitor_thread.join(); + } catch (InterruptedException e) { + } finally { + monitor_thread = null; + } + } + } + + void maybe_start_monitor() { + if (need_monitor() && monitor_thread == null) { + monitor_thread = new Thread(this); + monitor_thread.start(); } - (new Thread(reader)).start(); - (new Thread(this)).start(); } public void monitor(AltosSerialMonitor monitor) { synchronized(callbacks) { callbacks.add(monitor); + maybe_start_monitor(); } } - public AltosSerial(String serial_name) { + + public void unmonitor(AltosSerialMonitor monitor) { + synchronized(callbacks) { + callbacks.remove(monitor); + maybe_stop_monitor(); + } + } + + public void close() { + synchronized(callbacks) { + reader.close(); + maybe_stop_monitor(); + } + } + + public void open(File serial_name) throws FileNotFoundException { + reader.open(serial_name); + serial_out = new FileOutputStream(serial_name); try { - serial_in = new FileInputStream(serial_name); - serial_out = new FileOutputStream(serial_name); - reader = new AltosSerialReader(serial_in); - callbacks = new LinkedList(); - } catch (FileNotFoundException e) { + serial_out.write('?'); + serial_out.write('\r'); + } catch (IOException e) { } } + + void init() { + reader = new AltosSerialReader(); + callbacks = new LinkedList(); + } + + public AltosSerial() { + init(); + } + + public AltosSerial(File serial_name) throws FileNotFoundException { + init(); + open(serial_name); + } } diff --git a/ao-tools/altosui/AltosTelemetry.java b/ao-tools/altosui/AltosTelemetry.java index e072bb34..99e82bbf 100644 --- a/ao-tools/altosui/AltosTelemetry.java +++ b/ao-tools/altosui/AltosTelemetry.java @@ -36,25 +36,21 @@ class AltosGPSTime { try { return Integer.parseInt(v); } catch (NumberFormatException e) { - throw new ParseException(v, 0); + throw new ParseException("error parsing GPS value " + v, 0); } } public AltosGPSTime(String date, String time) throws ParseException { String[] ymd = date.split("-"); - if (ymd.length != 3) { - System.out.println("Error parsing GPS date " + date + " got " + ymd.length); - throw new ParseException(date, 0); - } + if (ymd.length != 3) + throw new ParseException("error parsing GPS date " + date + " got " + ymd.length, 0); year = parse_int(ymd[0]); month = parse_int(ymd[1]); day = parse_int(ymd[2]); String[] hms = time.split(":"); - if (hms.length != 3) { - System.out.println("Error parsing GPS time " + time + " got " + hms.length); - throw new ParseException(time, 0); - } + if (hms.length != 3) + throw new ParseException("Error parsing GPS time " + time + " got " + hms.length, 0); hour = parse_int(hms[0]); minute = parse_int(hms[1]); second = parse_int(hms[2]); @@ -95,6 +91,29 @@ class AltosGPSTracking { AltosGPSSat[] cc_gps_sat; } +/* + * The telemetry data stream is a bit of a mess at present, with no consistent + * formatting. In particular, the GPS data is formatted for viewing instead of parsing. + * However, the key feature is that every telemetry line contains all of the information + * necessary to describe the current rocket state, including the calibration values + * for accelerometer and barometer. + * + * GPS unlocked: + * + * VERSION 2 CALL KB0G SERIAL 51 FLIGHT 2 RSSI -68 STATUS ff STATE pad 1001 \ + * a: 16032 p: 21232 t: 20284 v: 25160 d: 204 m: 204 fa: 16038 ga: 16032 fv: 0 \ + * fp: 21232 gp: 21230 a+: 16049 a-: 16304 GPS 0 sat unlocked SAT 1 15 30 + * + * GPS locked: + * + * VERSION 2 CALL KB0G SERIAL 51 FLIGHT 2 RSSI -71 STATUS ff STATE pad 2504 \ + * a: 16028 p: 21220 t: 20360 v: 25004 d: 208 m: 200 fa: 16031 ga: 16032 fv: 330 \ + * fp: 21231 gp: 21230 a+: 16049 a-: 16304 \ + * GPS 9 sat 2010-02-13 17:16:51 35°20.0803'N 106°45.2235'W 1790m \ + * 0.00m/s(H) 0° 0.00m/s(V) 1.0(hdop) 0(herr) 0(verr) \ + * SAT 10 29 30 24 28 5 25 21 20 15 33 1 23 30 24 18 26 10 29 2 26 + */ + public class AltosTelemetry { int version; String callsign; @@ -124,8 +143,7 @@ public class AltosTelemetry { try { return Integer.parseInt(v); } catch (NumberFormatException e) { - System.out.println("error parsing int " + v); - throw new ParseException(v, 0); + throw new ParseException("error parsing int " + v, 0); } } @@ -133,8 +151,7 @@ public class AltosTelemetry { try { return Integer.parseInt(v, 16); } catch (NumberFormatException e) { - System.out.println("error parsing hex " + v); - throw new ParseException(v, 0); + throw new ParseException("error parsing hex " + v, 0); } } @@ -142,8 +159,7 @@ public class AltosTelemetry { try { return Double.parseDouble(v); } catch (NumberFormatException e) { - System.out.println("error parsing double " + v); - throw new ParseException(v, 0); + throw new ParseException("error parsing double " + v, 0); } } @@ -151,8 +167,7 @@ public class AltosTelemetry { String[] dsf = coord.split("\\D+"); if (dsf.length != 3) { - System.out.println("error parsing coord " + coord); - throw new ParseException(coord, 0); + throw new ParseException("error parsing coord " + coord, 0); } int deg = parse_int(dsf[0]); int min = parse_int(dsf[1]); @@ -172,8 +187,7 @@ public class AltosTelemetry { void word(String v, String m) throws ParseException { if (!v.equals(m)) { - System.out.println("error matching '" + v + "' '" + m + "'"); - throw new ParseException(v, 0); + throw new ParseException("error matching '" + v + "' '" + m + "'", 0); } } diff --git a/ao-tools/altosui/AltosUI.java b/ao-tools/altosui/AltosUI.java index b731725c..89eaac15 100644 --- a/ao-tools/altosui/AltosUI.java +++ b/ao-tools/altosui/AltosUI.java @@ -17,29 +17,14 @@ package altosui; -import java.awt.Color; -import java.awt.Dimension; -import java.awt.Font; -import java.awt.Toolkit; -import java.awt.Window; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.KeyEvent; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.awt.event.MouseListener; -import java.awt.event.WindowAdapter; -import java.awt.event.WindowEvent; -import javax.swing.JFrame; -import javax.swing.JMenu; -import javax.swing.JMenuBar; -import javax.swing.JMenuItem; -import javax.swing.JRadioButtonMenuItem; -import javax.swing.JSplitPane; -import javax.swing.JTable; -import javax.swing.KeyStroke; -import javax.swing.table.TableCellEditor; -import javax.swing.table.DefaultTableCellRenderer; +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import java.io.*; +import java.util.*; +import java.text.*; +import gnu.io.CommPortIdentifier; + import altosui.AltosSerial; import altosui.AltosSerialMonitor; @@ -71,13 +56,10 @@ public class AltosUI extends JFrame { createMenu(); - serialLine = new AltosSerial("/dev/ttyACM0"); + serialLine = new AltosSerial(); serialLine.monitor(new AltosUIMonitor()); - serialLine.start(); - Dimension size = Toolkit.getDefaultToolkit().getScreenSize(); - size.width = size.width*9/10; - size.height = size.height*9/10; - this.setSize(size); + int dpi = Toolkit.getDefaultToolkit().getScreenResolution(); + this.setSize(new Dimension (dpi * 5, dpi * 4)); this.validate(); setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE); addWindowListener(new WindowAdapter() { @@ -88,6 +70,94 @@ public class AltosUI extends JFrame { }); } + final JFileChooser deviceChooser = new JFileChooser(); + + private void PickSerialDevice() { + java.util.Enumeration port_list = CommPortIdentifier.getPortIdentifiers(); + while (port_list.hasMoreElements()) { + CommPortIdentifier identifier = port_list.nextElement(); + System.out.println("Serial port " + identifier.getName()); + } + } + + private void ConnectToDevice() { + PickSerialDevice(); + int returnVal = deviceChooser.showOpenDialog(AltosUI.this); + + if (returnVal == JFileChooser.APPROVE_OPTION) { + File file = deviceChooser.getSelectedFile(); + try { + serialLine.open(file); + } catch (FileNotFoundException ee) { + JOptionPane.showMessageDialog(AltosUI.this, + file.getName(), + "Cannot open serial port", + JOptionPane.ERROR_MESSAGE); + } + } + } + + String readline(FileInputStream s) throws IOException { + int c; + String line = ""; + + while ((c = s.read()) != -1) { + if (c == '\r') + continue; + if (c == '\n') + return line; + line = line + (char) c; + } + return null; + } + + private void Replay() { +// int returnVal = deviceChooser.showOpenDialog(AltosUI.this); + + /* if (returnVal == JFileChooser.APPROVE_OPTION) */ { +// File file = deviceChooser.getSelectedFile(); +// String filename = file.getName(); + String filename = "/home/keithp/src/cc1111/flights/2010-02-13-serial-051-flight-002.telem"; + try { +// FileInputStream replay = new FileInputStream(file); + FileInputStream replay = new FileInputStream(filename); + String line; + + try { + while ((line = readline(replay)) != null) { + try { + AltosTelemetry t = new AltosTelemetry(line); + System.out.println ("Version " + t.version + t.callsign); + } catch (ParseException pp) { + JOptionPane.showMessageDialog(AltosUI.this, + line, + "error parsing", + JOptionPane.ERROR_MESSAGE); + break; + } + } + } catch (IOException ee) { + JOptionPane.showMessageDialog(AltosUI.this, + filename, + "error reading", + JOptionPane.ERROR_MESSAGE); + } finally { + try { + replay.close(); + } catch (IOException e) {} + } + } catch (FileNotFoundException ee) { + JOptionPane.showMessageDialog(AltosUI.this, + filename, + "Cannot open serial port", + JOptionPane.ERROR_MESSAGE); + } + } + } + + private void SaveFlightData() { + } + private void createMenu() { JMenuBar menubar = new JMenuBar(); JMenu menu; @@ -120,6 +190,7 @@ public class AltosUI extends JFrame { item = new JMenuItem("Connect to Device",KeyEvent.VK_C); item.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { + ConnectToDevice(); } }); menu.add(item); @@ -127,6 +198,7 @@ public class AltosUI extends JFrame { item = new JMenuItem("Disconnect from Device",KeyEvent.VK_D); item.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { + serialLine.close(); } }); menu.add(item); @@ -136,6 +208,7 @@ public class AltosUI extends JFrame { item = new JMenuItem("Save Flight Data",KeyEvent.VK_S); item.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { + SaveFlightData(); } }); menu.add(item); @@ -143,6 +216,7 @@ public class AltosUI extends JFrame { item = new JMenuItem("Replay",KeyEvent.VK_R); item.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { + Replay(); } }); menu.add(item); @@ -186,16 +260,21 @@ public class AltosUI extends JFrame { menu = new JMenu("Channel", true); menu.setMnemonic(KeyEvent.VK_C); menubar.add(menu); + ButtonGroup group = new ButtonGroup(); for (int c = 0; c <= 9; c++) { - radioitem = new JRadioButtonMenuItem("Channel " + c + " (" + - (434.550 + c * .1) + ")", - c == 0); + radioitem = new JRadioButtonMenuItem(String.format("Channel %1d (%7.3fMHz)", c, + 434.550 + c * 0.1), + c == 0); + radioitem.setActionCommand(String.format("%d", c)); radioitem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { + System.out.println("Command: " + e.getActionCommand() + " param: " + + e.paramString()); } }); menu.add(radioitem); + group.add(radioitem); } } diff --git a/ao-tools/altosui/Makefile b/ao-tools/altosui/Makefile index cb422df8..090911ef 100644 --- a/ao-tools/altosui/Makefile +++ b/ao-tools/altosui/Makefile @@ -1,13 +1,18 @@ .SUFFIXES: .java .class -CLASSPATH=.. -CLASSFILES=AltosSerialMonitor.class AltosSerial.class AltosUI.class +CLASSPATH=..:/usr/share/java/* +CLASSFILES=AltosSerialMonitor.class AltosSerial.class AltosTelemetry.class AltosUI.class JAVAFLAGS=-Xlint:unchecked -all: $(CLASSFILES) +all: $(CLASSFILES) altosui .java.class: - javac -cp $(CLASSPATH) $(JAVAFLAGS) $*.java + javac -cp "$(CLASSPATH)" $(JAVAFLAGS) $*.java + +altosui: Makefile + (echo '#!/bin/sh'; \ + echo exec java -cp '"$(CLASSPATH)"' altosui/AltosUI) > $@ + chmod +x $@ clean: rm -f *.class \ No newline at end of file