summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore4
-rwxr-xr-xrun.sh7
-rw-r--r--src/com/benburwell/planes/gui/Main1090.java61
-rw-r--r--src/com/benburwell/planes/sbs/AggregateDataSource.java23
-rw-r--r--src/com/benburwell/planes/sbs/DataListener.java8
-rw-r--r--src/com/benburwell/planes/sbs/DataSource.java8
-rw-r--r--src/com/benburwell/planes/sbs/MalformedPacketException.java15
-rw-r--r--src/com/benburwell/planes/sbs/MessageType.java31
-rw-r--r--src/com/benburwell/planes/sbs/SBSPacket.java140
-rw-r--r--src/com/benburwell/planes/sbs/TCPDataSource.java56
-rw-r--r--src/com/benburwell/planes/sbs/TransmissionType.java34
-rw-r--r--src/com/benburwell/planes/sbs/UnrecognizedMessageTypeException.java20
-rw-r--r--src/com/benburwell/planes/sbs/UnrecognizedTransmissionTypeException.java20
13 files changed, 427 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..023292b
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,4 @@
+out/
+planes.jar
+.idea/
+1090.iml
diff --git a/run.sh b/run.sh
new file mode 100755
index 0000000..ea99c27
--- /dev/null
+++ b/run.sh
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+javac **/*.java
+cd out/production/1090
+jar -cvfe planes.jar com.benburwell.planes.gui.Main1090 **
+java -jar planes.jar
+
diff --git a/src/com/benburwell/planes/gui/Main1090.java b/src/com/benburwell/planes/gui/Main1090.java
new file mode 100644
index 0000000..5393dc0
--- /dev/null
+++ b/src/com/benburwell/planes/gui/Main1090.java
@@ -0,0 +1,61 @@
+/**
+ * Created by ben on 11/15/16.
+ */
+
+package com.benburwell.planes.gui;
+
+import com.benburwell.planes.sbs.*;
+
+import java.awt.*;
+import javax.swing.*;
+import java.awt.event.ActionEvent;
+import java.awt.event.KeyEvent;
+
+public class Main1090 extends JFrame {
+ private AggregateDataSource sbsDataSource = new AggregateDataSource();
+
+ public Main1090() {
+ this.initUI();
+ }
+
+ private void initUI() {
+ this.createMenuBar();
+
+ this.setTitle("1090");
+ this.setSize(100, 100);
+ this.setLocationRelativeTo(null);
+ this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
+
+ this.openDataSource();
+ }
+
+ private void createMenuBar() {
+ JMenuBar menubar = new JMenuBar();
+ JMenu file = new JMenu("1090");
+ file.setMnemonic(KeyEvent.VK_F);
+ JMenuItem eMenuItem = new JMenuItem("Quit");
+ eMenuItem.setMnemonic(KeyEvent.VK_E);
+ eMenuItem.setToolTipText("Exit 1090");
+ eMenuItem.addActionListener((ActionEvent event) -> {
+ System.exit(0);
+ });
+ file.add(eMenuItem);
+ menubar.add(file);
+ this.setJMenuBar(menubar);
+ }
+
+ private void openDataSource() {
+ System.out.println("asdfasdfasdfasdfasdf");
+ this.sbsDataSource.addSource(new TCPDataSource("10.0.0.111", 30003));
+ this.sbsDataSource.subscribe((SBSPacket packet) -> {
+ System.out.println("Got message: " + packet.toString());
+ });
+ }
+
+ public static void main(String[] args) {
+ EventQueue.invokeLater(() -> {
+ Main1090 app = new Main1090();
+ app.setVisible(true);
+ });
+ }
+}
diff --git a/src/com/benburwell/planes/sbs/AggregateDataSource.java b/src/com/benburwell/planes/sbs/AggregateDataSource.java
new file mode 100644
index 0000000..08b89ea
--- /dev/null
+++ b/src/com/benburwell/planes/sbs/AggregateDataSource.java
@@ -0,0 +1,23 @@
+package com.benburwell.planes.sbs;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Created by ben on 11/15/16.
+ */
+public class AggregateDataSource implements DataSource {
+ private List<DataListener> subscribers = new ArrayList<>();
+
+ public void addSource(DataSource source) {
+ source.subscribe((SBSPacket packet) -> {
+ for (DataListener listener : subscribers) {
+ listener.handleMessage(packet);
+ }
+ });
+ }
+
+ public void subscribe(DataListener listener) {
+ this.subscribers.add(listener);
+ }
+}
diff --git a/src/com/benburwell/planes/sbs/DataListener.java b/src/com/benburwell/planes/sbs/DataListener.java
new file mode 100644
index 0000000..b0da2ef
--- /dev/null
+++ b/src/com/benburwell/planes/sbs/DataListener.java
@@ -0,0 +1,8 @@
+package com.benburwell.planes.sbs;
+
+/**
+ * Created by ben on 11/15/16.
+ */
+public interface DataListener {
+ void handleMessage(SBSPacket packet);
+}
diff --git a/src/com/benburwell/planes/sbs/DataSource.java b/src/com/benburwell/planes/sbs/DataSource.java
new file mode 100644
index 0000000..959e273
--- /dev/null
+++ b/src/com/benburwell/planes/sbs/DataSource.java
@@ -0,0 +1,8 @@
+package com.benburwell.planes.sbs;
+
+/**
+ * Created by ben on 11/15/16.
+ */
+public interface DataSource {
+ void subscribe(DataListener listener);
+}
diff --git a/src/com/benburwell/planes/sbs/MalformedPacketException.java b/src/com/benburwell/planes/sbs/MalformedPacketException.java
new file mode 100644
index 0000000..6cbd1a3
--- /dev/null
+++ b/src/com/benburwell/planes/sbs/MalformedPacketException.java
@@ -0,0 +1,15 @@
+package com.benburwell.planes.sbs;
+
+/**
+ * Created by ben on 11/15/16.
+ */
+public class MalformedPacketException extends Exception {
+ private String message;
+ public MalformedPacketException(String message) {
+ this.message = message;
+ }
+
+ public String getMessage() {
+ return this.message;
+ }
+}
diff --git a/src/com/benburwell/planes/sbs/MessageType.java b/src/com/benburwell/planes/sbs/MessageType.java
new file mode 100644
index 0000000..a2ecc66
--- /dev/null
+++ b/src/com/benburwell/planes/sbs/MessageType.java
@@ -0,0 +1,31 @@
+package com.benburwell.planes.sbs;
+
+/**
+ * Created by ben on 11/15/16.
+ */
+public enum MessageType {
+ SELECTION_CHANGE("SEL"),
+ NEW_ID("ID"),
+ NEW_AIRCRAFT("AIR"),
+ STATUS_CHANGE("STA"),
+ CLICK("CLK"),
+ TRANSMISSION("MSG");
+
+ private String code;
+ MessageType(String code) {
+ this.code = code;
+ }
+
+ public String getCode() {
+ return this.code;
+ }
+
+ public static MessageType parse(String messageType) throws UnrecognizedMessageTypeException {
+ for (MessageType type : MessageType.values()) {
+ if (type.getCode().equals(messageType)) {
+ return type;
+ }
+ }
+ throw new UnrecognizedMessageTypeException(messageType);
+ }
+}
diff --git a/src/com/benburwell/planes/sbs/SBSPacket.java b/src/com/benburwell/planes/sbs/SBSPacket.java
new file mode 100644
index 0000000..0988f3a
--- /dev/null
+++ b/src/com/benburwell/planes/sbs/SBSPacket.java
@@ -0,0 +1,140 @@
+package com.benburwell.planes.sbs;
+
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.DoubleSummaryStatistics;
+
+/**
+ * Created by ben on 11/15/16.
+ */
+public class SBSPacket {
+ private MessageType messageType;
+ private TransmissionType transmissionType;
+ private String sessionId;
+ private String aircraftId;
+ private String hexIdent;
+ private String flightId;
+ private Date dateGenerated;
+ private Date dateLogged;
+ private String callsign;
+ private double altitude;
+ private double groundSpeed;
+ private double track;
+ private double latitude;
+ private double longitude;
+ private double verticalRate;
+ private String squawk;
+ private boolean alert;
+ private boolean emergency;
+ private boolean spi;
+ private boolean isOnGround;
+
+ public SBSPacket() {
+ }
+
+ public SBSPacket(String packet) throws MalformedPacketException {
+ this.parse(packet);
+ }
+
+ public void parse(String packet) throws MalformedPacketException {
+ String[] segments = packet.split(",", -1);
+ if (segments.length < 11) {
+ throw new MalformedPacketException("Packet must have at least 11 fields, but has only " + segments.length);
+ }
+
+ // get the message type
+ try {
+ this.messageType = MessageType.parse(segments[0]);
+ } catch (UnrecognizedMessageTypeException e) {
+ throw new MalformedPacketException("Packet has an unrecognized message type: " + e.getType());
+ }
+
+ // get the transmission type
+ if (this.messageType.equals(MessageType.TRANSMISSION)) {
+ try {
+ this.transmissionType = TransmissionType.parse(segments[1]);
+ } catch (UnrecognizedTransmissionTypeException e) {
+ throw new MalformedPacketException("Packet has an unrecognized transmission type code: " + e.getCode());
+ }
+ }
+
+ this.sessionId = segments[2];
+ this.aircraftId = segments[3];
+ this.hexIdent = segments[4];
+ this.flightId = segments[5];
+ this.dateGenerated = this.parseDateAndTime(segments[6], segments[7]);
+ this.dateLogged = this.parseDateAndTime(segments[8], segments[9]);
+ this.callsign = segments[10];
+
+ if (this.messageType.equals(MessageType.TRANSMISSION)) {
+ if (segments.length < 22) {
+ throw new MalformedPacketException("Packet is a message (22 fields), but only has " + segments.length);
+ }
+ if (segments[11].length() > 0) {
+ this.altitude = Double.parseDouble(segments[11]);
+ }
+ if (segments[12].length() > 0) {
+ this.groundSpeed = Double.parseDouble(segments[12]);
+ }
+ if (segments[13].length() > 0) {
+ this.track = Double.parseDouble(segments[13]);
+ }
+ if (segments[14].length() > 0) {
+ this.latitude = Double.parseDouble(segments[14]);
+ }
+ if (segments[15].length() > 0) {
+ this.longitude = Double.parseDouble(segments[15]);
+ }
+ if (segments[16].length() > 0) {
+ this.verticalRate = Double.parseDouble(segments[16]);
+ }
+ this.squawk = segments[17];
+ if (segments[18].length() > 0) {
+ this.alert = segments[18].equals("1");
+ }
+ if (segments[19].length() > 0) {
+ this.emergency = segments[19].equals("1");
+ }
+ if (segments[20].length() > 0) {
+ this.spi = segments[20].equals("1");
+ }
+ if (segments[21].length() > 0) {
+ this.isOnGround = segments[21].equals("1");
+ }
+ }
+ }
+
+ public Date parseDateAndTime(String date, String time) {
+ String combined = "";
+ Calendar now = Calendar.getInstance();
+ if (date == null || date.isEmpty()) {
+ combined += now.get(Calendar.YEAR) + "/" + now.get(Calendar.MONTH) + "/" + now.get(Calendar.DAY_OF_MONTH);
+ } else {
+ combined += date;
+ }
+
+ combined += " ";
+
+ if (time == null || time.isEmpty()) {
+ combined += now.get(Calendar.HOUR_OF_DAY) + ":" +
+ now.get(Calendar.MINUTE) + ":" +
+ now.get(Calendar.SECOND) + "." +
+ now.get(Calendar.MILLISECOND);
+ } else {
+ combined += time;
+ }
+
+ SimpleDateFormat fmt = new SimpleDateFormat("yyyy/MM/dd hh:mm:ss.sss");
+ try {
+ return fmt.parse(combined);
+ } catch (ParseException e) {
+ return null;
+ }
+ }
+
+ public String toString() {
+ return this.messageType.name();
+ }
+}
diff --git a/src/com/benburwell/planes/sbs/TCPDataSource.java b/src/com/benburwell/planes/sbs/TCPDataSource.java
new file mode 100644
index 0000000..6c0e51d
--- /dev/null
+++ b/src/com/benburwell/planes/sbs/TCPDataSource.java
@@ -0,0 +1,56 @@
+package com.benburwell.planes.sbs;
+
+import java.util.List;
+import java.util.ArrayList;
+import java.io.*;
+import java.net.*;
+
+/**
+ * Created by ben on 11/15/16.
+ */
+public class TCPDataSource implements DataSource {
+ private List<DataListener> subscribers = new ArrayList<>();
+
+ public TCPDataSource(String host, int port) {
+ new Thread(() -> {
+ System.out.println("Starting socket client");
+ Socket clientSocket;
+ BufferedReader socketReader;
+ try {
+ clientSocket = new Socket(host, port);
+ } catch (IOException e) {
+ System.out.println("Could not connect to " + host + " on port " + port + ": " + e.getMessage());
+ return;
+ }
+ try {
+ socketReader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
+ } catch (IOException e) {
+ System.out.println("Could not create socket reader: " + e.getMessage());
+ return;
+ }
+
+ String receivedMessage;
+ while (true) {
+ try {
+ receivedMessage = socketReader.readLine();
+ } catch (IOException e) {
+ System.out.println("Error reading from socket: " + e.getMessage());
+ return;
+ }
+ try {
+ SBSPacket packet = new SBSPacket(receivedMessage);
+ for (DataListener subscriber : subscribers) {
+ subscriber.handleMessage(packet);
+ }
+ } catch (MalformedPacketException e) {
+ System.out.println("Discarding malformed packet: " + receivedMessage);
+ System.out.println(e.getMessage());
+ }
+ }
+ }).start();
+ }
+
+ public void subscribe(DataListener listener) {
+ this.subscribers.add(listener);
+ }
+}
diff --git a/src/com/benburwell/planes/sbs/TransmissionType.java b/src/com/benburwell/planes/sbs/TransmissionType.java
new file mode 100644
index 0000000..fb1761e
--- /dev/null
+++ b/src/com/benburwell/planes/sbs/TransmissionType.java
@@ -0,0 +1,34 @@
+package com.benburwell.planes.sbs;
+
+/**
+ * Created by ben on 11/15/16.
+ */
+public enum TransmissionType {
+ ES_IDENTIFICATION(1),
+ ES_SURFACE_POSITION(2),
+ ES_AIRBORNE_POSITION(3),
+ ES_AIRBORNE_VELOCITY(4),
+ SURVEILLANCE_ALT(5),
+ SURVEILLANCE_ID(6),
+ AIR_TO_AIR(7),
+ ALL_CALL_REPLY(8);
+
+ private int id;
+ TransmissionType(int id) {
+ this.id = id;
+ }
+
+ public int getId() {
+ return this.id;
+ }
+
+ public static TransmissionType parse(String codeString) throws UnrecognizedTransmissionTypeException {
+ int code = Integer.parseInt(codeString);
+ for (TransmissionType transmissionType : TransmissionType.values()) {
+ if (transmissionType.getId() == code) {
+ return transmissionType;
+ }
+ }
+ throw new UnrecognizedTransmissionTypeException(code);
+ }
+}
diff --git a/src/com/benburwell/planes/sbs/UnrecognizedMessageTypeException.java b/src/com/benburwell/planes/sbs/UnrecognizedMessageTypeException.java
new file mode 100644
index 0000000..ee30a87
--- /dev/null
+++ b/src/com/benburwell/planes/sbs/UnrecognizedMessageTypeException.java
@@ -0,0 +1,20 @@
+package com.benburwell.planes.sbs;
+
+/**
+ * Created by ben on 11/15/16.
+ */
+public class UnrecognizedMessageTypeException extends Exception {
+ private String type;
+
+ public UnrecognizedMessageTypeException(String type) {
+ this.type = type;
+ }
+
+ public String getType() {
+ return this.type;
+ }
+
+ public String getMessage() {
+ return "Unrecognized message type: " + this.getType();
+ }
+}
diff --git a/src/com/benburwell/planes/sbs/UnrecognizedTransmissionTypeException.java b/src/com/benburwell/planes/sbs/UnrecognizedTransmissionTypeException.java
new file mode 100644
index 0000000..abab067
--- /dev/null
+++ b/src/com/benburwell/planes/sbs/UnrecognizedTransmissionTypeException.java
@@ -0,0 +1,20 @@
+package com.benburwell.planes.sbs;
+
+/**
+ * Created by ben on 11/15/16.
+ */
+public class UnrecognizedTransmissionTypeException extends Exception {
+ private int code;
+
+ public UnrecognizedTransmissionTypeException(int code) {
+ this.code = code;
+ }
+
+ public int getCode() {
+ return this.code;
+ }
+
+ public String getMessage() {
+ return "Unrecognized transmission type: " + this.getCode();
+ }
+}