Apostolos Fanakis
7 years ago
commit
09b45b4620
71 changed files with 4380 additions and 0 deletions
@ -0,0 +1,6 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<classpath> |
|||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/> |
|||
<classpathentry kind="src" path="src"/> |
|||
<classpathentry kind="output" path="bin"/> |
|||
</classpath> |
@ -0,0 +1,17 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<projectDescription> |
|||
<name>ComputerNetworksII</name> |
|||
<comment></comment> |
|||
<projects> |
|||
</projects> |
|||
<buildSpec> |
|||
<buildCommand> |
|||
<name>org.eclipse.jdt.core.javabuilder</name> |
|||
<arguments> |
|||
</arguments> |
|||
</buildCommand> |
|||
</buildSpec> |
|||
<natures> |
|||
<nature>org.eclipse.jdt.core.javanature</nature> |
|||
</natures> |
|||
</projectDescription> |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 52 KiB |
After Width: | Height: | Size: 52 KiB |
After Width: | Height: | Size: 52 KiB |
After Width: | Height: | Size: 53 KiB |
After Width: | Height: | Size: 53 KiB |
After Width: | Height: | Size: 51 KiB |
File diff suppressed because it is too large
@ -0,0 +1,26 @@ |
|||
package gr.auth.ee.computer_networks.actionListeners; |
|||
|
|||
import javax.swing.JCheckBox; |
|||
import javax.swing.JFormattedTextField; |
|||
import javax.swing.event.ChangeEvent; |
|||
import javax.swing.event.ChangeListener; |
|||
|
|||
public class AudioIsAdaptivelyQuantisedListener implements ChangeListener { |
|||
private final JFormattedTextField formatedTextFieldAudioBetaParameter; |
|||
|
|||
@SuppressWarnings("unused") |
|||
private AudioIsAdaptivelyQuantisedListener() { |
|||
// Disable default constructor
|
|||
formatedTextFieldAudioBetaParameter = null; |
|||
} |
|||
|
|||
public AudioIsAdaptivelyQuantisedListener(JFormattedTextField formatedTextFieldAudioBetaParameter) { |
|||
this.formatedTextFieldAudioBetaParameter = formatedTextFieldAudioBetaParameter; |
|||
} |
|||
|
|||
@Override |
|||
public void stateChanged(ChangeEvent e) { |
|||
this.formatedTextFieldAudioBetaParameter.setEnabled(!((JCheckBox) e.getSource()).isSelected()); |
|||
} |
|||
|
|||
} |
@ -0,0 +1,79 @@ |
|||
package gr.auth.ee.computer_networks.actionListeners; |
|||
|
|||
import java.awt.event.ActionEvent; |
|||
import java.awt.event.ActionListener; |
|||
|
|||
import javax.swing.JCheckBox; |
|||
import javax.swing.JComboBox; |
|||
import javax.swing.JFormattedTextField; |
|||
import javax.swing.JProgressBar; |
|||
import javax.swing.JTextPane; |
|||
|
|||
import gr.auth.ee.computer_networks.Main; |
|||
import gr.auth.ee.computer_networks.helpers.UDPBundle; |
|||
import gr.auth.ee.computer_networks.networkTests.Audio; |
|||
|
|||
public class AudioListener implements ActionListener { |
|||
|
|||
private final JFormattedTextField formatedTextFieldAudioRequestCode, formatedTextFieldAudioRequestSpecificSample, |
|||
formatedTextFieldAudioNumberOfPackets, formatedTextFieldAudioBetaParameter; |
|||
private final JComboBox<String> comboBoxAudioPoolSelect; |
|||
private final JCheckBox checkBoxAudioRequestSpecificSample, checkBoxAudioAdaptiveQuantiser; |
|||
private final JComboBox<Integer> comboBoxAudioQParameter; |
|||
private final JTextPane textPaneAudioStatsOutput; |
|||
private final JProgressBar progressBarAudioStreamer, progressBarAudioPlayer; |
|||
private final UDPBundle UDPConnection; |
|||
|
|||
@SuppressWarnings("unused") |
|||
private AudioListener() { |
|||
// Disable default constructor
|
|||
this.formatedTextFieldAudioRequestCode = null; |
|||
this.checkBoxAudioRequestSpecificSample = null; |
|||
this.formatedTextFieldAudioRequestSpecificSample = null; |
|||
this.comboBoxAudioPoolSelect = null; |
|||
this.formatedTextFieldAudioNumberOfPackets = null; |
|||
this.checkBoxAudioAdaptiveQuantiser = null; |
|||
this.formatedTextFieldAudioBetaParameter = null; |
|||
this.comboBoxAudioQParameter = null; |
|||
this.textPaneAudioStatsOutput = null; |
|||
this.progressBarAudioStreamer = null; |
|||
this.progressBarAudioPlayer = null; |
|||
this.UDPConnection = null; |
|||
} |
|||
|
|||
public AudioListener(JFormattedTextField formatedTextFieldAudioRequestCode, |
|||
JCheckBox checkBoxAudioRequestSpecificSample, |
|||
JFormattedTextField formatedTextFieldAudioRequestSpecificSample, JComboBox<String> comboBoxAudioPoolSelect, |
|||
JFormattedTextField formatedTextFieldAudioNumberOfPackets, JCheckBox checkBoxAudioAdaptiveQuantiser, |
|||
JFormattedTextField formatedTextFieldAudioBetaParameter, JComboBox<Integer> comboBoxAudioQParameter, |
|||
JTextPane textPaneAudioStatsOutput, JProgressBar progressBarAudioStreamer, |
|||
JProgressBar progressBarAudioPlayer, UDPBundle UDPConnection) { |
|||
this.formatedTextFieldAudioRequestCode = formatedTextFieldAudioRequestCode; |
|||
this.checkBoxAudioRequestSpecificSample = checkBoxAudioRequestSpecificSample; |
|||
this.formatedTextFieldAudioRequestSpecificSample = formatedTextFieldAudioRequestSpecificSample; |
|||
this.comboBoxAudioPoolSelect = comboBoxAudioPoolSelect; |
|||
this.formatedTextFieldAudioNumberOfPackets = formatedTextFieldAudioNumberOfPackets; |
|||
this.checkBoxAudioAdaptiveQuantiser = checkBoxAudioAdaptiveQuantiser; |
|||
this.formatedTextFieldAudioBetaParameter = formatedTextFieldAudioBetaParameter; |
|||
this.comboBoxAudioQParameter = comboBoxAudioQParameter; |
|||
this.textPaneAudioStatsOutput = textPaneAudioStatsOutput; |
|||
this.progressBarAudioStreamer = progressBarAudioStreamer; |
|||
this.progressBarAudioPlayer = progressBarAudioPlayer; |
|||
this.UDPConnection = UDPConnection; |
|||
} |
|||
|
|||
@Override |
|||
public void actionPerformed(ActionEvent arg0) { |
|||
Main.setSubmitButtonsEnabled(false); |
|||
Main.setStatusLineText("Test running...", Main.STATUS_LINE_ACTION_RUNNING); |
|||
(new Audio(UDPConnection, formatedTextFieldAudioRequestCode.getText(), |
|||
checkBoxAudioRequestSpecificSample.isSelected(), |
|||
Integer.parseInt(formatedTextFieldAudioRequestSpecificSample.getText().substring(1)), |
|||
comboBoxAudioPoolSelect.getItemAt(comboBoxAudioPoolSelect.getSelectedIndex()), |
|||
Integer.parseInt(formatedTextFieldAudioNumberOfPackets.getText()), |
|||
checkBoxAudioAdaptiveQuantiser.isSelected(), |
|||
Integer.parseInt(formatedTextFieldAudioBetaParameter.getText()), |
|||
comboBoxAudioQParameter.getItemAt(comboBoxAudioQParameter.getSelectedIndex()), textPaneAudioStatsOutput, |
|||
progressBarAudioStreamer, progressBarAudioPlayer)).execute(); |
|||
} |
|||
} |
@ -0,0 +1,37 @@ |
|||
package gr.auth.ee.computer_networks.actionListeners; |
|||
|
|||
import javax.swing.JCheckBox; |
|||
import javax.swing.JComboBox; |
|||
import javax.swing.JFormattedTextField; |
|||
import javax.swing.event.ChangeEvent; |
|||
import javax.swing.event.ChangeListener; |
|||
|
|||
public class AudioRequestSpecificSampleListener implements ChangeListener { |
|||
private final JFormattedTextField formatedTextFieldAudioRequestSpecificSample; |
|||
private final JComboBox<String> comboBoxAudioPoolSelect; |
|||
|
|||
@SuppressWarnings("unused") |
|||
private AudioRequestSpecificSampleListener() { |
|||
// Disable default constructor
|
|||
formatedTextFieldAudioRequestSpecificSample = null; |
|||
comboBoxAudioPoolSelect = null; |
|||
} |
|||
|
|||
public AudioRequestSpecificSampleListener(JFormattedTextField formatedTextFieldAudioRequestSpecificSample, |
|||
JComboBox<String> comboBoxAudioPoolSelect) { |
|||
this.formatedTextFieldAudioRequestSpecificSample = formatedTextFieldAudioRequestSpecificSample; |
|||
this.comboBoxAudioPoolSelect = comboBoxAudioPoolSelect; |
|||
} |
|||
|
|||
@Override |
|||
public void stateChanged(ChangeEvent e) { |
|||
boolean isSpecificSampleRequestSelected = ((JCheckBox) e.getSource()).isSelected(); |
|||
|
|||
if (isSpecificSampleRequestSelected) { |
|||
this.comboBoxAudioPoolSelect.setSelectedItem(comboBoxAudioPoolSelect.getItemAt(1)); |
|||
} |
|||
|
|||
this.formatedTextFieldAudioRequestSpecificSample.setEnabled(isSpecificSampleRequestSelected); |
|||
this.comboBoxAudioPoolSelect.setEnabled(!isSpecificSampleRequestSelected); |
|||
} |
|||
} |
@ -0,0 +1,65 @@ |
|||
package gr.auth.ee.computer_networks.actionListeners; |
|||
|
|||
import java.awt.event.ActionEvent; |
|||
import java.awt.event.ActionListener; |
|||
|
|||
import javax.swing.JLabel; |
|||
import javax.swing.JProgressBar; |
|||
import javax.swing.JSlider; |
|||
|
|||
import gr.auth.ee.computer_networks.Main; |
|||
import gr.auth.ee.computer_networks.helpers.TCPBundle; |
|||
import gr.auth.ee.computer_networks.networkTests.Copter; |
|||
|
|||
public class CopterListener implements ActionListener { |
|||
private final JSlider sliderCopterFlightLevel; |
|||
private final JLabel lblCopterTemperatureOutput; |
|||
private final JLabel lblCopterPressureOutput; |
|||
private final JLabel lblCopterAltitudeOutput; |
|||
private final JLabel lblCopterLeftMotorOutput; |
|||
private final JLabel lblCopterRightMotorOutput; |
|||
private final JLabel lblCopterImageOutput; |
|||
private final JProgressBar progressBarCopterLeftMotorPower; |
|||
private final JProgressBar progressBarCopterRightMotorPower; |
|||
private final TCPBundle TCPConnection; |
|||
|
|||
@SuppressWarnings("unused") |
|||
private CopterListener() { |
|||
// Disable default constructor
|
|||
this.sliderCopterFlightLevel = null; |
|||
this.lblCopterTemperatureOutput = null; |
|||
this.lblCopterPressureOutput = null; |
|||
this.lblCopterAltitudeOutput = null; |
|||
this.lblCopterLeftMotorOutput = null; |
|||
this.lblCopterRightMotorOutput = null; |
|||
this.lblCopterImageOutput = null; |
|||
this.progressBarCopterLeftMotorPower = null; |
|||
this.progressBarCopterRightMotorPower = null; |
|||
this.TCPConnection = null; |
|||
} |
|||
|
|||
public CopterListener(JSlider sliderCopterFlightLevel, JLabel lblCopterTemperatureOutput, |
|||
JLabel lblCopterPressureOutput, JLabel lblCopterAltitudeOutput, JLabel lblCopterLeftMotorOutput, |
|||
JLabel lblCopterRightMotorOutput, JLabel lblCopterImageOutput, JProgressBar progressBarCopterLeftMotorPower, |
|||
JProgressBar progressBarCopterRightMotorPower, TCPBundle TCPConnection) { |
|||
this.sliderCopterFlightLevel = sliderCopterFlightLevel; |
|||
this.lblCopterTemperatureOutput = lblCopterTemperatureOutput; |
|||
this.lblCopterPressureOutput = lblCopterPressureOutput; |
|||
this.lblCopterAltitudeOutput = lblCopterAltitudeOutput; |
|||
this.lblCopterLeftMotorOutput = lblCopterLeftMotorOutput; |
|||
this.lblCopterRightMotorOutput = lblCopterRightMotorOutput; |
|||
this.lblCopterImageOutput = lblCopterImageOutput; |
|||
this.progressBarCopterLeftMotorPower = progressBarCopterLeftMotorPower; |
|||
this.progressBarCopterRightMotorPower = progressBarCopterRightMotorPower; |
|||
this.TCPConnection = TCPConnection; |
|||
} |
|||
|
|||
@Override |
|||
public void actionPerformed(ActionEvent e) { |
|||
Main.setSubmitButtonsEnabled(false); |
|||
Main.setStatusLineText("Test running...", Main.STATUS_LINE_ACTION_RUNNING); |
|||
(new Copter(TCPConnection, sliderCopterFlightLevel.getValue(), lblCopterTemperatureOutput, |
|||
lblCopterPressureOutput, lblCopterAltitudeOutput, lblCopterLeftMotorOutput, lblCopterRightMotorOutput, |
|||
lblCopterImageOutput, progressBarCopterLeftMotorPower, progressBarCopterRightMotorPower)).execute(); |
|||
} |
|||
} |
@ -0,0 +1,26 @@ |
|||
package gr.auth.ee.computer_networks.actionListeners; |
|||
|
|||
import javax.swing.JLabel; |
|||
import javax.swing.JSlider; |
|||
import javax.swing.event.ChangeEvent; |
|||
import javax.swing.event.ChangeListener; |
|||
|
|||
public class CopterSliderListener implements ChangeListener { |
|||
private final JLabel lblCopterFlightLevel; |
|||
|
|||
@SuppressWarnings("unused") |
|||
private CopterSliderListener() { |
|||
// Disable default constructor
|
|||
lblCopterFlightLevel = null; |
|||
} |
|||
|
|||
public CopterSliderListener(JLabel lblCopterFlightLevel) { |
|||
this.lblCopterFlightLevel = lblCopterFlightLevel; |
|||
} |
|||
|
|||
@Override |
|||
public void stateChanged(ChangeEvent e) { |
|||
lblCopterFlightLevel.setText("Desired flight level:\t" + ((JSlider) e.getSource()).getValue()); |
|||
} |
|||
|
|||
} |
@ -0,0 +1,51 @@ |
|||
package gr.auth.ee.computer_networks.actionListeners; |
|||
|
|||
import java.awt.event.ActionEvent; |
|||
import java.awt.event.ActionListener; |
|||
|
|||
import javax.swing.JCheckBox; |
|||
import javax.swing.JTextField; |
|||
import javax.swing.JTextPane; |
|||
|
|||
import gr.auth.ee.computer_networks.Main; |
|||
import gr.auth.ee.computer_networks.helpers.UDPBundle; |
|||
import gr.auth.ee.computer_networks.networkTests.Echo; |
|||
|
|||
public class EchoListener implements ActionListener { |
|||
|
|||
private final JTextField textEchoRequestCode, textEchoDuration, textEchoNumberOfPackages; |
|||
private final JCheckBox checkBoxGetTemperature; |
|||
private final JTextPane runtimeOutput; |
|||
private final UDPBundle UDPConnection; |
|||
|
|||
@SuppressWarnings("unused") |
|||
private EchoListener() { |
|||
// Disable default constructor
|
|||
this.textEchoRequestCode = null; |
|||
this.textEchoDuration = null; |
|||
this.textEchoNumberOfPackages = null; |
|||
this.checkBoxGetTemperature = null; |
|||
this.runtimeOutput = null; |
|||
this.UDPConnection = null; |
|||
} |
|||
|
|||
public EchoListener(JTextField textEchoRequestCode, JTextField textEchoDuration, |
|||
JTextField textEchoNumberOfPackages, JCheckBox checkBoxGetTemperature, JTextPane runtimeOutput, |
|||
UDPBundle UDPConnection) { |
|||
this.textEchoRequestCode = textEchoRequestCode; |
|||
this.textEchoDuration = textEchoDuration; |
|||
this.textEchoNumberOfPackages = textEchoNumberOfPackages; |
|||
this.checkBoxGetTemperature = checkBoxGetTemperature; |
|||
this.runtimeOutput = runtimeOutput; |
|||
this.UDPConnection = UDPConnection; |
|||
} |
|||
|
|||
@Override |
|||
public void actionPerformed(ActionEvent arg0) { |
|||
Main.setSubmitButtonsEnabled(false); |
|||
Main.setStatusLineText("Test running...", Main.STATUS_LINE_ACTION_RUNNING); |
|||
(new Echo(UDPConnection, textEchoRequestCode.getText(), Integer.parseInt(textEchoDuration.getText()), |
|||
Integer.parseInt(textEchoNumberOfPackages.getText()), checkBoxGetTemperature.isSelected(), |
|||
runtimeOutput)).execute(); |
|||
} |
|||
} |
@ -0,0 +1,41 @@ |
|||
package gr.auth.ee.computer_networks.actionListeners; |
|||
|
|||
import java.awt.event.ActionEvent; |
|||
import java.awt.event.ActionListener; |
|||
|
|||
import javax.swing.JFormattedTextField; |
|||
|
|||
import gr.auth.ee.computer_networks.Main; |
|||
import gr.auth.ee.computer_networks.helpers.UDPBundle; |
|||
|
|||
public class GlobalSettingsListener implements ActionListener { |
|||
private final JFormattedTextField formatedTextFieldServerPort, formatedTextFieldClientPort; |
|||
private final UDPBundle UDPConnection; |
|||
|
|||
@SuppressWarnings("unused") |
|||
private GlobalSettingsListener() { |
|||
// Disable default constructor
|
|||
this.formatedTextFieldServerPort = null; |
|||
this.formatedTextFieldClientPort = null; |
|||
UDPConnection = null; |
|||
} |
|||
|
|||
public GlobalSettingsListener(JFormattedTextField formatedTextFieldServerPort, |
|||
JFormattedTextField formatedTextFieldClientPort, UDPBundle UDPConnection) { |
|||
this.formatedTextFieldServerPort = formatedTextFieldServerPort; |
|||
this.formatedTextFieldClientPort = formatedTextFieldClientPort; |
|||
this.UDPConnection = UDPConnection; |
|||
} |
|||
|
|||
@Override |
|||
public void actionPerformed(ActionEvent arg0) { |
|||
Main.setSubmitButtonsEnabled(false); |
|||
int newLocalPort = Integer.parseInt(formatedTextFieldClientPort.getText()); |
|||
int newServerPort = Integer.parseInt(formatedTextFieldServerPort.getText()); |
|||
|
|||
UDPConnection.setLocalPort(newLocalPort); |
|||
UDPConnection.setServerPort(newServerPort); |
|||
Main.setStatusLineText("Ports set.", Main.STATUS_LINE_ACTION_DONE); |
|||
Main.setSubmitButtonsEnabled(true); |
|||
} |
|||
} |
@ -0,0 +1,58 @@ |
|||
package gr.auth.ee.computer_networks.actionListeners; |
|||
|
|||
import java.awt.event.ActionEvent; |
|||
import java.awt.event.ActionListener; |
|||
|
|||
import javax.swing.JCheckBox; |
|||
import javax.swing.JComboBox; |
|||
import javax.swing.JFormattedTextField; |
|||
import javax.swing.JLabel; |
|||
import javax.swing.JTextPane; |
|||
|
|||
import gr.auth.ee.computer_networks.Main; |
|||
import gr.auth.ee.computer_networks.helpers.UDPBundle; |
|||
import gr.auth.ee.computer_networks.networkTests.Image; |
|||
|
|||
public class ImageListener implements ActionListener { |
|||
|
|||
private final JFormattedTextField formatedTextFieldImageRequestCode, formatedTextFieldImageDuration; |
|||
private final JCheckBox checkBoxImageControlFlow; |
|||
private final JComboBox<Integer> comboBoxImagePackageLength; |
|||
private final JTextPane runtimeStatsOutput; |
|||
private final JLabel runtimeImageOutput; |
|||
private final UDPBundle UDPConnection; |
|||
|
|||
@SuppressWarnings("unused") |
|||
private ImageListener() { |
|||
// Disable default constructor
|
|||
this.formatedTextFieldImageRequestCode = null; |
|||
this.checkBoxImageControlFlow = null; |
|||
this.comboBoxImagePackageLength = null; |
|||
this.formatedTextFieldImageDuration = null; |
|||
this.runtimeStatsOutput = null; |
|||
this.runtimeImageOutput = null; |
|||
this.UDPConnection = null; |
|||
} |
|||
|
|||
public ImageListener(JFormattedTextField formatedTextFieldImageRequestCode, JCheckBox checkBoxImageControlFlow, |
|||
JComboBox<Integer> comboBoxImagePackageLength, JFormattedTextField formatedTextFieldImageDuration, |
|||
JTextPane runtimeStatsOutput, JLabel runtimeImageOutput, UDPBundle UDPConnection) { |
|||
this.formatedTextFieldImageRequestCode = formatedTextFieldImageRequestCode; |
|||
this.checkBoxImageControlFlow = checkBoxImageControlFlow; |
|||
this.comboBoxImagePackageLength = comboBoxImagePackageLength; |
|||
this.formatedTextFieldImageDuration = formatedTextFieldImageDuration; |
|||
this.runtimeStatsOutput = runtimeStatsOutput; |
|||
this.runtimeImageOutput = runtimeImageOutput; |
|||
this.UDPConnection = UDPConnection; |
|||
} |
|||
|
|||
@Override |
|||
public void actionPerformed(ActionEvent arg0) { |
|||
Main.setSubmitButtonsEnabled(false); |
|||
Main.setStatusLineText("Test running...", Main.STATUS_LINE_ACTION_RUNNING); |
|||
(new Image(UDPConnection, formatedTextFieldImageRequestCode.getText(), |
|||
Integer.parseInt(formatedTextFieldImageDuration.getText()), checkBoxImageControlFlow.isSelected(), |
|||
comboBoxImagePackageLength.getItemAt(comboBoxImagePackageLength.getSelectedIndex()), runtimeStatsOutput, |
|||
runtimeImageOutput)).execute(); |
|||
} |
|||
} |
@ -0,0 +1,83 @@ |
|||
package gr.auth.ee.computer_networks.actionListeners; |
|||
|
|||
import java.awt.event.ActionEvent; |
|||
import java.awt.event.ActionListener; |
|||
|
|||
import javax.swing.JCheckBox; |
|||
import javax.swing.JFormattedTextField; |
|||
import javax.swing.JLabel; |
|||
|
|||
import gr.auth.ee.computer_networks.Main; |
|||
import gr.auth.ee.computer_networks.helpers.TCPBundle; |
|||
import gr.auth.ee.computer_networks.helpers.UDPBundle; |
|||
import gr.auth.ee.computer_networks.networkTests.Vehicle; |
|||
|
|||
public class VehicleListener implements ActionListener { |
|||
private final JFormattedTextField formatedTextFieldVehicleRequestCode; |
|||
private final JCheckBox checkBoxVehicleUseUDP; |
|||
private final JFormattedTextField formatedTextFieldVehicleDuration; |
|||
private final JLabel lblVehicleEngineRunTimeOutput; |
|||
private final JLabel lblVehicleAirTempOutput; |
|||
private final JLabel lblVehicleThrottlePositionOutput; |
|||
private final JLabel lblVehicleEngineRPMOutput; |
|||
private final JLabel lblVehicleSpeedOutput; |
|||
private final JLabel lblVehicleCoolantTemperatureOutput; |
|||
private final JLabel lblVehiclePacketsTotalTimeOutput; |
|||
private final TCPBundle TCPConnection; |
|||
private final UDPBundle UDPConnection; |
|||
|
|||
@SuppressWarnings("unused") |
|||
private VehicleListener() { |
|||
// Disable default constructor
|
|||
this.formatedTextFieldVehicleRequestCode = null; |
|||
this.checkBoxVehicleUseUDP = null; |
|||
this.formatedTextFieldVehicleDuration = null; |
|||
this.lblVehicleEngineRunTimeOutput = null; |
|||
this.lblVehicleAirTempOutput = null; |
|||
this.lblVehicleThrottlePositionOutput = null; |
|||
this.lblVehicleEngineRPMOutput = null; |
|||
this.lblVehicleSpeedOutput = null; |
|||
this.lblVehicleCoolantTemperatureOutput = null; |
|||
this.lblVehiclePacketsTotalTimeOutput = null; |
|||
this.TCPConnection = null; |
|||
this.UDPConnection = null; |
|||
} |
|||
|
|||
public VehicleListener(JFormattedTextField formatedTextFieldVehicleRequestCode, JCheckBox checkBoxVehicleUseUDP, |
|||
JFormattedTextField formatedTextFieldVehicleDuration, JLabel lblVehicleEngineRunTimeOutput, |
|||
JLabel lblVehicleAirTempOutput, JLabel lblVehicleThrottlePositionOutput, JLabel lblVehicleEngineRPMOutput, |
|||
JLabel lblVehicleSpeedOutput, JLabel lblVehicleCoolantTemperatureOutput, |
|||
JLabel lblVehiclePacketsTotalTimeOutput, TCPBundle TCPConnection, UDPBundle UDPConnection) { |
|||
this.formatedTextFieldVehicleRequestCode = formatedTextFieldVehicleRequestCode; |
|||
this.checkBoxVehicleUseUDP = checkBoxVehicleUseUDP; |
|||
this.formatedTextFieldVehicleDuration = formatedTextFieldVehicleDuration; |
|||
this.lblVehicleEngineRunTimeOutput = lblVehicleEngineRunTimeOutput; |
|||
this.lblVehicleAirTempOutput = lblVehicleAirTempOutput; |
|||
this.lblVehicleThrottlePositionOutput = lblVehicleThrottlePositionOutput; |
|||
this.lblVehicleEngineRPMOutput = lblVehicleEngineRPMOutput; |
|||
this.lblVehicleSpeedOutput = lblVehicleSpeedOutput; |
|||
this.lblVehicleCoolantTemperatureOutput = lblVehicleCoolantTemperatureOutput; |
|||
this.lblVehiclePacketsTotalTimeOutput = lblVehiclePacketsTotalTimeOutput; |
|||
this.TCPConnection = TCPConnection; |
|||
this.UDPConnection = UDPConnection; |
|||
} |
|||
|
|||
@Override |
|||
public void actionPerformed(ActionEvent arg0) { |
|||
Main.setSubmitButtonsEnabled(false); |
|||
Main.setStatusLineText("Test running...", Main.STATUS_LINE_ACTION_RUNNING); |
|||
if (checkBoxVehicleUseUDP.isSelected()) { |
|||
new Vehicle(UDPConnection, formatedTextFieldVehicleRequestCode.getText(), |
|||
Integer.parseInt(formatedTextFieldVehicleDuration.getText()), lblVehicleEngineRunTimeOutput, |
|||
lblVehicleAirTempOutput, lblVehicleThrottlePositionOutput, lblVehicleEngineRPMOutput, |
|||
lblVehicleSpeedOutput, lblVehicleCoolantTemperatureOutput, lblVehiclePacketsTotalTimeOutput) |
|||
.execute(); |
|||
} else { |
|||
new Vehicle(TCPConnection, formatedTextFieldVehicleRequestCode.getText(), |
|||
Integer.parseInt(formatedTextFieldVehicleDuration.getText()), lblVehicleEngineRunTimeOutput, |
|||
lblVehicleAirTempOutput, lblVehicleThrottlePositionOutput, lblVehicleEngineRPMOutput, |
|||
lblVehicleSpeedOutput, lblVehicleCoolantTemperatureOutput, lblVehiclePacketsTotalTimeOutput) |
|||
.execute(); |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,26 @@ |
|||
package gr.auth.ee.computer_networks.actionListeners; |
|||
|
|||
import javax.swing.JCheckBox; |
|||
import javax.swing.JFormattedTextField; |
|||
import javax.swing.event.ChangeEvent; |
|||
import javax.swing.event.ChangeListener; |
|||
|
|||
public class VehicleUseUDPListener implements ChangeListener { |
|||
private final JFormattedTextField formatedTextFieldVehicleRequestCode; |
|||
|
|||
@SuppressWarnings("unused") |
|||
private VehicleUseUDPListener() { |
|||
// Disable default constructor
|
|||
this.formatedTextFieldVehicleRequestCode = null; |
|||
} |
|||
|
|||
public VehicleUseUDPListener(JFormattedTextField formatedTextFieldVehicleRequestCode) { |
|||
// Disable default constructor
|
|||
this.formatedTextFieldVehicleRequestCode = formatedTextFieldVehicleRequestCode; |
|||
} |
|||
|
|||
@Override |
|||
public void stateChanged(ChangeEvent e) { |
|||
this.formatedTextFieldVehicleRequestCode.setEnabled(((JCheckBox) e.getSource()).isSelected()); |
|||
} |
|||
} |
@ -0,0 +1,572 @@ |
|||
package gr.auth.ee.computer_networks.helpers; |
|||
|
|||
/** |
|||
* Small, easy to use PID implementation with advanced controller |
|||
* capability.<br> |
|||
* Minimal usage:<br> |
|||
* MiniPID pid = new MiniPID(p,i,d); <br> |
|||
* ...looping code...{ <br> |
|||
* output= pid.getOutput(sensorvalue,target); <br> |
|||
* } |
|||
* |
|||
* @see http://brettbeauregard.com/blog/2011/04/improving-the-beginners-pid-direction/improving-the-beginners-pid-introduction
|
|||
*/ |
|||
public class MiniPID { |
|||
// **********************************
|
|||
// Class private variables
|
|||
// **********************************
|
|||
|
|||
private double P = 0; |
|||
private double I = 0; |
|||
private double D = 0; |
|||
private double F = 0; |
|||
|
|||
private double maxIOutput = 0; |
|||
private double maxError = 0; |
|||
private double errorSum = 0; |
|||
|
|||
private double maxOutput = 0; |
|||
private double minOutput = 0; |
|||
|
|||
private double setpoint = 0; |
|||
|
|||
private double lastActual = 0; |
|||
|
|||
private boolean firstRun = true; |
|||
private boolean reversed = false; |
|||
|
|||
private double outputRampRate = 0; |
|||
private double lastOutput = 0; |
|||
|
|||
private double outputFilter = 0; |
|||
|
|||
private double setpointRange = 0; |
|||
|
|||
// **********************************
|
|||
// Constructor functions
|
|||
// **********************************
|
|||
|
|||
/** |
|||
* Create a MiniPID class object. See setP, setI, setD methods for more detailed |
|||
* parameters. |
|||
* |
|||
* @param p |
|||
* Proportional gain. Large if large difference between setpoint and |
|||
* target. |
|||
* @param i |
|||
* Integral gain. Becomes large if setpoint cannot reach target |
|||
* quickly. |
|||
* @param d |
|||
* Derivative gain. Responds quickly to large changes in error. Small |
|||
* values prevents P and I terms from causing overshoot. |
|||
*/ |
|||
public MiniPID(double p, double i, double d) { |
|||
P = p; |
|||
I = i; |
|||
D = d; |
|||
checkSigns(); |
|||
} |
|||
|
|||
/** |
|||
* Create a MiniPID class object. See setP, setI, setD, setF methods for more |
|||
* detailed parameters. |
|||
* |
|||
* @param p |
|||
* Proportional gain. Large if large difference between setpoint and |
|||
* target. |
|||
* @param i |
|||
* Integral gain. Becomes large if setpoint cannot reach target |
|||
* quickly. |
|||
* @param d |
|||
* Derivative gain. Responds quickly to large changes in error. Small |
|||
* values prevents P and I terms from causing overshoot. |
|||
* @param f |
|||
* Feed-forward gain. Open loop "best guess" for the output should |
|||
* be. Only useful if setpoint represents a rate. |
|||
*/ |
|||
public MiniPID(double p, double i, double d, double f) { |
|||
P = p; |
|||
I = i; |
|||
D = d; |
|||
F = f; |
|||
checkSigns(); |
|||
} |
|||
|
|||
// **********************************
|
|||
// Configuration functions
|
|||
// **********************************
|
|||
/** |
|||
* Configure the Proportional gain parameter. <br> |
|||
* This responds quickly to changes in setpoint, and provides most of the |
|||
* initial driving force to make corrections. <br> |
|||
* Some systems can be used with only a P gain, and many can be operated with |
|||
* only PI.<br> |
|||
* For position based controllers, this is the first parameter to tune, with I |
|||
* second. <br> |
|||
* For rate controlled systems, this is often the second after F. |
|||
* |
|||
* @param p |
|||
* Proportional gain. Affects output according to |
|||
* <b>output+=P*(setpoint-current_value)</b> |
|||
*/ |
|||
public void setP(double p) { |
|||
P = p; |
|||
checkSigns(); |
|||
} |
|||
|
|||
/** |
|||
* Changes the I parameter <br> |
|||
* This is used for overcoming disturbances, and ensuring that the controller |
|||
* always gets to the control mode. Typically tuned second for "Position" based |
|||
* modes, and third for "Rate" or continuous based modes. <br> |
|||
* Affects output through <b>output+=previous_errors*Igain |
|||
* ;previous_errors+=current_error</b> |
|||
* |
|||
* @see {@link #setMaxIOutput(double) setMaxIOutput} for how to restrict |
|||
* |
|||
* @param i |
|||
* New gain value for the Integral term |
|||
*/ |
|||
public void setI(double i) { |
|||
if (I != 0) { |
|||
errorSum = errorSum * I / i; |
|||
} |
|||
if (maxIOutput != 0) { |
|||
maxError = maxIOutput / i; |
|||
} |
|||
I = i; |
|||
checkSigns(); |
|||
// Implementation note:
|
|||
// This Scales the accumulated error to avoid output errors.
|
|||
// As an example doubling the I term cuts the accumulated error in half, which
|
|||
// results in the
|
|||
// output change due to the I term constant during the transition.
|
|||
} |
|||
|
|||
/** |
|||
* Changes the D parameter <br> |
|||
* This has two primary effects: <list> |
|||
* <li>Adds a "startup kick" and speeds up system response during setpoint |
|||
* changes |
|||
* <li>Adds "drag" and slows the system when moving toward the target </list> A |
|||
* small D value can be useful for both improving response times, and preventing |
|||
* overshoot. However, in many systems a large D value will cause significant |
|||
* instability, particularly for large setpoint changes. <br> |
|||
* Affects output through <b>output += -D*(current_input_value - |
|||
* last_input_value)</b> |
|||
* |
|||
* @param d |
|||
* New gain value for the Derivative term |
|||
*/ |
|||
public void setD(double d) { |
|||
D = d; |
|||
checkSigns(); |
|||
} |
|||
|
|||
/** |
|||
* Configure the FeedForward parameter. <br> |
|||
* This is excellent for velocity, rate, and other continuous control modes |
|||
* where you can expect a rough output value based solely on the setpoint.<br> |
|||
* Should not be used in "position" based control modes.<br> |
|||
* Affects output according to <b>output+=F*Setpoint</b>. Note, that a F-only |
|||
* system is actually open loop. |
|||
* |
|||
* @param f |
|||
* Feed forward gain. |
|||
*/ |
|||
public void setF(double f) { |
|||
F = f; |
|||
checkSigns(); |
|||
} |
|||
|
|||
/** |
|||
* Configure the PID object. See setP, setI, setD methods for more detailed |
|||
* parameters. |
|||
* |
|||
* @param p |
|||
* Proportional gain. Large if large difference between setpoint and |
|||
* target. |
|||
* @param i |
|||
* Integral gain. Becomes large if setpoint cannot reach target |
|||
* quickly. |
|||
* @param d |
|||
* Derivative gain. Responds quickly to large changes in error. Small |
|||
* values prevents P and I terms from causing overshoot. |
|||
*/ |
|||
public void setPID(double p, double i, double d) { |
|||
P = p; |
|||
D = d; |
|||
// Note: the I term has additional calculations, so we need to use it's
|
|||
// specific method for setting it.
|
|||
setI(i); |
|||
checkSigns(); |
|||
} |
|||
|
|||
/** |
|||
* Configure the PID object. See setP, setI, setD, setF methods for more |
|||
* detailed parameters. |
|||
* |
|||
* @param p |
|||
* Proportional gain. Large if large difference between setpoint and |
|||
* target. |
|||
* @param i |
|||
* Integral gain. Becomes large if setpoint cannot reach target |
|||
* quickly. |
|||
* @param d |
|||
* Derivative gain. Responds quickly to large changes in error. Small |
|||
* values prevents P and I terms from causing overshoot. |
|||
* @param f |
|||
* Feed-forward gain. Open loop "best guess" for the output should |
|||
* be. Only useful if setpoint represents a rate. |
|||
*/ |
|||
public void setPID(double p, double i, double d, double f) { |
|||
P = p; |
|||
D = d; |
|||
F = f; |
|||
// Note: the I term has additional calculations, so we need to use it's
|
|||
// specific method for setting it.
|
|||
setI(i); |
|||
checkSigns(); |
|||
} |
|||
|
|||
/** |
|||
* Set the maximum output value contributed by the I component of the system |
|||
* This can be used to prevent large windup issues and make tuning simpler |
|||
* |
|||
* @param maximum. |
|||
* Units are the same as the expected output value |
|||
*/ |
|||
public void setMaxIOutput(double maximum) { |
|||
// Internally maxError and Izone are similar, but scaled for different purposes.
|
|||
// The maxError is generated for simplifying math, since calculations against
|
|||
// the max error are far more common than changing the I term or Izone.
|
|||
maxIOutput = maximum; |
|||
if (I != 0) { |
|||
maxError = maxIOutput / I; |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* Specify a maximum output range. <br> |
|||
* When one input is specified, output range is configured to <b>[-output, |
|||
* output]</b> |
|||
* |
|||
* @param output |
|||
*/ |
|||
public void setOutputLimits(double output) { |
|||
setOutputLimits(-output, output); |
|||
} |
|||
|
|||
/** |
|||
* Specify a maximum output. When two inputs specified, output range is |
|||
* configured to <b>[minimum, maximum]</b> |
|||
* |
|||
* @param minimum |
|||
* possible output value |
|||
* @param maximum |
|||
* possible output value |
|||
*/ |
|||
public void setOutputLimits(double minimum, double maximum) { |
|||
if (maximum < minimum) |
|||
return; |
|||
maxOutput = maximum; |
|||
minOutput = minimum; |
|||
|
|||
// Ensure the bounds of the I term are within the bounds of the allowable output
|
|||
// swing
|
|||
if (maxIOutput == 0 || maxIOutput > (maximum - minimum)) { |
|||
setMaxIOutput(maximum - minimum); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* Set the operating direction of the PID controller |
|||
* |
|||
* @param reversed |
|||
* Set true to reverse PID output |
|||
*/ |
|||
public void setDirection(boolean reversed) { |
|||
this.reversed = reversed; |
|||
} |
|||
|
|||
// **********************************
|
|||
// Primary operating functions
|
|||
// **********************************
|
|||
|
|||
/** |
|||
* Configure setpoint for the PID calculations<br> |
|||
* This represents the target for the PID system's, such as a position, |
|||
* velocity, or angle. <br> |
|||
* |
|||
* @see MiniPID#getOutput(actual) <br> |
|||
* @param setpoint |
|||
*/ |
|||
public void setSetpoint(double setpoint) { |
|||
this.setpoint = setpoint; |
|||
} |
|||
|
|||
/** |
|||
* Calculate the output value for the current PID cycle.<br> |
|||
* |
|||
* @param actual |
|||
* The monitored value, typically as a sensor input. |
|||
* @param setpoint |
|||
* The target value for the system |
|||
* @return calculated output value for driving the system |
|||
*/ |
|||
public double getOutput(double actual, double setpoint) { |
|||
double output; |
|||
double Poutput; |
|||
double Ioutput; |
|||
double Doutput; |
|||
double Foutput; |
|||
|
|||
this.setpoint = setpoint; |
|||
|
|||
// Ramp the setpoint used for calculations if user has opted to do so
|
|||
if (setpointRange != 0) { |
|||
setpoint = constrain(setpoint, actual - setpointRange, actual + setpointRange); |
|||
} |
|||
|
|||
// Do the simple parts of the calculations
|
|||
double error = setpoint - actual; |
|||
|
|||
// Calculate F output. Notice, this depends only on the setpoint, and not the
|
|||
// error.
|
|||
Foutput = F * setpoint; |
|||
|
|||
// Calculate P term
|
|||
Poutput = P * error; |
|||
|
|||
// If this is our first time running this, we don't actually _have_ a previous
|
|||
// input or output.
|
|||
// For sensor, sanely assume it was exactly where it is now.
|
|||
// For last output, we can assume it's the current time-independent outputs.
|
|||
if (firstRun) { |
|||
lastActual = actual; |
|||
lastOutput = Poutput + Foutput; |
|||
firstRun = false; |
|||
} |
|||
|
|||
// Calculate D Term
|
|||
// Note, this is negative. This actually "slows" the system if it's doing
|
|||
// the correct thing, and small values helps prevent output spikes and overshoot
|
|||
Doutput = -D * (actual - lastActual); |
|||
lastActual = actual; |
|||
|
|||
// The Iterm is more complex. There's several things to factor in to make it
|
|||
// easier to deal with.
|
|||
// 1. maxIoutput restricts the amount of output contributed by the Iterm.
|
|||
// 2. prevent windup by not increasing errorSum if we're already running against
|
|||
// our max Ioutput
|
|||
// 3. prevent windup by not increasing errorSum if output is output=maxOutput
|
|||
Ioutput = I * errorSum; |
|||
if (maxIOutput != 0) { |
|||
Ioutput = constrain(Ioutput, -maxIOutput, maxIOutput); |
|||
} |
|||
|
|||
// And, finally, we can just add the terms up
|
|||
output = Foutput + Poutput + Ioutput + Doutput; |
|||
|
|||
// Figure out what we're doing with the error.
|
|||
if (minOutput != maxOutput && !bounded(output, minOutput, maxOutput)) { |
|||
errorSum = error; |
|||
// reset the error sum to a sane level
|
|||
// Setting to current error ensures a smooth transition when the P term
|
|||
// decreases enough for the I term to start acting upon the controller
|
|||
// From that point the I term will build up as would be expected
|
|||
} else if (outputRampRate != 0 && !bounded(output, lastOutput - outputRampRate, lastOutput + outputRampRate)) { |
|||
errorSum = error; |
|||
} else if (maxIOutput != 0) { |
|||
errorSum = constrain(errorSum + error, -maxError, maxError); |
|||
// In addition to output limiting directly, we also want to prevent I term
|
|||
// buildup, so restrict the error directly
|
|||
} else { |
|||
errorSum += error; |
|||
} |
|||
|
|||
// Restrict output to our specified output and ramp limits
|
|||
if (outputRampRate != 0) { |
|||
output = constrain(output, lastOutput - outputRampRate, lastOutput + outputRampRate); |
|||
} |
|||
if (minOutput != maxOutput) { |
|||
output = constrain(output, minOutput, maxOutput); |
|||
} |
|||
if (outputFilter != 0) { |
|||
output = lastOutput * outputFilter + output * (1 - outputFilter); |
|||
} |
|||
|
|||
// Get a test printline with lots of details about the internal
|
|||
// calculations. This can be useful for debugging.
|
|||
// System.out.printf("Final output %5.2f [ %5.2f, %5.2f , %5.2f ], eSum
|
|||
// %.2f\n",output,Poutput, Ioutput, Doutput,errorSum );
|
|||
// System.out.printf("%5.2f\t%5.2f\t%5.2f\t%5.2f\n",output,Poutput, Ioutput,
|
|||
// Doutput );
|
|||
|
|||
lastOutput = output; |
|||
return output; |
|||
} |
|||
|
|||
/** |
|||
* Calculate the output value for the current PID cycle.<br> |
|||
* In no-parameter mode, this uses the last sensor value, and last setpoint |
|||
* value. <br> |
|||
* Not typically useful, and use of parameter modes is suggested. <br> |
|||
* |
|||
* @return calculated output value for driving the system |
|||
*/ |
|||
public double getOutput() { |
|||
return getOutput(lastActual, setpoint); |
|||
} |
|||
|
|||
/** |
|||
* Calculate the output value for the current PID cycle.<br> |
|||
* In one parameter mode, the last configured setpoint will be used.<br> |
|||
* |
|||
* @see MiniPID#setSetpoint() |
|||
* @param actual |
|||
* The monitored value, typically as a sensor input. |
|||
* @param setpoint |
|||
* The target value for the system |
|||
* @return calculated output value for driving the system |
|||
*/ |
|||
public double getOutput(double actual) { |
|||
return getOutput(actual, setpoint); |
|||
} |
|||
|
|||
/** |
|||
* Resets the controller. This erases the I term buildup, and removes D gain on |
|||
* the next loop.<br> |
|||
* This should be used any time the PID is disabled or inactive for extended |
|||
* duration, and the controlled portion of the system may have changed due to |
|||
* external forces. |
|||
*/ |
|||
public void reset() { |
|||
firstRun = true; |
|||
errorSum = 0; |
|||
} |
|||
|
|||
/** |
|||
* Set the maximum rate the output can increase per cycle.<br> |
|||
* This can prevent sharp jumps in output when changing setpoints or enabling a |
|||
* PID system, which might cause stress on physical or electrical systems. <br> |
|||
* Can be very useful for fast-reacting control loops, such as ones with large P |
|||
* or D values and feed-forward systems. |
|||
* |
|||
* @param rate, |
|||
* with units being the same as the output |
|||
*/ |
|||
public void setOutputRampRate(double rate) { |
|||
outputRampRate = rate; |
|||
} |
|||
|
|||
/** |
|||
* Set a limit on how far the setpoint can be from the current position <br> |
|||
* Can simplify tuning by helping tuning over a small range applies to a much |
|||
* larger range. <br> |
|||
* This limits the reactivity of P term, and restricts impact of large D term |
|||
* during large setpoint adjustments. Increases lag and I term if range is too |
|||
* small. |
|||
* |
|||
* @param range, |
|||
* with units being the same as the expected sensor range. |
|||
*/ |
|||
public void setSetpointRange(double range) { |
|||
setpointRange = range; |
|||
} |
|||
|
|||
/** |
|||
* Set a filter on the output to reduce sharp oscillations. <br> |
|||
* 0.1 is likely a sane starting value. Larger values use historical data more |
|||
* heavily, with low values weigh newer data. 0 will disable, filtering, and use |
|||
* only the most recent value. <br> |
|||
* Increasing the filter strength will P and D oscillations, but force larger I |
|||
* values and increase I term overshoot.<br> |
|||
* Uses an exponential wieghted rolling sum filter, according to a simple <br> |
|||
* |
|||
* <pre> |
|||
* output*(1-strength)*sum(0..n){output*strength^n} |
|||
* </pre> |
|||
* |
|||
* algorithm. |
|||
* |
|||
* @param output |
|||
* valid between [0..1), meaning [current output only.. historical |
|||
* output only) |
|||
*/ |
|||
public void setOutputFilter(double strength) { |
|||
if (strength == 0 || bounded(strength, 0, 1)) { |
|||
outputFilter = strength; |
|||
} |
|||
} |
|||
|
|||
// **************************************
|
|||
// Helper functions
|
|||
// **************************************
|
|||
|
|||
/** |
|||
* Forces a value into a specific range |
|||
* |
|||
* @param value |
|||
* input value |
|||
* @param min |
|||
* maximum returned value |
|||
* @param max |
|||
* minimum value in range |
|||
* @return Value if it's within provided range, min or max otherwise |
|||
*/ |
|||
private double constrain(double value, double min, double max) { |
|||
if (value > max) { |
|||
return max; |
|||
} |
|||
if (value < min) { |
|||
return min; |
|||
} |
|||
return value; |
|||
} |
|||
|
|||
/** |
|||
* Test if the value is within the min and max, inclusive |
|||
* |
|||
* @param value |
|||
* to test |
|||
* @param min |
|||
* Minimum value of range |
|||
* @param max |
|||
* Maximum value of range |
|||
* @return true if value is within range, false otherwise |
|||
*/ |
|||
private boolean bounded(double value, double min, double max) { |
|||
// Note, this is an inclusive range. This is so tests like
|
|||
// `bounded(constrain(0,0,1),0,1)` will return false.
|
|||
// This is more helpful for determining edge-case behaviour
|
|||
// than <= is.
|
|||
return (min < value) && (value < max); |
|||
} |
|||
|
|||
/** |
|||
* To operate correctly, all PID parameters require the same sign This should |
|||
* align with the {@literal}reversed value |
|||
*/ |
|||
private void checkSigns() { |
|||
if (reversed) { // all values should be below zero
|
|||
if (P > 0) |
|||
P *= -1; |
|||
if (I > 0) |
|||
I *= -1; |
|||
if (D > 0) |
|||
D *= -1; |
|||
if (F > 0) |
|||
F *= -1; |
|||
} else { // all values should be above zero
|
|||
if (P < 0) |
|||
P *= -1; |
|||
if (I < 0) |
|||
I *= -1; |
|||
if (D < 0) |
|||
D *= -1; |
|||
if (F < 0) |
|||
F *= -1; |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,64 @@ |
|||
package gr.auth.ee.computer_networks.helpers; |
|||
|
|||
import java.io.IOException; |
|||
import java.io.InputStream; |
|||
import java.io.OutputStream; |
|||
import java.net.InetAddress; |
|||
import java.net.Socket; |
|||
|
|||
public class TCPBundle { |
|||
private static final int CONNECTION_TIME_OUT = 2000; |
|||
|
|||
private String serverIp = ""; |
|||
private int serverPort = 0; |
|||
private Socket connection = null; |
|||
private InetAddress hostAddress = null; |
|||
private InputStream inputStream = null; |
|||
private OutputStream outputStream = null; |
|||
|
|||
@SuppressWarnings("unused") |
|||
private TCPBundle() { |
|||
// Disable default constructor
|
|||
} |
|||
|
|||
public TCPBundle(String serverIp, int serverPort) { |
|||
this.serverIp = serverIp; |
|||
this.serverPort = serverPort; |
|||
|
|||
try { |
|||
String[] serverIPSplit = this.serverIp.split("\\."); |
|||
byte[] serverIPBytes = { (byte) Integer.parseInt(serverIPSplit[0]), |
|||
(byte) Integer.parseInt(serverIPSplit[1]), (byte) Integer.parseInt(serverIPSplit[2]), |
|||
(byte) Integer.parseInt(serverIPSplit[3]) }; |
|||
hostAddress = InetAddress.getByAddress(serverIPBytes); |
|||
|
|||
connection = new Socket(this.hostAddress, this.serverPort); |
|||
connection.setSoTimeout(CONNECTION_TIME_OUT); |
|||
|
|||
inputStream = connection.getInputStream(); |
|||
outputStream = connection.getOutputStream(); |
|||
} catch (IOException exception) { |
|||
exception.printStackTrace(); |
|||
} |
|||
} |
|||
|
|||
public int getServerPort() { |
|||
return serverPort; |
|||
} |
|||
|
|||
public Socket getConnection() { |
|||
return connection; |
|||
} |
|||
|
|||
public InetAddress getHostAddress() { |
|||
return hostAddress; |
|||
} |
|||
|
|||
public InputStream getInputStream() { |
|||
return inputStream; |
|||
} |
|||
|
|||
public OutputStream getOutputStream() { |
|||
return outputStream; |
|||
} |
|||
} |
@ -0,0 +1,78 @@ |
|||
package gr.auth.ee.computer_networks.helpers; |
|||
|
|||
import java.net.DatagramSocket; |
|||
import java.net.InetAddress; |
|||
import java.net.SocketException; |
|||
import java.net.UnknownHostException; |
|||
|
|||
public class UDPBundle { |
|||
private static final int CONNECTION_TIME_OUT = 10000; |
|||
|
|||
private String serverIp = ""; |
|||
private int serverPort = 0, localPort = 0; |
|||
private DatagramSocket connection = null; |
|||
private static InetAddress hostAddress; |
|||
|
|||
@SuppressWarnings("unused") |
|||
private UDPBundle() { |
|||
// Disable default constructor
|
|||
} |
|||
|
|||
public UDPBundle(String serverIp, int serverPort, int localPort) { |
|||
this.serverIp = serverIp; |
|||
this.serverPort = serverPort; |
|||
this.localPort = localPort; |
|||
try { |
|||
connection = new DatagramSocket(this.localPort); |
|||
connection.setSoTimeout(CONNECTION_TIME_OUT); |
|||
|
|||
String[] serverIPSplit = serverIp.split("\\."); |
|||
byte[] serverIPBytes = { (byte) Integer.parseInt(serverIPSplit[0]), |
|||
(byte) Integer.parseInt(serverIPSplit[1]), (byte) Integer.parseInt(serverIPSplit[2]), |
|||
(byte) Integer.parseInt(serverIPSplit[3]) }; |
|||
hostAddress = InetAddress.getByAddress(serverIPBytes); |
|||
} catch (SocketException exception) { |
|||
exception.printStackTrace(); |
|||
} catch (UnknownHostException exception) { |
|||
exception.printStackTrace(); |
|||
} |
|||
} |
|||
|
|||
public String getServerIp() { |
|||
return serverIp; |
|||
} |
|||
|
|||
public int getServerPort() { |
|||
return serverPort; |
|||
} |
|||
|
|||
public int getLocalPort() { |
|||
return localPort; |
|||
} |
|||
|
|||
public DatagramSocket getConnection() { |
|||
return connection; |
|||
} |
|||
|
|||
public static InetAddress getHostAddress() { |
|||
return hostAddress; |
|||
} |
|||
|
|||
public void setServerPort(int serverPort) { |
|||
this.serverPort = serverPort; |
|||
} |
|||
|
|||
public boolean setLocalPort(int localPort) { |
|||
if (this.localPort == localPort) { |
|||
return true; |
|||
} |
|||
try { |
|||
connection = new DatagramSocket(localPort); |
|||
this.localPort = localPort; |
|||
return true; |
|||
} catch (SocketException exception) { |
|||
exception.printStackTrace(); |
|||
return false; |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,380 @@ |
|||
package gr.auth.ee.computer_networks.networkTests; |
|||
|
|||
import java.io.File; |
|||
import java.io.FileNotFoundException; |
|||
import java.io.FileOutputStream; |
|||
import java.io.IOException; |
|||
import java.net.DatagramPacket; |
|||
import java.nio.ByteBuffer; |
|||
import java.nio.ByteOrder; |
|||
import java.util.List; |
|||
|
|||
import javax.sound.sampled.AudioFormat; |
|||
import javax.sound.sampled.AudioSystem; |
|||
import javax.sound.sampled.LineUnavailableException; |
|||
import javax.sound.sampled.SourceDataLine; |
|||
import javax.swing.JProgressBar; |
|||
import javax.swing.JTextPane; |
|||
import javax.swing.SwingWorker; |
|||
|
|||
import gr.auth.ee.computer_networks.Main; |
|||
import gr.auth.ee.computer_networks.helpers.UDPBundle; |
|||
|
|||
public class Audio extends SwingWorker<Void, Void> { |
|||
private static final int NON_ADAPTIVELY_QUANTISED_PACKET_LENGTH = 128; |
|||
private static final int ADAPTIVELY_QUANTISED_PACKET_LENGTH = 132; |
|||
private static final int SAMPLE_RATE = 8000; |
|||
private static final int NUMBER_OF_CHANNELS = 1; |
|||
private static final boolean IS_SIGNED = true; |
|||
private static final boolean IS_BIG_ENDIAN = false; |
|||
|
|||
private static UDPBundle UDPConnection; |
|||
private String requestCode, audioPool; |
|||
private int specificSampleIndex, numberOfPacketsToRequest, betaParameter, qParameter; |
|||
private boolean isAdaptivelyQuantised, shouldRequestSpecificSample; |
|||
private static JTextPane runtimeStatsOutput; |
|||
private JProgressBar progressBarAudioStreamer, progressBarAudioPlayer; |
|||
|
|||
private boolean testSuccess = false; |
|||
private String testStatusOutput = "undefined"; |
|||
private int numberOfBytesWritenToBuffer = 0; |
|||
private int bytesPerPacket; |
|||
private float streamingProgress = 0; |
|||
private float streamingSpeed = 0; |
|||
private long playingProgress = 0; |
|||
|
|||
@SuppressWarnings("unused") |
|||
private Audio() { |
|||
// Disable default constructor
|
|||
} |
|||
|
|||
public Audio(UDPBundle UDPConnection, String requestCode, boolean shouldRequestSpecificSample, |
|||
int specificSampleIndex, String audioPool, int numberOfPacketsToRequest, boolean isAdaptivelyQuantised, |
|||
int betaParameter, int qParameter, JTextPane runtimeStatsOutput, JProgressBar progressBarAudioStreamer, |
|||
JProgressBar progressBarAudioPlayer) { |
|||
Audio.UDPConnection = UDPConnection; |
|||
this.requestCode = requestCode; |
|||
this.shouldRequestSpecificSample = shouldRequestSpecificSample; |
|||
this.specificSampleIndex = specificSampleIndex; |
|||
this.audioPool = audioPool; |
|||
this.numberOfPacketsToRequest = numberOfPacketsToRequest; |
|||
this.isAdaptivelyQuantised = isAdaptivelyQuantised; |
|||
this.betaParameter = betaParameter; |
|||
this.qParameter = qParameter; |
|||
Audio.runtimeStatsOutput = runtimeStatsOutput; |
|||
this.progressBarAudioStreamer = progressBarAudioStreamer; |
|||
this.progressBarAudioPlayer = progressBarAudioPlayer; |
|||
|
|||
if (!isAdaptivelyQuantised) { |
|||
bytesPerPacket = 128 * 2; |
|||
} else { |
|||
bytesPerPacket = 128 * 4; |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
protected Void doInBackground() { |
|||
int numberOfBytesPassedToLineOut = 0; |
|||
byte[] decodedDPCMBuffer = new byte[numberOfPacketsToRequest * bytesPerPacket]; |
|||
AudioFormat linearPCM = new AudioFormat(SAMPLE_RATE, qParameter, NUMBER_OF_CHANNELS, IS_SIGNED, IS_BIG_ENDIAN); |
|||
AudioStreamer audioStreamer = new AudioStreamer(decodedDPCMBuffer); |
|||
Thread audioStreamerThread = new Thread(audioStreamer); |
|||
SourceDataLine lineOut; |
|||
|
|||
audioStreamerThread.start(); |
|||
while (numberOfBytesWritenToBuffer < ((8192 - 7500) * (numberOfPacketsToRequest / 32))) { |
|||
publish(); |
|||
// wait a bit
|
|||
} |
|||
|
|||
playingProgress = 0; |
|||
try { |
|||
lineOut = AudioSystem.getSourceDataLine(linearPCM); |
|||
lineOut.open(linearPCM, 2560); |
|||
|
|||
lineOut.start(); |
|||
|
|||
while (audioStreamerThread.isAlive() && playingProgress < numberOfPacketsToRequest * bytesPerPacket) { |
|||
playingProgress = lineOut.getLongFramePosition(); |
|||
if (isAdaptivelyQuantised) { |
|||
playingProgress *= 2; |
|||
} |
|||
publish(); |
|||
|
|||
if (numberOfBytesPassedToLineOut != numberOfBytesWritenToBuffer) { |
|||
numberOfBytesPassedToLineOut += lineOut.write(decodedDPCMBuffer, numberOfBytesPassedToLineOut, |
|||
numberOfBytesWritenToBuffer - numberOfBytesPassedToLineOut); |
|||
} |
|||
} |
|||
|
|||
lineOut.stop(); |
|||
lineOut.close(); |
|||
} catch ( |
|||
|
|||
LineUnavailableException exception) { |
|||
exception.printStackTrace(); |
|||
} |
|||
streamingProgress = 100; |
|||
publish(); |
|||
|
|||
testSuccess = true; |
|||
testStatusOutput = "Test finished successfully."; |
|||
return null; |
|||
} |
|||
|
|||
@Override |
|||
protected void process(List<Void> notInUse) { |
|||
runtimeStatsOutput.setText("" + streamingSpeed + "KB/s"); |
|||
progressBarAudioStreamer.setValue((int) (streamingProgress + ((streamingProgress + 1) / 100))); |
|||
progressBarAudioPlayer |
|||
.setValue((int) (1000 * ((float) playingProgress / (numberOfPacketsToRequest * bytesPerPacket)))); |
|||
} |
|||
|
|||
@Override |
|||
protected void done() { |
|||
Main.setStatusLineText(testStatusOutput, |
|||
((testSuccess) ? Main.STATUS_LINE_ACTION_DONE : Main.STATUS_LINE_ACTION_ERROR)); |
|||
Main.setSubmitButtonsEnabled(true); |
|||
} |
|||
|
|||
class AudioStreamer implements Runnable { |
|||
private byte[] decodedDPCMBuffer; |
|||
private int[] meansArray = null, betasArray = null; |
|||
|
|||
public AudioStreamer(byte[] decodedDPCMBuffer) { |
|||
this.decodedDPCMBuffer = decodedDPCMBuffer; |
|||
} |
|||
|
|||
private void decodeDPCMPacket(byte[] packetBytes, byte[] decodedPacket, int beta, int packetIndex) { |
|||
for (int i = 0; i < packetBytes.length; i++) { |
|||
// Some noob code golf stuff here :P
|
|||
decodedPacket[packetIndex * bytesPerPacket + 2 * i] = (byte) ((((packetBytes[i] >> 4) & 0x0F) - 8) |
|||
+ beta * ((packetIndex > 0) ? decodedPacket[packetIndex * bytesPerPacket + 2 * i - 1] : 0)); |
|||
decodedPacket[packetIndex * bytesPerPacket + 2 * i + 1] = (byte) (((packetBytes[i] & 0x0F) - 8) |
|||
+ beta * decodedPacket[packetIndex * bytesPerPacket + 2 * i]); |
|||
} |
|||
} |
|||
|
|||
private int decodeAQDPCMPacket(byte[] packetBytes, byte[] decodedPacket, int packetIndex, int previousNibble) { |
|||
int nibble = previousNibble, mean = 0, beta = 1; |
|||
|
|||
{ |
|||
byte[] tempByte = new byte[4]; |
|||
byte meanSign = (byte) ((packetBytes[1] & 0x80) != 0 ? 0xff : 0x00); |
|||
tempByte[3] = meanSign; |
|||
tempByte[2] = meanSign; |
|||
tempByte[1] = packetBytes[1]; |
|||
tempByte[0] = packetBytes[0]; |
|||
|
|||
mean = ByteBuffer.wrap(tempByte).order(ByteOrder.LITTLE_ENDIAN).getInt(); |
|||
|
|||
byte betaSign = (byte) ((packetBytes[3] & 0x80) != 0 ? 0xff : 0x00); |
|||
tempByte[3] = betaSign; |
|||
tempByte[2] = betaSign; |
|||
tempByte[1] = packetBytes[3]; |
|||
tempByte[0] = packetBytes[2]; |
|||
|
|||
beta = ByteBuffer.wrap(tempByte).order(ByteOrder.LITTLE_ENDIAN).getInt(); |
|||
|
|||
meansArray[packetIndex] = mean; |
|||
betasArray[packetIndex] = beta; |
|||
} |
|||
|
|||
for (int i = 4; i < 132; ++i) { |
|||
int upperDifference = (((packetBytes[i] >>> 4) & 0x0f) - 8) * beta, |
|||
lowerDifference = ((packetBytes[i] & 0x0f) - 8) * beta; |
|||
|
|||
int firstSamplePair = upperDifference + nibble + mean; |
|||
int secondSamplePair = lowerDifference + upperDifference + mean; |
|||
nibble = lowerDifference; |
|||
|
|||
decodedPacket[packetIndex * 512 + 4 * (i - 4)] = (byte) (firstSamplePair); |
|||
decodedPacket[packetIndex * 512 + 4 * (i - 4) + 1] = (byte) (firstSamplePair / 256 > 127 ? 127 |
|||
: firstSamplePair / 256 < -128 ? -128 : firstSamplePair / 256); |
|||
decodedPacket[packetIndex * 512 + 4 * (i - 4) + 2] = (byte) (secondSamplePair); |
|||
decodedPacket[packetIndex * 512 + 4 * (i - 4) + 3] = (byte) (secondSamplePair / 256 > 127 ? 127 |
|||
: secondSamplePair / 256 < -128 ? -128 : secondSamplePair / 256); |
|||
} |
|||
return nibble; |
|||
} |
|||
|
|||
@Override |
|||
public void run() { |
|||
int numberOfPackets = 0, prevNibble = 0, audioOutputFileCounter = 0; |
|||
byte[] responseBuffer = null; |
|||
DatagramPacket audioRequestPacket = null, audioResponsePacket = null; |
|||
FileOutputStream audioDiffStream = null, audioOutputStream = null, audioParametersStream = null; |
|||
File audioDiffFile = null, audioOutputFile = null, audioParametersFile = null; |
|||
|
|||
do { |
|||
audioDiffFile = new File("output/audioDiff_" + requestCode |
|||
+ (audioOutputFileCounter == 0 ? "" : "_" + audioOutputFileCounter) + ".csv"); |
|||
audioOutputFile = new File("output/audio_" + requestCode |
|||
+ (audioOutputFileCounter == 0 ? "" : "_" + audioOutputFileCounter) + ".csv"); |
|||
if (isAdaptivelyQuantised) { |
|||
audioParametersFile = new File("output/audioParams_" + requestCode |
|||
+ (audioOutputFileCounter == 0 ? "" : "_" + audioOutputFileCounter) + ".csv"); |
|||
} |
|||
if (!audioDiffFile.isFile() && !audioOutputFile.isFile() |
|||
&& (!isAdaptivelyQuantised || !audioParametersFile.isFile())) { |
|||
break; |
|||
} |
|||
++audioOutputFileCounter; |
|||
} while (true); |
|||
|
|||
try { |
|||
audioDiffStream = new FileOutputStream(audioDiffFile, false); |
|||
audioOutputStream = new FileOutputStream(audioOutputFile, false); |
|||
if (isAdaptivelyQuantised) { |
|||
audioParametersStream = new FileOutputStream(audioParametersFile, false); |
|||
} |
|||
} catch (FileNotFoundException exception) { |
|||
exception.printStackTrace(); |
|||
testSuccess = false; |
|||
testStatusOutput = "File open failure!"; |
|||
return; |
|||
} |
|||
|
|||
if (!isAdaptivelyQuantised) { |
|||
responseBuffer = new byte[NON_ADAPTIVELY_QUANTISED_PACKET_LENGTH]; |
|||
audioResponsePacket = new DatagramPacket(responseBuffer, NON_ADAPTIVELY_QUANTISED_PACKET_LENGTH); |
|||
} else { |
|||
meansArray = new int[numberOfPacketsToRequest]; |
|||
betasArray = new int[numberOfPacketsToRequest]; |
|||
responseBuffer = new byte[ADAPTIVELY_QUANTISED_PACKET_LENGTH]; |
|||
requestCode = requestCode + "AQ"; |
|||
audioResponsePacket = new DatagramPacket(responseBuffer, ADAPTIVELY_QUANTISED_PACKET_LENGTH); |
|||
} |
|||
|
|||
if (shouldRequestSpecificSample) { |
|||
requestCode = requestCode + "L" |
|||
+ (specificSampleIndex < 10 ? "0" + specificSampleIndex : specificSampleIndex); |
|||
} |
|||
|
|||
requestCode = requestCode + audioPool + (numberOfPacketsToRequest < 100 |
|||
? "0" + (numberOfPacketsToRequest < 10 ? "0" + numberOfPacketsToRequest : numberOfPacketsToRequest) |
|||
: numberOfPacketsToRequest); |
|||
|
|||
audioRequestPacket = new DatagramPacket(requestCode.getBytes(), requestCode.getBytes().length, |
|||
UDPBundle.getHostAddress(), UDPConnection.getServerPort()); |
|||
try { |
|||
UDPConnection.getConnection().send(audioRequestPacket); |
|||
} catch (IOException exception) { |
|||
exception.printStackTrace(); |
|||
try { |
|||
audioDiffStream.close(); |
|||
audioOutputStream.close(); |
|||
if (isAdaptivelyQuantised) { |
|||
audioParametersStream.close(); |
|||
} |
|||
} catch (IOException inception) { |
|||
inception.printStackTrace(); |
|||
testSuccess = false; |
|||
testStatusOutput = "File close failure, after request send failure!"; |
|||
return; |
|||
} |
|||
testSuccess = false; |
|||
testStatusOutput = "Request send failure!"; |
|||
return; |
|||
} |
|||
|
|||
while (true) { |
|||
long packetDownloadTime = 0, packetStartTime = System.currentTimeMillis(); |
|||
|
|||
try { |
|||
UDPConnection.getConnection().receive(audioResponsePacket); |
|||
} catch (IOException exception) { |
|||
exception.printStackTrace(); |
|||
try { |
|||
audioDiffStream.close(); |
|||
audioOutputStream.close(); |
|||
if (isAdaptivelyQuantised) { |
|||
audioParametersStream.close(); |
|||
} |
|||
} catch (IOException inception) { |
|||
inception.printStackTrace(); |
|||
testSuccess = false; |
|||
testStatusOutput = "File close failure, after response receive failure!"; |
|||
return; |
|||
} |
|||
testSuccess = false; |
|||
testStatusOutput = "Response receive failure!"; |
|||
return; |
|||
} |
|||
|
|||
packetDownloadTime = System.currentTimeMillis() - packetStartTime; |
|||
|
|||
for (byte audioSample : responseBuffer) { |
|||
try { |
|||
audioDiffStream.write((audioSample + "\t").getBytes(), 0, |
|||
(audioSample + "\t").getBytes().length); |
|||
} catch (IOException exception) { |
|||
exception.printStackTrace(); |
|||
try { |
|||
audioDiffStream.close(); |
|||
audioOutputStream.close(); |
|||
if (isAdaptivelyQuantised) { |
|||
audioParametersStream.close(); |
|||
} |
|||
} catch (IOException inception) { |
|||
inception.printStackTrace(); |
|||
testSuccess = false; |
|||
testStatusOutput = "File close failure, after buffer write failure!"; |
|||
return; |
|||
} |
|||
testSuccess = false; |
|||
testStatusOutput = "Diff buffer write failure!"; |
|||
return; |
|||
} |
|||
} |
|||
|
|||
if (!isAdaptivelyQuantised) { |
|||
decodeDPCMPacket(responseBuffer, decodedDPCMBuffer, betaParameter, numberOfPackets); |
|||
} else { |
|||
prevNibble = decodeAQDPCMPacket(responseBuffer, decodedDPCMBuffer, numberOfPackets, prevNibble); |
|||
} |
|||
++numberOfPackets; |
|||
|
|||
streamingProgress = ((float) numberOfPackets / (float) numberOfPacketsToRequest) * 100; |
|||
streamingSpeed = (float) (2 * responseBuffer.length) / (float) (packetDownloadTime); |
|||
|
|||
numberOfBytesWritenToBuffer = numberOfPackets * bytesPerPacket; |
|||
|
|||
if (numberOfPackets == numberOfPacketsToRequest) { |
|||
break; |
|||
} |
|||
} |
|||
|
|||
try { |
|||
for (byte audioSample : decodedDPCMBuffer) { |
|||
audioOutputStream.write((audioSample + "\t").getBytes(), 0, (audioSample + "\t").getBytes().length); |
|||
} |
|||
|
|||
if (isAdaptivelyQuantised) { |
|||
for (int mean : meansArray) { |
|||
audioParametersStream.write((mean + "\t").getBytes(), 0, (mean + "\t").getBytes().length); |
|||
} |
|||
audioParametersStream.write(("\n").getBytes(), 0, ("\n").getBytes().length); |
|||
|
|||
for (int beta : betasArray) { |
|||
audioParametersStream.write((beta + "\t").getBytes(), 0, (beta + "\t").getBytes().length); |
|||
} |
|||
} |
|||
|
|||
audioDiffStream.flush(); |
|||
audioDiffStream.close(); |
|||
audioOutputStream.flush(); |
|||
audioOutputStream.close(); |
|||
if (isAdaptivelyQuantised) { |
|||
audioParametersStream.flush(); |
|||
audioParametersStream.close(); |
|||
} |
|||
} catch (IOException exception) { |
|||
exception.printStackTrace(); |
|||
testSuccess = false; |
|||
testStatusOutput = "Audio buffer write failure!"; |
|||
return; |
|||
} |
|||
} |
|||
} |
|||
} |
@ -0,0 +1,199 @@ |
|||
package gr.auth.ee.computer_networks.networkTests; |
|||
|
|||
import java.awt.image.BufferedImage; |
|||
import java.io.IOException; |
|||
import java.net.MalformedURLException; |
|||
import java.net.SocketTimeoutException; |
|||
import java.net.URL; |
|||
import java.text.DecimalFormat; |
|||
import java.util.List; |
|||
|
|||
import javax.imageio.ImageIO; |
|||
import javax.swing.ImageIcon; |
|||
import javax.swing.JLabel; |
|||
import javax.swing.JProgressBar; |
|||
import javax.swing.SwingWorker; |
|||
|
|||
import gr.auth.ee.computer_networks.Main; |
|||
import gr.auth.ee.computer_networks.helpers.MiniPID; |
|||
import gr.auth.ee.computer_networks.helpers.TCPBundle; |
|||
|
|||
public class Copter extends SwingWorker<Void, Void> { |
|||
private final static int PREAMPLE_RESPONSE_LENGTH = 429; |
|||
private final static String PREAMPLE_RESPONSE_STRING = "HTTP/1.1 200 OK\r\n" |
|||
+ "Server: Experimental Ithakicopter Java Server Version 0.4\r\n" + "Content-Type: text/html\r\n" + "\n" |
|||
+ "\n" + "\n" + "Ithakicopter remote control.<br>\r\n" |
|||
+ "Ready to enter a request-response control session.<br>\r\n" + "Request packet format :<br>\r\n" |
|||
+ "AUTO FLIGHTLEVEL=FFF LMOTOR=LLL RMOTOR=RRR PILOT <CR><LF><br>\r\n" + "Response packet format :<br>\r\n" |
|||
+ "ITHAKICOPTER LMOTOR=LLL RMOTOR=RRR ALTITUDE=AAA TEMPERATURE=TT.TT PRESSURE=PPPP.PP TELEMETRY <CR><LF><br>\r\n" |
|||
+ "<br>\r\n"; |
|||
private final static int MAX_RESPONSE_LENGTH = 128; |
|||
public final static String IMAGE_OUTPUT_URL = "http://ithaki.eng.auth.gr:38098/ithakicopter.msp&m=62&x=0&z=0&d=396&v=quad"; |
|||
public final static int IMAGE_OUTPUT_CROP_START_X = 4; |
|||
public final static int IMAGE_OUTPUT_CROP_START_Y = 2; |
|||
public final static int IMAGE_OUTPUT_CROP_WIDTH = 218; |
|||
public final static int IMAGE_OUTPUT_CROP_HEIGHT = 486; |
|||
|
|||
private final TCPBundle TCPConnection; |
|||
private final int desiredAltitude; |
|||
private final JLabel lblCopterTemperatureOutput; |
|||
private final JLabel lblCopterPressureOutput; |
|||
private final JLabel lblCopterAltitudeOutput; |
|||
private final JLabel lblCopterLeftMotorOutput; |
|||
private final JLabel lblCopterRightMotorOutput; |
|||
private final JLabel lblCopterImageOutput; |
|||
private final JProgressBar progressBarCopterLeftMotorPower; |
|||
private final JProgressBar progressBarCopterRightMotorPower; |
|||
|
|||
private boolean testSuccess = false; |
|||
private String testStatusOutput = "undefined"; |
|||
|
|||
private float copterOutputTemperature = 0, copterOutputPressure = 0; |
|||
private int copterOutputAltitude = 54; |
|||
private double copterOutputLeftMotor = 0, copterOutputRightMotor = 0; |
|||
private BufferedImage copterImageOutput = null; |
|||
|
|||
@SuppressWarnings("unused") |
|||
private Copter() { |
|||
// Disable default constructor
|
|||
this.TCPConnection = null; |
|||
this.desiredAltitude = 0; |
|||
this.lblCopterTemperatureOutput = null; |
|||
this.lblCopterPressureOutput = null; |
|||
this.lblCopterAltitudeOutput = null; |
|||
this.lblCopterLeftMotorOutput = null; |
|||
this.lblCopterRightMotorOutput = null; |
|||
this.lblCopterImageOutput = null; |
|||
this.progressBarCopterLeftMotorPower = null; |
|||
this.progressBarCopterRightMotorPower = null; |
|||
} |
|||
|
|||
public Copter(TCPBundle TCPConnection, int desiredAltitude, JLabel lblCopterTemperatureOutput, |
|||
JLabel lblCopterPressureOutput, JLabel lblCopterAltitudeOutput, JLabel lblCopterLeftMotorOutput, |
|||
JLabel lblCopterRightMotorOutput, JLabel lblCopterImageOutput, JProgressBar progressBarCopterLeftMotorPower, |
|||
JProgressBar progressBarCopterRightMotorPower) { |
|||
this.TCPConnection = TCPConnection; |
|||
this.desiredAltitude = desiredAltitude; |
|||
this.lblCopterTemperatureOutput = lblCopterTemperatureOutput; |
|||
this.lblCopterPressureOutput = lblCopterPressureOutput; |
|||
this.lblCopterAltitudeOutput = lblCopterAltitudeOutput; |
|||
this.lblCopterLeftMotorOutput = lblCopterLeftMotorOutput; |
|||
this.lblCopterRightMotorOutput = lblCopterRightMotorOutput; |
|||
this.lblCopterImageOutput = lblCopterImageOutput; |
|||
this.progressBarCopterLeftMotorPower = progressBarCopterLeftMotorPower; |
|||
this.progressBarCopterRightMotorPower = progressBarCopterRightMotorPower; |
|||
} |
|||
|
|||
@Override |
|||
protected Void doInBackground() { |
|||
byte[] responseBuffer = new byte[PREAMPLE_RESPONSE_LENGTH]; |
|||
String requestCode = "GET /index.html HTTP/1.0\r\n\r\n", responseString = ""; |
|||
URL copterImageOutputUrl; |
|||
|
|||
try { |
|||
copterImageOutputUrl = new URL(IMAGE_OUTPUT_URL); |
|||
} catch (MalformedURLException exception) { |
|||
// This should never happen
|
|||
exception.printStackTrace(); |
|||
testSuccess = false; |
|||
testStatusOutput = "Malformed image URL error, this should never happen!"; |
|||
return null; |
|||
} |
|||
|
|||
MiniPID miniPID = new MiniPID(0.058, 0.012, 0.009); |
|||
miniPID.setOutputLimits(0, 105); |
|||
miniPID.setSetpoint(desiredAltitude); |
|||
|
|||
try { |
|||
TCPConnection.getOutputStream().write(requestCode.getBytes()); |
|||
TCPConnection.getInputStream().read(responseBuffer); |
|||
} catch (IOException exception) { |
|||
exception.printStackTrace(); |
|||
testSuccess = false; |
|||
testStatusOutput = "Request send/response receive failure!"; |
|||
return null; |
|||
} |
|||
|
|||
for (byte responseByte : responseBuffer) { |
|||
responseString += (char) responseByte; |
|||
} |
|||
|
|||
if (!responseString.isEmpty() && responseString.equals(PREAMPLE_RESPONSE_STRING)) { |
|||
responseBuffer = new byte[MAX_RESPONSE_LENGTH]; |
|||
|
|||
while (true) { |
|||
int numberOfBytesRead, motorsLevel; |
|||
|
|||
responseString = ""; |
|||
motorsLevel = 150 + (int) Math.floor(miniPID.getOutput(copterOutputAltitude)); |
|||
requestCode = "AUTO FLIGHTLEVEL=" + desiredAltitude + " LMOTOR=" + motorsLevel + " RMOTOR=" |
|||
+ motorsLevel + " PILOT \r\n"; |
|||
|
|||
try { |
|||
TCPConnection.getOutputStream().write(requestCode.getBytes()); |
|||
numberOfBytesRead = TCPConnection.getInputStream().read(responseBuffer); |
|||
|
|||
if (numberOfBytesRead == -1) { |
|||
testSuccess = false; |
|||
testStatusOutput = "Server closed the connection, try running the test again after restarting the app."; |
|||
return null; |
|||
} |
|||
} catch (SocketTimeoutException exception) { |
|||
testSuccess = false; |
|||
testStatusOutput = "Response timed out!"; |
|||
return null; |
|||
} catch (IOException exception) { |
|||
exception.printStackTrace(); |
|||
testSuccess = false; |
|||
testStatusOutput = "Request send/response receive failure!"; |
|||
return null; |
|||
} |
|||
|
|||
for (byte responseByte : responseBuffer) { |
|||
responseString += (char) responseByte; |
|||
} |
|||
|
|||
copterOutputLeftMotor = Integer.parseInt(responseString.substring(20, 23)) / 2.55; |
|||
copterOutputRightMotor = Integer.parseInt(responseString.substring(31, 34)) / 2.55; |
|||
copterOutputAltitude = Integer.parseInt(responseString.substring(44, 47)); |
|||
copterOutputTemperature = Float.parseFloat(responseString.substring(61, 66)); |
|||
copterOutputPressure = Float.parseFloat(responseString.substring(76, 83)); |
|||
try { |
|||
copterImageOutput = ImageIO.read(copterImageOutputUrl); |
|||
} catch (IOException exception) { |
|||
exception.printStackTrace(); |
|||
testSuccess = false; |
|||
testStatusOutput = "Image stream failure!"; |
|||
return null; |
|||
} |
|||
copterImageOutput = copterImageOutput.getSubimage(IMAGE_OUTPUT_CROP_START_X, IMAGE_OUTPUT_CROP_START_Y, |
|||
IMAGE_OUTPUT_CROP_WIDTH, IMAGE_OUTPUT_CROP_HEIGHT); |
|||
publish(); |
|||
} |
|||
} |
|||
testSuccess = true; |
|||
testStatusOutput = "Test finished successfully."; |
|||
return null; |
|||
} |
|||
|
|||
@Override |
|||
protected void process(List<Void> notInUse) { |
|||
lblCopterTemperatureOutput.setText(copterOutputTemperature + " °C"); |
|||
lblCopterPressureOutput.setText(copterOutputPressure + " mBar"); |
|||
lblCopterAltitudeOutput.setText(copterOutputAltitude + " px above GND"); |
|||
lblCopterLeftMotorOutput.setText((new DecimalFormat("#.###")).format(copterOutputLeftMotor) + " %"); |
|||
lblCopterRightMotorOutput.setText((new DecimalFormat("#.###")).format(copterOutputRightMotor) + " %"); |
|||
|
|||
progressBarCopterLeftMotorPower.setValue((int) Math.floor(copterOutputLeftMotor)); |
|||
progressBarCopterRightMotorPower.setValue((int) Math.floor(copterOutputRightMotor)); |
|||
|
|||
lblCopterImageOutput.setIcon(new ImageIcon(copterImageOutput)); |
|||
} |
|||
|
|||
@Override |
|||
protected void done() { |
|||
Main.setStatusLineText(testStatusOutput, |
|||
((testSuccess) ? Main.STATUS_LINE_ACTION_DONE : Main.STATUS_LINE_ACTION_ERROR)); |
|||
Main.setSubmitButtonsEnabled(true); |
|||
} |
|||
} |
@ -0,0 +1,226 @@ |
|||
package gr.auth.ee.computer_networks.networkTests; |
|||
|
|||
import java.io.File; |
|||
import java.io.FileNotFoundException; |
|||
import java.io.FileOutputStream; |
|||
import java.io.IOException; |
|||
import java.net.DatagramPacket; |
|||
import java.util.List; |
|||
|
|||
import javax.swing.JTextPane; |
|||
import javax.swing.SwingWorker; |
|||
|
|||
import gr.auth.ee.computer_networks.Main; |
|||
import gr.auth.ee.computer_networks.helpers.UDPBundle; |
|||
|
|||
public class Echo extends SwingWorker<Void, Long> { |
|||
private static final int MAX_RESPONSE_LENGTH = 2048; |
|||
|
|||
private static UDPBundle UDPConnection; |
|||
private String requestCode; |
|||
private int duration, numberOfPackages; |
|||
private boolean getTemperature; |
|||
private static JTextPane runtimeOutput; |
|||
|
|||
private boolean testSuccess = false; |
|||
private String testStatusOutput = "undefined"; |
|||
|
|||
@SuppressWarnings("unused") |
|||
private Echo() { |
|||
// Disable default constructor
|
|||
} |
|||
|
|||
public Echo(UDPBundle UDPConnection, String requestCode, int duration, int numberOfPackages, boolean getTemperature, |
|||
JTextPane runtimeOutput) { |
|||
Echo.UDPConnection = UDPConnection; |
|||
this.requestCode = requestCode; |
|||
this.duration = duration; |
|||
this.numberOfPackages = numberOfPackages; |
|||
this.getTemperature = getTemperature; |
|||
Echo.runtimeOutput = runtimeOutput; |
|||
} |
|||
|
|||
@Override |
|||
protected Void doInBackground() { |
|||
int currentPackageNumber = 0, echoOutputFileCounter = 0; |
|||
boolean monitorNumberOfPackages = !(numberOfPackages == 0), monitorDuration = !(duration == 0); |
|||
byte responseBuffer[] = new byte[MAX_RESPONSE_LENGTH]; |
|||
DatagramPacket echoRequestPacket = null, |
|||
echoResponsePacket = new DatagramPacket(responseBuffer, MAX_RESPONSE_LENGTH); |
|||
long startTime = System.currentTimeMillis(), packageStartTime = 0, packageEndTime, runningTime = 0; |
|||
String temperatureString = null; |
|||
FileOutputStream echoOutputStream = null; |
|||
File echoOutputFile = null; |
|||
do { |
|||
echoOutputFile = new File("output/echo_" + requestCode |
|||
+ (echoOutputFileCounter == 0 ? "" : "_" + echoOutputFileCounter) + ".csv"); |
|||
if (!echoOutputFile.isFile()) { |
|||
break; |
|||
} |
|||
++echoOutputFileCounter; |
|||
} while (true); |
|||
|
|||
try { |
|||
echoOutputStream = new FileOutputStream(echoOutputFile, false); |
|||
} catch (FileNotFoundException exception) { |
|||
exception.printStackTrace(); |
|||
testSuccess = false; |
|||
testStatusOutput = "Echo file open failure!"; |
|||
return null; |
|||
} |
|||
|
|||
if (getTemperature) { |
|||
requestCode = requestCode + "T00"; |
|||
} |
|||
|
|||
requestCode = requestCode + "\r"; |
|||
|
|||
echoRequestPacket = new DatagramPacket(requestCode.getBytes(), requestCode.getBytes().length, |
|||
UDPBundle.getHostAddress(), UDPConnection.getServerPort()); |
|||
|
|||
while (true) { |
|||
currentPackageNumber++; |
|||
try { |
|||
UDPConnection.getConnection().send(echoRequestPacket); |
|||
} catch (IOException exception) { |
|||
exception.printStackTrace(); |
|||
try { |
|||
echoOutputStream.close(); |
|||
} catch (IOException inception) { |
|||
inception.printStackTrace(); |
|||
testSuccess = false; |
|||
testStatusOutput = "Echo file close failure, after request send failure!"; |
|||
return null; |
|||
} |
|||
testSuccess = false; |
|||
testStatusOutput = "Request send failure!"; |
|||
return null; |
|||
} |
|||
|
|||
try { |
|||
packageStartTime = System.currentTimeMillis(); |
|||
UDPConnection.getConnection().receive(echoResponsePacket); |
|||
} catch (IOException exception) { |
|||
exception.printStackTrace(); |
|||
try { |
|||
echoOutputStream.close(); |
|||
} catch (IOException inception) { |
|||
inception.printStackTrace(); |
|||
testSuccess = false; |
|||
testStatusOutput = "Echo file close failure, after response receive failure!"; |
|||
return null; |
|||
} |
|||
testSuccess = false; |
|||
testStatusOutput = "Response receive failure!"; |
|||
return null; |
|||
} |
|||
|
|||
String responseString = new String(responseBuffer); |
|||
if (!responseString.contains("PSTART") || !responseString.contains("PSTOP")) { |
|||
try { |
|||
echoOutputStream.close(); |
|||
} catch (IOException inception) { |
|||
inception.printStackTrace(); |
|||
testSuccess = false; |
|||
testStatusOutput = "Echo file close failure, after malformed response receive!"; |
|||
return null; |
|||
} |
|||
testSuccess = false; |
|||
testStatusOutput = "Malformed response!"; |
|||
return null; |
|||
} else { |
|||
packageEndTime = System.currentTimeMillis(); |
|||
long packageTime = packageEndTime - packageStartTime; |
|||
runningTime += packageTime; |
|||
|
|||
try { |
|||
echoOutputStream.write((packageTime + "\t").getBytes(), 0, (packageTime + "\t").getBytes().length); |
|||
} catch (IOException exception) { |
|||
exception.printStackTrace(); |
|||
try { |
|||
echoOutputStream.close(); |
|||
} catch (IOException inception) { |
|||
inception.printStackTrace(); |
|||
testSuccess = false; |
|||
testStatusOutput = "Echo file close failure, after buffer write failure!"; |
|||
return null; |
|||
} |
|||
testSuccess = false; |
|||
testStatusOutput = "Echo file buffer write failure!"; |
|||
return null; |
|||
} |
|||
|
|||
if (getTemperature) { |
|||
if (currentPackageNumber == 1) { |
|||
if (responseString.contains("+")) { |
|||
temperatureString = responseString.substring(responseString.indexOf("+"), |
|||
responseString.indexOf(" C")); |
|||
} else { |
|||
temperatureString = responseString.substring(responseString.indexOf("-"), |
|||
responseString.indexOf(" C")); |
|||
} |
|||
} |
|||
publish(packageTime, runningTime / currentPackageNumber, Long.parseLong(temperatureString)); |
|||
} else { |
|||
publish(packageTime, runningTime / currentPackageNumber, null); |
|||
} |
|||
} |
|||
|
|||
if (monitorNumberOfPackages) { |
|||
if (numberOfPackages == currentPackageNumber) { |
|||
try { |
|||
echoOutputStream.flush(); |
|||
echoOutputStream.close(); |
|||
} catch (IOException exception) { |
|||
exception.printStackTrace(); |
|||
testSuccess = false; |
|||
testStatusOutput = "Echo file buffer flush/close failure!"; |
|||
return null; |
|||
} |
|||
testSuccess = true; |
|||
testStatusOutput = "Test finished successfully."; |
|||
return null; |
|||
} |
|||
} |
|||
if (monitorDuration) { |
|||
if ((packageEndTime - startTime) >= (duration * 1000)) { |
|||
try { |
|||
echoOutputStream.flush(); |
|||
echoOutputStream.close(); |
|||
} catch (IOException exception) { |
|||
exception.printStackTrace(); |
|||
testSuccess = false; |
|||
testStatusOutput = "Echo file buffer flush/close failure!"; |
|||
return null; |
|||
} |
|||
testSuccess = true; |
|||
testStatusOutput = "Test finished successfully."; |
|||
return null; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
protected void process(List<Long> pingValues) { |
|||
if (pingValues.size() != 3) { |
|||
return; |
|||
} else { |
|||
if (pingValues.get(2) == null) { |
|||
runtimeOutput.setText("Last packet ping time:\t" + pingValues.get(0) |
|||
+ " ms\nAverage packet ping time:\t" + pingValues.get(1) + " ms\nTemperature = NaN"); |
|||
} else { |
|||
runtimeOutput |
|||
.setText("Last packet ping time:\t" + pingValues.get(0) + " ms\nAverage packet ping time:\t" |
|||
+ pingValues.get(1) + " ms\nTemperature = " + pingValues.get(2) + " °C"); |
|||
} |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
protected void done() { |
|||
Main.setStatusLineText(testStatusOutput, |
|||
((testSuccess) ? Main.STATUS_LINE_ACTION_DONE : Main.STATUS_LINE_ACTION_ERROR)); |
|||
Main.setSubmitButtonsEnabled(true); |
|||
} |
|||
} |
@ -0,0 +1,265 @@ |
|||
package gr.auth.ee.computer_networks.networkTests; |
|||
|
|||
import java.awt.Graphics2D; |
|||
import java.awt.RenderingHints; |
|||
import java.awt.image.BufferedImage; |
|||
import java.io.FileNotFoundException; |
|||
import java.io.FileOutputStream; |
|||
import java.io.IOException; |
|||
import java.net.DatagramPacket; |
|||
import java.util.ArrayList; |
|||
import java.util.List; |
|||
|
|||
import javax.swing.ImageIcon; |
|||
import javax.swing.JLabel; |
|||
import javax.swing.JTextPane; |
|||
import javax.swing.SwingWorker; |
|||
|
|||
import gr.auth.ee.computer_networks.Main; |
|||
import gr.auth.ee.computer_networks.helpers.UDPBundle; |
|||
|
|||
public class Image extends SwingWorker<Void, Boolean> { |
|||
private static final int IMAGE_WIDTH = 320; |
|||
private static final int IMAGE_HEIGHT = 240; |
|||
|
|||
private static UDPBundle UDPConnection; |
|||
private String requestCode; |
|||
private int duration, packageLength; |
|||
private boolean flowControl; |
|||
private static JTextPane runtimeStatsOutput; |
|||
private static JLabel runtimeImageOutput; |
|||
private ArrayList<Byte> dispImageBytesList; |
|||
|
|||
private boolean testSuccess = false; |
|||
private String testStatusOutput = "undefined"; |
|||
private long currentImageTimeElapsed = 0; |
|||
private int currentImageNumberOfPackages = 0; |
|||
private float averageImageTimeElapsed = 0, averageImageNumberOfPackages = 0, currentImageSize = 0, |
|||
averageImageSize = 0, fps = 0; |
|||
|
|||
@SuppressWarnings("unused") |
|||
private Image() { |
|||
// Disable default constructor
|
|||
} |
|||
|
|||
public Image(UDPBundle UDPConnection, String requestCode, int duration, boolean flowControl, int packageLength, |
|||
JTextPane runtimeStatsOutput, JLabel runtimeImageOutput) { |
|||
Image.UDPConnection = UDPConnection; |
|||
this.requestCode = requestCode; |
|||
this.duration = duration; |
|||
this.packageLength = packageLength; |
|||
this.flowControl = flowControl; |
|||
Image.runtimeStatsOutput = runtimeStatsOutput; |
|||
Image.runtimeImageOutput = runtimeImageOutput; |
|||
} |
|||
|
|||
@Override |
|||
protected Void doInBackground() { |
|||
boolean monitorDuration = !(duration == 0); |
|||
byte responseBuffer[] = new byte[packageLength]; |
|||
DatagramPacket imageRequestPacket = null, |
|||
imageResponsePacket = new DatagramPacket(responseBuffer, packageLength), imageNextPacket = null; |
|||
long startTime = System.currentTimeMillis(), totalImagesTimeElapsed = 0; |
|||
int numberOfImages = 0, totalImagesNumberOfPackages = 0, totalImagesSize = 0; |
|||
|
|||
averageImageTimeElapsed = 0; |
|||
averageImageNumberOfPackages = 0; |
|||
averageImageSize = 0; |
|||
fps = 0; |
|||
|
|||
if (flowControl) { |
|||
requestCode = requestCode + "FLOW=ON"; |
|||
imageNextPacket = new DatagramPacket("NEXT".getBytes(), "NEXT".getBytes().length, |
|||
UDPBundle.getHostAddress(), UDPConnection.getServerPort()); |
|||
} |
|||
if (packageLength != 128) { |
|||
requestCode = requestCode + "UDP=" + packageLength; |
|||
} |
|||
|
|||
requestCode = requestCode + "\r"; |
|||
|
|||
imageRequestPacket = new DatagramPacket(requestCode.getBytes(), requestCode.getBytes().length, |
|||
UDPBundle.getHostAddress(), UDPConnection.getServerPort()); |
|||
|
|||
while (true) { |
|||
ArrayList<Byte> loadingImageBytesList = new ArrayList<Byte>(); |
|||
FileOutputStream imageOutputStream = null; |
|||
try { |
|||
imageOutputStream = new FileOutputStream("output/image_" + requestCode + "_" + numberOfImages + ".jpg", |
|||
false); |
|||
} catch (FileNotFoundException exception) { |
|||
exception.printStackTrace(); |
|||
testSuccess = false; |
|||
testStatusOutput = "Image file open failure!"; |
|||
return null; |
|||
} |
|||
boolean shouldBreak = false; |
|||
currentImageNumberOfPackages = 0; |
|||
currentImageTimeElapsed = 0; |
|||
currentImageSize = 0; |
|||
try { |
|||
UDPConnection.getConnection().send(imageRequestPacket); |
|||
} catch (IOException exception) { |
|||
exception.printStackTrace(); |
|||
try { |
|||
imageOutputStream.close(); |
|||
} catch (IOException inception) { |
|||
inception.printStackTrace(); |
|||
testSuccess = false; |
|||
testStatusOutput = "Image file close failure, after request send failure!"; |
|||
return null; |
|||
} |
|||
testSuccess = false; |
|||
testStatusOutput = "Request send failure!"; |
|||
return null; |
|||
} |
|||
long currentImageTimeStart = System.currentTimeMillis(); |
|||
|
|||
while (true) { |
|||
try { |
|||
UDPConnection.getConnection().receive(imageResponsePacket); |
|||
} catch (IOException exception) { |
|||
exception.printStackTrace(); |
|||
try { |
|||
imageOutputStream.close(); |
|||
} catch (IOException inception) { |
|||
inception.printStackTrace(); |
|||
testSuccess = false; |
|||
testStatusOutput = "Image file close failure, after response receive failure!"; |
|||
return null; |
|||
} |
|||
testSuccess = false; |
|||
testStatusOutput = "Response receive failure!"; |
|||
return null; |
|||
} |
|||
|
|||
++currentImageNumberOfPackages; |
|||
|
|||
try { |
|||
imageOutputStream.write(responseBuffer, 0, responseBuffer.length); |
|||
} catch (IOException exception) { |
|||
exception.printStackTrace(); |
|||
try { |
|||
imageOutputStream.close(); |
|||
} catch (IOException inception) { |
|||
inception.printStackTrace(); |
|||
testSuccess = false; |
|||
testStatusOutput = "Image file close failure, after buffer write failure!"; |
|||
return null; |
|||
} |
|||
testSuccess = false; |
|||
testStatusOutput = "Image file buffer write failure!"; |
|||
return null; |
|||
} |
|||
|
|||
for (int i = 0; i < packageLength; ++i) { |
|||
loadingImageBytesList.add(responseBuffer[i]); |
|||
|
|||
if (responseBuffer[i] != 0) { |
|||
if ((i < packageLength - 1) && (responseBuffer[i] == (byte) 255) |
|||
&& (responseBuffer[i + 1] == (byte) 217)) { |
|||
shouldBreak = true; |
|||
} |
|||
|
|||
responseBuffer[i] = 0; |
|||
} |
|||
} |
|||
|
|||
if (currentImageNumberOfPackages % 20 == 0) { |
|||
currentImageSize = (float) ((loadingImageBytesList.size()) / 1000.0); |
|||
currentImageTimeElapsed = System.currentTimeMillis() - currentImageTimeStart; |
|||
publish(false); |
|||
} |
|||
|
|||
if (shouldBreak) { |
|||
currentImageTimeElapsed = System.currentTimeMillis() - currentImageTimeStart; |
|||
break; |
|||
} |
|||
|
|||
if (flowControl) { |
|||
try { |
|||
UDPConnection.getConnection().send(imageNextPacket); |
|||
} catch (IOException exception) { |
|||
exception.printStackTrace(); |
|||
try { |
|||
imageOutputStream.close(); |
|||
} catch (IOException inception) { |
|||
inception.printStackTrace(); |
|||
testSuccess = false; |
|||
testStatusOutput = "Image file close failure, after request send failure!"; |
|||
return null; |
|||
} |
|||
testSuccess = false; |
|||
testStatusOutput = "Request send failure!"; |
|||
return null; |
|||
} |
|||
} |
|||
} |
|||
|
|||
try { |
|||
imageOutputStream.flush(); |
|||
imageOutputStream.close(); |
|||
} catch (IOException exception) { |
|||
exception.printStackTrace(); |
|||
testSuccess = false; |
|||
testStatusOutput = "Image file buffer flush/close failure!"; |
|||
return null; |
|||
} |
|||
|
|||
++numberOfImages; |
|||
totalImagesTimeElapsed += currentImageTimeElapsed; |
|||
averageImageTimeElapsed = (float) totalImagesTimeElapsed / (float) numberOfImages; |
|||
totalImagesNumberOfPackages += currentImageNumberOfPackages; |
|||
averageImageNumberOfPackages = (float) totalImagesNumberOfPackages / (float) numberOfImages; |
|||
totalImagesSize += currentImageSize; |
|||
averageImageSize = totalImagesSize / (float) numberOfImages; |
|||
dispImageBytesList = loadingImageBytesList; |
|||
fps = (float) ((numberOfImages) / (totalImagesTimeElapsed / 1000.0)); |
|||
publish(true); |
|||
|
|||
if (monitorDuration) { |
|||
if ((System.currentTimeMillis() - startTime) >= (duration * 1000)) { |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
testSuccess = true; |
|||
testStatusOutput = "Test finished successfully."; |
|||
return null; |
|||
} |
|||
|
|||
@Override |
|||
protected void process(List<Boolean> shouldRefreshImage) { |
|||
runtimeStatsOutput.setText("Current Image" + "\t" + "\t" + "Average" + "\n" + "Time elapsed = " |
|||
+ currentImageTimeElapsed + " ms\t" + "Average image time = " + averageImageTimeElapsed + " ms\n" |
|||
+ "Number of packages = " + currentImageNumberOfPackages + "\t" + "Average number of packages = " |
|||
+ averageImageNumberOfPackages + "\n" + "Image size = " + currentImageSize + " KB\t" |
|||
+ "Average image size = " + averageImageSize + " KB\n" + "\n" + "FPS = " + fps); |
|||
|
|||
if (shouldRefreshImage.get(0)) { |
|||
byte[] imageBytes = new byte[dispImageBytesList.size()]; |
|||
for (int i = 0; i < dispImageBytesList.size(); ++i) { |
|||
imageBytes[i] = dispImageBytesList.get(i); |
|||
} |
|||
|
|||
ImageIcon image = new ImageIcon(imageBytes); |
|||
|
|||
BufferedImage resizedImg = new BufferedImage(IMAGE_WIDTH, IMAGE_HEIGHT, BufferedImage.TYPE_INT_ARGB); |
|||
Graphics2D g2 = resizedImg.createGraphics(); |
|||
|
|||
g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); |
|||
g2.drawImage(image.getImage(), 0, 0, IMAGE_WIDTH, IMAGE_HEIGHT, null); |
|||
g2.dispose(); |
|||
image = new ImageIcon(resizedImg); |
|||
|
|||
runtimeImageOutput.setIcon(image); |
|||
} |
|||
} |
|||
|
|||
@Override |
|||
protected void done() { |
|||
Main.setStatusLineText(testStatusOutput, |
|||
((testSuccess) ? Main.STATUS_LINE_ACTION_DONE : Main.STATUS_LINE_ACTION_ERROR)); |
|||
Main.setSubmitButtonsEnabled(true); |
|||
} |
|||
} |
@ -0,0 +1,393 @@ |
|||
package gr.auth.ee.computer_networks.networkTests; |
|||
|
|||
import java.io.File; |
|||
import java.io.FileNotFoundException; |
|||
import java.io.FileOutputStream; |
|||
import java.io.IOException; |
|||
import java.net.DatagramPacket; |
|||
import java.util.ArrayList; |
|||
import java.util.List; |
|||
|
|||
import javax.swing.JLabel; |
|||
import javax.swing.SwingWorker; |
|||
|
|||
import gr.auth.ee.computer_networks.Main; |
|||
import gr.auth.ee.computer_networks.helpers.TCPBundle; |
|||
import gr.auth.ee.computer_networks.helpers.UDPBundle; |
|||
|
|||
public class Vehicle extends SwingWorker<Void, Void> { |
|||
private static final int MAX_RESPONSE_LENGTH = 12; |
|||
private static final String[] OBD_UDP_REQUEST_CODES = new String[] { "01 1F", "01 0F", "01 11", "01 0C", "01 0D", |
|||
"01 05" }; |
|||
private static final int ENGINE_RUN_TIME = 0; |
|||
private static final int INTAKE_AIR_TEMPERATURE = 1; |
|||
private static final int THROTTLE_POSITION = 2; |
|||
private static final int ENGINE_RPM = 3; |
|||
private static final int VEHICLE_SPEED = 4; |
|||
private static final int COOLANT_TEMPERATURE = 5; |
|||
|
|||
private final TCPBundle TCPConnection; |
|||
private final UDPBundle UDPConnection; |
|||
private String requestCode; |
|||
private final boolean useUDP; |
|||
private final int duration; |
|||
private final JLabel lblVehicleEngineRunTimeOutput; |
|||
private final JLabel lblVehicleAirTempOutput; |
|||
private final JLabel lblVehicleThrottlePositionOutput; |
|||
private final JLabel lblVehicleEngineRPMOutput; |
|||
private final JLabel lblVehicleSpeedOutput; |
|||
private final JLabel lblVehicleCoolantTemperatureOutput; |
|||
private final JLabel lblVehiclePacketsTotalTimeOutput; |
|||
|
|||
private boolean testSuccess = false; |
|||
private String testStatusOutput = "undefined"; |
|||
private String[] outputData = new String[7]; |
|||
private ArrayList<Integer> engineRunTimeValues = new ArrayList<>(), intakeAirTemperatureValues = new ArrayList<>(), |
|||
vehicleSpeedValues = new ArrayList<>(), coolantTemperatureValues = new ArrayList<>(); |
|||
private ArrayList<Float> throttlePositionValues = new ArrayList<>(), engineRPMValues = new ArrayList<>(); |
|||
|
|||
@SuppressWarnings("unused") |
|||
private Vehicle() { |
|||
// Disable default constructor
|
|||
this.TCPConnection = null; |
|||
this.UDPConnection = null; |
|||
this.useUDP = false; |
|||
this.duration = 0; |
|||
this.lblVehicleEngineRunTimeOutput = null; |
|||
this.lblVehicleAirTempOutput = null; |
|||
this.lblVehicleThrottlePositionOutput = null; |
|||
this.lblVehicleEngineRPMOutput = null; |
|||
this.lblVehicleSpeedOutput = null; |
|||
this.lblVehicleCoolantTemperatureOutput = null; |
|||
this.lblVehiclePacketsTotalTimeOutput = null; |
|||
} |
|||
|
|||
public Vehicle(UDPBundle UDPConnection, String requestCode, int duration, JLabel lblVehicleEngineRunTimeOutput, |
|||
JLabel lblVehicleAirTempOutput, JLabel lblVehicleThrottlePositionOutput, JLabel lblVehicleEngineRPMOutput, |
|||
JLabel lblVehicleSpeedOutput, JLabel lblVehicleCoolantTemperatureOutput, |
|||
JLabel lblVehiclePacketsTotalTimeOutput) { |
|||
this.TCPConnection = null; |
|||
this.UDPConnection = UDPConnection; |
|||
this.requestCode = requestCode; |
|||
this.useUDP = true; |
|||
this.duration = duration; |
|||
this.lblVehicleEngineRunTimeOutput = lblVehicleEngineRunTimeOutput; |
|||
this.lblVehicleAirTempOutput = lblVehicleAirTempOutput; |
|||
this.lblVehicleThrottlePositionOutput = lblVehicleThrottlePositionOutput; |
|||
this.lblVehicleEngineRPMOutput = lblVehicleEngineRPMOutput; |
|||
this.lblVehicleSpeedOutput = lblVehicleSpeedOutput; |
|||
this.lblVehicleCoolantTemperatureOutput = lblVehicleCoolantTemperatureOutput; |
|||
this.lblVehiclePacketsTotalTimeOutput = lblVehiclePacketsTotalTimeOutput; |
|||
} |
|||
|
|||
public Vehicle(TCPBundle TCPConnection, String requestCode, int duration, JLabel lblVehicleEngineRunTimeOutput, |
|||
JLabel lblVehicleAirTempOutput, JLabel lblVehicleThrottlePositionOutput, JLabel lblVehicleEngineRPMOutput, |
|||
JLabel lblVehicleSpeedOutput, JLabel lblVehicleCoolantTemperatureOutput, |
|||
JLabel lblVehiclePacketsTotalTimeOutput) { |
|||
this.TCPConnection = TCPConnection; |
|||
this.UDPConnection = null; |
|||
this.requestCode = requestCode; |
|||
this.useUDP = false; |
|||
this.duration = duration; |
|||
this.lblVehicleEngineRunTimeOutput = lblVehicleEngineRunTimeOutput; |
|||
this.lblVehicleAirTempOutput = lblVehicleAirTempOutput; |
|||
this.lblVehicleThrottlePositionOutput = lblVehicleThrottlePositionOutput; |
|||
this.lblVehicleEngineRPMOutput = lblVehicleEngineRPMOutput; |
|||
this.lblVehicleSpeedOutput = lblVehicleSpeedOutput; |
|||
this.lblVehicleCoolantTemperatureOutput = lblVehicleCoolantTemperatureOutput; |
|||
this.lblVehiclePacketsTotalTimeOutput = lblVehiclePacketsTotalTimeOutput; |
|||
} |
|||
|
|||
private String getValueFromResponse(byte[] response, int bytesReturned, int loopIndex) { |
|||
int returnValueXX = 0, returnValueYY = 0; |
|||
String value = ""; |
|||
|
|||
if (bytesReturned == 9) { |
|||
String hexValueXX = "" + (char) response[6] + (char) response[7]; |
|||
|
|||
returnValueXX = Integer.parseInt(hexValueXX, 16); |
|||
} else if (bytesReturned == 12) { |
|||
String hexValueXX = "" + (char) response[6] + (char) response[7]; |
|||
String hexValueYY = "" + (char) response[9] + (char) response[10]; |
|||
|
|||
returnValueXX = Integer.parseInt(hexValueXX, 16); |
|||
returnValueYY = Integer.parseInt(hexValueYY, 16); |
|||
} else { |
|||
// Shouldn't happen
|
|||
return null; |
|||
} |
|||
|
|||
switch (loopIndex) { |
|||
case ENGINE_RUN_TIME: |
|||
value = "" + 256 * returnValueXX + returnValueYY; |
|||
engineRunTimeValues.add(256 * returnValueXX + returnValueYY); |
|||
break; |
|||
case INTAKE_AIR_TEMPERATURE: |
|||
value = "" + (returnValueXX - 40); |
|||
intakeAirTemperatureValues.add(returnValueXX - 40); |
|||
break; |
|||
case THROTTLE_POSITION: |
|||
value = "" + (100 * returnValueXX / 255); |
|||
throttlePositionValues.add((float) (100 * returnValueXX / 255)); |
|||
break; |
|||
case ENGINE_RPM: |
|||
value = "" + ((256 * returnValueXX + returnValueYY) / 4); |
|||
engineRPMValues.add((float) ((256 * returnValueXX + returnValueYY) / 4)); |
|||
break; |
|||
case VEHICLE_SPEED: |
|||
value = "" + returnValueXX; |
|||
vehicleSpeedValues.add(returnValueXX); |
|||
break; |
|||
case COOLANT_TEMPERATURE: |
|||
value = "" + (returnValueXX - 40); |
|||
coolantTemperatureValues.add(returnValueXX - 40); |
|||
break; |
|||
default: |
|||
break; |
|||
} |
|||
return value; |
|||
} |
|||
|
|||
@Override |
|||
protected Void doInBackground() { |
|||
int vehicleOutputFileCounter = 0; |
|||
byte responseBuffer[] = new byte[MAX_RESPONSE_LENGTH]; |
|||
long totalTimeElapsed = 0, OBDPacketStart = 0; |
|||
FileOutputStream vehicleOutputStream = null; |
|||
File vehicleOutputFile = null; |
|||
do { |
|||
vehicleOutputFile = new File("output/vehicle_" + (useUDP ? requestCode : "TCP") |
|||
+ (vehicleOutputFileCounter == 0 ? "" : "_" + vehicleOutputFileCounter) + ".csv"); |
|||
if (!vehicleOutputFile.isFile()) { |
|||
break; |
|||
} |
|||
++vehicleOutputFileCounter; |
|||
} while (true); |
|||
|
|||
try { |
|||
vehicleOutputStream = new FileOutputStream(vehicleOutputFile, false); |
|||
} catch (FileNotFoundException exception) { |
|||
exception.printStackTrace(); |
|||
testSuccess = false; |
|||
testStatusOutput = "Echo file open failure!"; |
|||
return null; |
|||
} |
|||
|
|||
if (useUDP) { |
|||
DatagramPacket OBDRequestPacket = null, |
|||
OBDResponsePacket = new DatagramPacket(responseBuffer, MAX_RESPONSE_LENGTH); |
|||
|
|||
while (totalTimeElapsed < duration * 1000) { |
|||
for (int i = 0; i < OBD_UDP_REQUEST_CODES.length; ++i) { |
|||
int bytesReturned = MAX_RESPONSE_LENGTH; |
|||
String OBDRequestCode = requestCode + "OBD=" + OBD_UDP_REQUEST_CODES[i]; |
|||
OBDRequestPacket = new DatagramPacket(OBDRequestCode.getBytes(), OBDRequestCode.getBytes().length, |
|||
UDPBundle.getHostAddress(), UDPConnection.getServerPort()); |
|||
|
|||
try { |
|||
UDPConnection.getConnection().send(OBDRequestPacket); |
|||
} catch (IOException exception) { |
|||
exception.printStackTrace(); |
|||
try { |
|||
vehicleOutputStream.close(); |
|||
} catch (IOException inception) { |
|||
inception.printStackTrace(); |
|||
testSuccess = false; |
|||
testStatusOutput = "Vehicle file close failure, after request send failure!"; |
|||
return null; |
|||
} |
|||
testSuccess = false; |
|||
testStatusOutput = "Request send failure!"; |
|||
return null; |
|||
} |
|||
|
|||
OBDPacketStart = System.currentTimeMillis(); |
|||
try { |
|||
UDPConnection.getConnection().receive(OBDResponsePacket); |
|||
} catch (IOException exception) { |
|||
exception.printStackTrace(); |
|||
try { |
|||
vehicleOutputStream.close(); |
|||
} catch (IOException inception) { |
|||
inception.printStackTrace(); |
|||
testSuccess = false; |
|||
testStatusOutput = "Vehicle file close failure, after response receive failure!"; |
|||
return null; |
|||
} |
|||
testSuccess = false; |
|||
testStatusOutput = "Response receive failure!"; |
|||
return null; |
|||
} |
|||
totalTimeElapsed += System.currentTimeMillis() - OBDPacketStart; |
|||
|
|||
for (int j = MAX_RESPONSE_LENGTH - 1; j > 0; --j) { |
|||
if (responseBuffer[j] == 0) { |
|||
--bytesReturned; |
|||
} |
|||
} |
|||
|
|||
outputData[i] = getValueFromResponse(responseBuffer, bytesReturned + 1, i); |
|||
|
|||
for (int j = 0; j < MAX_RESPONSE_LENGTH; ++j) { |
|||
responseBuffer[j] = 0; |
|||
} |
|||
} |
|||
|
|||
outputData[6] = "" + totalTimeElapsed; |
|||
publish(); |
|||
} |
|||
} else { |
|||
while (totalTimeElapsed < duration * 1000) { |
|||
for (int i = 0; i < OBD_UDP_REQUEST_CODES.length; ++i) { |
|||
int bytesReturned = 0; |
|||
|
|||
try { |
|||
TCPConnection.getOutputStream().write((OBD_UDP_REQUEST_CODES[i] + (char) 13).getBytes()); |
|||
} catch (IOException exception) { |
|||
exception.printStackTrace(); |
|||
try { |
|||
vehicleOutputStream.close(); |
|||
} catch (IOException inception) { |
|||
inception.printStackTrace(); |
|||
testSuccess = false; |
|||
testStatusOutput = "Vehicle file close failure, after request send failure!"; |
|||
return null; |
|||
} |
|||
testSuccess = false; |
|||
testStatusOutput = "Request send failure!"; |
|||
return null; |
|||
} |
|||
OBDPacketStart = System.currentTimeMillis(); |
|||
try { |
|||
bytesReturned = TCPConnection.getInputStream().read(responseBuffer); |
|||
} catch (IOException exception) { |
|||
exception.printStackTrace(); |
|||
try { |
|||
vehicleOutputStream.close(); |
|||
} catch (IOException inception) { |
|||
inception.printStackTrace(); |
|||
testSuccess = false; |
|||
testStatusOutput = "Vehicle file close failure, after response receive failure!"; |
|||
return null; |
|||
} |
|||
testSuccess = false; |
|||
testStatusOutput = "Response receive failure!"; |
|||
return null; |
|||
} |
|||
totalTimeElapsed += System.currentTimeMillis() - OBDPacketStart; |
|||
|
|||
if (bytesReturned == -1) { |
|||
try { |
|||
vehicleOutputStream.close(); |
|||
} catch (IOException inception) { |
|||
inception.printStackTrace(); |
|||
testSuccess = false; |
|||
testStatusOutput = "Vehicle file close failure, after connection failure!"; |
|||
return null; |
|||
} |
|||
testSuccess = false; |
|||
testStatusOutput = "Server closed the connection, try running the test again after restarting the app."; |
|||
return null; |
|||
} else if (bytesReturned != 9 && bytesReturned != 12) { |
|||
try { |
|||
vehicleOutputStream.close(); |
|||
} catch (IOException inception) { |
|||
inception.printStackTrace(); |
|||
testSuccess = false; |
|||
testStatusOutput = "Vehicle file close failure, after malformed response failure!"; |
|||
return null; |
|||
} |
|||
testSuccess = false; |
|||
testStatusOutput = "Malformed response."; |
|||
return null; |
|||
} |
|||
|
|||
outputData[i] = getValueFromResponse(responseBuffer, bytesReturned, i); |
|||
} |
|||
outputData[6] = "" + totalTimeElapsed; |
|||
publish(); |
|||
} |
|||
} |
|||
try { |
|||
|
|||
for (Integer engineRunTime : engineRunTimeValues) { |
|||
vehicleOutputStream.write((engineRunTime + "\t").getBytes(), 0, |
|||
(engineRunTime + "\t").getBytes().length); |
|||
} |
|||
vehicleOutputStream.write(("\n").getBytes(), 0, ("\n").getBytes().length); |
|||
|
|||
for (Integer intakeAirTemperatureValues : intakeAirTemperatureValues) { |
|||
vehicleOutputStream.write((intakeAirTemperatureValues + "\t").getBytes(), 0, |
|||
(intakeAirTemperatureValues + "\t").getBytes().length); |
|||
} |
|||
vehicleOutputStream.write(("\n").getBytes(), 0, ("\n").getBytes().length); |
|||
|
|||
for (Float throttlePositionValues : throttlePositionValues) { |
|||
vehicleOutputStream.write((throttlePositionValues + "\t").getBytes(), 0, |
|||
(throttlePositionValues + "\t").getBytes().length); |
|||
} |
|||
vehicleOutputStream.write(("\n").getBytes(), 0, ("\n").getBytes().length); |
|||
|
|||
for (Float engineRPMValues : engineRPMValues) { |
|||
vehicleOutputStream.write((engineRPMValues + "\t").getBytes(), 0, |
|||
(engineRPMValues + "\t").getBytes().length); |
|||
} |
|||
vehicleOutputStream.write(("\n").getBytes(), 0, ("\n").getBytes().length); |
|||
|
|||
for (Integer vehicleSpeedValues : vehicleSpeedValues) { |
|||
vehicleOutputStream.write((vehicleSpeedValues + "\t").getBytes(), 0, |
|||
(vehicleSpeedValues + "\t").getBytes().length); |
|||
} |
|||
vehicleOutputStream.write(("\n").getBytes(), 0, ("\n").getBytes().length); |
|||
|
|||
for (Integer coolantTemperatureValues : coolantTemperatureValues) { |
|||
vehicleOutputStream.write((coolantTemperatureValues + "\t").getBytes(), 0, |
|||
(coolantTemperatureValues + "\t").getBytes().length); |
|||
} |
|||
} catch (IOException exception) { |
|||
exception.printStackTrace(); |
|||
try { |
|||
vehicleOutputStream.close(); |
|||
} catch (IOException inception) { |
|||
inception.printStackTrace(); |
|||
testSuccess = false; |
|||
testStatusOutput = "Vehicle file close failure, after buffer write failure!"; |
|||
return null; |
|||
} |
|||
testSuccess = false; |
|||
testStatusOutput = "Vehicle file buffer write failure!"; |
|||
return null; |
|||
} |
|||
|
|||
try { |
|||
vehicleOutputStream.flush(); |
|||
vehicleOutputStream.close(); |
|||
} catch (IOException exception) { |
|||
exception.printStackTrace(); |
|||
testSuccess = false; |
|||
testStatusOutput = "Vehicle file buffer flush/close failure!"; |
|||
return null; |
|||
} |
|||
testSuccess = true; |
|||
testStatusOutput = "Test finished successfully."; |
|||
return null; |
|||
} |
|||
|
|||
@Override |
|||
protected void process(List<Void> notInUse) { |
|||
lblVehicleEngineRunTimeOutput.setText(outputData[0] + " s"); |
|||
lblVehicleAirTempOutput.setText(outputData[1] + " °C"); |
|||
lblVehicleThrottlePositionOutput.setText(outputData[2] + " %"); |
|||
lblVehicleEngineRPMOutput.setText(outputData[3] + " RPM"); |
|||
lblVehicleSpeedOutput.setText(outputData[4] + " Km/h"); |
|||
lblVehicleCoolantTemperatureOutput.setText(outputData[5] + " °C"); |
|||
lblVehiclePacketsTotalTimeOutput.setText(outputData[6] + " ms"); |
|||
} |
|||
|
|||
@Override |
|||
protected void done() { |
|||
Main.setStatusLineText(testStatusOutput, |
|||
((testSuccess) ? Main.STATUS_LINE_ACTION_DONE : Main.STATUS_LINE_ACTION_ERROR)); |
|||
Main.setSubmitButtonsEnabled(true); |
|||
} |
|||
} |
@ -0,0 +1,105 @@ |
|||
/******************************************************************************* |
|||
* Copyright (c) 2011 Google, Inc. |
|||
* All rights reserved. This program and the accompanying materials |
|||
* are made available under the terms of the Eclipse Public License v1.0 |
|||
* which accompanies this distribution, and is available at |
|||
* http://www.eclipse.org/legal/epl-v10.html
|
|||
* |
|||
* Contributors: |
|||
* Google, Inc. - initial API and implementation |
|||
*******************************************************************************/ |
|||
package org.eclipse.wb.swing; |
|||
|
|||
import java.awt.Component; |
|||
import java.awt.Container; |
|||
import java.awt.FocusTraversalPolicy; |
|||
|
|||
/** |
|||
* Cyclic focus traversal policy based on array of components. |
|||
* <p> |
|||
* This class may be freely distributed as part of any application or plugin. |
|||
* |
|||
* @author scheglov_ke |
|||
*/ |
|||
public class FocusTraversalOnArray extends FocusTraversalPolicy { |
|||
private final Component m_Components[]; |
|||
|
|||
////////////////////////////////////////////////////////////////////////////
|
|||
//
|
|||
// Constructor
|
|||
//
|
|||
////////////////////////////////////////////////////////////////////////////
|
|||
public FocusTraversalOnArray(Component components[]) { |
|||
m_Components = components; |
|||
} |
|||
|
|||
////////////////////////////////////////////////////////////////////////////
|
|||
//
|
|||
// Utilities
|
|||
//
|
|||
////////////////////////////////////////////////////////////////////////////
|
|||
private int indexCycle(int index, int delta) { |
|||
int size = m_Components.length; |
|||
int next = (index + delta + size) % size; |
|||
return next; |
|||
} |
|||
|
|||
private Component cycle(Component currentComponent, int delta) { |
|||
int index = -1; |
|||
loop: for (int i = 0; i < m_Components.length; i++) { |
|||
Component component = m_Components[i]; |
|||
for (Component c = currentComponent; c != null; c = c.getParent()) { |
|||
if (component == c) { |
|||
index = i; |
|||
break loop; |
|||
} |
|||
} |
|||
} |
|||
// try to find enabled component in "delta" direction
|
|||
int initialIndex = index; |
|||
while (true) { |
|||
int newIndex = indexCycle(index, delta); |
|||
if (newIndex == initialIndex) { |
|||
break; |
|||
} |
|||
index = newIndex; |
|||
//
|
|||
Component component = m_Components[newIndex]; |
|||
if (component.isEnabled() && component.isVisible() && component.isFocusable()) { |
|||
return component; |
|||
} |
|||
} |
|||
// not found
|
|||
return currentComponent; |
|||
} |
|||
|
|||
////////////////////////////////////////////////////////////////////////////
|
|||
//
|
|||
// FocusTraversalPolicy
|
|||
//
|
|||
////////////////////////////////////////////////////////////////////////////
|
|||
@Override |
|||
public Component getComponentAfter(Container container, Component component) { |
|||
return cycle(component, 1); |
|||
} |
|||
|
|||
@Override |
|||
public Component getComponentBefore(Container container, Component component) { |
|||
return cycle(component, -1); |
|||
} |
|||
|
|||
@Override |
|||
public Component getFirstComponent(Container container) { |
|||
return m_Components[0]; |
|||
} |
|||
|
|||
@Override |
|||
public Component getLastComponent(Container container) { |
|||
return m_Components[m_Components.length - 1]; |
|||
} |
|||
|
|||
@Override |
|||
public Component getDefaultComponent(Container container) { |
|||
return getFirstComponent(container); |
|||
} |
|||
} |
Loading…
Reference in new issue