diff --git a/GroundStation/v2/ConnectionPanel.java b/GroundStation/v2/ConnectionPanel.java new file mode 100644 index 0000000..0b04c8f --- /dev/null +++ b/GroundStation/v2/ConnectionPanel.java @@ -0,0 +1,245 @@ +import java.util.ArrayList; +import java.util.Scanner; + +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.event.*; + +// communication +import java.lang.*; +import java.io.*; +import java.net.*; + +/** + * + */ +class ConnectionPanel extends JPanel implements ActionListener { + /** list to hold subscribed actionlisteners */ + private ArrayList listeners = new ArrayList(); + + /** TCP connection options */ + private JPanel tcpOptions; + /** label for address field */ + private JLabel hostAddrLabel; + /** host address field */ + private JTextField hostAddr; + /** label for port field */ + private JLabel hostPortLabel; + /** port field */ + private JTextField hostPort; + /** connect button */ + private JButton connectButton; + + /** holds outgoing message info */ + private MessageContent contentOut; + /** holds incomming message info */ + private MessageContent contentIn; + + /** timer to cause repeating sends */ + private Timer tcpTimer; + /** tcp connection socket */ + private Socket tcpSocket; + /** scanner for incomming tcp messages */ + public BufferedReader in; + /** printwriter for outgoing tcp messages */ + public PrintWriter out; + + /** + * no-args constructor + */ + public ConnectionPanel() { + setLayout( new FlowLayout() ); + + tcpOptions = new JPanel(); + tcpOptions.setLayout( new FlowLayout() ); + + hostAddrLabel = new JLabel( "Host Address: " ); + hostAddr = new JTextField( "192.168.42.1" ); + hostAddr.setColumns( 10 ); + hostPortLabel = new JLabel( "Port: " ); + hostPort = new JTextField( "51717" ); + hostPort.setColumns( 6 ); + + tcpOptions.add( hostAddrLabel ); + tcpOptions.add( hostAddr ); + tcpOptions.add( hostPortLabel ); + tcpOptions.add( hostPort ); + add( tcpOptions ); + + connectButton = new JButton( "Connect" ); + connectButton.addActionListener( this ); + add( connectButton ); + } + + /** + * @param outgoing - MessageContent object containing options for + */ + public ConnectionPanel( MessageContent outgoing, MessageContent incomming ) { + this(); + contentOut = outgoing; + contentIn = incomming; + } + + /** + * connect to tcp socket bound to port at host addres addr + * @param addr - host address + * @param port - port of socket at host + */ + public void connectTcp( String addr, int port ) { + try { + tcpSocket = new Socket( addr, port ); + in = new BufferedReader( new InputStreamReader( tcpSocket.getInputStream() ) ); + out = new PrintWriter( tcpSocket.getOutputStream(), true ); //autoflushing + tcpTimer = new Timer( 100, this ); // .1 seconds + out.println( "PROTOCOL_2" ); // identify protocol to be used with tcp + tcpTimer.start(); + setGui( true ); + fireActionPerformed( new ActionEvent( this, ActionEvent.ACTION_PERFORMED, "CONNECT" ) ); + } + catch( Exception ex ) { + System.out.println( "Error Connecting to TCP server: " + ex ); + } + } + + /** + * disconnects from tcp server + * @param reconnect - tells server whether to listen for new connections. If false, server will shut down + */ + public void disconnectTcp( boolean reconnect ) { + out.print( "DISCONNECT" ); + if( reconnect ) out.print( "_R" ); + out.println(); + + try { + in.close(); + out.close(); + tcpSocket.close(); + setGui( false ); + fireActionPerformed( new ActionEvent( this, ActionEvent.ACTION_PERFORMED, "DISCONNECT" ) ); + } + catch( IOException ex ) { + System.out.println( ex ); + } + } + + /** + * + */ + private void sendTCP() { + out.print( "H " ); // Heartbeat / begin message indicator + if( contentOut.getMotorsEnabled() ) out.print( "E " ); // enable motors + if( contentOut.motorTesting ) { + for( int i = 0; i < contentOut.motorValues.length; i++ ) + out.print( "M" + i + "_" + contentOut.motorValues[i] + " " ); + } + if( contentOut.controls ) { + for( int i = 0; i < contentOut.controlValues.length; i++ ) + out.print( "C" + i + "_" + contentOut.controlValues[i] + " " ); + } + out.println(); + } + + /** + * + */ + private void readTCP() { + try { + if( in.ready() ) { + String messageIn = in.readLine(); + Scanner temp = new Scanner( messageIn ); + while( temp.hasNext() ) { + String next = temp.next(); + if( next.indexOf( "H" ) == 0 ) System.out.print( "\nH" ); + System.out.print( next ); + if( next.indexOf( "M" ) > 0 ) { + Scanner motorScan = new Scanner( next ); + + } + } + } + contentIn.orientation = true; + contentIn.fireActionPerformed( new ActionEvent(contentIn, ActionEvent.ACTION_PERFORMED, "" ) ); + } + catch( IOException ex ) {} + } + + /** + * @param enabled - true to + */ + private void setGui( Boolean connected ) { + if( connected ) connectButton.setText( "disconnect" ); + else connectButton.setText( "connect" ); + hostAddr.setEnabled( !connected ); + hostPort.setEnabled( !connected ); + } + + /** + * sets everything in the panel enabled/disabled + * @param state - desired enable status (true = enabled, false = disabled) + */ + public void setEnabled( boolean state ) { + hostAddr.setEnabled( state ); + hostPort.setEnabled( state ); + connectButton.setEnabled( state ); + } + + /////////////////////////////////////// + + /** + * sends message over tcp + */ + public void actionPerformed( ActionEvent evt ) { + if( evt.getSource() == connectButton ) { + if( evt.getActionCommand().equals( "disconnect" ) ) { + disconnectTcp( false ); + } + else { + connectTcp( hostAddr.getText(), Integer.parseInt( hostPort.getText() ) ); + } + } + else { + sendTCP(); + readTCP(); + } + } + + //////////////////////////////////////// + + /** + * adds actionlistener to subscribd listener list + * @param al - actionlistener to add + */ + public void addActionListener( ActionListener al ) { + listeners.add( al ); + } + + /** + * removes actionlistener from subscribed listener list + * @param al - actionlistener to remove + */ + public void removeActionListener( ActionListener al ) { + listeners.remove( al ); + } + + /** + * sends an actionevent to subscribed listeners + * @param ae - actionevent to use as parameter to all subscribed listeners + */ + public void fireActionPerformed( ActionEvent ae ) { + for( ActionListener al : listeners ) { + al.actionPerformed( ae ); + } + } + + /** + * + */ + public void fireActionPerformed() { + fireActionPerformed( new ActionEvent( this, ActionEvent.ACTION_PERFORMED, "" ) ); + } +} + + + + diff --git a/GroundStation/v2/Display3d.java b/GroundStation/v2/Display3d.java new file mode 100644 index 0000000..e9f6dc9 --- /dev/null +++ b/GroundStation/v2/Display3d.java @@ -0,0 +1,96 @@ +import javax.swing.*; +import javax.swing.event.*; +import java.awt.*; +import java.awt.event.*; + +/** + * + */ +class Display3d extends JPanel implements ActionListener, ChangeListener { + + private JSlider slider; + private MessageContent source = new MessageContent(); + private Font normalFont = new Font( "Normal", Font.PLAIN, 15 ); + + /** + * no-args constructor + */ + public Display3d() { + setBackground( Color.DARK_GRAY ); + setPreferredSize( new Dimension( 500, 100 ) ); + } + + /** + * + */ + public Display3d( MessageContent orientationSource ) { + source = orientationSource; + source.addActionListener( this ); + + setBackground( Color.DARK_GRAY ); + setPreferredSize( new Dimension( 0, 100 ) ); + + setLayout( new BorderLayout() ); + slider = new JSlider(); + slider.setOrientation( JSlider.VERTICAL ); + slider.addChangeListener( this ); + add( slider, BorderLayout.EAST ); + } + + /** + * overrides super.paintComponent + */ + public void paintComponent( Graphics g ) { + super.paintComponent( g ); + + int centerX = getWidth() / 2; + int centerY = getHeight() / 2; + + slider.setEnabled( source.orientation ); + + if( source.orientation ) { + + // yaw axis + g.setColor( Color.BLUE ); + //g.drawLine( centerX, centerY, , ); + + g.setColor( Color.RED ); + //g.drawLine( centerX, centerY, X, Y ); + + g.setColor( Color.GREEN ); + //g.drawLine( centerX, centerY, X, Y ); + + g.setColor( Color.BLACK ); + g.setFont( normalFont ); + g.drawString( "w = " + source.orientValues[ 0 ], 10, 35 ); + g.drawString( "x = " + source.orientValues[ 1 ], 10, 60 ); + g.drawString( "y = " + source.orientValues[ 2 ], 10, 85 ); + g.drawString( "z = " + source.orientValues[ 3 ], 10, 110 ); + } + else { + g.setColor( Color.RED ); + g.setFont( new Font( "Alert", Font.BOLD, 30 ) ); + g.drawString( "NO ORIENTATION DATA", centerX - 180, centerY + 15 ); + } + } + + /** + * + */ + public void actionPerformed( ActionEvent evt ) { + repaint(); + } + + /** + * + */ + public void stateChanged( ChangeEvent evt ) { + repaint(); + } +} + + + + + + diff --git a/GroundStation/v2/EStopWindow.java b/GroundStation/v2/EStopWindow.java new file mode 100644 index 0000000..3dbf817 --- /dev/null +++ b/GroundStation/v2/EStopWindow.java @@ -0,0 +1,89 @@ +import java.util.*; +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.event.*; + +/** + * + */ +class EStopWindow extends JFrame implements ActionListener { + /** list to hold subscribed actionlisteners */ + private ArrayList listeners = new ArrayList(); + + /** stop sign image */ + //private Image sign = new Image( "./stopSign.png" ); + + /** Emergency stop button */ + private JButton disableButton; + + /** + * + */ + public EStopWindow() { + super("Emergency Stop"); + setDefaultCloseOperation( JFrame.DO_NOTHING_ON_CLOSE ); + setAlwaysOnTop( true ); + setLocation( 600, 100 ); + + //disableButton = new JButton( "DISABLE" ); + disableButton = new JButton( new ImageIcon( (new ImageIcon( "./stopSign.png" )).getImage().getScaledInstance( 200, 200, Image.SCALE_DEFAULT) ) ); + disableButton.addActionListener( this ); + add( disableButton ); + + setEnabled( true ); + pack(); + setVisible( true ); + } + + /** + * + */ + public void actionPerformed( ActionEvent evt ) { + if( evt.getSource() == disableButton ) { + fireActionPerformed(); + } + } + + ///////////////////////////////////// + + /** + * + */ + public void setEnabled( boolean enable ) { + disableButton.setEnabled( enable ); + } + + /** + * adds actionlistener to subscribd listener list + * @param al - actionlistener to add + */ + public void addActionListener( ActionListener al ) { + listeners.add( al ); + } + + /** + * removes actionlistener from subscribed listener list + * @param al - actionlistener to remove + */ + public void removeActionListener( ActionListener al ) { + listeners.remove( al ); + } + + /** + * sends an actionevent to subscribed listeners + * @param ae - actionevent to use as parameter to all subscribed listeners + */ + public void fireActionPerformed( ActionEvent ae ) { + for( ActionListener al : listeners ) { + al.actionPerformed( ae ); + } + } + + /** + * + */ + public void fireActionPerformed() { + fireActionPerformed( new ActionEvent( this, ActionEvent.ACTION_PERFORMED, "CLICKED" ) ); + } +} \ No newline at end of file diff --git a/GroundStation/v2/GroundStation.java b/GroundStation/v2/GroundStation.java new file mode 100644 index 0000000..7d60718 --- /dev/null +++ b/GroundStation/v2/GroundStation.java @@ -0,0 +1,93 @@ +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.event.*; + +/** + * + */ +class GroundStation implements ActionListener { + + /** main window to hold everything */ + private JFrame mainWindow; + /** window to hold emergency stop button */ + private EStopWindow eStopWindow; + + /** connection options section of window */ + private ConnectionPanel connectPanel; + + /** tabbed pane to hold stuff */ + private JTabbedPane tabbedPane; + /** motor testing panel */ + private MotorTestPanel motorTestPanel; + /** */ + private Display3d orientationPanel; + /** outgoing message content options */ + public MessageContent sendContent = new MessageContent(); + /** incoming message content */ + public MessageContent receiveContent = new MessageContent(); + + public GroundStation() { + mainWindow = new JFrame( "PiCopter Ground Station" ); + mainWindow.setResizable( true ); + mainWindow.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); + mainWindow.getContentPane().setLayout( new BoxLayout( mainWindow.getContentPane(), BoxLayout.PAGE_AXIS ) ); + + connectPanel = new ConnectionPanel( sendContent, receiveContent ); + connectPanel.setEnabled( true ); + mainWindow.getContentPane().add( connectPanel ); + + tabbedPane = new JTabbedPane(); + mainWindow.getContentPane().add( tabbedPane ); + + orientationPanel = new Display3d( receiveContent ); + tabbedPane.add( orientationPanel, "Orientation" ); + + motorTestPanel = new MotorTestPanel( sendContent ); + motorTestPanel.setEnabled( false ); + tabbedPane.add( motorTestPanel, "Motor Test" ); + + connectPanel.addActionListener( this ); + sendContent.addActionListener( this ); + + mainWindow.pack(); + mainWindow.setVisible( true ); + } + + public void disableMotors() { + connectPanel.setEnabled( true ); + eStopWindow.dispose(); + } + + public void enableMotors() { + connectPanel.setEnabled( false ); + eStopWindow = new EStopWindow(); + eStopWindow.addActionListener( this ); + } + + public void actionPerformed( ActionEvent evt ) { + if( evt.getSource() == eStopWindow ) { + sendContent.setMotorsEnabled( false ); + } + if( evt.getSource() == connectPanel ) { + if( evt.getActionCommand().equals( "CONNECT" ) ) { + mainWindow.setDefaultCloseOperation( JFrame.DO_NOTHING_ON_CLOSE ); + motorTestPanel.setEnabled( true ); + } + else if( evt.getActionCommand().equals( "DISCONNECT" ) ) { + mainWindow.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); + motorTestPanel.setEnabled( false ); + } + } + else if( evt.getActionCommand().equals( "ENABLE_MOTORS" ) ) { + enableMotors(); + } + else if( evt.getActionCommand().equals( "DISABLE_MOTORS" ) ) { + disableMotors(); + } + } + + public static void main( String[] args ) { + GroundStation station = new GroundStation(); + } +} \ No newline at end of file diff --git a/GroundStation/v2/MessageContent.java b/GroundStation/v2/MessageContent.java new file mode 100644 index 0000000..62ca4cd --- /dev/null +++ b/GroundStation/v2/MessageContent.java @@ -0,0 +1,70 @@ +import java.util.*; +import java.awt.event.*; + +/** + * + */ +class MessageContent { + /** list to hold subscribed actionlisteners */ + private ArrayList listeners = new ArrayList(); + + private boolean motorsEnabled = false; + + public boolean motorTesting = false; + public int[] motorValues = { 0, 0, 0, 0 }; + + public boolean controls = false; + public int[] controlValues = { 0, 0, 0, 0, 0, 0 }; + + public boolean orientation = false; + public double[] orientValues = { 1, 0, 0, 0 }; // w, x, y, z + + /** + * sets motorsEnabled variable and triggers fireActionPerformed + * @param enable - boolean value to set motorsEnabled to + */ + public void setMotorsEnabled( Boolean enable ) { + motorsEnabled = enable; + if( enable ) { + fireActionPerformed( new ActionEvent( this, ActionEvent.ACTION_PERFORMED, "ENABLE_MOTORS" ) ); + } + else { + fireActionPerformed( new ActionEvent( this, ActionEvent.ACTION_PERFORMED, "DISABLE_MOTORS" ) ); + } + } + + /** + * @return motorsEnabled status + */ + public Boolean getMotorsEnabled() { + return motorsEnabled; + } + + ///////////////////////////////////////////// + + /** + * adds actionlistener to subscribd listener list + * @param al - actionlistener to add + */ + public void addActionListener( ActionListener al ) { + listeners.add( al ); + } + + /** + * removes actionlistener from subscribed listener list + * @param al - actionlistener to remove + */ + public void removeActionListener( ActionListener al ) { + listeners.remove( al ); + } + + /** + * sends an actionevent to subscribed listeners + * @param ae - actionevent to use as parameter to all subscribed listeners + */ + public void fireActionPerformed( ActionEvent ae ) { + for( ActionListener al : listeners ) { + al.actionPerformed( ae ); + } + } +} \ No newline at end of file diff --git a/GroundStation/v2/MotorTestPanel.java b/GroundStation/v2/MotorTestPanel.java new file mode 100644 index 0000000..2b1af87 --- /dev/null +++ b/GroundStation/v2/MotorTestPanel.java @@ -0,0 +1,189 @@ +import java.util.*; +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.event.*; + +/** + * + */ +class MotorTestPanel extends JPanel implements ActionListener { + + /** checkBox to enable/disable motor testing */ + private JCheckBox checkBox; + /** panel to hold sliders */ + private JPanel sliderPanel; + + /** slider for motor 1 */ + public VerticalSlider slider0; + /** slider for motor 2 */ + public VerticalSlider slider1; + /** slider for motor 3 */ + public VerticalSlider slider2; + /** slider for motor 4 */ + public VerticalSlider slider3; + /** slider for all motors */ + private VerticalSlider masterSlider; + + /** */ + public MessageContent controlOutput = new MessageContent(); + + /** list to hold subscribed actionlisteners */ + private ArrayList listeners; + + /** + * + */ + public MotorTestPanel() { + listeners = new ArrayList(); + + this.setLayout( new BorderLayout() ); + checkBox = new JCheckBox( "Enable Motor Testing" ); + checkBox.addActionListener( this ); + this.add( checkBox, BorderLayout.NORTH ); + + sliderPanel = new JPanel( new FlowLayout() ); + slider0 = new VerticalSlider( "Motor 0" ); + slider1 = new VerticalSlider( "Motor 1" ); + slider2 = new VerticalSlider( "Motor 2" ); + slider3 = new VerticalSlider( "Motor 3" ); + masterSlider = new VerticalSlider( "Master" ); + + slider0.addActionListener( this ); + slider1.addActionListener( this ); + slider2.addActionListener( this ); + slider3.addActionListener( this ); + masterSlider.addActionListener( this ); + + sliderPanel.add( slider0 ); + sliderPanel.add( slider1 ); + sliderPanel.add( slider2 ); + sliderPanel.add( slider3 ); + sliderPanel.add( masterSlider ); + + this.add( sliderPanel, BorderLayout.CENTER ); + + setTestStatus( false ); + } + + /** + * + */ + public MotorTestPanel( MessageContent controls ) { + this(); + controlOutput = controls; + controlOutput.addActionListener( this ); + } + + /** + * + */ + public void setEnabled( boolean state ) { + if( !state ) { + setTestStatus( false ); + } + checkBox.setEnabled( state ); + } + + /** + * + */ + public void setTestStatus( boolean enable ) { + checkBox.setSelected( enable ); + controlOutput.setMotorsEnabled( enable ); + controlOutput.motorTesting = enable; + if( !enable ) { + masterSlider.setValue( 0 ); + masterSlider.fireActionPerformed(); + } + + slider0.setEnabled( enable ); + slider1.setEnabled( enable ); + slider2.setEnabled( enable ); + slider3.setEnabled( enable ); + masterSlider.setEnabled( enable ); + } + + /** + * @return true if testing is enabled + */ + public boolean getTestStatus() { + return checkBox.isSelected(); + } + + /** + * + */ + public int[] getValues() { + int[] values = {slider0.getValue(), + slider1.getValue(), + slider2.getValue(), + slider3.getValue() }; + return values; + } + + /** + * + */ + public void actionPerformed( ActionEvent evt ) { + if( evt.getSource() == controlOutput ) { + if( evt.getActionCommand().equals( "DISABLE_MOTORS" ) && getTestStatus() ) { + setTestStatus( false ); + } + return; + } + if( evt.getSource() == checkBox ) { + setTestStatus( checkBox.isSelected() ); + return; + } + if( evt.getSource() == masterSlider ) { + slider0.setValue( Integer.parseInt( evt.getActionCommand() ) ); + slider1.setValue( Integer.parseInt( evt.getActionCommand() ) ); + slider2.setValue( Integer.parseInt( evt.getActionCommand() ) ); + slider3.setValue( Integer.parseInt( evt.getActionCommand() ) ); + } + fireActionPerformed(); + } + + //////////////////////////////////////////// + + /** + * adds actionlistener to subscribd listener list + * @param al - actionlistener to add + */ + public void addActionListener( ActionListener al ) { + listeners.add( al ); + } + + /** + * removes actionlistener from subscribed listener list + * @param al - actionlistener to remove + */ + public void removeActionListener( ActionListener al ) { + listeners.remove( al ); + } + + /** + * sends an actionevent to subscribed listeners + * @param ae - actionevent to use as parameter to all subscribed listeners + */ + public void fireActionPerformed( ActionEvent ae ) { + //controlOutput.motorValues = { slider0.getValue(), slider1.getValue(), slider2.getValue(), slider3.getValue() }; + controlOutput.motorValues[0] = slider0.getValue(); + controlOutput.motorValues[1] = slider1.getValue(); + controlOutput.motorValues[2] = slider2.getValue(); + controlOutput.motorValues[3] = slider3.getValue(); + + + for( ActionListener al : listeners ) { + al.actionPerformed( ae ); + } + } + + /** + * + */ + public void fireActionPerformed() { + fireActionPerformed( new ActionEvent( this, ActionEvent.ACTION_PERFORMED, "" ) ); + } +} \ No newline at end of file diff --git a/GroundStation/v2/VerticalSlider.java b/GroundStation/v2/VerticalSlider.java new file mode 100644 index 0000000..3939a68 --- /dev/null +++ b/GroundStation/v2/VerticalSlider.java @@ -0,0 +1,194 @@ +import java.util.*; +import java.awt.*; +import java.awt.event.*; +import javax.swing.*; +import javax.swing.event.*; + +class VerticalSlider extends JPanel implements ActionListener, ChangeListener { + + /** up button */ + private JButton up; + /** slider bar */ + private JSlider slider; + /** down button */ + private JButton down; + /** value field */ + private JTextField value; + /** list to hold subscribed actionlisteners */ + private ArrayList listeners; + /** set to false for use fo setValue */ + private boolean internalTrigger = true; + + //////////////////////// + ///// CONSTRUCTORS ///// + //////////////////////// + + /** + * no-args constructor + */ + public VerticalSlider() { + setLayout( new BoxLayout( this, BoxLayout.PAGE_AXIS ) ); + setLabel( "" ); + + + up = new JButton( "\u25B2" ); + slider = new JSlider(); + slider.setOrientation( JSlider.VERTICAL ); + slider.setValue( 0 ); + down = new JButton( "\u25BC" ); + + value = new JTextField( "0" ); + + up.addActionListener( this ); + down.addActionListener( this ); + value.addActionListener( this ); + + slider.addChangeListener( this ); + + this.add( up ); + this.add( slider ); + this.add( down ); + this.add( value ); + + listeners = new ArrayList(); + } + + /** + * sets label of slider on construction + * @param newLabel - label to put on slider + */ + public VerticalSlider( String newLabel ) { + this(); + setLabel( newLabel ); + } + + /** + * sets slider extremes + * also sets slider value to minimum + * @param sliderMin - minimum extreme value of slider + * @param sliderMax - maximum extreme value of slider + */ + public VerticalSlider( int sliderMin, int sliderMax ) { + this(); + slider.setMinimum( sliderMin ); + slider.setMaximum( sliderMax ); + setValue( sliderMin ); + } + + /** + * sets label of slider and sets slider extremes + * also sets slider value to minimum + * @param newLabel - label to put on slider + * @param sliderMin - minimum extreme value of slider + * @param sliderMax - maximum extreme value of slider + */ + public VerticalSlider( String newLabel, int sliderMin, int sliderMax ) { + this( sliderMin, sliderMax ); + setLabel( newLabel ); + } + + /////////////////// + ///// METHODS ///// + /////////////////// + + /** + * @return the value of the slider + */ + public int getValue() { + return slider.getValue(); + } + + /** + * @param newVal - value to set slider to + */ + public void setValue( int newVal ) { + internalTrigger = false; + slider.setValue( newVal ); // will trigger changeListener and update everything else + internalTrigger = true; + } + + /** + * changes the slider's label + * @param newLabel - the new name to put on slider + */ + public void setLabel( String newLabel ) { + setBorder( BorderFactory.createTitledBorder( newLabel ) ); + } + + /** + * implementation of actionlistener interface + */ + public void actionPerformed( ActionEvent evt ) { + if( evt.getSource() == up ) { + slider.setValue( slider.getValue() + 1 ); + } + else if( evt.getSource() == down ) { + slider.setValue( slider.getValue() - 1 ); + } + else if( evt.getSource() == value ) { + slider.setValue( Integer.parseInt( value.getText() ) ); + } + } + + /** + * run whenever slider changes position + * implementation of changelistener interface + */ + public void stateChanged( ChangeEvent evt ) { + if( evt.getSource() == slider ) { + value.setText( ""+ slider.getValue() ); + if( internalTrigger ) { + fireActionPerformed(); + } + } + } + + /** + * + */ + public void setEnabled( boolean enable ) { + up.setEnabled( enable ); + slider.setEnabled( enable ); + down.setEnabled( enable ); + value.setEnabled( enable ); + } + + /** + * adds actionlistener to subscribd listener list + * @param al - actionlistener to add + */ + public void addActionListener( ActionListener al ) { + listeners.add( al ); + } + + /** + * removes actionlistener from subscribed listener list + * @param al - actionlistener to remove + */ + public void removeActionListener( ActionListener al ) { + listeners.remove( al ); + } + + /** + * sends an actionevent to subscribed listeners + * @param ae - actionevent to use as parameter to all subscribed listeners + */ + public void fireActionPerformed( ActionEvent ae ) { + for( ActionListener al : listeners ) { + al.actionPerformed( ae ); + } + } + + /** + * + */ + public void fireActionPerformed() { + fireActionPerformed( new ActionEvent( this, ActionEvent.ACTION_PERFORMED, ""+ slider.getValue() ) ); + } +} + + + + + + diff --git a/GroundStation/v2/stopSign.png b/GroundStation/v2/stopSign.png new file mode 100644 index 0000000..d23a886 Binary files /dev/null and b/GroundStation/v2/stopSign.png differ