mirror of
https://github.com/brendanhaines/RasPi.git
synced 2024-11-09 16:44:40 -07:00
558 lines
19 KiB
Java
558 lines
19 KiB
Java
// graphics
|
|
import java.awt.*;
|
|
import java.awt.event.*;
|
|
import javax.swing.*;
|
|
import javax.swing.event.*;
|
|
import java.awt.image.*;
|
|
import javax.swing.border.*;
|
|
|
|
// communication
|
|
import java.lang.*;
|
|
import java.io.*;
|
|
import java.net.*;
|
|
|
|
/**
|
|
* Replaces GroundStation.java
|
|
* Written by Brendan Haines
|
|
*/
|
|
class GroundStation implements ActionListener, ChangeListener, Runnable {
|
|
|
|
//////////////////
|
|
///// FIELDS /////
|
|
//////////////////
|
|
|
|
/** string to hold the connection type */
|
|
private String connectionType = "";
|
|
/** boolean to hold connected/disconnected status */
|
|
private boolean connectionStatus = false;
|
|
/** TCP/IP socket for communication */
|
|
private Socket tcpSocket;
|
|
/** input buffer handling for tcpSocket */
|
|
private BufferedReader tcpIn;
|
|
/** output handler for tcpSocket */
|
|
private PrintWriter tcpOut;
|
|
/** thread to listen to tcpSocket */
|
|
private Thread tcpListener;
|
|
/** FC arm status */
|
|
private boolean armStatus = false;
|
|
|
|
// Main GUI components
|
|
/** window to hold GUI */
|
|
private JFrame mainFrame;
|
|
/** panel to fill mainFrame */
|
|
private JPanel mainPanel;
|
|
|
|
/** panel to hold connection options */
|
|
private JPanel connectionPanel;
|
|
/** connection options panel */
|
|
private JPanel connectionOptionsPanel;
|
|
/** connection type selection box */
|
|
private JComboBox connectionTypeComboBox;
|
|
/** card layout container for different connection types */
|
|
private JPanel connectionTypePanel;
|
|
/** JPanel to hold TCP/IP settings */
|
|
private JPanel tcpPanel;
|
|
/** label for host address field */
|
|
private JLabel tcpHostAddressFieldLabel;
|
|
/** text field for host address */
|
|
private JTextField tcpHostAddressField;
|
|
/** label for port field */
|
|
private JLabel tcpHostPortFieldLabel;
|
|
/** text field for port of socket */
|
|
private JTextField tcpHostPortField;
|
|
/** connect/disconnect button */
|
|
private JButton connectButton;
|
|
|
|
/** tabbed pane to hold many features */
|
|
private JTabbedPane tabbedPane;
|
|
/** command line interface tab */
|
|
private JPanel cliPanel;
|
|
/** panel to hold display options */
|
|
private JPanel cliOptionsPanel;
|
|
/** checkbox to display confirmation/replies from pi */
|
|
private JCheckBox cliShowReceivedCheckBox;
|
|
/** scrolling pane to hold command area */
|
|
private JScrollPane cliCommandScrollPane;
|
|
/** text area to display commands */
|
|
private JTextArea cliCommandArea;
|
|
/** panel to hold input stuff */
|
|
private JPanel cliInputPanel;
|
|
/** text field to enter commands */
|
|
private JTextField cliInputField;
|
|
/** send command button */
|
|
private JButton cliInputButton;
|
|
/** control panel */
|
|
private JPanel controlPanel;
|
|
/** arm/disarm flight controller button */
|
|
private JButton armDisarmButton;
|
|
/** calibrate IMU button */
|
|
private JButton calibrateImuButton;
|
|
/** motor testing tab */
|
|
private JPanel motorTestPanel;
|
|
/** Motor testing enable checkbox */
|
|
private JCheckBox motorTestEnableCheckBox;
|
|
/** Motor test values panel */
|
|
private JPanel motorTestValuesPanel;
|
|
/** Motor 0 slider */
|
|
private JSlider motor0Slider;
|
|
/** Motor 1 slider */
|
|
private JSlider motor1Slider;
|
|
/** Motor 2 slider */
|
|
private JSlider motor2Slider;
|
|
/** Motor 3 slider */
|
|
private JSlider motor3Slider;
|
|
/** Master slider. sets all motor sliders to its value when changed */
|
|
private JSlider motorMasterSlider;
|
|
|
|
////////////////////////
|
|
///// CONSTRUCTORS /////
|
|
////////////////////////
|
|
|
|
public GroundStation() {
|
|
setupWindow();
|
|
}
|
|
|
|
///////////////////
|
|
///// METHODS /////
|
|
///////////////////
|
|
|
|
/**
|
|
* sets up GUI
|
|
*/
|
|
private void setupWindow() {
|
|
mainFrame = new JFrame( "PiCopter Ground Station" );
|
|
mainFrame.setResizable( true );
|
|
mainFrame.setDefaultCloseOperation( JFrame.DISPOSE_ON_CLOSE );
|
|
|
|
mainPanel = new JPanel();
|
|
mainPanel.setLayout( new BorderLayout() );
|
|
|
|
setupConnectionPanel();
|
|
setupTabbedPane();
|
|
|
|
mainPanel.add( connectionPanel, BorderLayout.NORTH );
|
|
mainPanel.add( tabbedPane, BorderLayout.CENTER );
|
|
|
|
mainFrame.add( mainPanel );
|
|
|
|
mainFrame.pack();
|
|
mainFrame.setVisible( true );
|
|
}
|
|
|
|
/**
|
|
* sets up the connection panel
|
|
*/
|
|
private void setupConnectionPanel() {
|
|
connectionPanel = new JPanel( new BorderLayout() );
|
|
connectionPanel.setBorder( BorderFactory.createTitledBorder( "connection options" ) );
|
|
connectionOptionsPanel = new JPanel( new FlowLayout() );
|
|
|
|
connectionTypeComboBox = new JComboBox();
|
|
connectionTypeComboBox.addItem( "TCP/IP" );
|
|
connectionTypeComboBox.setSelectedIndex( 0 );
|
|
connectionOptionsPanel.add( connectionTypeComboBox );
|
|
|
|
connectionTypePanel = new JPanel( new CardLayout() );
|
|
|
|
tcpPanel = new JPanel( new FlowLayout() );
|
|
|
|
tcpHostAddressFieldLabel = new JLabel( "Host Address:" );
|
|
tcpHostAddressField = new JTextField();
|
|
tcpHostAddressField.setColumns( 10 );
|
|
tcpHostAddressField.setText( "192.168.42.1" );
|
|
tcpHostPortFieldLabel = new JLabel( "Port:" );
|
|
tcpHostPortField = new JTextField();
|
|
tcpHostPortField.setColumns( 6 );
|
|
tcpHostPortField.setText( "51717" );
|
|
|
|
tcpPanel.add( tcpHostAddressFieldLabel );
|
|
tcpPanel.add( tcpHostAddressField );
|
|
tcpPanel.add( tcpHostPortFieldLabel );
|
|
tcpPanel.add( tcpHostPortField );
|
|
|
|
connectionTypePanel.add( tcpPanel, "TCP/IP" );
|
|
|
|
connectionOptionsPanel.add( connectionTypePanel );
|
|
connectionPanel.add( connectionOptionsPanel, BorderLayout.NORTH );
|
|
|
|
connectButton = new JButton( "connect" );
|
|
connectButton.addActionListener( this );
|
|
connectionPanel.add( connectButton, BorderLayout.SOUTH );
|
|
}
|
|
|
|
/**
|
|
* sets up tabs
|
|
*/
|
|
private void setupTabbedPane() {
|
|
tabbedPane = new JTabbedPane();
|
|
|
|
setupCliTab();
|
|
setupControlTab();
|
|
setupMotorTestTab();
|
|
|
|
tabbedPane.add( cliPanel, "CLI", 0 );
|
|
tabbedPane.add( controlPanel, "Control", 1 );
|
|
tabbedPane.add( motorTestPanel, "Motor Testing", 2 );
|
|
tabbedPane.setEnabledAt( 1, false );
|
|
tabbedPane.setEnabledAt( 2, false );
|
|
}
|
|
|
|
/**
|
|
* sets up command line interface tab
|
|
*/
|
|
private void setupCliTab() {
|
|
cliPanel = new JPanel();
|
|
cliPanel.setLayout( new BorderLayout() );
|
|
|
|
cliOptionsPanel = new JPanel();
|
|
cliOptionsPanel.setLayout( new FlowLayout( FlowLayout.LEFT ) );
|
|
|
|
cliShowReceivedCheckBox = new JCheckBox( "show receive" );
|
|
cliShowReceivedCheckBox.setSelected( true );
|
|
cliShowReceivedCheckBox.addActionListener( this );
|
|
cliOptionsPanel.add( cliShowReceivedCheckBox );
|
|
|
|
cliCommandArea = new JTextArea();
|
|
cliCommandArea.setEditable( false );
|
|
cliCommandScrollPane = new JScrollPane( cliCommandArea );
|
|
cliCommandScrollPane.setPreferredSize( new Dimension( 400, 200 ) );
|
|
new SmartScroller( cliCommandScrollPane );
|
|
|
|
cliInputPanel = new JPanel();
|
|
cliInputPanel.setLayout( new BorderLayout() );
|
|
cliInputField = new JTextField();
|
|
cliInputField.addActionListener( this );
|
|
cliInputButton = new JButton( "send" );
|
|
cliInputButton.addActionListener( this );
|
|
cliInputPanel.add( cliInputField, BorderLayout.CENTER );
|
|
cliInputPanel.add( cliInputButton, BorderLayout.EAST );
|
|
|
|
cliPanel.add( cliOptionsPanel, BorderLayout.NORTH );
|
|
cliPanel.add( cliCommandScrollPane, BorderLayout.CENTER );
|
|
cliPanel.add( cliInputPanel, BorderLayout.SOUTH );
|
|
}
|
|
|
|
/**
|
|
* sets up control panel tab
|
|
*/
|
|
private void setupControlTab() {
|
|
controlPanel = new JPanel( new FlowLayout( FlowLayout.LEFT ) );
|
|
|
|
armDisarmButton = new JButton( "arm" );
|
|
armDisarmButton.addActionListener( this );
|
|
|
|
calibrateImuButton = new JButton( "calibrate IMU" );
|
|
calibrateImuButton.addActionListener( this );
|
|
|
|
controlPanel.add( armDisarmButton);
|
|
controlPanel.add( calibrateImuButton);
|
|
}
|
|
|
|
/**
|
|
* sets up motor testing tab
|
|
*/
|
|
private void setupMotorTestTab() {
|
|
motorTestPanel = new JPanel();
|
|
motorTestPanel.setLayout( new BorderLayout() );
|
|
|
|
motorTestEnableCheckBox = new JCheckBox( "Enable Motor Testing" );
|
|
motorTestEnableCheckBox.setSelected( false );
|
|
motorTestEnableCheckBox.addActionListener( this );
|
|
|
|
motorTestValuesPanel = new JPanel();
|
|
motorTestValuesPanel.setLayout( new FlowLayout() );
|
|
|
|
motor0Slider = new JSlider( 150, 600, 150 );
|
|
motor0Slider.setOrientation( JSlider.VERTICAL );
|
|
motor0Slider.addChangeListener( this );
|
|
|
|
motor1Slider = new JSlider( 150, 600, 150 );
|
|
motor1Slider.setOrientation( JSlider.VERTICAL );
|
|
motor1Slider.addChangeListener( this );
|
|
|
|
motor2Slider = new JSlider( 150, 600, 150 );
|
|
motor2Slider.setOrientation( JSlider.VERTICAL );
|
|
motor2Slider.addChangeListener( this );
|
|
|
|
motor3Slider = new JSlider( 150, 600, 150 );
|
|
motor3Slider.setOrientation( JSlider.VERTICAL );
|
|
motor3Slider.addChangeListener( this );
|
|
|
|
motorMasterSlider = new JSlider( 150, 600, 150 );
|
|
motorMasterSlider.setOrientation( JSlider.VERTICAL );
|
|
motorMasterSlider.addChangeListener( this );
|
|
|
|
motorTestValuesPanel.add( motor0Slider );
|
|
motorTestValuesPanel.add( motor1Slider );
|
|
motorTestValuesPanel.add( motor2Slider );
|
|
motorTestValuesPanel.add( motor3Slider );
|
|
motorTestValuesPanel.add( motorMasterSlider );
|
|
|
|
enableComponents( motorTestValuesPanel, false );
|
|
|
|
motorTestPanel.add( motorTestEnableCheckBox, BorderLayout.NORTH );
|
|
motorTestPanel.add( motorTestValuesPanel, BorderLayout.CENTER );
|
|
}
|
|
|
|
/**
|
|
* enables/disables all components in a container
|
|
* @param container - the container to enable/disable components of
|
|
* @param enable - boolean value for .setEnabled()
|
|
*/
|
|
private void enableComponents( Container container, boolean enable ) {
|
|
Component[] components = container.getComponents();
|
|
for( Component component : components ) {
|
|
component.setEnabled( enable );
|
|
if (component instanceof Container) {
|
|
enableComponents( (Container) component, enable );
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* actionPerformed method to handle ActionEvents from all buttons and GUI interaction
|
|
*/
|
|
public void actionPerformed( ActionEvent evt ) {
|
|
|
|
// command line interface
|
|
if( evt.getSource() == cliInputButton || evt.getSource() == cliInputField ) {
|
|
String inputText = cliInputField.getText();
|
|
cliInputField.setText( "" );
|
|
if( inputText.equals( "" ) ) return; // if cliInput field is empty, do nothing
|
|
cliCommandArea.append( inputText + "\n" );
|
|
|
|
if( inputText.indexOf( "CONNECT" ) == 0 ) {
|
|
cliCommandArea.append( "--ERROR - connection with command line interface not supported\n");
|
|
}
|
|
else if( inputText.indexOf( "DISCONNECT") == 0 ) {
|
|
disconnect();
|
|
}
|
|
else if( inputText.indexOf( "SEND " ) == 0 ) {
|
|
String sendText = inputText.substring( 5, inputText.length() );
|
|
cliCommandArea.append( "--SENDING: " + sendText + "\n" );
|
|
tcpOut.println( sendText );
|
|
}
|
|
else if( inputText.indexOf( "CLEAR" ) == 0 ) {
|
|
cliCommandArea.setText( "" );
|
|
}
|
|
|
|
else {
|
|
|
|
}
|
|
}
|
|
|
|
// connect button
|
|
else if( evt.getSource() == connectButton && evt.getActionCommand().equals( "connect" ) ) {
|
|
if( connectionTypeComboBox.getSelectedItem().equals( "TCP/IP" ) ) {
|
|
connectionType = "TCP/IP";
|
|
if( tcpHostAddressField.getText().equals( "" ) || tcpHostPortField.getText().equals( "" ) ) {
|
|
System.out.println( "must enter an address & port for TCP/IP" );
|
|
}
|
|
else if( connectTCP( tcpHostAddressField.getText(), Integer.parseInt( tcpHostPortField.getText() ) ) ) {
|
|
startTcpListener();
|
|
}
|
|
else {
|
|
System.out.println( "failed to connect to TCP/IP server" );
|
|
}
|
|
}
|
|
else {
|
|
System.out.println( "idk how you did that, but this protocol isn't supported...connectionTypeComboBox conains \"" + connectionTypeComboBox.getSelectedItem() + "\"" );
|
|
}
|
|
}
|
|
|
|
// disconnect button
|
|
else if( evt.getSource() == connectButton && evt.getActionCommand().equals( "disconnect" ) ) {
|
|
disconnect();
|
|
}
|
|
|
|
// arm button
|
|
else if( evt.getSource().equals( armDisarmButton ) && evt.getActionCommand().equals( "arm" ) ){
|
|
cliCommandArea.append( "--ARMING..." );
|
|
tcpOut.println( "ARM_CONTROLLER" );
|
|
armStatus = true;
|
|
armDisarmButton.setText( "disarm" );
|
|
cliCommandArea.append( "DONE\n" );
|
|
}
|
|
|
|
// disarm button
|
|
else if( evt.getSource().equals( armDisarmButton ) && evt.getActionCommand().equals( "disarm" ) ) {
|
|
cliCommandArea.append( "--DISARMING..." );
|
|
tcpOut.println( "DISARM_CONTROLLER" );
|
|
armStatus = false;
|
|
armDisarmButton.setText( "arm" );
|
|
cliCommandArea.append( "DONE\n" );
|
|
}
|
|
|
|
// motor test checkbox
|
|
else if( evt.getSource().equals( motorTestEnableCheckBox ) ) {
|
|
if( motorTestEnableCheckBox.isSelected() ) {
|
|
enableComponents( motorTestValuesPanel, true );
|
|
}
|
|
else {
|
|
disableMotorTest();
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* handles changes in JSlider positions
|
|
*/
|
|
public void stateChanged( ChangeEvent evt ) {
|
|
if( evt.getSource().equals( motor0Slider ) ) {
|
|
tcpOut.println( "SET_MOTOR_00_" + motor0Slider.getValue() );
|
|
}
|
|
else if( evt.getSource().equals( motor1Slider ) ) {
|
|
tcpOut.println( "SET_MOTOR_01_" + motor1Slider.getValue() );
|
|
}
|
|
else if( evt.getSource().equals( motor2Slider ) ) {
|
|
tcpOut.println( "SET_MOTOR_02_" + motor2Slider.getValue() );
|
|
}
|
|
else if( evt.getSource().equals( motor3Slider ) ) {
|
|
tcpOut.println( "SET_MOTOR_03_" + motor3Slider.getValue() );
|
|
}
|
|
else if( evt.getSource().equals( motorMasterSlider ) ) {
|
|
motor0Slider.setValue( motorMasterSlider.getValue() );
|
|
motor1Slider.setValue( motorMasterSlider.getValue() );
|
|
motor2Slider.setValue( motorMasterSlider.getValue() );
|
|
motor3Slider.setValue( motorMasterSlider.getValue() );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* connects over TCP/IP protocol
|
|
* @param hostAddress - the ip address of the server host
|
|
* @param hostPort - the port of the socket at the host
|
|
* @return true on success, false on failure
|
|
*/
|
|
private boolean connectTCP( String hostAddress, int hostPort ) {
|
|
cliCommandArea.append( "--CONNECTING WITH TCP..." );
|
|
|
|
try {
|
|
tcpSocket = new Socket( hostAddress, hostPort );
|
|
tcpIn = new BufferedReader( new InputStreamReader( tcpSocket.getInputStream() ) );
|
|
tcpOut = new PrintWriter( tcpSocket.getOutputStream(), true );
|
|
startTcpListener();
|
|
}
|
|
catch( UnknownHostException ex ) {
|
|
cliCommandArea.append( "UnknownHostException\n" );
|
|
return false;
|
|
}
|
|
catch( IOException ex ) {
|
|
cliCommandArea.append( "IOException\n" );
|
|
return false;
|
|
}
|
|
|
|
setGuiConnected();
|
|
connectionStatus = true;
|
|
cliCommandArea.append( "DONE\n" );
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
*
|
|
*/
|
|
private void startTcpListener() {
|
|
tcpListener = new Thread( this, "tcpListenerThread" );
|
|
tcpListener.start();
|
|
}
|
|
|
|
/**
|
|
* the method used by the TCP listening thread
|
|
*/
|
|
public void run() {
|
|
while( connectionStatus ) {
|
|
try {
|
|
if( tcpIn.ready() ) {
|
|
cliRxAppend( "--READING: " + tcpIn.readLine() + "\n" );
|
|
}
|
|
}
|
|
catch( Exception ex ) {}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* will add the message to cli view if show receive checkbox is checked
|
|
*/
|
|
public void cliRxAppend( String message ) {
|
|
if( cliShowReceivedCheckBox.isSelected() ) {
|
|
cliCommandArea.append( message );
|
|
}
|
|
}
|
|
|
|
/**
|
|
*
|
|
*/
|
|
private void setGuiConnected() {
|
|
connectButton.setText( "disconnect" );
|
|
tabbedPane.setEnabledAt( 1, true ); // control panel
|
|
tabbedPane.setEnabledAt( 2, true ); // motor testing panel
|
|
enableComponents( connectionOptionsPanel, false );
|
|
mainFrame.setDefaultCloseOperation( JFrame.DO_NOTHING_ON_CLOSE );
|
|
}
|
|
|
|
/**
|
|
*
|
|
*/
|
|
private void setGuiDisconnected() {
|
|
connectButton.setText( "connect" );
|
|
tabbedPane.setSelectedIndex( 0 );
|
|
tabbedPane.setEnabledAt( 1, false ); // control panel
|
|
tabbedPane.setEnabledAt( 2, false ); // motor testing panel
|
|
enableComponents( connectionOptionsPanel, true );
|
|
mainFrame.setDefaultCloseOperation( JFrame.DISPOSE_ON_CLOSE );
|
|
}
|
|
|
|
/**
|
|
* disconnects from whatever connection has been set up with Raspberry Pi
|
|
*/
|
|
private void disconnect() {
|
|
cliCommandArea.append( "--DISCONNECTING...\n");
|
|
|
|
disableMotorTest();
|
|
// Thread.sleep( 5 );
|
|
tcpOut.println( "DISCONNECT" );
|
|
|
|
try {
|
|
tcpIn.close();
|
|
tcpOut.close();
|
|
}
|
|
catch( IOException ex ) {
|
|
cliCommandArea.append( "IOException\n" );
|
|
return;
|
|
}
|
|
|
|
setGuiDisconnected();
|
|
connectionStatus = false;
|
|
cliCommandArea.append( "DONE\n" );
|
|
}
|
|
|
|
/**
|
|
*
|
|
*/
|
|
private void disableMotorTest() {
|
|
motorMasterSlider.setValue( 150 );
|
|
motor0Slider.setValue( 150 );
|
|
motor1Slider.setValue( 150 );
|
|
motor2Slider.setValue( 150 );
|
|
motor3Slider.setValue( 150 );
|
|
enableComponents( motorTestValuesPanel, false );
|
|
|
|
try{
|
|
Thread.sleep( 500 );
|
|
}
|
|
catch( Exception e ) {}
|
|
|
|
motorTestEnableCheckBox.setSelected( false );
|
|
}
|
|
|
|
/**
|
|
* main begins the ground station
|
|
*/
|
|
public static void main( String[] args ) {
|
|
GroundStation groundStation = new GroundStation();
|
|
}
|
|
}
|
|
|
|
|
|
|