diff --git a/Praktikum/VINF_MaerklinControl/bin/.gitignore b/Praktikum/VINF_MaerklinControl/bin/.gitignore index c14b100539d33e27c566ee63e8f25be8379cf169..ad3d6b1e1acb320d8e6c9ac6f380dfd4976b76e7 100644 --- a/Praktikum/VINF_MaerklinControl/bin/.gitignore +++ b/Praktikum/VINF_MaerklinControl/bin/.gitignore @@ -1 +1,2 @@ +/common/ /gui/ diff --git a/Praktikum/VINF_MaerklinControl/build.fxbuild b/Praktikum/VINF_MaerklinControl/build.fxbuild index 4b284df8176d91bd1ef0e56411869e4ca02eec84..e46771ba6ab7b7dd14e1945fb518a467f8efd31e 100644 --- a/Praktikum/VINF_MaerklinControl/build.fxbuild +++ b/Praktikum/VINF_MaerklinControl/build.fxbuild @@ -1,8 +1,8 @@ <?xml version="1.0" encoding="ASCII"?> <anttasks:AntTask xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:anttasks="http://org.eclipse.fx.ide.jdt/1.0" buildDirectory="${project}/build"> - <deploy> - <application name="TestMopped"/> - <info/> + <deploy packagingFormat="exe"> + <application name="TestMopped" mainclass="gui.MainApp" version="0.9" toolkit="fx"/> + <info title="Märklin Control" vendor="lf.ps"/> </deploy> <signjar/> </anttasks:AntTask> diff --git a/Praktikum/VINF_MaerklinControl/build/build.xml b/Praktikum/VINF_MaerklinControl/build/build.xml new file mode 100644 index 0000000000000000000000000000000000000000..e4b798a61000ce54533f3758edbefaa37c2af86e --- /dev/null +++ b/Praktikum/VINF_MaerklinControl/build/build.xml @@ -0,0 +1,143 @@ +<?xml version="1.0" encoding="UTF-8"?> + <project name="VINF_MaerklinControl" default="do-deploy" basedir="." xmlns:fx="javafx:com.sun.javafx.tools.ant"> + <target name="init-fx-tasks"> + <path id="fxant"> + <filelist> + <file name="${java.home}\..\lib\ant-javafx.jar"/> + <file name="${java.home}\lib\jfxrt.jar"/> + <file name="${basedir}"/> + </filelist> + </path> + + <taskdef resource="com/sun/javafx/tools/ant/antlib.xml" + uri="javafx:com.sun.javafx.tools.ant" + classpathref="fxant"/> + </target> + <target name="setup-staging-area"> + <delete dir="externalLibs" /> + <delete dir="project" /> + <delete dir="projectRefs" /> + + <mkdir dir="externalLibs" /> + + <copy todir="externalLibs"> + <fileset dir="D:\Users\Philipp\gitlab\VInf\Praktikum\VINF_MaerklinControl"> + <filename name="controlsfx-8.40.12.jar"/> + </fileset> + </copy> + + <mkdir dir="project" /> + <copy todir="project"> + <fileset dir="D:\Users\Philipp\gitlab\VInf\Praktikum\VINF_MaerklinControl"> + <include name="src/**" /> + </fileset> + </copy> + + <mkdir dir="projectRefs" /> + </target> + <target name='do-compile'> + <delete dir="build" /> + <mkdir dir="build/src" /> + <mkdir dir="build/libs" /> + <mkdir dir="build/classes" /> + + <!-- Copy project-libs references --> + <copy todir="build/libs"> + <fileset dir="externalLibs"> + <include name="controlsfx-8.40.12.jar"/> + </fileset> + </copy> + + <!-- Copy project references --> + + <!-- Copy project sources itself --> + <copy todir="build/src"> + <fileset dir="project/src"> + <include name="**/*"/> + </fileset> + </copy> + + <javac includeantruntime="false" source="1.8" target="1.8" srcdir="build/src" destdir="build/classes" encoding="Cp1252"> + <classpath> + <fileset dir="build/libs"> + <include name="*"/> + </fileset> + </classpath> + </javac> + + <!-- Copy over none Java-Files --> + <copy todir="build/classes"> + <fileset dir="project/src"> + <exclude name="**/*.java"/> + </fileset> + </copy> + + + </target> + <target name="do-deploy" depends="setup-staging-area, do-compile, init-fx-tasks"> + <delete file="dist"/> + <delete file="deploy" /> + + <mkdir dir="dist" /> + <mkdir dir="dist/libs" /> + + <copy todir="dist/libs"> + <fileset dir="externalLibs"> + <include name="*" /> + </fileset> + </copy> + + + <fx:resources id="appRes"> + <fx:fileset dir="dist" includes="VINF_MaerklinControl.jar"/> + <fx:fileset dir="dist" includes="libs/*"/> + <fx:fileset dir="dist" includes="res/**"/> + </fx:resources> + + <fx:application id="fxApplication" + name="Märklin Control" + mainClass="gui.MainApp" + toolkit="fx" + version="0.9" + /> + + <mkdir dir="build/classes/META-INF" /> + + + + <fx:jar destfile="dist/VINF_MaerklinControl.jar"> + <fx:application refid="fxApplication"/> + <fileset dir="build/classes"> + </fileset> + <fx:resources refid="appRes"/> + + <manifest> + <attribute name="Implementation-Vendor" value="lf.ps"/> + <attribute name="Implementation-Title" value="Märklin Control"/> + <attribute name="Implementation-Version" value="0.9"/> + <attribute name="JavaFX-Feature-Proxy" value="None"/> + </manifest> + </fx:jar> + + + <mkdir dir="deploy" /> + <!-- Need to use ${basedir} because somehow the ant task is calculating the directory differently --> + <fx:deploy + embedJNLP="false" + extension="false" + includeDT="false" + offlineAllowed="true" + outdir="${basedir}/deploy" + outfile="VINF_MaerklinControl" nativeBundles="exe" + updatemode="background" > + + <fx:platform basedir="${java.home}"/> + <fx:info title="VINF_MaerklinControl" vendor="lf.ps"/> + + <fx:application refId="fxApplication"/> + <fx:resources refid="appRes"/> + </fx:deploy> + + + </target> +</project> diff --git a/Praktikum/VINF_MaerklinControl/build/build/classes/common/Properties.class b/Praktikum/VINF_MaerklinControl/build/build/classes/common/Properties.class new file mode 100644 index 0000000000000000000000000000000000000000..849c1428b30014fb554f1cfcc6e8d94bad1590ad Binary files /dev/null and b/Praktikum/VINF_MaerklinControl/build/build/classes/common/Properties.class differ diff --git a/Praktikum/VINF_MaerklinControl/build/build/classes/gui/MainApp$EstablishConnection$1.class b/Praktikum/VINF_MaerklinControl/build/build/classes/gui/MainApp$EstablishConnection$1.class new file mode 100644 index 0000000000000000000000000000000000000000..d5f15fd46ccfafc40f45e68790d96cb914a6c91e Binary files /dev/null and b/Praktikum/VINF_MaerklinControl/build/build/classes/gui/MainApp$EstablishConnection$1.class differ diff --git a/Praktikum/VINF_MaerklinControl/build/build/classes/gui/MainApp$EstablishConnection$2.class b/Praktikum/VINF_MaerklinControl/build/build/classes/gui/MainApp$EstablishConnection$2.class new file mode 100644 index 0000000000000000000000000000000000000000..73188c27211a468413b13f48a6c4394abb4fdf44 Binary files /dev/null and b/Praktikum/VINF_MaerklinControl/build/build/classes/gui/MainApp$EstablishConnection$2.class differ diff --git a/Praktikum/VINF_MaerklinControl/build/build/classes/gui/MainApp$EstablishConnection.class b/Praktikum/VINF_MaerklinControl/build/build/classes/gui/MainApp$EstablishConnection.class new file mode 100644 index 0000000000000000000000000000000000000000..f4bcce177a7078ab7d667f3ceacd3a1da9de7f11 Binary files /dev/null and b/Praktikum/VINF_MaerklinControl/build/build/classes/gui/MainApp$EstablishConnection.class differ diff --git a/Praktikum/VINF_MaerklinControl/build/build/classes/gui/MainApp$UpdateFunctionality$1.class b/Praktikum/VINF_MaerklinControl/build/build/classes/gui/MainApp$UpdateFunctionality$1.class new file mode 100644 index 0000000000000000000000000000000000000000..9dbbd302f47463dc5e2587663acdc501cfd03a96 Binary files /dev/null and b/Praktikum/VINF_MaerklinControl/build/build/classes/gui/MainApp$UpdateFunctionality$1.class differ diff --git a/Praktikum/VINF_MaerklinControl/build/build/classes/gui/MainApp$UpdateFunctionality$2.class b/Praktikum/VINF_MaerklinControl/build/build/classes/gui/MainApp$UpdateFunctionality$2.class new file mode 100644 index 0000000000000000000000000000000000000000..bae321e7c6e87c68585cfa933747b1e5d194b046 Binary files /dev/null and b/Praktikum/VINF_MaerklinControl/build/build/classes/gui/MainApp$UpdateFunctionality$2.class differ diff --git a/Praktikum/VINF_MaerklinControl/build/build/classes/gui/MainApp$UpdateFunctionality.class b/Praktikum/VINF_MaerklinControl/build/build/classes/gui/MainApp$UpdateFunctionality.class new file mode 100644 index 0000000000000000000000000000000000000000..0e7045bc2524fa77577947ea1ddfe0f4fe972f02 Binary files /dev/null and b/Praktikum/VINF_MaerklinControl/build/build/classes/gui/MainApp$UpdateFunctionality.class differ diff --git a/Praktikum/VINF_MaerklinControl/build/build/classes/gui/MainApp.class b/Praktikum/VINF_MaerklinControl/build/build/classes/gui/MainApp.class new file mode 100644 index 0000000000000000000000000000000000000000..0d6c40cfaae235aca37aa634eda26d2ad458c620 Binary files /dev/null and b/Praktikum/VINF_MaerklinControl/build/build/classes/gui/MainApp.class differ diff --git a/Praktikum/VINF_MaerklinControl/build/build/classes/gui/model/Engine.class b/Praktikum/VINF_MaerklinControl/build/build/classes/gui/model/Engine.class new file mode 100644 index 0000000000000000000000000000000000000000..4b82588a2adee8101a90afdfe01634d7fc373f87 Binary files /dev/null and b/Praktikum/VINF_MaerklinControl/build/build/classes/gui/model/Engine.class differ diff --git a/Praktikum/VINF_MaerklinControl/build/build/classes/gui/model/Settings.class b/Praktikum/VINF_MaerklinControl/build/build/classes/gui/model/Settings.class new file mode 100644 index 0000000000000000000000000000000000000000..de6862ae631f89a15321dac3f3c9bf6649ac645c Binary files /dev/null and b/Praktikum/VINF_MaerklinControl/build/build/classes/gui/model/Settings.class differ diff --git a/Praktikum/VINF_MaerklinControl/build/build/classes/gui/model/Switch.class b/Praktikum/VINF_MaerklinControl/build/build/classes/gui/model/Switch.class new file mode 100644 index 0000000000000000000000000000000000000000..40ca319475b28521dbbc7a3f077226874ee0e705 Binary files /dev/null and b/Praktikum/VINF_MaerklinControl/build/build/classes/gui/model/Switch.class differ diff --git a/Praktikum/VINF_MaerklinControl/build/build/classes/gui/view/Engine.fxml b/Praktikum/VINF_MaerklinControl/build/build/classes/gui/view/Engine.fxml new file mode 100644 index 0000000000000000000000000000000000000000..8aea2f6655bb319214b2079f17b9325526cc44fd --- /dev/null +++ b/Praktikum/VINF_MaerklinControl/build/build/classes/gui/view/Engine.fxml @@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<?import javafx.geometry.Insets?> +<?import javafx.scene.control.ChoiceBox?> +<?import javafx.scene.control.Slider?> +<?import javafx.scene.control.ToggleButton?> +<?import javafx.scene.control.ToggleGroup?> +<?import javafx.scene.image.ImageView?> +<?import javafx.scene.layout.AnchorPane?> +<?import javafx.scene.layout.HBox?> +<?import javafx.scene.layout.VBox?> + +<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" fx:controller="gui.view.EngineController"> + <children> + <VBox alignment="BOTTOM_CENTER" prefHeight="200.0" prefWidth="100.0" AnchorPane.bottomAnchor="20.0" AnchorPane.leftAnchor="20.0" AnchorPane.rightAnchor="20.0" AnchorPane.topAnchor="0.0"> + <children> + <ImageView fx:id="engineImage" fitHeight="50.0" fitWidth="150.0" pickOnBounds="true" preserveRatio="true"> + <VBox.margin> + <Insets bottom="10.0" /> + </VBox.margin></ImageView> + <Slider fx:id="engineSpeedSlider" showTickLabels="true" showTickMarks="true" /> + <HBox alignment="CENTER" prefWidth="300.0"> + <children> + <ToggleButton fx:id="engineRevButton" mnemonicParsing="false" onAction="#handleEngineDirection" text="<"> + <toggleGroup> + <ToggleGroup fx:id="direction" /> + </toggleGroup></ToggleButton> + <ChoiceBox fx:id="engineChoiceBox" prefWidth="150.0" /> + <ToggleButton fx:id="engineFwdButton" mnemonicParsing="false" onAction="#handleEngineDirection" text=">" toggleGroup="$direction" /> + </children> + </HBox> + </children> + <opaqueInsets> + <Insets right="9.0" /> + </opaqueInsets> + </VBox> + </children> +</AnchorPane> diff --git a/Praktikum/VINF_MaerklinControl/build/build/classes/gui/view/EngineController$1.class b/Praktikum/VINF_MaerklinControl/build/build/classes/gui/view/EngineController$1.class new file mode 100644 index 0000000000000000000000000000000000000000..afa47df4df3264081f4885aece8f99061d2cd6da Binary files /dev/null and b/Praktikum/VINF_MaerklinControl/build/build/classes/gui/view/EngineController$1.class differ diff --git a/Praktikum/VINF_MaerklinControl/build/build/classes/gui/view/EngineController.class b/Praktikum/VINF_MaerklinControl/build/build/classes/gui/view/EngineController.class new file mode 100644 index 0000000000000000000000000000000000000000..15553e747ff737404482762152267b90b1151c1a Binary files /dev/null and b/Praktikum/VINF_MaerklinControl/build/build/classes/gui/view/EngineController.class differ diff --git a/Praktikum/VINF_MaerklinControl/build/build/classes/gui/view/RootLayout.fxml b/Praktikum/VINF_MaerklinControl/build/build/classes/gui/view/RootLayout.fxml new file mode 100644 index 0000000000000000000000000000000000000000..4ba58c6ec993ec52eafb3eefce71c76bfe0f9fb4 --- /dev/null +++ b/Praktikum/VINF_MaerklinControl/build/build/classes/gui/view/RootLayout.fxml @@ -0,0 +1,60 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<?import javafx.geometry.Insets?> +<?import javafx.scene.control.Button?> +<?import javafx.scene.control.Menu?> +<?import javafx.scene.control.MenuBar?> +<?import javafx.scene.control.MenuItem?> +<?import javafx.scene.control.TabPane?> +<?import javafx.scene.layout.BorderPane?> +<?import javafx.scene.layout.VBox?> +<?import javafx.scene.text.Font?> +<?import org.controlsfx.control.StatusBar?> + +<BorderPane prefHeight="600.0" prefWidth="340.0" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" fx:controller="gui.view.RootLayoutController"> + <top> + <MenuBar BorderPane.alignment="CENTER"> + <menus> + <Menu mnemonicParsing="false" text="File"> + <items> + <MenuItem mnemonicParsing="false" text="Close" /> + </items> + </Menu> + <Menu mnemonicParsing="false" text="Edit"> + <items> + <MenuItem mnemonicParsing="false" text="Delete" /> + </items> + </Menu> + <Menu mnemonicParsing="false" text="Help"> + <items> + <MenuItem mnemonicParsing="false" text="About" /> + </items> + </Menu> + </menus> + </MenuBar> + </top> + <center> + <TabPane fx:id="rootTabPane" prefHeight="200.0" prefWidth="200.0" tabClosingPolicy="UNAVAILABLE" BorderPane.alignment="CENTER"> + <tabs> + </tabs> + </TabPane> + </center> + <bottom> + <VBox alignment="TOP_CENTER" BorderPane.alignment="CENTER"> + <children> + <Button fx:id="emergencyStop" mnemonicParsing="false" onAction="#emergencyStopHandler" prefHeight="50.0" prefWidth="300.0" style="-fx-background-color: red;" text="NOTAUS" textFill="WHITE"> + <padding> + <Insets bottom="10.0" left="5.0" right="5.0" top="5.0" /> + </padding> + <font> + <Font name="System Bold" size="14.0" /> + </font> + <VBox.margin> + <Insets bottom="10.0" top="10.0" /> + </VBox.margin> + </Button> + <StatusBar fx:id="statusBar" /> + </children> + </VBox> + </bottom> +</BorderPane> diff --git a/Praktikum/VINF_MaerklinControl/build/build/classes/gui/view/RootLayoutController.class b/Praktikum/VINF_MaerklinControl/build/build/classes/gui/view/RootLayoutController.class new file mode 100644 index 0000000000000000000000000000000000000000..a5386cc44364f5dae4d47bf1f985584681f2c13a Binary files /dev/null and b/Praktikum/VINF_MaerklinControl/build/build/classes/gui/view/RootLayoutController.class differ diff --git a/Praktikum/VINF_MaerklinControl/build/build/classes/gui/view/Settings.fxml b/Praktikum/VINF_MaerklinControl/build/build/classes/gui/view/Settings.fxml new file mode 100644 index 0000000000000000000000000000000000000000..ae4aa387c7b48f44b6543370de2436cd14318546 --- /dev/null +++ b/Praktikum/VINF_MaerklinControl/build/build/classes/gui/view/Settings.fxml @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<?import javafx.geometry.Insets?> +<?import javafx.scene.control.Button?> +<?import javafx.scene.control.Label?> +<?import javafx.scene.control.TextField?> +<?import javafx.scene.layout.AnchorPane?> +<?import javafx.scene.layout.VBox?> + +<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" fx:controller="gui.view.SettingsController"> + <children> + <VBox prefHeight="200.0" prefWidth="100.0" AnchorPane.bottomAnchor="20.0" AnchorPane.leftAnchor="20.0" AnchorPane.rightAnchor="20.0" AnchorPane.topAnchor="20.0"> + <children> + <Label text="Server-IP" /> + <TextField fx:id="serverIP" prefHeight="25.0" prefWidth="158.0" text="127.0.0.1"> + <VBox.margin> + <Insets top="5.0" /> + </VBox.margin> + </TextField> + <Button fx:id="connectButton" mnemonicParsing="false" onAction="#connectHandler" text="Verbindung herstellen"> + <VBox.margin> + <Insets top="5.0" /> + </VBox.margin> + </Button> + </children> + <padding> + <Insets top="20.0" /> + </padding> + </VBox> + </children> +</AnchorPane> diff --git a/Praktikum/VINF_MaerklinControl/build/build/classes/gui/view/SettingsController.class b/Praktikum/VINF_MaerklinControl/build/build/classes/gui/view/SettingsController.class new file mode 100644 index 0000000000000000000000000000000000000000..e0810b6fb6e6464a8fec7773e3172062aceb03d8 Binary files /dev/null and b/Praktikum/VINF_MaerklinControl/build/build/classes/gui/view/SettingsController.class differ diff --git a/Praktikum/VINF_MaerklinControl/build/build/classes/gui/view/Switch.fxml b/Praktikum/VINF_MaerklinControl/build/build/classes/gui/view/Switch.fxml new file mode 100644 index 0000000000000000000000000000000000000000..ab56159a5a1986f3f5e401b29d3c6ac34f01253a --- /dev/null +++ b/Praktikum/VINF_MaerklinControl/build/build/classes/gui/view/Switch.fxml @@ -0,0 +1,43 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<?import javafx.geometry.Insets?> +<?import javafx.scene.control.Label?> +<?import javafx.scene.image.Image?> +<?import javafx.scene.image.ImageView?> +<?import javafx.scene.layout.HBox?> +<?import org.controlsfx.control.ToggleSwitch?> + +<fx:root alignment="TOP_CENTER" type="javafx.scene.layout.HBox" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1"> + <Label fx:id="nameLabel" minWidth="75" prefHeight="25.0" prefWidth="75.0" text="Weiche"> + <padding> + <Insets top="5.0" /> + </padding> + </Label> + <ImageView fx:id="straightIcon" fitHeight="20.0" fitWidth="20.0" pickOnBounds="true" preserveRatio="true"> + <image> + <Image url="@../../../res/MagIcon_00_01_i.png" /> + </image> + <HBox.margin> + <Insets right="5.0" /> + </HBox.margin> + </ImageView> + <ToggleSwitch fx:id="stateToggleSwitch" prefWidth="32.0"> + <HBox.margin> + <Insets right="5.0" /> + </HBox.margin> + <padding> + <Insets top="1.0" /> + </padding> + </ToggleSwitch> + <ImageView fx:id="bentIcon" fitHeight="20.0" fitWidth="20.0" pickOnBounds="true" preserveRatio="true"> + <image> + <Image url="@../../../res/MagIcon_00_00_i.png" /> + </image> + <HBox.margin> + <Insets right="5.0" /> + </HBox.margin> + </ImageView> + <padding> + <Insets bottom="5.0" top="5.0" /> + </padding> +</fx:root> diff --git a/Praktikum/VINF_MaerklinControl/build/build/classes/gui/view/SwitchControl$1.class b/Praktikum/VINF_MaerklinControl/build/build/classes/gui/view/SwitchControl$1.class new file mode 100644 index 0000000000000000000000000000000000000000..27afe568c0707971939d1805904d4c780d04319d Binary files /dev/null and b/Praktikum/VINF_MaerklinControl/build/build/classes/gui/view/SwitchControl$1.class differ diff --git a/Praktikum/VINF_MaerklinControl/build/build/classes/gui/view/SwitchControl.class b/Praktikum/VINF_MaerklinControl/build/build/classes/gui/view/SwitchControl.class new file mode 100644 index 0000000000000000000000000000000000000000..4b2806dd4f566ba180178118160d26bb4bdd807d Binary files /dev/null and b/Praktikum/VINF_MaerklinControl/build/build/classes/gui/view/SwitchControl.class differ diff --git a/Praktikum/VINF_MaerklinControl/build/build/classes/gui/view/SwitchList.fxml b/Praktikum/VINF_MaerklinControl/build/build/classes/gui/view/SwitchList.fxml new file mode 100644 index 0000000000000000000000000000000000000000..1af1e0f3fc0cd43cdd008cab17b1cc50f76de7b9 --- /dev/null +++ b/Praktikum/VINF_MaerklinControl/build/build/classes/gui/view/SwitchList.fxml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<?import javafx.geometry.Insets?> +<?import javafx.scene.layout.AnchorPane?> +<?import javafx.scene.layout.VBox?> + +<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefWidth="340.0" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" fx:controller="gui.view.SwitchListController"> + <children> + <VBox fx:id="switchesVBox" alignment="TOP_CENTER" prefWidth="300.0"> + <padding> + <Insets bottom="5.0" left="20.0" right="20.0" top="5.0" /> + </padding></VBox> + </children> +</AnchorPane> diff --git a/Praktikum/VINF_MaerklinControl/build/build/classes/gui/view/SwitchListController.class b/Praktikum/VINF_MaerklinControl/build/build/classes/gui/view/SwitchListController.class new file mode 100644 index 0000000000000000000000000000000000000000..22284c9d03939448ccf389fbc24bbbbc01fd7b11 Binary files /dev/null and b/Praktikum/VINF_MaerklinControl/build/build/classes/gui/view/SwitchListController.class differ diff --git a/Praktikum/VINF_MaerklinControl/build/build/classes/gui/view/Turntable.fxml b/Praktikum/VINF_MaerklinControl/build/build/classes/gui/view/Turntable.fxml new file mode 100644 index 0000000000000000000000000000000000000000..06a134e01bbae972b01bea37b66201782deb0f46 --- /dev/null +++ b/Praktikum/VINF_MaerklinControl/build/build/classes/gui/view/Turntable.fxml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<?import javafx.scene.control.ChoiceBox?> +<?import javafx.scene.control.Button?> +<?import javafx.scene.layout.AnchorPane?> +<?import javafx.scene.layout.HBox?> + +<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" fx:controller="gui.view.TurntableController"> + <children> + <HBox alignment="BOTTOM_CENTER" layoutX="70.0" layoutY="457.0" AnchorPane.bottomAnchor="20.0" AnchorPane.leftAnchor="20.0" AnchorPane.rightAnchor="20.0" AnchorPane.topAnchor="0.0"> + <children> + <Button fx:id="turntableLeftButton" mnemonicParsing="false" onAction="#handleTurnCCW" text="<" /> + <ChoiceBox fx:id="slotChoiceBox" prefWidth="150.0" /> + <Button fx:id="turntableRightButton" mnemonicParsing="false" onAction="#handleTurnCW" text=">" /> + </children> + </HBox> + </children> +</AnchorPane> diff --git a/Praktikum/VINF_MaerklinControl/build/build/classes/gui/view/TurntableController.class b/Praktikum/VINF_MaerklinControl/build/build/classes/gui/view/TurntableController.class new file mode 100644 index 0000000000000000000000000000000000000000..8284f46c166f96cad749b4b72db2616f05523b5c Binary files /dev/null and b/Praktikum/VINF_MaerklinControl/build/build/classes/gui/view/TurntableController.class differ diff --git a/Praktikum/VINF_MaerklinControl/build/build/classes/server/ClientThread.class b/Praktikum/VINF_MaerklinControl/build/build/classes/server/ClientThread.class new file mode 100644 index 0000000000000000000000000000000000000000..58384503524c74fbe48dc4af31f2c2c707d42c7b Binary files /dev/null and b/Praktikum/VINF_MaerklinControl/build/build/classes/server/ClientThread.class differ diff --git a/Praktikum/VINF_MaerklinControl/build/build/classes/server/Engine.class b/Praktikum/VINF_MaerklinControl/build/build/classes/server/Engine.class new file mode 100644 index 0000000000000000000000000000000000000000..6f7d7d6831e8a4cbf98f77ab16fb7d74a12a6c22 Binary files /dev/null and b/Praktikum/VINF_MaerklinControl/build/build/classes/server/Engine.class differ diff --git a/Praktikum/VINF_MaerklinControl/build/build/classes/server/HandleThread.class b/Praktikum/VINF_MaerklinControl/build/build/classes/server/HandleThread.class new file mode 100644 index 0000000000000000000000000000000000000000..044e2c5bc002802239bd677b719a801deeeff273 Binary files /dev/null and b/Praktikum/VINF_MaerklinControl/build/build/classes/server/HandleThread.class differ diff --git a/Praktikum/VINF_MaerklinControl/build/build/classes/server/MaerklinProtocol.class b/Praktikum/VINF_MaerklinControl/build/build/classes/server/MaerklinProtocol.class new file mode 100644 index 0000000000000000000000000000000000000000..b80ce81faa36ef12ab00819557f1259bb7f3ae94 Binary files /dev/null and b/Praktikum/VINF_MaerklinControl/build/build/classes/server/MaerklinProtocol.class differ diff --git a/Praktikum/VINF_MaerklinControl/build/build/classes/server/MaerklinServer.class b/Praktikum/VINF_MaerklinControl/build/build/classes/server/MaerklinServer.class new file mode 100644 index 0000000000000000000000000000000000000000..1d36d9f7d893fab4c383fab75e5f30994357a8c0 Binary files /dev/null and b/Praktikum/VINF_MaerklinControl/build/build/classes/server/MaerklinServer.class differ diff --git a/Praktikum/VINF_MaerklinControl/build/build/classes/server/MaerklinServerApplication.class b/Praktikum/VINF_MaerklinControl/build/build/classes/server/MaerklinServerApplication.class new file mode 100644 index 0000000000000000000000000000000000000000..b23e62fc49c169f611f47205be09e96acb599696 Binary files /dev/null and b/Praktikum/VINF_MaerklinControl/build/build/classes/server/MaerklinServerApplication.class differ diff --git a/Praktikum/VINF_MaerklinControl/build/build/classes/server/ServerThread.class b/Praktikum/VINF_MaerklinControl/build/build/classes/server/ServerThread.class new file mode 100644 index 0000000000000000000000000000000000000000..6de9abfcb19e9d16031a08a0c79ffd086089d03b Binary files /dev/null and b/Praktikum/VINF_MaerklinControl/build/build/classes/server/ServerThread.class differ diff --git a/Praktikum/VINF_MaerklinControl/build/build/classes/server/Switch.class b/Praktikum/VINF_MaerklinControl/build/build/classes/server/Switch.class new file mode 100644 index 0000000000000000000000000000000000000000..9b4c60dc5ac84289301dd24c0b2d095c8aae1eb1 Binary files /dev/null and b/Praktikum/VINF_MaerklinControl/build/build/classes/server/Switch.class differ diff --git a/Praktikum/VINF_MaerklinControl/build/build/classes/server/UDPListener.class b/Praktikum/VINF_MaerklinControl/build/build/classes/server/UDPListener.class new file mode 100644 index 0000000000000000000000000000000000000000..e989840483d3c4ae8c9a473e1b70aafbd203f084 Binary files /dev/null and b/Praktikum/VINF_MaerklinControl/build/build/classes/server/UDPListener.class differ diff --git a/Praktikum/VINF_MaerklinControl/build/build/classes/server/UpdateThread.class b/Praktikum/VINF_MaerklinControl/build/build/classes/server/UpdateThread.class new file mode 100644 index 0000000000000000000000000000000000000000..01fc2de93f9674d2969207cef30af111fee14d2f Binary files /dev/null and b/Praktikum/VINF_MaerklinControl/build/build/classes/server/UpdateThread.class differ diff --git a/Praktikum/VINF_MaerklinControl/build/build/libs/controlsfx-8.40.12.jar b/Praktikum/VINF_MaerklinControl/build/build/libs/controlsfx-8.40.12.jar new file mode 100644 index 0000000000000000000000000000000000000000..212a66cfc2c408bb7953c0b57d4b9deb0a30a7c5 Binary files /dev/null and b/Praktikum/VINF_MaerklinControl/build/build/libs/controlsfx-8.40.12.jar differ diff --git a/Praktikum/VINF_MaerklinControl/build/build/src/common/Properties.java b/Praktikum/VINF_MaerklinControl/build/build/src/common/Properties.java new file mode 100644 index 0000000000000000000000000000000000000000..144b96d85315ffd068b2e2bba3fc0cd2b7b83e47 --- /dev/null +++ b/Praktikum/VINF_MaerklinControl/build/build/src/common/Properties.java @@ -0,0 +1,45 @@ +package common; + +public class Properties { + + // Defining server-ip and port + public final static int PORT = 23456; + + // Setting ports and defining size of the buffers + public final static int IN_BUFFER_SIZE = 5; // First and second byte: accessory-ID, third byte: command, fourth and fifth byte: potential parameters + public final static int OUT_BUFFER_SIZE = 128; + + // Defining client-commands + public final static byte SEPERATOR = (byte) 0xFE; + + public final static int SESSION_ABORT = -1; + + public final static byte SYSTEM_STOP = 0x00; + public final static byte SYSTEM_GO = 0x01; + public final static byte GET_STATUS = 0x02; + public final static byte ENGINE_SET_SPEED = 0x03; + public final static byte ENGINE_INCREASE_SPEED = 0x04; + public final static byte ENGINE_DECREASE_SPEED = 0x05; + public final static byte ENGINE_SET_DIRECTION = 0x06; + public final static byte ENGINE_SWITCH_DIRECTION = 0x07; + public final static byte SWITCH_SET_DIRECTION = 0x08; + public final static byte SWITCH_SWITCH_DIRECTION = 0x09; + + //Defining accessory-ids + public final static int ICE_ID = 0x0002; + public final static int LOK_ID = 0x4005; + public final static int REICHSBAHN_ID = 0x4007; + + public final static int SWITCH4_ID = 0x3003; + public final static int SWITCH5_ID = 0x3004; + public final static int SWITCH6_ID = 0x3005; + public final static int SWITCH8_ID = 0x3007; + public final static int SWITCH9_ID = 0x3008; + public final static int SWITCH10_ID = 0x3009; + public final static int SWITCH12_ID = 0x300B; + public final static int SWITCH13_ID = 0x300C; + public final static int SWITCH14_ID = 0x300D; + public final static int SWITCH15_ID = 0x300E; + public final static int TURNTABLE_ID = 0x30E2; + +} diff --git a/Praktikum/VINF_MaerklinControl/build/build/src/gui/MainApp.java b/Praktikum/VINF_MaerklinControl/build/build/src/gui/MainApp.java new file mode 100644 index 0000000000000000000000000000000000000000..fc13d4868095e42e0f3b2e05a0c12f5a6cbb7165 --- /dev/null +++ b/Praktikum/VINF_MaerklinControl/build/build/src/gui/MainApp.java @@ -0,0 +1,484 @@ +package gui; +import java.io.BufferedInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.Socket; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +import javax.xml.bind.DatatypeConverter; + +import gui.model.Engine; +import gui.model.Switch; +import gui.model.Settings; +import gui.view.EngineController; +import gui.view.TurntableController; +import gui.view.RootLayoutController; +import gui.view.SettingsController; +import gui.view.SwitchListController; +import javafx.application.Application; +import javafx.application.Platform; +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; +import javafx.fxml.FXMLLoader; +import javafx.scene.Scene; +import javafx.scene.control.Tab; +import javafx.scene.image.Image; +import javafx.scene.layout.AnchorPane; +import javafx.scene.layout.BorderPane; +import javafx.stage.Stage; +import common.Properties; + +public class MainApp extends Application { + + private Stage primaryStage; + private BorderPane rootLayout; + private RootLayoutController rootController; + + private AnchorPane enginePane, turntablePane, settingsPane, switchListPane; + private EngineController engineController; + private SwitchListController switchListController; + private TurntableController turntableController; + + private Settings configuration; + private SettingsController settingsController; + + private ObservableList<Tab> tabs = FXCollections.observableArrayList(); + private ObservableList<Switch> switches = FXCollections.observableArrayList(); + private ObservableList<Engine> engines = FXCollections.observableArrayList(); + private Switch turntable; + + private Socket client; + private InputStream in; + private OutputStream out; + + final ExecutorService UTILITY_THREAD_EXECUTOR; + + private Boolean connectionEstablished = false; + private Boolean running = false; + + /** + * Constructor + */ + public MainApp() { + UTILITY_THREAD_EXECUTOR = Executors.newFixedThreadPool(2); + + configuration = new Settings(); + + // Add the already known engines + engines.add(new Engine("ICE", Properties.ICE_ID, "res/ICE 1.png")); + engines.add(new Engine("Dampflok", Properties.LOK_ID, "res/BR 86.png")); + engines.add(new Engine("Reichsbahn", Properties.REICHSBAHN_ID, "res/E 50.png")); + + // Add the already known switches // yes, lazy, i know + for (int i=4;i<=15;i++){ + if (i != 11 && i != 7) { + switches.add(new Switch("Weiche "+i, Properties.SWITCH4_ID+i-4)); + } + } + + turntable = new Switch("Drehteller", Properties.TURNTABLE_ID); + + } + + /** + * Returns the objects as an observable list. + * @return + */ + public ObservableList<Tab> getTabs() { + return tabs; + } + + public ObservableList<Engine> getEngines() { + return engines; + } + + public ObservableList<Switch> getSwitches() { + return switches; + } + + + @Override + public void start(Stage primaryStage) { + this.primaryStage = primaryStage; + this.primaryStage.setTitle("M�rklin Control Client"); + this.primaryStage.getIcons().add(new Image("file:res/BO.png")); + initRootLayout(); + initTabs(); + } + + public void initRootLayout() { + try { + // Load root layout from fxml file. + FXMLLoader loader = new FXMLLoader(); + loader.setLocation(MainApp.class.getResource("view/RootLayout.fxml")); + rootLayout = (BorderPane) loader.load(); + rootController = loader.getController(); // only works if loader.load() has been called already + rootController.setMainApp(this); + + // Show the scene containing the root layout. + Scene scene = new Scene(rootLayout); + primaryStage.setScene(scene); + primaryStage.show(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + /** + * Shows the control tabs inside the root layout. + */ + public void initTabs() { + try { + FXMLLoader loader = new FXMLLoader(); + + loader.setLocation(MainApp.class.getResource("view/Engine.fxml")); + enginePane = loader.load(); + engineController = loader.getController(); // only works if loader.load() has been called already + engineController.setMainApp(this); + + FXMLLoader switchListLoader = new FXMLLoader(); + switchListLoader.setLocation(MainApp.class.getResource("view/SwitchList.fxml")); + switchListPane = switchListLoader.load(); + switchListController = switchListLoader.getController(); + switchListController.setMainApp(this); + switchListController.setSwitchControls(); + + FXMLLoader turntableLoader = new FXMLLoader(); + turntableLoader.setLocation(MainApp.class.getResource("view/Turntable.fxml")); + turntablePane = turntableLoader.load(); + turntableController = turntableLoader.getController(); + turntableController.setMainApp(this); + + FXMLLoader settingsLoader = new FXMLLoader(); + settingsLoader.setLocation(MainApp.class.getResource("view/Settings.fxml")); + settingsPane = settingsLoader.load(); + settingsController = settingsLoader.getController(); + settingsController.setMainApp(this); + settingsController.setSettings(configuration); + + // Add the tabs + tabs.add(new Tab("Loks", enginePane)); + tabs.add(new Tab("Weichen", switchListPane)); + tabs.add(new Tab("Drehteller", turntablePane)); + tabs.add(new Tab("Einstellungen", settingsPane)); + rootController.loadTabs(); + + } catch (IOException e) { + e.printStackTrace(); + } + + } + + /** + * Returns the main stage. + * @return + */ + + public void setStatus(String status){ + rootController.setStatus(status); + } + + public Stage getPrimaryStage() { + return primaryStage; + } + + public static void main(String[] args) { + launch(args); + } + + public void emergencyStopHandler() { + emergencyStop(); + for(Engine eng:engines){ + eng.setSpeed(0); + } + engineController.updateEngineStatus(); + setStatus("NOTAUS"); + + } + + public void emergencyStop () { + if (connectionEstablished) { + try { + if (running) { + byte[] datagram = {Properties.SEPERATOR, (byte) 0x00, (byte) 0x00, (byte) Properties.SYSTEM_STOP, (byte) 0x00, (byte) 0x00}; + out.write(datagram); + running = false; + } + else { + byte[] datagram = {Properties.SEPERATOR, (byte) 0x00, (byte) 0x00, (byte) Properties.SYSTEM_GO, (byte) 0x00, (byte) 0x00}; + out.write(datagram); + running = true; + } + } catch (Exception e) { + setStatus("Error at: emergencyStop"); + e.printStackTrace(); + } + } + } + + public Boolean getConnectionEstablished() { + return connectionEstablished; + } + + public void setEngineDirection (Engine eng) { + if (connectionEstablished) { + try { + byte dir; + if (eng.getDirection().get()) + dir = (byte) 0x01; + else + dir = (byte) 0x02; + + byte[] datagram = {Properties.SEPERATOR, (byte) ((eng.getMaerklinID().get()/(1<<8))%(1<<8)), (byte) (eng.getMaerklinID().get()%(1<<8)), (byte) Properties.ENGINE_SET_DIRECTION, dir, (byte) 0x00}; + out.write(datagram); + } catch (Exception e) { + setStatus("Error at: engineSetDirectionRight"); + e.printStackTrace(); + } + } + } + + public void setEngineSpeed (Engine eng) { + if (connectionEstablished) { + try { + int newEngineSpeed = eng.getSpeed().get(); + byte[] datagram = {Properties.SEPERATOR, (byte) ((eng.getMaerklinID().get()/(1<<8))%(1<<8)), (byte) (eng.getMaerklinID().get()%(1<<8)), (byte) Properties.ENGINE_SET_SPEED, (byte) ((newEngineSpeed/(1<<8))%(1<<8)), (byte) (newEngineSpeed%(1<<8))}; + out.write(datagram); + } catch (Exception e) { + setStatus("engineSetSpeed"); + e.printStackTrace(); + } + } + } + + public void setSwitchState (Switch sw) { + if (connectionEstablished) { + try { + byte dir; + if (!sw.getState().get()) //gerade + dir = (byte) 0x01; + else //krumm + dir = (byte) 0x00; + + byte[] datagram = {Properties.SEPERATOR, (byte) ((sw.getMaerklinID().get()/(1<<8))%(1<<8)), (byte) (sw.getMaerklinID().get()%(1<<8)), (byte) Properties.SWITCH_SET_DIRECTION, dir, (byte) 0x00}; + out.write(datagram); + } catch (Exception e) { + setStatus("Error at: setSwitchState"); + e.printStackTrace(); + } + } + } + + public void turntableTurnCW () { + if (connectionEstablished) { + try { + byte[] datagram = {Properties.SEPERATOR, (byte) ((turntable.getMaerklinID().get()/(1<<8))%(1<<8)), (byte) (turntable.getMaerklinID().get()%(1<<8)), (byte) Properties.SWITCH_SET_DIRECTION, (byte) 0x00, (byte) 0x00}; + out.write(datagram); + } catch (Exception e) { + setStatus("Error at: turntableTurnCW"); + e.printStackTrace(); + } + } + } + + public void turntableTurnCCW () { + if (connectionEstablished) { + try { + byte[] datagram = {Properties.SEPERATOR, (byte) ((turntable.getMaerklinID().get()/(1<<8))%(1<<8)), (byte) (turntable.getMaerklinID().get()%(1<<8)), (byte) Properties.SWITCH_SET_DIRECTION, (byte) 0x01, (byte) 0x00}; + out.write(datagram); + } catch (Exception e) { + setStatus("Error at: turntableTurnCCW"); + e.printStackTrace(); + } + } + } + + public void establishConnetion () { + if (connectionEstablished) { + try { + byte[] datagram = {Properties.SEPERATOR, (byte) 0x00, (byte) 0x00, (byte) Properties.SESSION_ABORT, (byte) 0x00, (byte) 0x00}; + out.write(datagram); + client.close(); + connectionEstablished = false; + running = false; + settingsController.updateSettingsStatus(); + + } catch (Exception e) { + setStatus("Error at: establishConnection (shutting down connection"); + e.printStackTrace(); + } + } + else { + UTILITY_THREAD_EXECUTOR.submit((new EstablishConnection(this))); + } + } + + class EstablishConnection implements Runnable { + + private final MainApp CONTROLLER_INSTANCE; + + EstablishConnection (MainApp controller) { + CONTROLLER_INSTANCE = controller; + } + + @Override + public void run() { + Thread.yield(); + if (!connectionEstablished) { + try (Socket socket = new Socket(configuration.getSocketAddress().get().getHostName(), configuration.getSocketAddress().get().getPort())) { + client = socket; + client.setKeepAlive(true); + client.setReuseAddress(true); + in = client.getInputStream(); + out = client.getOutputStream(); + connectionEstablished = true; + running = true; + UTILITY_THREAD_EXECUTOR.submit((new UpdateFunctionality(CONTROLLER_INSTANCE, in))); + Platform.runLater(new Runnable() { + + @Override + public void run() { + CONTROLLER_INSTANCE.setStatus("Verbindung zu "+client.getRemoteSocketAddress()+" aufgebaut!"); + CONTROLLER_INSTANCE.settingsController.updateSettingsStatus(); + } + + }); + while (connectionEstablished) { + Thread.sleep(100); + } + } + catch (Exception e) { + Platform.runLater(new Runnable() { + + @Override + public void run() { + CONTROLLER_INSTANCE.setStatus("Error at: establishConnection (establishing connection"); + } + + }); + e.printStackTrace(); + } + finally { + CONTROLLER_INSTANCE.UTILITY_THREAD_EXECUTOR.shutdownNow(); + } + } + } + } + + class UpdateFunctionality implements Runnable { + + private final MainApp CONTROLLER_INSTANCE; + private final BufferedInputStream INPUT_STREAM; + + UpdateFunctionality (MainApp controller, InputStream in) { + CONTROLLER_INSTANCE = controller; + INPUT_STREAM = new BufferedInputStream(in, Properties.OUT_BUFFER_SIZE); + } + + public void parseDatagram (byte[] datagram) { + System.out.println("2: "+DatatypeConverter.printHexBinary(datagram)); + if (datagram.length < 5) { + setStatus("Error while updating!"); + return; + } + for (Engine eng : engines){ + if(eng.getMaerklinID().get()==((datagram[0]&0xFF)*(1<<8)+(datagram[1]&0xFF))){ + int engSpeed = (datagram[2]&0xFF)*(1<<8)+(datagram[3]&0xFF); + boolean engDirection = (datagram[4] == (0x01)); + if (engSpeed != eng.getSpeed().get()) { + eng.setSpeed(engSpeed); + //System.out.println("Setting speed of engine "+(datagram[0]&0xFF)*(1<<8)+(datagram[1]&0xFF)+" to "+(datagram[2]&0xFF)*(1<<8)+(datagram[3]&0xFF)+"."); + } + if (engDirection != eng.getDirection().get()) { + eng.setDirection(engDirection); + //System.out.println("Setting direction of engine "+(datagram[0]&0xFF)*(1<<8)+(datagram[1]&0xFF)+" to "+datagram[4]+"."); + } + if (eng.equals(engineController.getSelectedEngine())){} + } + } + for (Switch sw : switches){ + if(sw.getMaerklinID().get()==((datagram[0]&0xFF)*(1<<8)+(datagram[1]&0xFF))){ + boolean swState = !(datagram[4] == (byte) 0x01); + if (swState != sw.getState().get()) { + sw.setState(swState); + //System.out.println("Setting direction of switch "+(datagram[0]&0xFF)*(1<<8)+(datagram[1]&0xFF)+" to "+ datagram[4]+"."); + } + } + } + } + + public void updateGUI () { + engineController.updateEngineStatus(); + for (Switch sw : switches){ + sw.getController().get().updateSwitchStatus(); + } + } + + @Override + public void run() { + int stopCounter, dataCounter, counter; + byte buffer[] = new byte[Properties.OUT_BUFFER_SIZE]; + byte datagram[] = new byte[Properties.IN_BUFFER_SIZE]; + boolean startByte; + try { + while (connectionEstablished) { + stopCounter = 0; + dataCounter = 0; + counter = 0; + startByte = false; + while (INPUT_STREAM.available() > 0 && stopCounter < 5) { + buffer[counter%Properties.OUT_BUFFER_SIZE] = (byte) INPUT_STREAM.read(); + if (stopCounter == 2) { + startByte = true; + } + if (buffer[counter%Properties.OUT_BUFFER_SIZE] == Properties.SEPERATOR && dataCounter != 4) { + dataCounter = 0; + stopCounter++; + } + else { + stopCounter = 0; + dataCounter++; + if (dataCounter == 5 && startByte) { + dataCounter = 0; + for (int i = 0; i < Properties.IN_BUFFER_SIZE; i++) { + datagram[i] = buffer[counter-Properties.IN_BUFFER_SIZE+i+1]; + } + System.out.println("1: "+DatatypeConverter.printHexBinary(datagram)); + parseDatagram(datagram); + } + else if (dataCounter > 5 && startByte) { + throw (new Exception("Wrong data-update-format!")); + } + } + counter++; + } + while (INPUT_STREAM.available() != 0) { + INPUT_STREAM.read(); + } + Platform.runLater(new Runnable() { + + @Override + public void run() { + updateGUI(); + } + + }); + Thread.sleep(50); + } + } + catch (Exception e) { + e.printStackTrace(); + Platform.runLater(new Runnable() { + + @Override + public void run() { + CONTROLLER_INSTANCE.setStatus("Error while updating!"); + } + + }); + } + } + } +} \ No newline at end of file diff --git a/Praktikum/VINF_MaerklinControl/build/build/src/gui/model/Engine.java b/Praktikum/VINF_MaerklinControl/build/build/src/gui/model/Engine.java new file mode 100644 index 0000000000000000000000000000000000000000..75b59b24d1c4d633f9426b0e47d41eabe22a504f --- /dev/null +++ b/Praktikum/VINF_MaerklinControl/build/build/src/gui/model/Engine.java @@ -0,0 +1,92 @@ +package gui.model; + +import javafx.beans.property.IntegerProperty; +import javafx.beans.property.ObjectProperty; + +import javafx.beans.property.BooleanProperty; +import javafx.beans.property.SimpleIntegerProperty; +import javafx.beans.property.SimpleObjectProperty; +import javafx.beans.property.SimpleBooleanProperty; +import javafx.beans.property.SimpleStringProperty; +import javafx.beans.property.StringProperty; +import javafx.scene.image.Image; + +/** + * Model class for a Model Engine. + * + * @author Philipp Stenkamp + */ +public class Engine { + + private final StringProperty name; + private final IntegerProperty id; + private final IntegerProperty speed; + private final BooleanProperty fwd; + private final ObjectProperty<Image> img; + + /** + * Default constructor. + */ + public Engine() { + this(null, null, null); + } + + public Engine(String name, Integer id) { + this(name, id, null); + } + + /** + * Constructor with some initial data. + * + * @param name + * @param id + */ + + public Engine(String name, Integer id, String imgPath) { + this.name = new SimpleStringProperty(name); + this.id = new SimpleIntegerProperty(id); + this.img = new SimpleObjectProperty<Image>(new Image("file:" + imgPath)); + + // Initialize the switch in a straigt (=false) state + this.fwd = new SimpleBooleanProperty(true); + this.speed = new SimpleIntegerProperty(0); + + } + + @Override + public String toString() { + return name.getValue(); + } + + public StringProperty getName() { + return name; + } + + public IntegerProperty getMaerklinID() { + return id; + } + + public BooleanProperty getDirection() { + return fwd; + } + + public void setDirection(Boolean fwd) { + this.fwd.set(fwd); + } + + public IntegerProperty getSpeed() { + return speed; + } + + public void setSpeed(Integer speed) { + this.speed.set(speed); + } + + public ObjectProperty<Image> getImg(){ + return img; + } + + public void setImg(Image img){ + this.img.set(img); + } +} diff --git a/Praktikum/VINF_MaerklinControl/build/build/src/gui/model/Settings.java b/Praktikum/VINF_MaerklinControl/build/build/src/gui/model/Settings.java new file mode 100644 index 0000000000000000000000000000000000000000..a6a737f271c650347fcd7b3d9af0e9db22708841 --- /dev/null +++ b/Praktikum/VINF_MaerklinControl/build/build/src/gui/model/Settings.java @@ -0,0 +1,33 @@ +package gui.model; + +import java.net.InetSocketAddress; + +import common.Properties; +import javafx.beans.property.ObjectProperty; +import javafx.beans.property.SimpleObjectProperty; + + +/** + * Model class for a Model Engine. + * + * @author Philipp Stenkamp + */ +public class Settings { + private final ObjectProperty<InetSocketAddress> server; + + /** + * Default constructor. + */ + public Settings() { + this.server = new SimpleObjectProperty<InetSocketAddress> (new InetSocketAddress("localhost", Properties.PORT)); + } + + public ObjectProperty<InetSocketAddress> getSocketAddress() { + return server; + } + + public void setSocketAddress(InetSocketAddress server) { + this.server.set(server); + } + +} diff --git a/Praktikum/VINF_MaerklinControl/build/build/src/gui/model/Switch.java b/Praktikum/VINF_MaerklinControl/build/build/src/gui/model/Switch.java new file mode 100644 index 0000000000000000000000000000000000000000..6058fb846c77ab7d066974baaa04d7453614a37d --- /dev/null +++ b/Praktikum/VINF_MaerklinControl/build/build/src/gui/model/Switch.java @@ -0,0 +1,85 @@ +package gui.model; + +import javafx.beans.property.IntegerProperty; +import gui.view.SwitchControl; +import javafx.beans.property.BooleanProperty; +import javafx.beans.property.SimpleIntegerProperty; +import javafx.beans.property.SimpleObjectProperty; +import javafx.beans.property.SimpleBooleanProperty; +import javafx.beans.property.SimpleStringProperty; +import javafx.beans.property.StringProperty; +import javafx.beans.property.ObjectProperty; + +/** + * Model class for a Model Train Switch. + * + * @author Philipp Stenkamp + */ +public class Switch{ + + private final StringProperty name; + private final IntegerProperty id; + private final BooleanProperty state; + private final ObjectProperty<SwitchControl> controller; + + /** + * Default constructor. + */ + public Switch() { + this(null, null, null); + } + + /** + * Constructor with some initial data. + * + * @param name + * @param id + */ + + public Switch(String name, Integer id){ + this(name, id, null); + } + + public Switch(String name, Integer id, SwitchControl controller) { + this.name = new SimpleStringProperty(name); + this.id = new SimpleIntegerProperty(id); + this.controller = new SimpleObjectProperty<SwitchControl>(controller); + + // Initialize the switch in a straigt (=false) state + this.state = new SimpleBooleanProperty(false); + + } + + @Override + public String toString() { + return name.getValue(); + } + + public StringProperty getName() { + return name; + } + + public void setName(String name) { + this.name.set(name); + } + + public IntegerProperty getMaerklinID() { + return id; + } + + public BooleanProperty getState() { + return state; + } + + public void setState(Boolean state) { + this.state.set(state); + } + + public ObjectProperty<SwitchControl> getController(){ + return controller; + } + + public void setController(SwitchControl controller){ + this.controller.setValue(controller); + } +} diff --git a/Praktikum/VINF_MaerklinControl/build/build/src/gui/view/Engine.fxml b/Praktikum/VINF_MaerklinControl/build/build/src/gui/view/Engine.fxml new file mode 100644 index 0000000000000000000000000000000000000000..8aea2f6655bb319214b2079f17b9325526cc44fd --- /dev/null +++ b/Praktikum/VINF_MaerklinControl/build/build/src/gui/view/Engine.fxml @@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<?import javafx.geometry.Insets?> +<?import javafx.scene.control.ChoiceBox?> +<?import javafx.scene.control.Slider?> +<?import javafx.scene.control.ToggleButton?> +<?import javafx.scene.control.ToggleGroup?> +<?import javafx.scene.image.ImageView?> +<?import javafx.scene.layout.AnchorPane?> +<?import javafx.scene.layout.HBox?> +<?import javafx.scene.layout.VBox?> + +<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" fx:controller="gui.view.EngineController"> + <children> + <VBox alignment="BOTTOM_CENTER" prefHeight="200.0" prefWidth="100.0" AnchorPane.bottomAnchor="20.0" AnchorPane.leftAnchor="20.0" AnchorPane.rightAnchor="20.0" AnchorPane.topAnchor="0.0"> + <children> + <ImageView fx:id="engineImage" fitHeight="50.0" fitWidth="150.0" pickOnBounds="true" preserveRatio="true"> + <VBox.margin> + <Insets bottom="10.0" /> + </VBox.margin></ImageView> + <Slider fx:id="engineSpeedSlider" showTickLabels="true" showTickMarks="true" /> + <HBox alignment="CENTER" prefWidth="300.0"> + <children> + <ToggleButton fx:id="engineRevButton" mnemonicParsing="false" onAction="#handleEngineDirection" text="<"> + <toggleGroup> + <ToggleGroup fx:id="direction" /> + </toggleGroup></ToggleButton> + <ChoiceBox fx:id="engineChoiceBox" prefWidth="150.0" /> + <ToggleButton fx:id="engineFwdButton" mnemonicParsing="false" onAction="#handleEngineDirection" text=">" toggleGroup="$direction" /> + </children> + </HBox> + </children> + <opaqueInsets> + <Insets right="9.0" /> + </opaqueInsets> + </VBox> + </children> +</AnchorPane> diff --git a/Praktikum/VINF_MaerklinControl/build/build/src/gui/view/EngineController.java b/Praktikum/VINF_MaerklinControl/build/build/src/gui/view/EngineController.java new file mode 100644 index 0000000000000000000000000000000000000000..98eded74290c84c51acddd125d109d3ae4572037 --- /dev/null +++ b/Praktikum/VINF_MaerklinControl/build/build/src/gui/view/EngineController.java @@ -0,0 +1,100 @@ +package gui.view; + +import javafx.beans.value.ChangeListener; +import javafx.beans.value.ObservableValue; +import javafx.fxml.FXML; +import javafx.scene.control.Slider; +import javafx.scene.control.ChoiceBox; +import javafx.scene.control.ToggleButton; +import javafx.scene.image.ImageView; +import gui.MainApp; +import gui.model.Engine; + +public class EngineController { + @FXML + private ImageView engineImage; + @FXML + private Slider engineSpeedSlider; + @FXML + private ChoiceBox<Engine> engineChoiceBox; + @FXML + private ToggleButton engineRevButton, engineFwdButton; + + // Reference to the main application. + private MainApp mainApp; + private Engine eng; + + /** + * The constructor. + * The constructor is called before the initialize() method. + */ + public EngineController() { + } + + /** + * Initializes the controller class. This method is automatically called + * after the fxml file has been loaded. + */ + @FXML + private void initialize() { + engineSpeedSlider.setValue(0); + engineFwdButton.setSelected(true); // initializes the forward Button as pressed + engineChoiceBox.getSelectionModel().selectedItemProperty().addListener( + (observable, oldValue, newValue) -> setSelectedEngine(newValue)); + + engineSpeedSlider.valueProperty().addListener(new ChangeListener<Number>() { + public void changed(ObservableValue<? extends Number> ov, + Number old_val, Number new_val) { + eng.setSpeed(new_val.intValue()*10); + mainApp.setEngineSpeed(eng); + updateEngineStatus(); + } + }); + } + + /** + * Is called by the main application to give a reference back to itself. + * + * @param mainApp + */ + public void setMainApp(MainApp mainApp) { + this.mainApp = mainApp; + engineChoiceBox.setItems(mainApp.getEngines()); + engineChoiceBox.setValue(mainApp.getEngines().get(0)); + engineImage.setImage(mainApp.getEngines().get(0).getImg().get()); + } + + public void handleEngineDirection(){ + eng.setDirection(engineFwdButton.isSelected()); + eng.setSpeed(0); + mainApp.setEngineDirection(eng); + updateEngineStatus(); + } + + public void updateEngineStatus(){ + engineImage.setImage(eng.getImg().get()); + engineSpeedSlider.setValue(eng.getSpeed().get()/10); + + StringBuilder status = new StringBuilder("Letztes Kommando: "); + status.append(eng.toString() + " "); + status.append(eng.getSpeed().get()/10 + "% "); + engineFwdButton.setSelected(eng.getDirection().get()); + engineRevButton.setSelected(!eng.getDirection().get()); + if (eng.getDirection().get()) + status.append("vorw�rts"); + else + status.append("r�ckw�rts"); + mainApp.setStatus(status.toString()); + } + + public void setSelectedEngine(Engine eng){ + this.eng = eng; + mainApp.setStatus(eng.toString() + " ausgew�hlt"); + updateEngineStatus(); + } + + public Engine getSelectedEngine(){ + return eng; + } + +} diff --git a/Praktikum/VINF_MaerklinControl/build/build/src/gui/view/RootLayout.fxml b/Praktikum/VINF_MaerklinControl/build/build/src/gui/view/RootLayout.fxml new file mode 100644 index 0000000000000000000000000000000000000000..4ba58c6ec993ec52eafb3eefce71c76bfe0f9fb4 --- /dev/null +++ b/Praktikum/VINF_MaerklinControl/build/build/src/gui/view/RootLayout.fxml @@ -0,0 +1,60 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<?import javafx.geometry.Insets?> +<?import javafx.scene.control.Button?> +<?import javafx.scene.control.Menu?> +<?import javafx.scene.control.MenuBar?> +<?import javafx.scene.control.MenuItem?> +<?import javafx.scene.control.TabPane?> +<?import javafx.scene.layout.BorderPane?> +<?import javafx.scene.layout.VBox?> +<?import javafx.scene.text.Font?> +<?import org.controlsfx.control.StatusBar?> + +<BorderPane prefHeight="600.0" prefWidth="340.0" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" fx:controller="gui.view.RootLayoutController"> + <top> + <MenuBar BorderPane.alignment="CENTER"> + <menus> + <Menu mnemonicParsing="false" text="File"> + <items> + <MenuItem mnemonicParsing="false" text="Close" /> + </items> + </Menu> + <Menu mnemonicParsing="false" text="Edit"> + <items> + <MenuItem mnemonicParsing="false" text="Delete" /> + </items> + </Menu> + <Menu mnemonicParsing="false" text="Help"> + <items> + <MenuItem mnemonicParsing="false" text="About" /> + </items> + </Menu> + </menus> + </MenuBar> + </top> + <center> + <TabPane fx:id="rootTabPane" prefHeight="200.0" prefWidth="200.0" tabClosingPolicy="UNAVAILABLE" BorderPane.alignment="CENTER"> + <tabs> + </tabs> + </TabPane> + </center> + <bottom> + <VBox alignment="TOP_CENTER" BorderPane.alignment="CENTER"> + <children> + <Button fx:id="emergencyStop" mnemonicParsing="false" onAction="#emergencyStopHandler" prefHeight="50.0" prefWidth="300.0" style="-fx-background-color: red;" text="NOTAUS" textFill="WHITE"> + <padding> + <Insets bottom="10.0" left="5.0" right="5.0" top="5.0" /> + </padding> + <font> + <Font name="System Bold" size="14.0" /> + </font> + <VBox.margin> + <Insets bottom="10.0" top="10.0" /> + </VBox.margin> + </Button> + <StatusBar fx:id="statusBar" /> + </children> + </VBox> + </bottom> +</BorderPane> diff --git a/Praktikum/VINF_MaerklinControl/build/build/src/gui/view/RootLayoutController.java b/Praktikum/VINF_MaerklinControl/build/build/src/gui/view/RootLayoutController.java new file mode 100644 index 0000000000000000000000000000000000000000..f47880d0f782ae54864ad646cee46dc944ef21e3 --- /dev/null +++ b/Praktikum/VINF_MaerklinControl/build/build/src/gui/view/RootLayoutController.java @@ -0,0 +1,35 @@ +package gui.view; + +import javafx.fxml.FXML; +import javafx.scene.control.TabPane; + +import org.controlsfx.control.StatusBar; + +import gui.MainApp; + +public class RootLayoutController { + @FXML + private TabPane rootTabPane; + @FXML + private StatusBar statusBar; + + + // Reference to the main application. + private MainApp mainApp; + + public void setMainApp(MainApp mainApp) { + this.mainApp = mainApp; + } + + public void loadTabs(){ + rootTabPane.getTabs().addAll(mainApp.getTabs()); //can't be in the constructor + } + + public void setStatus(String status){ + statusBar.setText(status); + } + + public void emergencyStopHandler(){ + mainApp.emergencyStopHandler(); + } +} diff --git a/Praktikum/VINF_MaerklinControl/build/build/src/gui/view/Settings.fxml b/Praktikum/VINF_MaerklinControl/build/build/src/gui/view/Settings.fxml new file mode 100644 index 0000000000000000000000000000000000000000..ae4aa387c7b48f44b6543370de2436cd14318546 --- /dev/null +++ b/Praktikum/VINF_MaerklinControl/build/build/src/gui/view/Settings.fxml @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<?import javafx.geometry.Insets?> +<?import javafx.scene.control.Button?> +<?import javafx.scene.control.Label?> +<?import javafx.scene.control.TextField?> +<?import javafx.scene.layout.AnchorPane?> +<?import javafx.scene.layout.VBox?> + +<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" fx:controller="gui.view.SettingsController"> + <children> + <VBox prefHeight="200.0" prefWidth="100.0" AnchorPane.bottomAnchor="20.0" AnchorPane.leftAnchor="20.0" AnchorPane.rightAnchor="20.0" AnchorPane.topAnchor="20.0"> + <children> + <Label text="Server-IP" /> + <TextField fx:id="serverIP" prefHeight="25.0" prefWidth="158.0" text="127.0.0.1"> + <VBox.margin> + <Insets top="5.0" /> + </VBox.margin> + </TextField> + <Button fx:id="connectButton" mnemonicParsing="false" onAction="#connectHandler" text="Verbindung herstellen"> + <VBox.margin> + <Insets top="5.0" /> + </VBox.margin> + </Button> + </children> + <padding> + <Insets top="20.0" /> + </padding> + </VBox> + </children> +</AnchorPane> diff --git a/Praktikum/VINF_MaerklinControl/build/build/src/gui/view/SettingsController.java b/Praktikum/VINF_MaerklinControl/build/build/src/gui/view/SettingsController.java new file mode 100644 index 0000000000000000000000000000000000000000..85161fac87685a5a2c937269a3abacca54bcd7d9 --- /dev/null +++ b/Praktikum/VINF_MaerklinControl/build/build/src/gui/view/SettingsController.java @@ -0,0 +1,68 @@ +package gui.view; + +import javafx.fxml.FXML; +import javafx.scene.control.TextField; +import javafx.scene.control.Button; + +import java.net.InetSocketAddress; + +import gui.MainApp; +import gui.model.Settings; + +public class SettingsController { + @FXML + TextField serverIP; + + @FXML + Button connectButton; + + private Settings settings; + + private MainApp mainApp; + + public SettingsController(){ + } + + /** + * Initializes the controller class. This method is automatically called + * after the fxml file has been loaded. + */ + @FXML + private void initialize() { + } + + /** + * Is called by the main application to give a reference back to itself. + * + * @param mainApp + */ + public void setMainApp(MainApp mainApp) { + this.mainApp = mainApp; + } + + @FXML + private void connectHandler(){ + InetSocketAddress address = new InetSocketAddress(serverIP.getText(), settings.getSocketAddress().get().getPort()); + settings.setSocketAddress(address); + updateSettingsStatus(); + mainApp.establishConnetion(); + } + + public void updateSettingsStatus(){ + InetSocketAddress addr = settings.getSocketAddress().get(); + StringBuilder status = new StringBuilder("Verbindung herstellen mit "); + status.append(addr.getHostName()); + status.append(" (" + addr.getAddress() + ":" + addr.getPort() + ")"); + mainApp.setStatus(status.toString()); + if (mainApp.getConnectionEstablished()) { + connectButton.setText("Verbindung trennen"); + } + else { + connectButton.setText("Verbindung herstellen"); + } + } + + public void setSettings(Settings settings) { + this.settings = settings; + } +} diff --git a/Praktikum/VINF_MaerklinControl/build/build/src/gui/view/Switch.fxml b/Praktikum/VINF_MaerklinControl/build/build/src/gui/view/Switch.fxml new file mode 100644 index 0000000000000000000000000000000000000000..ab56159a5a1986f3f5e401b29d3c6ac34f01253a --- /dev/null +++ b/Praktikum/VINF_MaerklinControl/build/build/src/gui/view/Switch.fxml @@ -0,0 +1,43 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<?import javafx.geometry.Insets?> +<?import javafx.scene.control.Label?> +<?import javafx.scene.image.Image?> +<?import javafx.scene.image.ImageView?> +<?import javafx.scene.layout.HBox?> +<?import org.controlsfx.control.ToggleSwitch?> + +<fx:root alignment="TOP_CENTER" type="javafx.scene.layout.HBox" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1"> + <Label fx:id="nameLabel" minWidth="75" prefHeight="25.0" prefWidth="75.0" text="Weiche"> + <padding> + <Insets top="5.0" /> + </padding> + </Label> + <ImageView fx:id="straightIcon" fitHeight="20.0" fitWidth="20.0" pickOnBounds="true" preserveRatio="true"> + <image> + <Image url="@../../../res/MagIcon_00_01_i.png" /> + </image> + <HBox.margin> + <Insets right="5.0" /> + </HBox.margin> + </ImageView> + <ToggleSwitch fx:id="stateToggleSwitch" prefWidth="32.0"> + <HBox.margin> + <Insets right="5.0" /> + </HBox.margin> + <padding> + <Insets top="1.0" /> + </padding> + </ToggleSwitch> + <ImageView fx:id="bentIcon" fitHeight="20.0" fitWidth="20.0" pickOnBounds="true" preserveRatio="true"> + <image> + <Image url="@../../../res/MagIcon_00_00_i.png" /> + </image> + <HBox.margin> + <Insets right="5.0" /> + </HBox.margin> + </ImageView> + <padding> + <Insets bottom="5.0" top="5.0" /> + </padding> +</fx:root> diff --git a/Praktikum/VINF_MaerklinControl/build/build/src/gui/view/SwitchControl.java b/Praktikum/VINF_MaerklinControl/build/build/src/gui/view/SwitchControl.java new file mode 100644 index 0000000000000000000000000000000000000000..e14c05fbe2f93d2884930cc518fcc5cee7d41e00 --- /dev/null +++ b/Praktikum/VINF_MaerklinControl/build/build/src/gui/view/SwitchControl.java @@ -0,0 +1,101 @@ +package gui.view; + +import javafx.beans.value.ChangeListener; +import javafx.beans.value.ObservableValue; +import javafx.fxml.FXML; +import javafx.fxml.FXMLLoader; +import javafx.scene.control.Label; +import javafx.scene.image.Image; +import javafx.scene.image.ImageView; +import javafx.scene.layout.HBox; + +import java.io.IOException; + +import org.controlsfx.control.ToggleSwitch; +import gui.MainApp; +import gui.model.Switch; + +public class SwitchControl extends HBox{ + @FXML + private Label nameLabel; + @FXML + private ToggleSwitch stateToggleSwitch; + @FXML + private ImageView straightIcon; + @FXML + private ImageView bentIcon; + + // Reference to the main application. + private MainApp mainApp; + private Switch sw; + private Image straightActive = new Image("file:res/MagIcon_00_01_a.png"); + private Image straightInactive = new Image("file:res/MagIcon_00_01_i.png"); + private Image bentActive = new Image("file:res/MagIcon_00_00_a.png"); + private Image bentInactive = new Image("file:res/MagIcon_00_00_i.png"); + + + /** + * The constructor. + * The constructor is called before the initialize() method. + */ + public SwitchControl(Switch sw) { + this.sw = sw; + + FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("Switch.fxml")); + fxmlLoader.setRoot(this); + fxmlLoader.setController(this); + sw.setController(this); + + try { + fxmlLoader.load(); + } catch (IOException exception) { + throw new RuntimeException(exception); + } + } + + /** + * Initializes the controller class. This method is automatically called + * after the fxml file has been loaded. + */ + @FXML + private void initialize() { + nameLabel.setText(sw.toString()); + straightIcon.setImage(straightActive); + bentIcon.setImage(bentInactive); + stateToggleSwitch.selectedProperty().addListener(new ChangeListener<Boolean>(){ + public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) { + sw.setState(newValue); + mainApp.setSwitchState(sw); + updateSwitchStatus(); + } + }); + } + + /** + * Is called by the main application to give a reference back to itself. + * + * @param mainApp + */ + public void setMainApp(MainApp mainApp) { + this.mainApp = mainApp; + } + + + public void updateSwitchStatus(){ + stateToggleSwitch.setSelected(sw.getState().get()); + + StringBuilder status = new StringBuilder("Letztes Kommando: "); + status.append(sw.toString() + " "); + if (!sw.getState().get()){ + status.append("gerade"); + straightIcon.setImage(straightActive); + bentIcon.setImage(bentInactive); + } + else{ + status.append("krumm"); + straightIcon.setImage(straightInactive); + bentIcon.setImage(bentActive); + } + mainApp.setStatus(status.toString()); + } +} diff --git a/Praktikum/VINF_MaerklinControl/build/build/src/gui/view/SwitchList.fxml b/Praktikum/VINF_MaerklinControl/build/build/src/gui/view/SwitchList.fxml new file mode 100644 index 0000000000000000000000000000000000000000..1af1e0f3fc0cd43cdd008cab17b1cc50f76de7b9 --- /dev/null +++ b/Praktikum/VINF_MaerklinControl/build/build/src/gui/view/SwitchList.fxml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<?import javafx.geometry.Insets?> +<?import javafx.scene.layout.AnchorPane?> +<?import javafx.scene.layout.VBox?> + +<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefWidth="340.0" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" fx:controller="gui.view.SwitchListController"> + <children> + <VBox fx:id="switchesVBox" alignment="TOP_CENTER" prefWidth="300.0"> + <padding> + <Insets bottom="5.0" left="20.0" right="20.0" top="5.0" /> + </padding></VBox> + </children> +</AnchorPane> diff --git a/Praktikum/VINF_MaerklinControl/build/build/src/gui/view/SwitchListController.java b/Praktikum/VINF_MaerklinControl/build/build/src/gui/view/SwitchListController.java new file mode 100644 index 0000000000000000000000000000000000000000..de5eebb19ff70962904f45575d52bb181f31be79 --- /dev/null +++ b/Praktikum/VINF_MaerklinControl/build/build/src/gui/view/SwitchListController.java @@ -0,0 +1,53 @@ +package gui.view; + +import javafx.fxml.FXML; +import javafx.scene.layout.VBox; +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; +import gui.MainApp; +import gui.model.Switch; + +public class SwitchListController { + @FXML + private VBox switchesVBox; + + // Reference to the main application. + private MainApp mainApp; + + /** + * The constructor. + * The constructor is called before the initialize() method. + */ + public SwitchListController(){ + + } + + /** + * Initializes the controller class. This method is automatically called + * after the fxml file has been loaded. + */ + @FXML + private void initialize() { + //setSwitchControls(); // would be nice to do this here, doesn't work until setMainApp has been called + } + + /** + * Is called by the main application to give a reference back to itself. + * + * @param mainApp + */ + public void setMainApp(MainApp mainApp) { + this.mainApp = mainApp; + + } + + public void setSwitchControls(){ + ObservableList<Switch> switches = mainApp.getSwitches(); + ObservableList<SwitchControl> switchControls = FXCollections.observableArrayList(); + for ( int i=0; i<switches.size();i++ ){ + switchControls.add(new SwitchControl(switches.get(i))); + switches.get(i).getController().get().setMainApp(mainApp); + }; + switchesVBox.getChildren().addAll(switchControls); + } +} diff --git a/Praktikum/VINF_MaerklinControl/build/build/src/gui/view/Turntable.fxml b/Praktikum/VINF_MaerklinControl/build/build/src/gui/view/Turntable.fxml new file mode 100644 index 0000000000000000000000000000000000000000..06a134e01bbae972b01bea37b66201782deb0f46 --- /dev/null +++ b/Praktikum/VINF_MaerklinControl/build/build/src/gui/view/Turntable.fxml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<?import javafx.scene.control.ChoiceBox?> +<?import javafx.scene.control.Button?> +<?import javafx.scene.layout.AnchorPane?> +<?import javafx.scene.layout.HBox?> + +<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" fx:controller="gui.view.TurntableController"> + <children> + <HBox alignment="BOTTOM_CENTER" layoutX="70.0" layoutY="457.0" AnchorPane.bottomAnchor="20.0" AnchorPane.leftAnchor="20.0" AnchorPane.rightAnchor="20.0" AnchorPane.topAnchor="0.0"> + <children> + <Button fx:id="turntableLeftButton" mnemonicParsing="false" onAction="#handleTurnCCW" text="<" /> + <ChoiceBox fx:id="slotChoiceBox" prefWidth="150.0" /> + <Button fx:id="turntableRightButton" mnemonicParsing="false" onAction="#handleTurnCW" text=">" /> + </children> + </HBox> + </children> +</AnchorPane> diff --git a/Praktikum/VINF_MaerklinControl/build/build/src/gui/view/TurntableController.java b/Praktikum/VINF_MaerklinControl/build/build/src/gui/view/TurntableController.java new file mode 100644 index 0000000000000000000000000000000000000000..0c8c6c16ae5ea763adf615195f6e70b1a7ad1cb2 --- /dev/null +++ b/Praktikum/VINF_MaerklinControl/build/build/src/gui/view/TurntableController.java @@ -0,0 +1,46 @@ +package gui.view; + +import gui.MainApp; +import javafx.fxml.FXML; +import javafx.scene.control.Button; +import javafx.scene.control.ChoiceBox; + +public class TurntableController { + + @FXML + private Button turntableLeftButton; + @FXML + private Button turntableRightButton; + @FXML + private ChoiceBox<Number> slotChoiceBox; + private MainApp mainApp; + + /** + * Initializes the controller class. This method is automatically called + * after the fxml file has been loaded. + */ + @FXML + private void initialize() { + + } + + /** + * Is called by the main application to give a reference back to itself. + * + * @param mainApp + */ + public void setMainApp(MainApp mainApp) { + this.mainApp = mainApp; + + } + + public void handleTurnCCW (){ + mainApp.turntableTurnCCW(); + mainApp.setStatus("Letztes Kommando: Drehteller links drehen"); + } + + public void handleTurnCW (){ + mainApp.turntableTurnCW(); + mainApp.setStatus("Letztes Kommando: Drehteller rechts drehen"); + } +} diff --git a/Praktikum/VINF_MaerklinControl/build/build/src/server/Engine.java b/Praktikum/VINF_MaerklinControl/build/build/src/server/Engine.java new file mode 100644 index 0000000000000000000000000000000000000000..60f39ceeff56b80bc26de0989f3df7adabf4a71e --- /dev/null +++ b/Praktikum/VINF_MaerklinControl/build/build/src/server/Engine.java @@ -0,0 +1,106 @@ +package server; + + +import java.util.ArrayList; + +public class Engine { + + static ArrayList<Engine> engines; + + private int engineID; + int engineDirection; + int engineSpeed; + + private MaerklinProtocol udpProtocol; + private UDPListener listener; + + public Engine(){ + this(0, 1, 0); + + // For offline-debugging + /*if (engines == null) { + engines = new ArrayList<Engine>(); + } + udpProtocol = new MaerklinProtocol(); + listener = new UDPListener(); + engines.add(this); + engineID = 0; + engineDirection = 1; + engineSpeed = 0;*/ + } + + public Engine(int id, int direction, int speed){ + if (engines == null) { + engines = new ArrayList<Engine>(); + } + udpProtocol = new MaerklinProtocol(); + listener = new UDPListener(); + engines.add(this); + try { + setEngineID(id); + setEngineDirection(direction); + setEngineSpeed(speed); + } + catch(Exception e){ + System.out.println(e.getMessage()); + } + } + + public void setEngineID(int newID){ + engineID = newID; + } + + public void setEngineDirection(int newEngineDirection) throws Exception { + if (newEngineDirection == 1 || newEngineDirection == 2){ + engineDirection = newEngineDirection; + } + else if (newEngineDirection == 3){ + if (engineDirection == 1){ + engineDirection = 2; + } + else { + engineDirection = 1; + } + } + else { + Exception e = new Exception("No viable direction!"); + throw e; + } + udpProtocol.changeEngineDirection(engineID, engineDirection); + listener.listen(); + } + + public void setEngineSpeed(int newEngineSpeed) throws Exception { + if (newEngineSpeed <= 1000 && newEngineSpeed >= 0){ + engineSpeed = newEngineSpeed; + } + else { + Exception e = new Exception("No viable speed value!"); + throw e; + } + udpProtocol.changeEngineSpeed(engineID, engineSpeed); + } + + public void increaseEngineSpeed() throws Exception { + engineSpeed = engineSpeed+50; + udpProtocol.changeEngineSpeed(engineID, engineSpeed); + } + + public void decreaseEngineSpeed() throws Exception{ + engineSpeed = engineSpeed-50; + udpProtocol.changeEngineSpeed(engineID, engineSpeed); + } + + public int getEngineID(){ + return engineID; + } + + public int getEngineDirection(){ + return engineDirection; + } + + public int getEngineSpeed(){ + return engineSpeed; + } + +} diff --git a/Praktikum/VINF_MaerklinControl/build/build/src/server/MaerklinProtocol.java b/Praktikum/VINF_MaerklinControl/build/build/src/server/MaerklinProtocol.java new file mode 100644 index 0000000000000000000000000000000000000000..30a97706453531fa3102adddf8cbe7daf618c1c4 --- /dev/null +++ b/Praktikum/VINF_MaerklinControl/build/build/src/server/MaerklinProtocol.java @@ -0,0 +1,58 @@ +package server; + +import java.net.*; + +public class MaerklinProtocol { + + private final static int port = 15731; + private final static String ip ="192.168.74.118"; + + public MaerklinProtocol(){ + //Nothing to do... + } + + private void writeDatagram(String ip, int port, byte[] data){ + //System.out.printf("\nGesendet: " + DatatypeConverter.printHexBinary(data)); + try(DatagramSocket socket = new DatagramSocket()){ + socket.setReuseAddress(true); + InetAddress address = InetAddress.getByName(ip); + DatagramPacket outgoingData = new DatagramPacket(data, data.length, address, port); + socket.send(outgoingData); + } + catch (Exception e) { + e.printStackTrace(); + } + } + + public void systemGo(){ + byte[] out = {(byte) 0x00, (byte) 0x00, (byte) 0x07, (byte) 0x78, (byte) 0x05, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00}; + this.writeDatagram(ip, port, out); + } + + public void systemStop(){ + byte[] out = {(byte) 0x00, (byte) 0x00, (byte) 0x07, (byte) 0x78, (byte) 0x05, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00}; + this.writeDatagram(ip, port, out); + } + + public void changeEngineSpeed(int mfxAddress, int newEngineSpeed){ + byte[] engineSpeed = {(byte) Math.floor(newEngineSpeed/256), (byte) Math.floor(newEngineSpeed%256)}; + byte[] address = {(byte) Math.floor(mfxAddress/256), (byte) Math.floor(mfxAddress%256)}; + byte[] out = {(byte) 0x00, (byte) 0x08, (byte) 0x07, (byte) 0x78, (byte) 0x06, (byte) 0x00, (byte) 0x00, address[0], address[1], engineSpeed[0], engineSpeed[1], (byte) 0x00, (byte) 0x00}; + this.writeDatagram(ip, port, out); + } + + public void changeEngineDirection(int mfxAddress, int newEngineDirection){ + byte engineDirection = (byte) Math.floor(newEngineDirection%256); + byte[] address = {(byte) Math.floor(mfxAddress/256), (byte) Math.floor(mfxAddress%256)}; + byte[] out = {(byte) 0x00, (byte) 0x0A, (byte) 0x07, (byte) 0x78, (byte) 0x05, (byte) 0x00, (byte) 0x00, address[0], address[1], engineDirection, (byte) 0x00, (byte) 0x00, (byte) 0x00}; + this.writeDatagram(ip, port, out); + } + + public void changeSwitchDirection(int mfxAddress, int newSwitchDirection){ + byte switchDirection = (byte) Math.floor(newSwitchDirection%256); + byte[] address = {(byte) Math.floor(mfxAddress/256), (byte) Math.floor(mfxAddress%256)}; + byte[] out = {(byte) 0x00, (byte) 0x16, (byte) 0x07, (byte) 0x78, (byte) 0x06, (byte) 0x00, (byte) 0x00, address[0], address[1], switchDirection, (byte) 0x01, (byte) 0x00, (byte) 0x00}; + this.writeDatagram(ip, port, out); + } + +} diff --git a/Praktikum/VINF_MaerklinControl/build/build/src/server/MaerklinServer.java b/Praktikum/VINF_MaerklinControl/build/build/src/server/MaerklinServer.java new file mode 100644 index 0000000000000000000000000000000000000000..c2774bd217d4ce717b1fc7c705dc880e43323880 --- /dev/null +++ b/Praktikum/VINF_MaerklinControl/build/build/src/server/MaerklinServer.java @@ -0,0 +1,435 @@ +package server; + +import java.io.BufferedInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.ServerSocket; +import java.net.Socket; +import java.util.ArrayList; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +import javax.xml.bind.DatatypeConverter; + +import common.Properties; + +public class MaerklinServer{ + + // Declaration of objects + ArrayList<Socket> clients; + + private MaerklinProtocol protocol; + private UDPListener overwatch; + private ServerThread serverThread; + + final ExecutorService SERVER_THREAD_EXECUTOR; + final ExecutorService CLIENT_THREAD_EXECUTOR; + final ExecutorService UTILITY_THREAD_EXECUTOR; + + private Engine ice; + private Engine lok; + private Engine reichsbahn; + + private Switch switch4; + private Switch switch5; + private Switch switch6; + private Switch switch8; + private Switch switch9; + private Switch switch10; + private Switch switch12; + private Switch switch13; + private Switch switch14; + private Switch switch15; + private Switch turntable; + + public MaerklinServer(){ + + // Initializing + System.out.println("Initializing..."); + + clients = new ArrayList<Socket>(); + + protocol = new MaerklinProtocol(); + overwatch = new UDPListener(); + serverThread = new ServerThread(this); + + SERVER_THREAD_EXECUTOR = Executors.newFixedThreadPool(2); + CLIENT_THREAD_EXECUTOR = Executors.newCachedThreadPool(); + UTILITY_THREAD_EXECUTOR = Executors.newCachedThreadPool(); + + ice = new Engine(); + lok = new Engine(); + reichsbahn = new Engine(); + + switch4 = new Switch(); + switch5 = new Switch(); + switch6 = new Switch(); + switch8 = new Switch(); + switch9 = new Switch(); + switch10 = new Switch(); + switch12 = new Switch(); + switch13 = new Switch(); + switch14 = new Switch(); + switch15 = new Switch(); + turntable = new Switch(); + + // Setting IDs + ice.setEngineID(Properties.ICE_ID); + lok.setEngineID(Properties.LOK_ID); + reichsbahn.setEngineID(Properties.REICHSBAHN_ID); + + switch4.setSwitchID(Properties.SWITCH4_ID); + switch5.setSwitchID(Properties.SWITCH5_ID); + switch6.setSwitchID(Properties.SWITCH6_ID); + switch8.setSwitchID(Properties.SWITCH8_ID); + switch9.setSwitchID(Properties.SWITCH9_ID); + switch10.setSwitchID(Properties.SWITCH10_ID); + switch12.setSwitchID(Properties.SWITCH12_ID); + switch13.setSwitchID(Properties.SWITCH13_ID); + switch14.setSwitchID(Properties.SWITCH14_ID); + switch15.setSwitchID(Properties.SWITCH15_ID); + turntable.setSwitchID(Properties.TURNTABLE_ID); + + // Starting the system and setting ("safe") values + try { + start(); + initialize(); + } + catch (Exception e){ + System.out.println(e.getMessage()); + System.exit(1); + } + } + + // Emergency stop + public void emergencyStop() throws Exception { + protocol.systemStop(); + ice.setEngineSpeed(0); + lok.setEngineSpeed(0); + reichsbahn.setEngineSpeed(0); + } + + // Emergency stop + public void start() throws Exception { + protocol.systemGo(); + } + + // Initialize; setting ("safe") values + public void initialize() throws Exception { + ice.setEngineDirection(1); + ice.setEngineSpeed(0); + + lok.setEngineDirection(1); + lok.setEngineSpeed(0); + + reichsbahn.setEngineDirection(1); + reichsbahn.setEngineSpeed(0); + + switch4.setSwitchDirection(1); + switch5.setSwitchDirection(1); + switch6.setSwitchDirection(1); + switch8.setSwitchDirection(1); + switch9.setSwitchDirection(1); + switch10.setSwitchDirection(1); + switch12.setSwitchDirection(1); + switch13.setSwitchDirection(1); + switch14.setSwitchDirection(1); + switch15.setSwitchDirection(1); + } + + // Starts the listener-thread + public void startListener(){ + SERVER_THREAD_EXECUTOR.submit(overwatch); + } + + // Listens to the client-port and initializes a new Thread to handle the client-messages + public void listen(){ + SERVER_THREAD_EXECUTOR.submit(serverThread); + } + + // Starts the thread to broadcast the current status + public void statusUpdate(){ + for (Socket clientSocket : clients) { + try { + //System.out.println("Updating client: "+clientSocket.getRemoteSocketAddress()); + UTILITY_THREAD_EXECUTOR.submit(new UpdateThread(clientSocket.getOutputStream())); + } + catch (IOException e) { + System.out.println("Failed to receive output-stream of one of the clients!"); + } + } + } + +} + +//Opens a server-port and establishes a new handling-thread for every client that connects to the server +class ServerThread implements Runnable { + + // Declaration of objects + private final MaerklinServer SERVER_INSTANCE; + + // Constructor + ServerThread (MaerklinServer server) { + SERVER_INSTANCE = server; + } + + @Override + public void run() { + try(ServerSocket serverSocket = new ServerSocket(Properties.PORT)){ + serverSocket.setReuseAddress(true); + System.out.println("Server-socket established!"); + while (true) { + Socket socket = serverSocket.accept(); + System.out.println("Connection to client "+socket.getRemoteSocketAddress()+" established!"); + SERVER_INSTANCE.CLIENT_THREAD_EXECUTOR.submit(new ClientThread(SERVER_INSTANCE, socket, socket.getInputStream())); + } + } + catch (Exception e) { + System.out.println("Accessing user-interaction-port failed! Trying again!"); + run(); + } + finally { + SERVER_INSTANCE.SERVER_THREAD_EXECUTOR.shutdownNow(); + SERVER_INSTANCE.CLIENT_THREAD_EXECUTOR.shutdownNow(); + SERVER_INSTANCE.UTILITY_THREAD_EXECUTOR.shutdownNow(); + } + } + +} + +// Handles the communication with the clients in the background +class ClientThread implements Runnable { + + // Declaration of objects + private final Socket CLIENT; + private final BufferedInputStream IN_STREAM; + private final MaerklinServer SERVER_INSTANCE; + byte[] data; + + // Constructor + ClientThread (MaerklinServer server, Socket socket, InputStream in) { + CLIENT = socket; + IN_STREAM = new BufferedInputStream(in); + SERVER_INSTANCE = server; + SERVER_INSTANCE.clients.add(socket); + data = new byte[Properties.IN_BUFFER_SIZE]; + } + + @Override + public void run() { + int buffer; + while (true) { + try { + if (IN_STREAM.available() != 0) { + buffer = IN_STREAM.read(); + if ((byte) buffer == (byte) Properties.SESSION_ABORT) { + SERVER_INSTANCE.clients.remove(CLIENT); + CLIENT.close(); + System.out.println("Conenction to client "+CLIENT.getRemoteSocketAddress()+" aborted!"); + return; + } + else if ((byte) buffer == (byte) Properties.SEPERATOR) { + for (int i = 0; i < Properties.IN_BUFFER_SIZE; i++) { + buffer = IN_STREAM.read(); + if ((byte) buffer == (byte) Properties.SESSION_ABORT) { + SERVER_INSTANCE.clients.remove(CLIENT); + CLIENT.close(); + System.out.println("Connection to client "+CLIENT.getRemoteSocketAddress()+" aborted!"); + return; + } + else { + data[i] = (byte) (buffer%(1<<8)); + } + } + SERVER_INSTANCE.UTILITY_THREAD_EXECUTOR.submit(new HandleThread(SERVER_INSTANCE, data)); + } + } + else { + Thread.sleep(10); + } + } + catch (Exception e) { + System.out.println("An error occured while reading the clients input-stream!"); + SERVER_INSTANCE.clients.remove(CLIENT); + System.out.println("Conenction to client "+CLIENT.getRemoteSocketAddress()+" aborted!"); + return; + } + } + } + +} + +// Processes the incoming datagram and initializes appropriate actions +class HandleThread implements Runnable { + + // Declaration of objects + private final MaerklinServer SERVER_INSTANCE; + byte[] data; + + // Constructor + HandleThread (MaerklinServer server, byte[] incomingData) { + SERVER_INSTANCE = server; + data = incomingData; + } + + @Override + public void run() { + try { + switch (data[2]) { + case Properties.SYSTEM_STOP: + //System.out.println("System stop"); + SERVER_INSTANCE.emergencyStop(); + break; + case Properties.SYSTEM_GO: + //System.out.println("System go"); + SERVER_INSTANCE.start(); + break; + case Properties.GET_STATUS: + //System.out.println("Status update"); + SERVER_INSTANCE.statusUpdate(); + break; + case Properties.ENGINE_SET_SPEED: + for (Engine train : Engine.engines) { + if (train.getEngineID() == ((data[0]&0xFF)*(1<<8)+(data[1]&0xFF))) { + //System.out.println("Set engine speed"); + train.setEngineSpeed((data[3]&0xFF)*(1<<8)+(data[4]&0xFF)); + break; + } + } + break; + case Properties.ENGINE_INCREASE_SPEED: + for (Engine train : Engine.engines) { + if (train.getEngineID() == ((data[0]&0xFF)*(1<<8)+(data[1]&0xFF))) { + //System.out.println("Increase engine speed"); + train.increaseEngineSpeed(); + break; + } + } + break; + case Properties.ENGINE_DECREASE_SPEED: + for (Engine train : Engine.engines) { + if (train.getEngineID() == ((data[0]&0xFF)*(1<<8)+(data[1]&0xFF))) { + //System.out.println("Decrease engine speed"); + train.decreaseEngineSpeed(); + break; + } + } + break; + case Properties.ENGINE_SET_DIRECTION: + for (Engine train : Engine.engines) { + if (train.getEngineID() == ((data[0]&0xFF)*(1<<8)+(data[1]&0xFF))) { + //System.out.println("Set engine direction"); + train.setEngineDirection(data[3]); + break; + } + } + break; + case Properties.ENGINE_SWITCH_DIRECTION: + for (Engine train : Engine.engines) { + if (train.getEngineID() == ((data[0]&0xFF)*(1<<8)+(data[1]&0xFF))) { + //System.out.println("Switch engine direction"); + train.setEngineDirection(3); + break; + } + } + break; + case Properties.SWITCH_SET_DIRECTION: + for (Switch sw : Switch.switches) { + if (sw.getSwitchID() == ((data[0]&0xFF)*(1<<8)+(data[1]&0xFF))) { + //System.out.println("Set switch direction"); + sw.setSwitchDirection(data[3]); + break; + } + } + break; + case Properties.SWITCH_SWITCH_DIRECTION: + for (Switch sw : Switch.switches) { + if (sw.getSwitchID() == ((data[0]&0xFF)*(1<<8)+(data[1]&0xFF))) { + //System.out.println("Switch switch direction"); + sw.changeSwitchDirection(); + break; + } + } + break; + default: + System.out.println("No viable command!\n"); + } + } + catch (Exception e) { + System.out.println(e.getMessage()); + } + } + +} + +//Broadcasts the current status +class UpdateThread implements Runnable { + + // Declaration of objects + private final OutputStream OUT_STREAM; + private byte[] outgoingData; + + // Constructor + UpdateThread (OutputStream out) { + + // Setting the broadcast-port + OUT_STREAM = out; + + // Initializing + outgoingData = new byte[Properties.OUT_BUFFER_SIZE]; + } + + // Reads every registered objects data into outgoingData and broadcasts the status + @Override + public void run() { + int position = 0; + try { + outgoingData[position++] = Properties.SEPERATOR; + outgoingData[position++] = Properties.SEPERATOR; + for (Engine train : Engine.engines) { + if (position >= Properties.OUT_BUFFER_SIZE-9) { + Exception e = new Exception("Overload of registered elements! Update-buffer too small!"); + throw e; + } + outgoingData[position++] = (byte) ((train.getEngineID()/(1<<8))%(1<<8)); + outgoingData[position++] = (byte) ((train.getEngineID()%(1<<8))); + outgoingData[position++] = (byte) ((train.getEngineSpeed()/(1<<8))%(1<<8)); + outgoingData[position++] = (byte) ((train.getEngineSpeed()%(1<<8))); + outgoingData[position++] = (byte) ((train.getEngineDirection()%(1<<24))); + outgoingData[position++] = Properties.SEPERATOR; + } + outgoingData[position++] = Properties.SEPERATOR; + outgoingData[position++] = Properties.SEPERATOR; + outgoingData[position++] = Properties.SEPERATOR; + for (Switch sw : Switch.switches) { + if (position >= Properties.OUT_BUFFER_SIZE-10) { + Exception e = new Exception("Overload of registered elements! Update-buffer too small!"); + throw e; + } + outgoingData[position++] = (byte) ((sw.getSwitchID()/(1<<8))%(1<<8)); + outgoingData[position++] = (byte) ((sw.getSwitchID()%(1<<8))); + outgoingData[position++] = (byte) 0x00; + outgoingData[position++] = (byte) 0x00; + outgoingData[position++] = (byte) ((sw.getSwitchDirection()%(1<<24))); + outgoingData[position++] = Properties.SEPERATOR; + } + outgoingData[position++] = Properties.SEPERATOR; + outgoingData[position++] = Properties.SEPERATOR; + outgoingData[position++] = Properties.SEPERATOR; + outgoingData[position++] = Properties.SEPERATOR; + } + catch (Exception e) { + System.out.println(e.getMessage()); + e.printStackTrace(); + } + //System.out.printf("\nSende: " + DatatypeConverter.printHexBinary(outgoingData)); + try { + OUT_STREAM.write(outgoingData, 0, Properties.OUT_BUFFER_SIZE); + } + catch (Exception e) { + System.out.println("Communication-error whilst status-update!"); + } + } + +} diff --git a/Praktikum/VINF_MaerklinControl/build/build/src/server/MaerklinServerApplication.java b/Praktikum/VINF_MaerklinControl/build/build/src/server/MaerklinServerApplication.java new file mode 100644 index 0000000000000000000000000000000000000000..7bbd8c583b8818b0232a810ef61c347e928926ab --- /dev/null +++ b/Praktikum/VINF_MaerklinControl/build/build/src/server/MaerklinServerApplication.java @@ -0,0 +1,37 @@ +package server; + +public class MaerklinServerApplication { + + // Defining a threshold value for when the status-update is to be executed (in milliseconds) + private final static long updateThreshold = 500; + + public static void main(String[] args) { + + // Creating timestamp for the update-functionality + long timestamp = System.currentTimeMillis(); + + // Calling constructor + MaerklinServer server = new MaerklinServer(); + + // Starting listener-thread + server.startListener(); + + // Starting the client-handling + server.listen(); + + while (true){ + if (System.currentTimeMillis()-timestamp >= updateThreshold) { + server.statusUpdate(); + timestamp = System.currentTimeMillis(); + } + else { + try { + Thread.sleep(50); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + } + +} diff --git a/Praktikum/VINF_MaerklinControl/build/build/src/server/Switch.java b/Praktikum/VINF_MaerklinControl/build/build/src/server/Switch.java new file mode 100644 index 0000000000000000000000000000000000000000..ea03fbf954828e18a33f0b2dd72dabe69f806f16 --- /dev/null +++ b/Praktikum/VINF_MaerklinControl/build/build/src/server/Switch.java @@ -0,0 +1,77 @@ +package server; + +import java.util.ArrayList; + +public class Switch { + + static ArrayList<Switch> switches; + + private int switchID; + int switchDirection; + + private MaerklinProtocol udpProtocol; + private UDPListener listener; + + public Switch(){ + this(0, 1); + + // For offline-debugging + /*if (switches == null) { + switches = new ArrayList<Switch>(); + } + udpProtocol = new MaerklinProtocol(); + listener = new UDPListener(); + switches.add(this); + switchID = 0; + switchDirection = 1;*/ + } + + public Switch(int id, int direction){ + if (switches == null) { + switches = new ArrayList<Switch>(); + } + udpProtocol = new MaerklinProtocol(); + listener = new UDPListener(); + switches.add(this); + try { + setSwitchID(id); + setSwitchDirection(direction); + } + catch(Exception e){ + System.out.println(e.getMessage()); + } + } + + public void setSwitchID(int newSwitchID){ + switchID = newSwitchID; + } + + public void setSwitchDirection(int newSwitchDirection) throws Exception { + if (newSwitchDirection == 0x01 || newSwitchDirection == 0x00){ + switchDirection = newSwitchDirection; + } + else { + Exception e = new Exception("No viable switch direction!"); + throw e; + } + udpProtocol.changeSwitchDirection(switchID, switchDirection); + } + + public void changeSwitchDirection() throws Exception { + if (switchDirection == 0x00){ + setSwitchDirection(0x01); + } + else { + setSwitchDirection(0x00); + } + } + + public int getSwitchID(){ + return switchID; + } + + public int getSwitchDirection(){ + return switchDirection; + } + +} diff --git a/Praktikum/VINF_MaerklinControl/build/build/src/server/UDPListener.java b/Praktikum/VINF_MaerklinControl/build/build/src/server/UDPListener.java new file mode 100644 index 0000000000000000000000000000000000000000..0563ea5fa357bd093b18b96b28b25408bf8b7f23 --- /dev/null +++ b/Praktikum/VINF_MaerklinControl/build/build/src/server/UDPListener.java @@ -0,0 +1,131 @@ +package server; + + +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import javax.xml.bind.DatatypeConverter; + +public class UDPListener implements Runnable{ + + private final static int port = 15730; + + private byte[] in = new byte[13]; + + public UDPListener(){ + // Nothing to do... + } + + public void listen(){ + try(DatagramSocket socket = new DatagramSocket(port)){ + socket.setReuseAddress(true); + DatagramPacket incomingData = new DatagramPacket(in, in.length); + socket.receive(incomingData); + in = incomingData.getData(); + } + catch (Exception e) { + e.printStackTrace(); + } + } + + public byte[] getData(){ + return in; + } + + public int getEngineSpeed(){ + return ((in[9]&0xFF)*(1<<8)+(in[10]&0xFF)); + } + + public int getEngineDirection(){ + return (in[9]&0xFF); + } + + public int getSwitchDirection(){ + return (in[9]&0xFF); + } + + public int getAddress(){ + return ((in[7]&0xFF)*(1<<8)+(in[8]&0xFF)); + } + + public int getCommand(){ + return ((in[1]&0xFF)&0xFE); + } + + public boolean isAnswer(){ + if ((in[1]&0x01) == 1){ + return true; + } + else { + return false; + } + } + + public void printData(byte[] data){ + try{ + byte[] kennung = new byte[4]; + byte[] laenge = new byte[1]; + byte[] nutzdaten = new byte[8]; + System.arraycopy(data, 0, kennung, 0, 4); + System.arraycopy(data, 4, laenge, 0, 1); + System.arraycopy(data, 5, nutzdaten, 0, 8); + System.out.print("\n\nKennung DLC Nutzdaten\n" + DatatypeConverter.printHexBinary(kennung) + " " + DatatypeConverter.printHexBinary(laenge) + " " + DatatypeConverter.printHexBinary(nutzdaten)); + } + catch(Exception e){ + e.printStackTrace(); + } + } + + public static void main(String args[]){ + UDPListener testListener = new UDPListener(); + while (true){ + testListener.listen(); + testListener.printData(testListener.getData()); + } + } + + @Override + public void run() { + //System.out.println("UDPListener start!"); + try(DatagramSocket socket = new DatagramSocket(port)){ + socket.setReuseAddress(true); + while (true){ + DatagramPacket incomingData = new DatagramPacket(in, in.length); + socket.receive(incomingData); + in = incomingData.getData(); + if (isAnswer()){ + if (getCommand() == 0x08){ + for (Engine train : Engine.engines){ + if (train.getEngineID() == getAddress()){ + train.engineSpeed = getEngineSpeed(); + //System.out.println("Speed of Engine "+train.getEngineID()+" changed to "+train.getEngineSpeed()); + break; + } + } + } + else if (getCommand() == 0x0A){ + for (Engine train : Engine.engines){ + if (train.getEngineID() == getAddress()){ + train.engineDirection = getEngineDirection(); + //System.out.println("Direction of Engine "+train.getEngineID()+" changed to "+train.getEngineDirection()); + break; + } + } + } + else if (getCommand() == 0x16){ + for (Switch sw : Switch.switches){ + if (sw.getSwitchID() == getAddress()){ + sw.switchDirection = getEngineDirection(); + //System.out.println("Direction of Switch "+sw.getSwitchID()+" changed to "+sw.getSwitchDirection()); + break; + } + } + } + } + } + } + catch (Exception e) { + e.printStackTrace(); + } + } + +} diff --git a/Praktikum/VINF_MaerklinControl/build/deploy/VINF_MaerklinControl.html b/Praktikum/VINF_MaerklinControl/build/deploy/VINF_MaerklinControl.html new file mode 100644 index 0000000000000000000000000000000000000000..86056ec22a15614e3781e9c34b8feacbd913234e --- /dev/null +++ b/Praktikum/VINF_MaerklinControl/build/deploy/VINF_MaerklinControl.html @@ -0,0 +1,43 @@ +<html><head> + <SCRIPT src="http://java.com/js/dtjava.js"></SCRIPT> +<script> + function launchApplication(jnlpfile) { + dtjava.launch( { + url : 'VINF_MaerklinControl.jnlp' + }, + { + javafx : '8.0+' + }, + {} + ); + return false; + } +</script> + +<script> + function javafxEmbedfxApplication() { + dtjava.embed( + { + id : 'fxApplication', + url : 'VINF_MaerklinControl.jnlp', + placeholder : 'javafx-app-placeholder', + width : '0', + height : '0' + }, + { + javafx : '8.0+' + }, + {} + ); + } + <!-- Embed FX application into web page once page is loaded --> + dtjava.addOnloadCallback(javafxEmbedfxApplication); +</script> + +</head><body> +<h2>Test page for <b>M�rklin Control</b></h2> + <b>Webstart:</b> <a href='VINF_MaerklinControl.jnlp' onclick="return launchApplication('VINF_MaerklinControl.jnlp');">click to launch this app as webstart</a><br><hr><br> + + <!-- Applet will be inserted here --> + <div id='javafx-app-placeholder'></div> +</body></html> diff --git a/Praktikum/VINF_MaerklinControl/build/deploy/VINF_MaerklinControl.jar b/Praktikum/VINF_MaerklinControl/build/deploy/VINF_MaerklinControl.jar new file mode 100644 index 0000000000000000000000000000000000000000..eef9eff31d7e45750a5e98aa91e50f3936ac93ab Binary files /dev/null and b/Praktikum/VINF_MaerklinControl/build/deploy/VINF_MaerklinControl.jar differ diff --git a/Praktikum/VINF_MaerklinControl/build/deploy/VINF_MaerklinControl.jnlp b/Praktikum/VINF_MaerklinControl/build/deploy/VINF_MaerklinControl.jnlp new file mode 100644 index 0000000000000000000000000000000000000000..3ab857f01d6515f467880fcb681e6964f935ab30 --- /dev/null +++ b/Praktikum/VINF_MaerklinControl/build/deploy/VINF_MaerklinControl.jnlp @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="utf-8"?> +<jnlp spec="1.0" xmlns:jfx="http://javafx.com" href="VINF_MaerklinControl.jnlp"> + <information> + <title>VINF_MaerklinControl</title> + <vendor>lf.ps</vendor> + <description>M�rklin Control</description> + <offline-allowed/> + </information> + <resources> + <j2se version="1.6+" href="http://java.sun.com/products/autodl/j2se"/> + <jar href="VINF_MaerklinControl.jar" size="38833" download="eager" /> + <jar href="libs\controlsfx-8.40.12.jar" size="996389" download="eager" /> + </resources> + <jfx:javafx-desc width="0" height="0" main-class="gui.MainApp" name="M�rklin Control" /> + <update check="background"/> +</jnlp> diff --git "a/Praktikum/VINF_MaerklinControl/build/deploy/bundles/M\303\244rklin Control-0.9.exe" "b/Praktikum/VINF_MaerklinControl/build/deploy/bundles/M\303\244rklin Control-0.9.exe" new file mode 100644 index 0000000000000000000000000000000000000000..e539f1e1ed6e882be7ae930c20c4b4711e7b1b8e Binary files /dev/null and "b/Praktikum/VINF_MaerklinControl/build/deploy/bundles/M\303\244rklin Control-0.9.exe" differ diff --git a/Praktikum/VINF_MaerklinControl/build/deploy/libs/controlsfx-8.40.12.jar b/Praktikum/VINF_MaerklinControl/build/deploy/libs/controlsfx-8.40.12.jar new file mode 100644 index 0000000000000000000000000000000000000000..212a66cfc2c408bb7953c0b57d4b9deb0a30a7c5 Binary files /dev/null and b/Praktikum/VINF_MaerklinControl/build/deploy/libs/controlsfx-8.40.12.jar differ diff --git a/Praktikum/VINF_MaerklinControl/build/dist/VINF_MaerklinControl.jar b/Praktikum/VINF_MaerklinControl/build/dist/VINF_MaerklinControl.jar new file mode 100644 index 0000000000000000000000000000000000000000..eef9eff31d7e45750a5e98aa91e50f3936ac93ab Binary files /dev/null and b/Praktikum/VINF_MaerklinControl/build/dist/VINF_MaerklinControl.jar differ diff --git a/Praktikum/VINF_MaerklinControl/build/dist/libs/controlsfx-8.40.12.jar b/Praktikum/VINF_MaerklinControl/build/dist/libs/controlsfx-8.40.12.jar new file mode 100644 index 0000000000000000000000000000000000000000..212a66cfc2c408bb7953c0b57d4b9deb0a30a7c5 Binary files /dev/null and b/Praktikum/VINF_MaerklinControl/build/dist/libs/controlsfx-8.40.12.jar differ diff --git a/Praktikum/VINF_MaerklinControl/build/externalLibs/controlsfx-8.40.12.jar b/Praktikum/VINF_MaerklinControl/build/externalLibs/controlsfx-8.40.12.jar new file mode 100644 index 0000000000000000000000000000000000000000..212a66cfc2c408bb7953c0b57d4b9deb0a30a7c5 Binary files /dev/null and b/Praktikum/VINF_MaerklinControl/build/externalLibs/controlsfx-8.40.12.jar differ diff --git a/Praktikum/VINF_MaerklinControl/build/package/dist/res/BR 86.png b/Praktikum/VINF_MaerklinControl/build/package/dist/res/BR 86.png new file mode 100644 index 0000000000000000000000000000000000000000..ade033a2d89e5b1722783efd994f52b6c843a090 Binary files /dev/null and b/Praktikum/VINF_MaerklinControl/build/package/dist/res/BR 86.png differ diff --git a/Praktikum/VINF_MaerklinControl/build/package/dist/res/E 50.png b/Praktikum/VINF_MaerklinControl/build/package/dist/res/E 50.png new file mode 100644 index 0000000000000000000000000000000000000000..274060003d8650342a14a37e2501166ec8584c4a Binary files /dev/null and b/Praktikum/VINF_MaerklinControl/build/package/dist/res/E 50.png differ diff --git a/Praktikum/VINF_MaerklinControl/build/package/dist/res/ICE 1.png b/Praktikum/VINF_MaerklinControl/build/package/dist/res/ICE 1.png new file mode 100644 index 0000000000000000000000000000000000000000..877f549943aa4d160db9bcd6e0cb544143f1a60a Binary files /dev/null and b/Praktikum/VINF_MaerklinControl/build/package/dist/res/ICE 1.png differ diff --git a/Praktikum/VINF_MaerklinControl/build/package/dist/res/MagIcon_00_00_a.png b/Praktikum/VINF_MaerklinControl/build/package/dist/res/MagIcon_00_00_a.png new file mode 100644 index 0000000000000000000000000000000000000000..8d7d3b3668711e4465f14c8df8e95322e6e753ae Binary files /dev/null and b/Praktikum/VINF_MaerklinControl/build/package/dist/res/MagIcon_00_00_a.png differ diff --git a/Praktikum/VINF_MaerklinControl/build/package/dist/res/MagIcon_00_00_i.png b/Praktikum/VINF_MaerklinControl/build/package/dist/res/MagIcon_00_00_i.png new file mode 100644 index 0000000000000000000000000000000000000000..33f8dda4e9fd0fdd879776581a92c5218182a7a5 Binary files /dev/null and b/Praktikum/VINF_MaerklinControl/build/package/dist/res/MagIcon_00_00_i.png differ diff --git a/Praktikum/VINF_MaerklinControl/build/package/dist/res/MagIcon_00_01_a.png b/Praktikum/VINF_MaerklinControl/build/package/dist/res/MagIcon_00_01_a.png new file mode 100644 index 0000000000000000000000000000000000000000..1cbaed4e9e8757ea73a758be0d2321f4d42426f2 Binary files /dev/null and b/Praktikum/VINF_MaerklinControl/build/package/dist/res/MagIcon_00_01_a.png differ diff --git a/Praktikum/VINF_MaerklinControl/build/package/dist/res/MagIcon_00_01_i.png b/Praktikum/VINF_MaerklinControl/build/package/dist/res/MagIcon_00_01_i.png new file mode 100644 index 0000000000000000000000000000000000000000..1c8d8dbfba1b1652c6250919a2ccf4fc128dcc1e Binary files /dev/null and b/Praktikum/VINF_MaerklinControl/build/package/dist/res/MagIcon_00_01_i.png differ diff --git a/Praktikum/VINF_MaerklinControl/build/package/dist/res/bo.png b/Praktikum/VINF_MaerklinControl/build/package/dist/res/bo.png new file mode 100644 index 0000000000000000000000000000000000000000..d6a76b9318eb4b1ad635ef7ce5fff9bbe8033f12 Binary files /dev/null and b/Praktikum/VINF_MaerklinControl/build/package/dist/res/bo.png differ diff --git "a/Praktikum/VINF_MaerklinControl/build/package/windows/M\303\244rklin Control.ico" "b/Praktikum/VINF_MaerklinControl/build/package/windows/M\303\244rklin Control.ico" new file mode 100644 index 0000000000000000000000000000000000000000..e49d052447d0d4c8cfb926db4bdf3d8019348cb6 Binary files /dev/null and "b/Praktikum/VINF_MaerklinControl/build/package/windows/M\303\244rklin Control.ico" differ diff --git a/Praktikum/VINF_MaerklinControl/build/project/src/common/Properties.java b/Praktikum/VINF_MaerklinControl/build/project/src/common/Properties.java new file mode 100644 index 0000000000000000000000000000000000000000..144b96d85315ffd068b2e2bba3fc0cd2b7b83e47 --- /dev/null +++ b/Praktikum/VINF_MaerklinControl/build/project/src/common/Properties.java @@ -0,0 +1,45 @@ +package common; + +public class Properties { + + // Defining server-ip and port + public final static int PORT = 23456; + + // Setting ports and defining size of the buffers + public final static int IN_BUFFER_SIZE = 5; // First and second byte: accessory-ID, third byte: command, fourth and fifth byte: potential parameters + public final static int OUT_BUFFER_SIZE = 128; + + // Defining client-commands + public final static byte SEPERATOR = (byte) 0xFE; + + public final static int SESSION_ABORT = -1; + + public final static byte SYSTEM_STOP = 0x00; + public final static byte SYSTEM_GO = 0x01; + public final static byte GET_STATUS = 0x02; + public final static byte ENGINE_SET_SPEED = 0x03; + public final static byte ENGINE_INCREASE_SPEED = 0x04; + public final static byte ENGINE_DECREASE_SPEED = 0x05; + public final static byte ENGINE_SET_DIRECTION = 0x06; + public final static byte ENGINE_SWITCH_DIRECTION = 0x07; + public final static byte SWITCH_SET_DIRECTION = 0x08; + public final static byte SWITCH_SWITCH_DIRECTION = 0x09; + + //Defining accessory-ids + public final static int ICE_ID = 0x0002; + public final static int LOK_ID = 0x4005; + public final static int REICHSBAHN_ID = 0x4007; + + public final static int SWITCH4_ID = 0x3003; + public final static int SWITCH5_ID = 0x3004; + public final static int SWITCH6_ID = 0x3005; + public final static int SWITCH8_ID = 0x3007; + public final static int SWITCH9_ID = 0x3008; + public final static int SWITCH10_ID = 0x3009; + public final static int SWITCH12_ID = 0x300B; + public final static int SWITCH13_ID = 0x300C; + public final static int SWITCH14_ID = 0x300D; + public final static int SWITCH15_ID = 0x300E; + public final static int TURNTABLE_ID = 0x30E2; + +} diff --git a/Praktikum/VINF_MaerklinControl/build/project/src/gui/MainApp.java b/Praktikum/VINF_MaerklinControl/build/project/src/gui/MainApp.java new file mode 100644 index 0000000000000000000000000000000000000000..fc13d4868095e42e0f3b2e05a0c12f5a6cbb7165 --- /dev/null +++ b/Praktikum/VINF_MaerklinControl/build/project/src/gui/MainApp.java @@ -0,0 +1,484 @@ +package gui; +import java.io.BufferedInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.Socket; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +import javax.xml.bind.DatatypeConverter; + +import gui.model.Engine; +import gui.model.Switch; +import gui.model.Settings; +import gui.view.EngineController; +import gui.view.TurntableController; +import gui.view.RootLayoutController; +import gui.view.SettingsController; +import gui.view.SwitchListController; +import javafx.application.Application; +import javafx.application.Platform; +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; +import javafx.fxml.FXMLLoader; +import javafx.scene.Scene; +import javafx.scene.control.Tab; +import javafx.scene.image.Image; +import javafx.scene.layout.AnchorPane; +import javafx.scene.layout.BorderPane; +import javafx.stage.Stage; +import common.Properties; + +public class MainApp extends Application { + + private Stage primaryStage; + private BorderPane rootLayout; + private RootLayoutController rootController; + + private AnchorPane enginePane, turntablePane, settingsPane, switchListPane; + private EngineController engineController; + private SwitchListController switchListController; + private TurntableController turntableController; + + private Settings configuration; + private SettingsController settingsController; + + private ObservableList<Tab> tabs = FXCollections.observableArrayList(); + private ObservableList<Switch> switches = FXCollections.observableArrayList(); + private ObservableList<Engine> engines = FXCollections.observableArrayList(); + private Switch turntable; + + private Socket client; + private InputStream in; + private OutputStream out; + + final ExecutorService UTILITY_THREAD_EXECUTOR; + + private Boolean connectionEstablished = false; + private Boolean running = false; + + /** + * Constructor + */ + public MainApp() { + UTILITY_THREAD_EXECUTOR = Executors.newFixedThreadPool(2); + + configuration = new Settings(); + + // Add the already known engines + engines.add(new Engine("ICE", Properties.ICE_ID, "res/ICE 1.png")); + engines.add(new Engine("Dampflok", Properties.LOK_ID, "res/BR 86.png")); + engines.add(new Engine("Reichsbahn", Properties.REICHSBAHN_ID, "res/E 50.png")); + + // Add the already known switches // yes, lazy, i know + for (int i=4;i<=15;i++){ + if (i != 11 && i != 7) { + switches.add(new Switch("Weiche "+i, Properties.SWITCH4_ID+i-4)); + } + } + + turntable = new Switch("Drehteller", Properties.TURNTABLE_ID); + + } + + /** + * Returns the objects as an observable list. + * @return + */ + public ObservableList<Tab> getTabs() { + return tabs; + } + + public ObservableList<Engine> getEngines() { + return engines; + } + + public ObservableList<Switch> getSwitches() { + return switches; + } + + + @Override + public void start(Stage primaryStage) { + this.primaryStage = primaryStage; + this.primaryStage.setTitle("M�rklin Control Client"); + this.primaryStage.getIcons().add(new Image("file:res/BO.png")); + initRootLayout(); + initTabs(); + } + + public void initRootLayout() { + try { + // Load root layout from fxml file. + FXMLLoader loader = new FXMLLoader(); + loader.setLocation(MainApp.class.getResource("view/RootLayout.fxml")); + rootLayout = (BorderPane) loader.load(); + rootController = loader.getController(); // only works if loader.load() has been called already + rootController.setMainApp(this); + + // Show the scene containing the root layout. + Scene scene = new Scene(rootLayout); + primaryStage.setScene(scene); + primaryStage.show(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + /** + * Shows the control tabs inside the root layout. + */ + public void initTabs() { + try { + FXMLLoader loader = new FXMLLoader(); + + loader.setLocation(MainApp.class.getResource("view/Engine.fxml")); + enginePane = loader.load(); + engineController = loader.getController(); // only works if loader.load() has been called already + engineController.setMainApp(this); + + FXMLLoader switchListLoader = new FXMLLoader(); + switchListLoader.setLocation(MainApp.class.getResource("view/SwitchList.fxml")); + switchListPane = switchListLoader.load(); + switchListController = switchListLoader.getController(); + switchListController.setMainApp(this); + switchListController.setSwitchControls(); + + FXMLLoader turntableLoader = new FXMLLoader(); + turntableLoader.setLocation(MainApp.class.getResource("view/Turntable.fxml")); + turntablePane = turntableLoader.load(); + turntableController = turntableLoader.getController(); + turntableController.setMainApp(this); + + FXMLLoader settingsLoader = new FXMLLoader(); + settingsLoader.setLocation(MainApp.class.getResource("view/Settings.fxml")); + settingsPane = settingsLoader.load(); + settingsController = settingsLoader.getController(); + settingsController.setMainApp(this); + settingsController.setSettings(configuration); + + // Add the tabs + tabs.add(new Tab("Loks", enginePane)); + tabs.add(new Tab("Weichen", switchListPane)); + tabs.add(new Tab("Drehteller", turntablePane)); + tabs.add(new Tab("Einstellungen", settingsPane)); + rootController.loadTabs(); + + } catch (IOException e) { + e.printStackTrace(); + } + + } + + /** + * Returns the main stage. + * @return + */ + + public void setStatus(String status){ + rootController.setStatus(status); + } + + public Stage getPrimaryStage() { + return primaryStage; + } + + public static void main(String[] args) { + launch(args); + } + + public void emergencyStopHandler() { + emergencyStop(); + for(Engine eng:engines){ + eng.setSpeed(0); + } + engineController.updateEngineStatus(); + setStatus("NOTAUS"); + + } + + public void emergencyStop () { + if (connectionEstablished) { + try { + if (running) { + byte[] datagram = {Properties.SEPERATOR, (byte) 0x00, (byte) 0x00, (byte) Properties.SYSTEM_STOP, (byte) 0x00, (byte) 0x00}; + out.write(datagram); + running = false; + } + else { + byte[] datagram = {Properties.SEPERATOR, (byte) 0x00, (byte) 0x00, (byte) Properties.SYSTEM_GO, (byte) 0x00, (byte) 0x00}; + out.write(datagram); + running = true; + } + } catch (Exception e) { + setStatus("Error at: emergencyStop"); + e.printStackTrace(); + } + } + } + + public Boolean getConnectionEstablished() { + return connectionEstablished; + } + + public void setEngineDirection (Engine eng) { + if (connectionEstablished) { + try { + byte dir; + if (eng.getDirection().get()) + dir = (byte) 0x01; + else + dir = (byte) 0x02; + + byte[] datagram = {Properties.SEPERATOR, (byte) ((eng.getMaerklinID().get()/(1<<8))%(1<<8)), (byte) (eng.getMaerklinID().get()%(1<<8)), (byte) Properties.ENGINE_SET_DIRECTION, dir, (byte) 0x00}; + out.write(datagram); + } catch (Exception e) { + setStatus("Error at: engineSetDirectionRight"); + e.printStackTrace(); + } + } + } + + public void setEngineSpeed (Engine eng) { + if (connectionEstablished) { + try { + int newEngineSpeed = eng.getSpeed().get(); + byte[] datagram = {Properties.SEPERATOR, (byte) ((eng.getMaerklinID().get()/(1<<8))%(1<<8)), (byte) (eng.getMaerklinID().get()%(1<<8)), (byte) Properties.ENGINE_SET_SPEED, (byte) ((newEngineSpeed/(1<<8))%(1<<8)), (byte) (newEngineSpeed%(1<<8))}; + out.write(datagram); + } catch (Exception e) { + setStatus("engineSetSpeed"); + e.printStackTrace(); + } + } + } + + public void setSwitchState (Switch sw) { + if (connectionEstablished) { + try { + byte dir; + if (!sw.getState().get()) //gerade + dir = (byte) 0x01; + else //krumm + dir = (byte) 0x00; + + byte[] datagram = {Properties.SEPERATOR, (byte) ((sw.getMaerklinID().get()/(1<<8))%(1<<8)), (byte) (sw.getMaerklinID().get()%(1<<8)), (byte) Properties.SWITCH_SET_DIRECTION, dir, (byte) 0x00}; + out.write(datagram); + } catch (Exception e) { + setStatus("Error at: setSwitchState"); + e.printStackTrace(); + } + } + } + + public void turntableTurnCW () { + if (connectionEstablished) { + try { + byte[] datagram = {Properties.SEPERATOR, (byte) ((turntable.getMaerklinID().get()/(1<<8))%(1<<8)), (byte) (turntable.getMaerklinID().get()%(1<<8)), (byte) Properties.SWITCH_SET_DIRECTION, (byte) 0x00, (byte) 0x00}; + out.write(datagram); + } catch (Exception e) { + setStatus("Error at: turntableTurnCW"); + e.printStackTrace(); + } + } + } + + public void turntableTurnCCW () { + if (connectionEstablished) { + try { + byte[] datagram = {Properties.SEPERATOR, (byte) ((turntable.getMaerklinID().get()/(1<<8))%(1<<8)), (byte) (turntable.getMaerklinID().get()%(1<<8)), (byte) Properties.SWITCH_SET_DIRECTION, (byte) 0x01, (byte) 0x00}; + out.write(datagram); + } catch (Exception e) { + setStatus("Error at: turntableTurnCCW"); + e.printStackTrace(); + } + } + } + + public void establishConnetion () { + if (connectionEstablished) { + try { + byte[] datagram = {Properties.SEPERATOR, (byte) 0x00, (byte) 0x00, (byte) Properties.SESSION_ABORT, (byte) 0x00, (byte) 0x00}; + out.write(datagram); + client.close(); + connectionEstablished = false; + running = false; + settingsController.updateSettingsStatus(); + + } catch (Exception e) { + setStatus("Error at: establishConnection (shutting down connection"); + e.printStackTrace(); + } + } + else { + UTILITY_THREAD_EXECUTOR.submit((new EstablishConnection(this))); + } + } + + class EstablishConnection implements Runnable { + + private final MainApp CONTROLLER_INSTANCE; + + EstablishConnection (MainApp controller) { + CONTROLLER_INSTANCE = controller; + } + + @Override + public void run() { + Thread.yield(); + if (!connectionEstablished) { + try (Socket socket = new Socket(configuration.getSocketAddress().get().getHostName(), configuration.getSocketAddress().get().getPort())) { + client = socket; + client.setKeepAlive(true); + client.setReuseAddress(true); + in = client.getInputStream(); + out = client.getOutputStream(); + connectionEstablished = true; + running = true; + UTILITY_THREAD_EXECUTOR.submit((new UpdateFunctionality(CONTROLLER_INSTANCE, in))); + Platform.runLater(new Runnable() { + + @Override + public void run() { + CONTROLLER_INSTANCE.setStatus("Verbindung zu "+client.getRemoteSocketAddress()+" aufgebaut!"); + CONTROLLER_INSTANCE.settingsController.updateSettingsStatus(); + } + + }); + while (connectionEstablished) { + Thread.sleep(100); + } + } + catch (Exception e) { + Platform.runLater(new Runnable() { + + @Override + public void run() { + CONTROLLER_INSTANCE.setStatus("Error at: establishConnection (establishing connection"); + } + + }); + e.printStackTrace(); + } + finally { + CONTROLLER_INSTANCE.UTILITY_THREAD_EXECUTOR.shutdownNow(); + } + } + } + } + + class UpdateFunctionality implements Runnable { + + private final MainApp CONTROLLER_INSTANCE; + private final BufferedInputStream INPUT_STREAM; + + UpdateFunctionality (MainApp controller, InputStream in) { + CONTROLLER_INSTANCE = controller; + INPUT_STREAM = new BufferedInputStream(in, Properties.OUT_BUFFER_SIZE); + } + + public void parseDatagram (byte[] datagram) { + System.out.println("2: "+DatatypeConverter.printHexBinary(datagram)); + if (datagram.length < 5) { + setStatus("Error while updating!"); + return; + } + for (Engine eng : engines){ + if(eng.getMaerklinID().get()==((datagram[0]&0xFF)*(1<<8)+(datagram[1]&0xFF))){ + int engSpeed = (datagram[2]&0xFF)*(1<<8)+(datagram[3]&0xFF); + boolean engDirection = (datagram[4] == (0x01)); + if (engSpeed != eng.getSpeed().get()) { + eng.setSpeed(engSpeed); + //System.out.println("Setting speed of engine "+(datagram[0]&0xFF)*(1<<8)+(datagram[1]&0xFF)+" to "+(datagram[2]&0xFF)*(1<<8)+(datagram[3]&0xFF)+"."); + } + if (engDirection != eng.getDirection().get()) { + eng.setDirection(engDirection); + //System.out.println("Setting direction of engine "+(datagram[0]&0xFF)*(1<<8)+(datagram[1]&0xFF)+" to "+datagram[4]+"."); + } + if (eng.equals(engineController.getSelectedEngine())){} + } + } + for (Switch sw : switches){ + if(sw.getMaerklinID().get()==((datagram[0]&0xFF)*(1<<8)+(datagram[1]&0xFF))){ + boolean swState = !(datagram[4] == (byte) 0x01); + if (swState != sw.getState().get()) { + sw.setState(swState); + //System.out.println("Setting direction of switch "+(datagram[0]&0xFF)*(1<<8)+(datagram[1]&0xFF)+" to "+ datagram[4]+"."); + } + } + } + } + + public void updateGUI () { + engineController.updateEngineStatus(); + for (Switch sw : switches){ + sw.getController().get().updateSwitchStatus(); + } + } + + @Override + public void run() { + int stopCounter, dataCounter, counter; + byte buffer[] = new byte[Properties.OUT_BUFFER_SIZE]; + byte datagram[] = new byte[Properties.IN_BUFFER_SIZE]; + boolean startByte; + try { + while (connectionEstablished) { + stopCounter = 0; + dataCounter = 0; + counter = 0; + startByte = false; + while (INPUT_STREAM.available() > 0 && stopCounter < 5) { + buffer[counter%Properties.OUT_BUFFER_SIZE] = (byte) INPUT_STREAM.read(); + if (stopCounter == 2) { + startByte = true; + } + if (buffer[counter%Properties.OUT_BUFFER_SIZE] == Properties.SEPERATOR && dataCounter != 4) { + dataCounter = 0; + stopCounter++; + } + else { + stopCounter = 0; + dataCounter++; + if (dataCounter == 5 && startByte) { + dataCounter = 0; + for (int i = 0; i < Properties.IN_BUFFER_SIZE; i++) { + datagram[i] = buffer[counter-Properties.IN_BUFFER_SIZE+i+1]; + } + System.out.println("1: "+DatatypeConverter.printHexBinary(datagram)); + parseDatagram(datagram); + } + else if (dataCounter > 5 && startByte) { + throw (new Exception("Wrong data-update-format!")); + } + } + counter++; + } + while (INPUT_STREAM.available() != 0) { + INPUT_STREAM.read(); + } + Platform.runLater(new Runnable() { + + @Override + public void run() { + updateGUI(); + } + + }); + Thread.sleep(50); + } + } + catch (Exception e) { + e.printStackTrace(); + Platform.runLater(new Runnable() { + + @Override + public void run() { + CONTROLLER_INSTANCE.setStatus("Error while updating!"); + } + + }); + } + } + } +} \ No newline at end of file diff --git a/Praktikum/VINF_MaerklinControl/build/project/src/gui/model/Engine.java b/Praktikum/VINF_MaerklinControl/build/project/src/gui/model/Engine.java new file mode 100644 index 0000000000000000000000000000000000000000..75b59b24d1c4d633f9426b0e47d41eabe22a504f --- /dev/null +++ b/Praktikum/VINF_MaerklinControl/build/project/src/gui/model/Engine.java @@ -0,0 +1,92 @@ +package gui.model; + +import javafx.beans.property.IntegerProperty; +import javafx.beans.property.ObjectProperty; + +import javafx.beans.property.BooleanProperty; +import javafx.beans.property.SimpleIntegerProperty; +import javafx.beans.property.SimpleObjectProperty; +import javafx.beans.property.SimpleBooleanProperty; +import javafx.beans.property.SimpleStringProperty; +import javafx.beans.property.StringProperty; +import javafx.scene.image.Image; + +/** + * Model class for a Model Engine. + * + * @author Philipp Stenkamp + */ +public class Engine { + + private final StringProperty name; + private final IntegerProperty id; + private final IntegerProperty speed; + private final BooleanProperty fwd; + private final ObjectProperty<Image> img; + + /** + * Default constructor. + */ + public Engine() { + this(null, null, null); + } + + public Engine(String name, Integer id) { + this(name, id, null); + } + + /** + * Constructor with some initial data. + * + * @param name + * @param id + */ + + public Engine(String name, Integer id, String imgPath) { + this.name = new SimpleStringProperty(name); + this.id = new SimpleIntegerProperty(id); + this.img = new SimpleObjectProperty<Image>(new Image("file:" + imgPath)); + + // Initialize the switch in a straigt (=false) state + this.fwd = new SimpleBooleanProperty(true); + this.speed = new SimpleIntegerProperty(0); + + } + + @Override + public String toString() { + return name.getValue(); + } + + public StringProperty getName() { + return name; + } + + public IntegerProperty getMaerklinID() { + return id; + } + + public BooleanProperty getDirection() { + return fwd; + } + + public void setDirection(Boolean fwd) { + this.fwd.set(fwd); + } + + public IntegerProperty getSpeed() { + return speed; + } + + public void setSpeed(Integer speed) { + this.speed.set(speed); + } + + public ObjectProperty<Image> getImg(){ + return img; + } + + public void setImg(Image img){ + this.img.set(img); + } +} diff --git a/Praktikum/VINF_MaerklinControl/build/project/src/gui/model/Settings.java b/Praktikum/VINF_MaerklinControl/build/project/src/gui/model/Settings.java new file mode 100644 index 0000000000000000000000000000000000000000..a6a737f271c650347fcd7b3d9af0e9db22708841 --- /dev/null +++ b/Praktikum/VINF_MaerklinControl/build/project/src/gui/model/Settings.java @@ -0,0 +1,33 @@ +package gui.model; + +import java.net.InetSocketAddress; + +import common.Properties; +import javafx.beans.property.ObjectProperty; +import javafx.beans.property.SimpleObjectProperty; + + +/** + * Model class for a Model Engine. + * + * @author Philipp Stenkamp + */ +public class Settings { + private final ObjectProperty<InetSocketAddress> server; + + /** + * Default constructor. + */ + public Settings() { + this.server = new SimpleObjectProperty<InetSocketAddress> (new InetSocketAddress("localhost", Properties.PORT)); + } + + public ObjectProperty<InetSocketAddress> getSocketAddress() { + return server; + } + + public void setSocketAddress(InetSocketAddress server) { + this.server.set(server); + } + +} diff --git a/Praktikum/VINF_MaerklinControl/build/project/src/gui/model/Switch.java b/Praktikum/VINF_MaerklinControl/build/project/src/gui/model/Switch.java new file mode 100644 index 0000000000000000000000000000000000000000..6058fb846c77ab7d066974baaa04d7453614a37d --- /dev/null +++ b/Praktikum/VINF_MaerklinControl/build/project/src/gui/model/Switch.java @@ -0,0 +1,85 @@ +package gui.model; + +import javafx.beans.property.IntegerProperty; +import gui.view.SwitchControl; +import javafx.beans.property.BooleanProperty; +import javafx.beans.property.SimpleIntegerProperty; +import javafx.beans.property.SimpleObjectProperty; +import javafx.beans.property.SimpleBooleanProperty; +import javafx.beans.property.SimpleStringProperty; +import javafx.beans.property.StringProperty; +import javafx.beans.property.ObjectProperty; + +/** + * Model class for a Model Train Switch. + * + * @author Philipp Stenkamp + */ +public class Switch{ + + private final StringProperty name; + private final IntegerProperty id; + private final BooleanProperty state; + private final ObjectProperty<SwitchControl> controller; + + /** + * Default constructor. + */ + public Switch() { + this(null, null, null); + } + + /** + * Constructor with some initial data. + * + * @param name + * @param id + */ + + public Switch(String name, Integer id){ + this(name, id, null); + } + + public Switch(String name, Integer id, SwitchControl controller) { + this.name = new SimpleStringProperty(name); + this.id = new SimpleIntegerProperty(id); + this.controller = new SimpleObjectProperty<SwitchControl>(controller); + + // Initialize the switch in a straigt (=false) state + this.state = new SimpleBooleanProperty(false); + + } + + @Override + public String toString() { + return name.getValue(); + } + + public StringProperty getName() { + return name; + } + + public void setName(String name) { + this.name.set(name); + } + + public IntegerProperty getMaerklinID() { + return id; + } + + public BooleanProperty getState() { + return state; + } + + public void setState(Boolean state) { + this.state.set(state); + } + + public ObjectProperty<SwitchControl> getController(){ + return controller; + } + + public void setController(SwitchControl controller){ + this.controller.setValue(controller); + } +} diff --git a/Praktikum/VINF_MaerklinControl/build/project/src/gui/view/Engine.fxml b/Praktikum/VINF_MaerklinControl/build/project/src/gui/view/Engine.fxml new file mode 100644 index 0000000000000000000000000000000000000000..8aea2f6655bb319214b2079f17b9325526cc44fd --- /dev/null +++ b/Praktikum/VINF_MaerklinControl/build/project/src/gui/view/Engine.fxml @@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<?import javafx.geometry.Insets?> +<?import javafx.scene.control.ChoiceBox?> +<?import javafx.scene.control.Slider?> +<?import javafx.scene.control.ToggleButton?> +<?import javafx.scene.control.ToggleGroup?> +<?import javafx.scene.image.ImageView?> +<?import javafx.scene.layout.AnchorPane?> +<?import javafx.scene.layout.HBox?> +<?import javafx.scene.layout.VBox?> + +<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" fx:controller="gui.view.EngineController"> + <children> + <VBox alignment="BOTTOM_CENTER" prefHeight="200.0" prefWidth="100.0" AnchorPane.bottomAnchor="20.0" AnchorPane.leftAnchor="20.0" AnchorPane.rightAnchor="20.0" AnchorPane.topAnchor="0.0"> + <children> + <ImageView fx:id="engineImage" fitHeight="50.0" fitWidth="150.0" pickOnBounds="true" preserveRatio="true"> + <VBox.margin> + <Insets bottom="10.0" /> + </VBox.margin></ImageView> + <Slider fx:id="engineSpeedSlider" showTickLabels="true" showTickMarks="true" /> + <HBox alignment="CENTER" prefWidth="300.0"> + <children> + <ToggleButton fx:id="engineRevButton" mnemonicParsing="false" onAction="#handleEngineDirection" text="<"> + <toggleGroup> + <ToggleGroup fx:id="direction" /> + </toggleGroup></ToggleButton> + <ChoiceBox fx:id="engineChoiceBox" prefWidth="150.0" /> + <ToggleButton fx:id="engineFwdButton" mnemonicParsing="false" onAction="#handleEngineDirection" text=">" toggleGroup="$direction" /> + </children> + </HBox> + </children> + <opaqueInsets> + <Insets right="9.0" /> + </opaqueInsets> + </VBox> + </children> +</AnchorPane> diff --git a/Praktikum/VINF_MaerklinControl/build/project/src/gui/view/EngineController.java b/Praktikum/VINF_MaerklinControl/build/project/src/gui/view/EngineController.java new file mode 100644 index 0000000000000000000000000000000000000000..98eded74290c84c51acddd125d109d3ae4572037 --- /dev/null +++ b/Praktikum/VINF_MaerklinControl/build/project/src/gui/view/EngineController.java @@ -0,0 +1,100 @@ +package gui.view; + +import javafx.beans.value.ChangeListener; +import javafx.beans.value.ObservableValue; +import javafx.fxml.FXML; +import javafx.scene.control.Slider; +import javafx.scene.control.ChoiceBox; +import javafx.scene.control.ToggleButton; +import javafx.scene.image.ImageView; +import gui.MainApp; +import gui.model.Engine; + +public class EngineController { + @FXML + private ImageView engineImage; + @FXML + private Slider engineSpeedSlider; + @FXML + private ChoiceBox<Engine> engineChoiceBox; + @FXML + private ToggleButton engineRevButton, engineFwdButton; + + // Reference to the main application. + private MainApp mainApp; + private Engine eng; + + /** + * The constructor. + * The constructor is called before the initialize() method. + */ + public EngineController() { + } + + /** + * Initializes the controller class. This method is automatically called + * after the fxml file has been loaded. + */ + @FXML + private void initialize() { + engineSpeedSlider.setValue(0); + engineFwdButton.setSelected(true); // initializes the forward Button as pressed + engineChoiceBox.getSelectionModel().selectedItemProperty().addListener( + (observable, oldValue, newValue) -> setSelectedEngine(newValue)); + + engineSpeedSlider.valueProperty().addListener(new ChangeListener<Number>() { + public void changed(ObservableValue<? extends Number> ov, + Number old_val, Number new_val) { + eng.setSpeed(new_val.intValue()*10); + mainApp.setEngineSpeed(eng); + updateEngineStatus(); + } + }); + } + + /** + * Is called by the main application to give a reference back to itself. + * + * @param mainApp + */ + public void setMainApp(MainApp mainApp) { + this.mainApp = mainApp; + engineChoiceBox.setItems(mainApp.getEngines()); + engineChoiceBox.setValue(mainApp.getEngines().get(0)); + engineImage.setImage(mainApp.getEngines().get(0).getImg().get()); + } + + public void handleEngineDirection(){ + eng.setDirection(engineFwdButton.isSelected()); + eng.setSpeed(0); + mainApp.setEngineDirection(eng); + updateEngineStatus(); + } + + public void updateEngineStatus(){ + engineImage.setImage(eng.getImg().get()); + engineSpeedSlider.setValue(eng.getSpeed().get()/10); + + StringBuilder status = new StringBuilder("Letztes Kommando: "); + status.append(eng.toString() + " "); + status.append(eng.getSpeed().get()/10 + "% "); + engineFwdButton.setSelected(eng.getDirection().get()); + engineRevButton.setSelected(!eng.getDirection().get()); + if (eng.getDirection().get()) + status.append("vorw�rts"); + else + status.append("r�ckw�rts"); + mainApp.setStatus(status.toString()); + } + + public void setSelectedEngine(Engine eng){ + this.eng = eng; + mainApp.setStatus(eng.toString() + " ausgew�hlt"); + updateEngineStatus(); + } + + public Engine getSelectedEngine(){ + return eng; + } + +} diff --git a/Praktikum/VINF_MaerklinControl/build/project/src/gui/view/RootLayout.fxml b/Praktikum/VINF_MaerklinControl/build/project/src/gui/view/RootLayout.fxml new file mode 100644 index 0000000000000000000000000000000000000000..4ba58c6ec993ec52eafb3eefce71c76bfe0f9fb4 --- /dev/null +++ b/Praktikum/VINF_MaerklinControl/build/project/src/gui/view/RootLayout.fxml @@ -0,0 +1,60 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<?import javafx.geometry.Insets?> +<?import javafx.scene.control.Button?> +<?import javafx.scene.control.Menu?> +<?import javafx.scene.control.MenuBar?> +<?import javafx.scene.control.MenuItem?> +<?import javafx.scene.control.TabPane?> +<?import javafx.scene.layout.BorderPane?> +<?import javafx.scene.layout.VBox?> +<?import javafx.scene.text.Font?> +<?import org.controlsfx.control.StatusBar?> + +<BorderPane prefHeight="600.0" prefWidth="340.0" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" fx:controller="gui.view.RootLayoutController"> + <top> + <MenuBar BorderPane.alignment="CENTER"> + <menus> + <Menu mnemonicParsing="false" text="File"> + <items> + <MenuItem mnemonicParsing="false" text="Close" /> + </items> + </Menu> + <Menu mnemonicParsing="false" text="Edit"> + <items> + <MenuItem mnemonicParsing="false" text="Delete" /> + </items> + </Menu> + <Menu mnemonicParsing="false" text="Help"> + <items> + <MenuItem mnemonicParsing="false" text="About" /> + </items> + </Menu> + </menus> + </MenuBar> + </top> + <center> + <TabPane fx:id="rootTabPane" prefHeight="200.0" prefWidth="200.0" tabClosingPolicy="UNAVAILABLE" BorderPane.alignment="CENTER"> + <tabs> + </tabs> + </TabPane> + </center> + <bottom> + <VBox alignment="TOP_CENTER" BorderPane.alignment="CENTER"> + <children> + <Button fx:id="emergencyStop" mnemonicParsing="false" onAction="#emergencyStopHandler" prefHeight="50.0" prefWidth="300.0" style="-fx-background-color: red;" text="NOTAUS" textFill="WHITE"> + <padding> + <Insets bottom="10.0" left="5.0" right="5.0" top="5.0" /> + </padding> + <font> + <Font name="System Bold" size="14.0" /> + </font> + <VBox.margin> + <Insets bottom="10.0" top="10.0" /> + </VBox.margin> + </Button> + <StatusBar fx:id="statusBar" /> + </children> + </VBox> + </bottom> +</BorderPane> diff --git a/Praktikum/VINF_MaerklinControl/build/project/src/gui/view/RootLayoutController.java b/Praktikum/VINF_MaerklinControl/build/project/src/gui/view/RootLayoutController.java new file mode 100644 index 0000000000000000000000000000000000000000..f47880d0f782ae54864ad646cee46dc944ef21e3 --- /dev/null +++ b/Praktikum/VINF_MaerklinControl/build/project/src/gui/view/RootLayoutController.java @@ -0,0 +1,35 @@ +package gui.view; + +import javafx.fxml.FXML; +import javafx.scene.control.TabPane; + +import org.controlsfx.control.StatusBar; + +import gui.MainApp; + +public class RootLayoutController { + @FXML + private TabPane rootTabPane; + @FXML + private StatusBar statusBar; + + + // Reference to the main application. + private MainApp mainApp; + + public void setMainApp(MainApp mainApp) { + this.mainApp = mainApp; + } + + public void loadTabs(){ + rootTabPane.getTabs().addAll(mainApp.getTabs()); //can't be in the constructor + } + + public void setStatus(String status){ + statusBar.setText(status); + } + + public void emergencyStopHandler(){ + mainApp.emergencyStopHandler(); + } +} diff --git a/Praktikum/VINF_MaerklinControl/build/project/src/gui/view/Settings.fxml b/Praktikum/VINF_MaerklinControl/build/project/src/gui/view/Settings.fxml new file mode 100644 index 0000000000000000000000000000000000000000..ae4aa387c7b48f44b6543370de2436cd14318546 --- /dev/null +++ b/Praktikum/VINF_MaerklinControl/build/project/src/gui/view/Settings.fxml @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<?import javafx.geometry.Insets?> +<?import javafx.scene.control.Button?> +<?import javafx.scene.control.Label?> +<?import javafx.scene.control.TextField?> +<?import javafx.scene.layout.AnchorPane?> +<?import javafx.scene.layout.VBox?> + +<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" fx:controller="gui.view.SettingsController"> + <children> + <VBox prefHeight="200.0" prefWidth="100.0" AnchorPane.bottomAnchor="20.0" AnchorPane.leftAnchor="20.0" AnchorPane.rightAnchor="20.0" AnchorPane.topAnchor="20.0"> + <children> + <Label text="Server-IP" /> + <TextField fx:id="serverIP" prefHeight="25.0" prefWidth="158.0" text="127.0.0.1"> + <VBox.margin> + <Insets top="5.0" /> + </VBox.margin> + </TextField> + <Button fx:id="connectButton" mnemonicParsing="false" onAction="#connectHandler" text="Verbindung herstellen"> + <VBox.margin> + <Insets top="5.0" /> + </VBox.margin> + </Button> + </children> + <padding> + <Insets top="20.0" /> + </padding> + </VBox> + </children> +</AnchorPane> diff --git a/Praktikum/VINF_MaerklinControl/build/project/src/gui/view/SettingsController.java b/Praktikum/VINF_MaerklinControl/build/project/src/gui/view/SettingsController.java new file mode 100644 index 0000000000000000000000000000000000000000..85161fac87685a5a2c937269a3abacca54bcd7d9 --- /dev/null +++ b/Praktikum/VINF_MaerklinControl/build/project/src/gui/view/SettingsController.java @@ -0,0 +1,68 @@ +package gui.view; + +import javafx.fxml.FXML; +import javafx.scene.control.TextField; +import javafx.scene.control.Button; + +import java.net.InetSocketAddress; + +import gui.MainApp; +import gui.model.Settings; + +public class SettingsController { + @FXML + TextField serverIP; + + @FXML + Button connectButton; + + private Settings settings; + + private MainApp mainApp; + + public SettingsController(){ + } + + /** + * Initializes the controller class. This method is automatically called + * after the fxml file has been loaded. + */ + @FXML + private void initialize() { + } + + /** + * Is called by the main application to give a reference back to itself. + * + * @param mainApp + */ + public void setMainApp(MainApp mainApp) { + this.mainApp = mainApp; + } + + @FXML + private void connectHandler(){ + InetSocketAddress address = new InetSocketAddress(serverIP.getText(), settings.getSocketAddress().get().getPort()); + settings.setSocketAddress(address); + updateSettingsStatus(); + mainApp.establishConnetion(); + } + + public void updateSettingsStatus(){ + InetSocketAddress addr = settings.getSocketAddress().get(); + StringBuilder status = new StringBuilder("Verbindung herstellen mit "); + status.append(addr.getHostName()); + status.append(" (" + addr.getAddress() + ":" + addr.getPort() + ")"); + mainApp.setStatus(status.toString()); + if (mainApp.getConnectionEstablished()) { + connectButton.setText("Verbindung trennen"); + } + else { + connectButton.setText("Verbindung herstellen"); + } + } + + public void setSettings(Settings settings) { + this.settings = settings; + } +} diff --git a/Praktikum/VINF_MaerklinControl/build/project/src/gui/view/Switch.fxml b/Praktikum/VINF_MaerklinControl/build/project/src/gui/view/Switch.fxml new file mode 100644 index 0000000000000000000000000000000000000000..ab56159a5a1986f3f5e401b29d3c6ac34f01253a --- /dev/null +++ b/Praktikum/VINF_MaerklinControl/build/project/src/gui/view/Switch.fxml @@ -0,0 +1,43 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<?import javafx.geometry.Insets?> +<?import javafx.scene.control.Label?> +<?import javafx.scene.image.Image?> +<?import javafx.scene.image.ImageView?> +<?import javafx.scene.layout.HBox?> +<?import org.controlsfx.control.ToggleSwitch?> + +<fx:root alignment="TOP_CENTER" type="javafx.scene.layout.HBox" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1"> + <Label fx:id="nameLabel" minWidth="75" prefHeight="25.0" prefWidth="75.0" text="Weiche"> + <padding> + <Insets top="5.0" /> + </padding> + </Label> + <ImageView fx:id="straightIcon" fitHeight="20.0" fitWidth="20.0" pickOnBounds="true" preserveRatio="true"> + <image> + <Image url="@../../../res/MagIcon_00_01_i.png" /> + </image> + <HBox.margin> + <Insets right="5.0" /> + </HBox.margin> + </ImageView> + <ToggleSwitch fx:id="stateToggleSwitch" prefWidth="32.0"> + <HBox.margin> + <Insets right="5.0" /> + </HBox.margin> + <padding> + <Insets top="1.0" /> + </padding> + </ToggleSwitch> + <ImageView fx:id="bentIcon" fitHeight="20.0" fitWidth="20.0" pickOnBounds="true" preserveRatio="true"> + <image> + <Image url="@../../../res/MagIcon_00_00_i.png" /> + </image> + <HBox.margin> + <Insets right="5.0" /> + </HBox.margin> + </ImageView> + <padding> + <Insets bottom="5.0" top="5.0" /> + </padding> +</fx:root> diff --git a/Praktikum/VINF_MaerklinControl/build/project/src/gui/view/SwitchControl.java b/Praktikum/VINF_MaerklinControl/build/project/src/gui/view/SwitchControl.java new file mode 100644 index 0000000000000000000000000000000000000000..e14c05fbe2f93d2884930cc518fcc5cee7d41e00 --- /dev/null +++ b/Praktikum/VINF_MaerklinControl/build/project/src/gui/view/SwitchControl.java @@ -0,0 +1,101 @@ +package gui.view; + +import javafx.beans.value.ChangeListener; +import javafx.beans.value.ObservableValue; +import javafx.fxml.FXML; +import javafx.fxml.FXMLLoader; +import javafx.scene.control.Label; +import javafx.scene.image.Image; +import javafx.scene.image.ImageView; +import javafx.scene.layout.HBox; + +import java.io.IOException; + +import org.controlsfx.control.ToggleSwitch; +import gui.MainApp; +import gui.model.Switch; + +public class SwitchControl extends HBox{ + @FXML + private Label nameLabel; + @FXML + private ToggleSwitch stateToggleSwitch; + @FXML + private ImageView straightIcon; + @FXML + private ImageView bentIcon; + + // Reference to the main application. + private MainApp mainApp; + private Switch sw; + private Image straightActive = new Image("file:res/MagIcon_00_01_a.png"); + private Image straightInactive = new Image("file:res/MagIcon_00_01_i.png"); + private Image bentActive = new Image("file:res/MagIcon_00_00_a.png"); + private Image bentInactive = new Image("file:res/MagIcon_00_00_i.png"); + + + /** + * The constructor. + * The constructor is called before the initialize() method. + */ + public SwitchControl(Switch sw) { + this.sw = sw; + + FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("Switch.fxml")); + fxmlLoader.setRoot(this); + fxmlLoader.setController(this); + sw.setController(this); + + try { + fxmlLoader.load(); + } catch (IOException exception) { + throw new RuntimeException(exception); + } + } + + /** + * Initializes the controller class. This method is automatically called + * after the fxml file has been loaded. + */ + @FXML + private void initialize() { + nameLabel.setText(sw.toString()); + straightIcon.setImage(straightActive); + bentIcon.setImage(bentInactive); + stateToggleSwitch.selectedProperty().addListener(new ChangeListener<Boolean>(){ + public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) { + sw.setState(newValue); + mainApp.setSwitchState(sw); + updateSwitchStatus(); + } + }); + } + + /** + * Is called by the main application to give a reference back to itself. + * + * @param mainApp + */ + public void setMainApp(MainApp mainApp) { + this.mainApp = mainApp; + } + + + public void updateSwitchStatus(){ + stateToggleSwitch.setSelected(sw.getState().get()); + + StringBuilder status = new StringBuilder("Letztes Kommando: "); + status.append(sw.toString() + " "); + if (!sw.getState().get()){ + status.append("gerade"); + straightIcon.setImage(straightActive); + bentIcon.setImage(bentInactive); + } + else{ + status.append("krumm"); + straightIcon.setImage(straightInactive); + bentIcon.setImage(bentActive); + } + mainApp.setStatus(status.toString()); + } +} diff --git a/Praktikum/VINF_MaerklinControl/build/project/src/gui/view/SwitchList.fxml b/Praktikum/VINF_MaerklinControl/build/project/src/gui/view/SwitchList.fxml new file mode 100644 index 0000000000000000000000000000000000000000..1af1e0f3fc0cd43cdd008cab17b1cc50f76de7b9 --- /dev/null +++ b/Praktikum/VINF_MaerklinControl/build/project/src/gui/view/SwitchList.fxml @@ -0,0 +1,14 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<?import javafx.geometry.Insets?> +<?import javafx.scene.layout.AnchorPane?> +<?import javafx.scene.layout.VBox?> + +<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefWidth="340.0" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" fx:controller="gui.view.SwitchListController"> + <children> + <VBox fx:id="switchesVBox" alignment="TOP_CENTER" prefWidth="300.0"> + <padding> + <Insets bottom="5.0" left="20.0" right="20.0" top="5.0" /> + </padding></VBox> + </children> +</AnchorPane> diff --git a/Praktikum/VINF_MaerklinControl/build/project/src/gui/view/SwitchListController.java b/Praktikum/VINF_MaerklinControl/build/project/src/gui/view/SwitchListController.java new file mode 100644 index 0000000000000000000000000000000000000000..de5eebb19ff70962904f45575d52bb181f31be79 --- /dev/null +++ b/Praktikum/VINF_MaerklinControl/build/project/src/gui/view/SwitchListController.java @@ -0,0 +1,53 @@ +package gui.view; + +import javafx.fxml.FXML; +import javafx.scene.layout.VBox; +import javafx.collections.FXCollections; +import javafx.collections.ObservableList; +import gui.MainApp; +import gui.model.Switch; + +public class SwitchListController { + @FXML + private VBox switchesVBox; + + // Reference to the main application. + private MainApp mainApp; + + /** + * The constructor. + * The constructor is called before the initialize() method. + */ + public SwitchListController(){ + + } + + /** + * Initializes the controller class. This method is automatically called + * after the fxml file has been loaded. + */ + @FXML + private void initialize() { + //setSwitchControls(); // would be nice to do this here, doesn't work until setMainApp has been called + } + + /** + * Is called by the main application to give a reference back to itself. + * + * @param mainApp + */ + public void setMainApp(MainApp mainApp) { + this.mainApp = mainApp; + + } + + public void setSwitchControls(){ + ObservableList<Switch> switches = mainApp.getSwitches(); + ObservableList<SwitchControl> switchControls = FXCollections.observableArrayList(); + for ( int i=0; i<switches.size();i++ ){ + switchControls.add(new SwitchControl(switches.get(i))); + switches.get(i).getController().get().setMainApp(mainApp); + }; + switchesVBox.getChildren().addAll(switchControls); + } +} diff --git a/Praktikum/VINF_MaerklinControl/build/project/src/gui/view/Turntable.fxml b/Praktikum/VINF_MaerklinControl/build/project/src/gui/view/Turntable.fxml new file mode 100644 index 0000000000000000000000000000000000000000..06a134e01bbae972b01bea37b66201782deb0f46 --- /dev/null +++ b/Praktikum/VINF_MaerklinControl/build/project/src/gui/view/Turntable.fxml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<?import javafx.scene.control.ChoiceBox?> +<?import javafx.scene.control.Button?> +<?import javafx.scene.layout.AnchorPane?> +<?import javafx.scene.layout.HBox?> + +<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="180.0" prefWidth="200.0" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" fx:controller="gui.view.TurntableController"> + <children> + <HBox alignment="BOTTOM_CENTER" layoutX="70.0" layoutY="457.0" AnchorPane.bottomAnchor="20.0" AnchorPane.leftAnchor="20.0" AnchorPane.rightAnchor="20.0" AnchorPane.topAnchor="0.0"> + <children> + <Button fx:id="turntableLeftButton" mnemonicParsing="false" onAction="#handleTurnCCW" text="<" /> + <ChoiceBox fx:id="slotChoiceBox" prefWidth="150.0" /> + <Button fx:id="turntableRightButton" mnemonicParsing="false" onAction="#handleTurnCW" text=">" /> + </children> + </HBox> + </children> +</AnchorPane> diff --git a/Praktikum/VINF_MaerklinControl/build/project/src/gui/view/TurntableController.java b/Praktikum/VINF_MaerklinControl/build/project/src/gui/view/TurntableController.java new file mode 100644 index 0000000000000000000000000000000000000000..0c8c6c16ae5ea763adf615195f6e70b1a7ad1cb2 --- /dev/null +++ b/Praktikum/VINF_MaerklinControl/build/project/src/gui/view/TurntableController.java @@ -0,0 +1,46 @@ +package gui.view; + +import gui.MainApp; +import javafx.fxml.FXML; +import javafx.scene.control.Button; +import javafx.scene.control.ChoiceBox; + +public class TurntableController { + + @FXML + private Button turntableLeftButton; + @FXML + private Button turntableRightButton; + @FXML + private ChoiceBox<Number> slotChoiceBox; + private MainApp mainApp; + + /** + * Initializes the controller class. This method is automatically called + * after the fxml file has been loaded. + */ + @FXML + private void initialize() { + + } + + /** + * Is called by the main application to give a reference back to itself. + * + * @param mainApp + */ + public void setMainApp(MainApp mainApp) { + this.mainApp = mainApp; + + } + + public void handleTurnCCW (){ + mainApp.turntableTurnCCW(); + mainApp.setStatus("Letztes Kommando: Drehteller links drehen"); + } + + public void handleTurnCW (){ + mainApp.turntableTurnCW(); + mainApp.setStatus("Letztes Kommando: Drehteller rechts drehen"); + } +} diff --git a/Praktikum/VINF_MaerklinControl/build/project/src/server/Engine.java b/Praktikum/VINF_MaerklinControl/build/project/src/server/Engine.java new file mode 100644 index 0000000000000000000000000000000000000000..60f39ceeff56b80bc26de0989f3df7adabf4a71e --- /dev/null +++ b/Praktikum/VINF_MaerklinControl/build/project/src/server/Engine.java @@ -0,0 +1,106 @@ +package server; + + +import java.util.ArrayList; + +public class Engine { + + static ArrayList<Engine> engines; + + private int engineID; + int engineDirection; + int engineSpeed; + + private MaerklinProtocol udpProtocol; + private UDPListener listener; + + public Engine(){ + this(0, 1, 0); + + // For offline-debugging + /*if (engines == null) { + engines = new ArrayList<Engine>(); + } + udpProtocol = new MaerklinProtocol(); + listener = new UDPListener(); + engines.add(this); + engineID = 0; + engineDirection = 1; + engineSpeed = 0;*/ + } + + public Engine(int id, int direction, int speed){ + if (engines == null) { + engines = new ArrayList<Engine>(); + } + udpProtocol = new MaerklinProtocol(); + listener = new UDPListener(); + engines.add(this); + try { + setEngineID(id); + setEngineDirection(direction); + setEngineSpeed(speed); + } + catch(Exception e){ + System.out.println(e.getMessage()); + } + } + + public void setEngineID(int newID){ + engineID = newID; + } + + public void setEngineDirection(int newEngineDirection) throws Exception { + if (newEngineDirection == 1 || newEngineDirection == 2){ + engineDirection = newEngineDirection; + } + else if (newEngineDirection == 3){ + if (engineDirection == 1){ + engineDirection = 2; + } + else { + engineDirection = 1; + } + } + else { + Exception e = new Exception("No viable direction!"); + throw e; + } + udpProtocol.changeEngineDirection(engineID, engineDirection); + listener.listen(); + } + + public void setEngineSpeed(int newEngineSpeed) throws Exception { + if (newEngineSpeed <= 1000 && newEngineSpeed >= 0){ + engineSpeed = newEngineSpeed; + } + else { + Exception e = new Exception("No viable speed value!"); + throw e; + } + udpProtocol.changeEngineSpeed(engineID, engineSpeed); + } + + public void increaseEngineSpeed() throws Exception { + engineSpeed = engineSpeed+50; + udpProtocol.changeEngineSpeed(engineID, engineSpeed); + } + + public void decreaseEngineSpeed() throws Exception{ + engineSpeed = engineSpeed-50; + udpProtocol.changeEngineSpeed(engineID, engineSpeed); + } + + public int getEngineID(){ + return engineID; + } + + public int getEngineDirection(){ + return engineDirection; + } + + public int getEngineSpeed(){ + return engineSpeed; + } + +} diff --git a/Praktikum/VINF_MaerklinControl/build/project/src/server/MaerklinProtocol.java b/Praktikum/VINF_MaerklinControl/build/project/src/server/MaerklinProtocol.java new file mode 100644 index 0000000000000000000000000000000000000000..30a97706453531fa3102adddf8cbe7daf618c1c4 --- /dev/null +++ b/Praktikum/VINF_MaerklinControl/build/project/src/server/MaerklinProtocol.java @@ -0,0 +1,58 @@ +package server; + +import java.net.*; + +public class MaerklinProtocol { + + private final static int port = 15731; + private final static String ip ="192.168.74.118"; + + public MaerklinProtocol(){ + //Nothing to do... + } + + private void writeDatagram(String ip, int port, byte[] data){ + //System.out.printf("\nGesendet: " + DatatypeConverter.printHexBinary(data)); + try(DatagramSocket socket = new DatagramSocket()){ + socket.setReuseAddress(true); + InetAddress address = InetAddress.getByName(ip); + DatagramPacket outgoingData = new DatagramPacket(data, data.length, address, port); + socket.send(outgoingData); + } + catch (Exception e) { + e.printStackTrace(); + } + } + + public void systemGo(){ + byte[] out = {(byte) 0x00, (byte) 0x00, (byte) 0x07, (byte) 0x78, (byte) 0x05, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00}; + this.writeDatagram(ip, port, out); + } + + public void systemStop(){ + byte[] out = {(byte) 0x00, (byte) 0x00, (byte) 0x07, (byte) 0x78, (byte) 0x05, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00}; + this.writeDatagram(ip, port, out); + } + + public void changeEngineSpeed(int mfxAddress, int newEngineSpeed){ + byte[] engineSpeed = {(byte) Math.floor(newEngineSpeed/256), (byte) Math.floor(newEngineSpeed%256)}; + byte[] address = {(byte) Math.floor(mfxAddress/256), (byte) Math.floor(mfxAddress%256)}; + byte[] out = {(byte) 0x00, (byte) 0x08, (byte) 0x07, (byte) 0x78, (byte) 0x06, (byte) 0x00, (byte) 0x00, address[0], address[1], engineSpeed[0], engineSpeed[1], (byte) 0x00, (byte) 0x00}; + this.writeDatagram(ip, port, out); + } + + public void changeEngineDirection(int mfxAddress, int newEngineDirection){ + byte engineDirection = (byte) Math.floor(newEngineDirection%256); + byte[] address = {(byte) Math.floor(mfxAddress/256), (byte) Math.floor(mfxAddress%256)}; + byte[] out = {(byte) 0x00, (byte) 0x0A, (byte) 0x07, (byte) 0x78, (byte) 0x05, (byte) 0x00, (byte) 0x00, address[0], address[1], engineDirection, (byte) 0x00, (byte) 0x00, (byte) 0x00}; + this.writeDatagram(ip, port, out); + } + + public void changeSwitchDirection(int mfxAddress, int newSwitchDirection){ + byte switchDirection = (byte) Math.floor(newSwitchDirection%256); + byte[] address = {(byte) Math.floor(mfxAddress/256), (byte) Math.floor(mfxAddress%256)}; + byte[] out = {(byte) 0x00, (byte) 0x16, (byte) 0x07, (byte) 0x78, (byte) 0x06, (byte) 0x00, (byte) 0x00, address[0], address[1], switchDirection, (byte) 0x01, (byte) 0x00, (byte) 0x00}; + this.writeDatagram(ip, port, out); + } + +} diff --git a/Praktikum/VINF_MaerklinControl/build/project/src/server/MaerklinServer.java b/Praktikum/VINF_MaerklinControl/build/project/src/server/MaerklinServer.java new file mode 100644 index 0000000000000000000000000000000000000000..c2774bd217d4ce717b1fc7c705dc880e43323880 --- /dev/null +++ b/Praktikum/VINF_MaerklinControl/build/project/src/server/MaerklinServer.java @@ -0,0 +1,435 @@ +package server; + +import java.io.BufferedInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.ServerSocket; +import java.net.Socket; +import java.util.ArrayList; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +import javax.xml.bind.DatatypeConverter; + +import common.Properties; + +public class MaerklinServer{ + + // Declaration of objects + ArrayList<Socket> clients; + + private MaerklinProtocol protocol; + private UDPListener overwatch; + private ServerThread serverThread; + + final ExecutorService SERVER_THREAD_EXECUTOR; + final ExecutorService CLIENT_THREAD_EXECUTOR; + final ExecutorService UTILITY_THREAD_EXECUTOR; + + private Engine ice; + private Engine lok; + private Engine reichsbahn; + + private Switch switch4; + private Switch switch5; + private Switch switch6; + private Switch switch8; + private Switch switch9; + private Switch switch10; + private Switch switch12; + private Switch switch13; + private Switch switch14; + private Switch switch15; + private Switch turntable; + + public MaerklinServer(){ + + // Initializing + System.out.println("Initializing..."); + + clients = new ArrayList<Socket>(); + + protocol = new MaerklinProtocol(); + overwatch = new UDPListener(); + serverThread = new ServerThread(this); + + SERVER_THREAD_EXECUTOR = Executors.newFixedThreadPool(2); + CLIENT_THREAD_EXECUTOR = Executors.newCachedThreadPool(); + UTILITY_THREAD_EXECUTOR = Executors.newCachedThreadPool(); + + ice = new Engine(); + lok = new Engine(); + reichsbahn = new Engine(); + + switch4 = new Switch(); + switch5 = new Switch(); + switch6 = new Switch(); + switch8 = new Switch(); + switch9 = new Switch(); + switch10 = new Switch(); + switch12 = new Switch(); + switch13 = new Switch(); + switch14 = new Switch(); + switch15 = new Switch(); + turntable = new Switch(); + + // Setting IDs + ice.setEngineID(Properties.ICE_ID); + lok.setEngineID(Properties.LOK_ID); + reichsbahn.setEngineID(Properties.REICHSBAHN_ID); + + switch4.setSwitchID(Properties.SWITCH4_ID); + switch5.setSwitchID(Properties.SWITCH5_ID); + switch6.setSwitchID(Properties.SWITCH6_ID); + switch8.setSwitchID(Properties.SWITCH8_ID); + switch9.setSwitchID(Properties.SWITCH9_ID); + switch10.setSwitchID(Properties.SWITCH10_ID); + switch12.setSwitchID(Properties.SWITCH12_ID); + switch13.setSwitchID(Properties.SWITCH13_ID); + switch14.setSwitchID(Properties.SWITCH14_ID); + switch15.setSwitchID(Properties.SWITCH15_ID); + turntable.setSwitchID(Properties.TURNTABLE_ID); + + // Starting the system and setting ("safe") values + try { + start(); + initialize(); + } + catch (Exception e){ + System.out.println(e.getMessage()); + System.exit(1); + } + } + + // Emergency stop + public void emergencyStop() throws Exception { + protocol.systemStop(); + ice.setEngineSpeed(0); + lok.setEngineSpeed(0); + reichsbahn.setEngineSpeed(0); + } + + // Emergency stop + public void start() throws Exception { + protocol.systemGo(); + } + + // Initialize; setting ("safe") values + public void initialize() throws Exception { + ice.setEngineDirection(1); + ice.setEngineSpeed(0); + + lok.setEngineDirection(1); + lok.setEngineSpeed(0); + + reichsbahn.setEngineDirection(1); + reichsbahn.setEngineSpeed(0); + + switch4.setSwitchDirection(1); + switch5.setSwitchDirection(1); + switch6.setSwitchDirection(1); + switch8.setSwitchDirection(1); + switch9.setSwitchDirection(1); + switch10.setSwitchDirection(1); + switch12.setSwitchDirection(1); + switch13.setSwitchDirection(1); + switch14.setSwitchDirection(1); + switch15.setSwitchDirection(1); + } + + // Starts the listener-thread + public void startListener(){ + SERVER_THREAD_EXECUTOR.submit(overwatch); + } + + // Listens to the client-port and initializes a new Thread to handle the client-messages + public void listen(){ + SERVER_THREAD_EXECUTOR.submit(serverThread); + } + + // Starts the thread to broadcast the current status + public void statusUpdate(){ + for (Socket clientSocket : clients) { + try { + //System.out.println("Updating client: "+clientSocket.getRemoteSocketAddress()); + UTILITY_THREAD_EXECUTOR.submit(new UpdateThread(clientSocket.getOutputStream())); + } + catch (IOException e) { + System.out.println("Failed to receive output-stream of one of the clients!"); + } + } + } + +} + +//Opens a server-port and establishes a new handling-thread for every client that connects to the server +class ServerThread implements Runnable { + + // Declaration of objects + private final MaerklinServer SERVER_INSTANCE; + + // Constructor + ServerThread (MaerklinServer server) { + SERVER_INSTANCE = server; + } + + @Override + public void run() { + try(ServerSocket serverSocket = new ServerSocket(Properties.PORT)){ + serverSocket.setReuseAddress(true); + System.out.println("Server-socket established!"); + while (true) { + Socket socket = serverSocket.accept(); + System.out.println("Connection to client "+socket.getRemoteSocketAddress()+" established!"); + SERVER_INSTANCE.CLIENT_THREAD_EXECUTOR.submit(new ClientThread(SERVER_INSTANCE, socket, socket.getInputStream())); + } + } + catch (Exception e) { + System.out.println("Accessing user-interaction-port failed! Trying again!"); + run(); + } + finally { + SERVER_INSTANCE.SERVER_THREAD_EXECUTOR.shutdownNow(); + SERVER_INSTANCE.CLIENT_THREAD_EXECUTOR.shutdownNow(); + SERVER_INSTANCE.UTILITY_THREAD_EXECUTOR.shutdownNow(); + } + } + +} + +// Handles the communication with the clients in the background +class ClientThread implements Runnable { + + // Declaration of objects + private final Socket CLIENT; + private final BufferedInputStream IN_STREAM; + private final MaerklinServer SERVER_INSTANCE; + byte[] data; + + // Constructor + ClientThread (MaerklinServer server, Socket socket, InputStream in) { + CLIENT = socket; + IN_STREAM = new BufferedInputStream(in); + SERVER_INSTANCE = server; + SERVER_INSTANCE.clients.add(socket); + data = new byte[Properties.IN_BUFFER_SIZE]; + } + + @Override + public void run() { + int buffer; + while (true) { + try { + if (IN_STREAM.available() != 0) { + buffer = IN_STREAM.read(); + if ((byte) buffer == (byte) Properties.SESSION_ABORT) { + SERVER_INSTANCE.clients.remove(CLIENT); + CLIENT.close(); + System.out.println("Conenction to client "+CLIENT.getRemoteSocketAddress()+" aborted!"); + return; + } + else if ((byte) buffer == (byte) Properties.SEPERATOR) { + for (int i = 0; i < Properties.IN_BUFFER_SIZE; i++) { + buffer = IN_STREAM.read(); + if ((byte) buffer == (byte) Properties.SESSION_ABORT) { + SERVER_INSTANCE.clients.remove(CLIENT); + CLIENT.close(); + System.out.println("Connection to client "+CLIENT.getRemoteSocketAddress()+" aborted!"); + return; + } + else { + data[i] = (byte) (buffer%(1<<8)); + } + } + SERVER_INSTANCE.UTILITY_THREAD_EXECUTOR.submit(new HandleThread(SERVER_INSTANCE, data)); + } + } + else { + Thread.sleep(10); + } + } + catch (Exception e) { + System.out.println("An error occured while reading the clients input-stream!"); + SERVER_INSTANCE.clients.remove(CLIENT); + System.out.println("Conenction to client "+CLIENT.getRemoteSocketAddress()+" aborted!"); + return; + } + } + } + +} + +// Processes the incoming datagram and initializes appropriate actions +class HandleThread implements Runnable { + + // Declaration of objects + private final MaerklinServer SERVER_INSTANCE; + byte[] data; + + // Constructor + HandleThread (MaerklinServer server, byte[] incomingData) { + SERVER_INSTANCE = server; + data = incomingData; + } + + @Override + public void run() { + try { + switch (data[2]) { + case Properties.SYSTEM_STOP: + //System.out.println("System stop"); + SERVER_INSTANCE.emergencyStop(); + break; + case Properties.SYSTEM_GO: + //System.out.println("System go"); + SERVER_INSTANCE.start(); + break; + case Properties.GET_STATUS: + //System.out.println("Status update"); + SERVER_INSTANCE.statusUpdate(); + break; + case Properties.ENGINE_SET_SPEED: + for (Engine train : Engine.engines) { + if (train.getEngineID() == ((data[0]&0xFF)*(1<<8)+(data[1]&0xFF))) { + //System.out.println("Set engine speed"); + train.setEngineSpeed((data[3]&0xFF)*(1<<8)+(data[4]&0xFF)); + break; + } + } + break; + case Properties.ENGINE_INCREASE_SPEED: + for (Engine train : Engine.engines) { + if (train.getEngineID() == ((data[0]&0xFF)*(1<<8)+(data[1]&0xFF))) { + //System.out.println("Increase engine speed"); + train.increaseEngineSpeed(); + break; + } + } + break; + case Properties.ENGINE_DECREASE_SPEED: + for (Engine train : Engine.engines) { + if (train.getEngineID() == ((data[0]&0xFF)*(1<<8)+(data[1]&0xFF))) { + //System.out.println("Decrease engine speed"); + train.decreaseEngineSpeed(); + break; + } + } + break; + case Properties.ENGINE_SET_DIRECTION: + for (Engine train : Engine.engines) { + if (train.getEngineID() == ((data[0]&0xFF)*(1<<8)+(data[1]&0xFF))) { + //System.out.println("Set engine direction"); + train.setEngineDirection(data[3]); + break; + } + } + break; + case Properties.ENGINE_SWITCH_DIRECTION: + for (Engine train : Engine.engines) { + if (train.getEngineID() == ((data[0]&0xFF)*(1<<8)+(data[1]&0xFF))) { + //System.out.println("Switch engine direction"); + train.setEngineDirection(3); + break; + } + } + break; + case Properties.SWITCH_SET_DIRECTION: + for (Switch sw : Switch.switches) { + if (sw.getSwitchID() == ((data[0]&0xFF)*(1<<8)+(data[1]&0xFF))) { + //System.out.println("Set switch direction"); + sw.setSwitchDirection(data[3]); + break; + } + } + break; + case Properties.SWITCH_SWITCH_DIRECTION: + for (Switch sw : Switch.switches) { + if (sw.getSwitchID() == ((data[0]&0xFF)*(1<<8)+(data[1]&0xFF))) { + //System.out.println("Switch switch direction"); + sw.changeSwitchDirection(); + break; + } + } + break; + default: + System.out.println("No viable command!\n"); + } + } + catch (Exception e) { + System.out.println(e.getMessage()); + } + } + +} + +//Broadcasts the current status +class UpdateThread implements Runnable { + + // Declaration of objects + private final OutputStream OUT_STREAM; + private byte[] outgoingData; + + // Constructor + UpdateThread (OutputStream out) { + + // Setting the broadcast-port + OUT_STREAM = out; + + // Initializing + outgoingData = new byte[Properties.OUT_BUFFER_SIZE]; + } + + // Reads every registered objects data into outgoingData and broadcasts the status + @Override + public void run() { + int position = 0; + try { + outgoingData[position++] = Properties.SEPERATOR; + outgoingData[position++] = Properties.SEPERATOR; + for (Engine train : Engine.engines) { + if (position >= Properties.OUT_BUFFER_SIZE-9) { + Exception e = new Exception("Overload of registered elements! Update-buffer too small!"); + throw e; + } + outgoingData[position++] = (byte) ((train.getEngineID()/(1<<8))%(1<<8)); + outgoingData[position++] = (byte) ((train.getEngineID()%(1<<8))); + outgoingData[position++] = (byte) ((train.getEngineSpeed()/(1<<8))%(1<<8)); + outgoingData[position++] = (byte) ((train.getEngineSpeed()%(1<<8))); + outgoingData[position++] = (byte) ((train.getEngineDirection()%(1<<24))); + outgoingData[position++] = Properties.SEPERATOR; + } + outgoingData[position++] = Properties.SEPERATOR; + outgoingData[position++] = Properties.SEPERATOR; + outgoingData[position++] = Properties.SEPERATOR; + for (Switch sw : Switch.switches) { + if (position >= Properties.OUT_BUFFER_SIZE-10) { + Exception e = new Exception("Overload of registered elements! Update-buffer too small!"); + throw e; + } + outgoingData[position++] = (byte) ((sw.getSwitchID()/(1<<8))%(1<<8)); + outgoingData[position++] = (byte) ((sw.getSwitchID()%(1<<8))); + outgoingData[position++] = (byte) 0x00; + outgoingData[position++] = (byte) 0x00; + outgoingData[position++] = (byte) ((sw.getSwitchDirection()%(1<<24))); + outgoingData[position++] = Properties.SEPERATOR; + } + outgoingData[position++] = Properties.SEPERATOR; + outgoingData[position++] = Properties.SEPERATOR; + outgoingData[position++] = Properties.SEPERATOR; + outgoingData[position++] = Properties.SEPERATOR; + } + catch (Exception e) { + System.out.println(e.getMessage()); + e.printStackTrace(); + } + //System.out.printf("\nSende: " + DatatypeConverter.printHexBinary(outgoingData)); + try { + OUT_STREAM.write(outgoingData, 0, Properties.OUT_BUFFER_SIZE); + } + catch (Exception e) { + System.out.println("Communication-error whilst status-update!"); + } + } + +} diff --git a/Praktikum/VINF_MaerklinControl/build/project/src/server/MaerklinServerApplication.java b/Praktikum/VINF_MaerklinControl/build/project/src/server/MaerklinServerApplication.java new file mode 100644 index 0000000000000000000000000000000000000000..7bbd8c583b8818b0232a810ef61c347e928926ab --- /dev/null +++ b/Praktikum/VINF_MaerklinControl/build/project/src/server/MaerklinServerApplication.java @@ -0,0 +1,37 @@ +package server; + +public class MaerklinServerApplication { + + // Defining a threshold value for when the status-update is to be executed (in milliseconds) + private final static long updateThreshold = 500; + + public static void main(String[] args) { + + // Creating timestamp for the update-functionality + long timestamp = System.currentTimeMillis(); + + // Calling constructor + MaerklinServer server = new MaerklinServer(); + + // Starting listener-thread + server.startListener(); + + // Starting the client-handling + server.listen(); + + while (true){ + if (System.currentTimeMillis()-timestamp >= updateThreshold) { + server.statusUpdate(); + timestamp = System.currentTimeMillis(); + } + else { + try { + Thread.sleep(50); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + } + +} diff --git a/Praktikum/VINF_MaerklinControl/build/project/src/server/Switch.java b/Praktikum/VINF_MaerklinControl/build/project/src/server/Switch.java new file mode 100644 index 0000000000000000000000000000000000000000..ea03fbf954828e18a33f0b2dd72dabe69f806f16 --- /dev/null +++ b/Praktikum/VINF_MaerklinControl/build/project/src/server/Switch.java @@ -0,0 +1,77 @@ +package server; + +import java.util.ArrayList; + +public class Switch { + + static ArrayList<Switch> switches; + + private int switchID; + int switchDirection; + + private MaerklinProtocol udpProtocol; + private UDPListener listener; + + public Switch(){ + this(0, 1); + + // For offline-debugging + /*if (switches == null) { + switches = new ArrayList<Switch>(); + } + udpProtocol = new MaerklinProtocol(); + listener = new UDPListener(); + switches.add(this); + switchID = 0; + switchDirection = 1;*/ + } + + public Switch(int id, int direction){ + if (switches == null) { + switches = new ArrayList<Switch>(); + } + udpProtocol = new MaerklinProtocol(); + listener = new UDPListener(); + switches.add(this); + try { + setSwitchID(id); + setSwitchDirection(direction); + } + catch(Exception e){ + System.out.println(e.getMessage()); + } + } + + public void setSwitchID(int newSwitchID){ + switchID = newSwitchID; + } + + public void setSwitchDirection(int newSwitchDirection) throws Exception { + if (newSwitchDirection == 0x01 || newSwitchDirection == 0x00){ + switchDirection = newSwitchDirection; + } + else { + Exception e = new Exception("No viable switch direction!"); + throw e; + } + udpProtocol.changeSwitchDirection(switchID, switchDirection); + } + + public void changeSwitchDirection() throws Exception { + if (switchDirection == 0x00){ + setSwitchDirection(0x01); + } + else { + setSwitchDirection(0x00); + } + } + + public int getSwitchID(){ + return switchID; + } + + public int getSwitchDirection(){ + return switchDirection; + } + +} diff --git a/Praktikum/VINF_MaerklinControl/build/project/src/server/UDPListener.java b/Praktikum/VINF_MaerklinControl/build/project/src/server/UDPListener.java new file mode 100644 index 0000000000000000000000000000000000000000..0563ea5fa357bd093b18b96b28b25408bf8b7f23 --- /dev/null +++ b/Praktikum/VINF_MaerklinControl/build/project/src/server/UDPListener.java @@ -0,0 +1,131 @@ +package server; + + +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import javax.xml.bind.DatatypeConverter; + +public class UDPListener implements Runnable{ + + private final static int port = 15730; + + private byte[] in = new byte[13]; + + public UDPListener(){ + // Nothing to do... + } + + public void listen(){ + try(DatagramSocket socket = new DatagramSocket(port)){ + socket.setReuseAddress(true); + DatagramPacket incomingData = new DatagramPacket(in, in.length); + socket.receive(incomingData); + in = incomingData.getData(); + } + catch (Exception e) { + e.printStackTrace(); + } + } + + public byte[] getData(){ + return in; + } + + public int getEngineSpeed(){ + return ((in[9]&0xFF)*(1<<8)+(in[10]&0xFF)); + } + + public int getEngineDirection(){ + return (in[9]&0xFF); + } + + public int getSwitchDirection(){ + return (in[9]&0xFF); + } + + public int getAddress(){ + return ((in[7]&0xFF)*(1<<8)+(in[8]&0xFF)); + } + + public int getCommand(){ + return ((in[1]&0xFF)&0xFE); + } + + public boolean isAnswer(){ + if ((in[1]&0x01) == 1){ + return true; + } + else { + return false; + } + } + + public void printData(byte[] data){ + try{ + byte[] kennung = new byte[4]; + byte[] laenge = new byte[1]; + byte[] nutzdaten = new byte[8]; + System.arraycopy(data, 0, kennung, 0, 4); + System.arraycopy(data, 4, laenge, 0, 1); + System.arraycopy(data, 5, nutzdaten, 0, 8); + System.out.print("\n\nKennung DLC Nutzdaten\n" + DatatypeConverter.printHexBinary(kennung) + " " + DatatypeConverter.printHexBinary(laenge) + " " + DatatypeConverter.printHexBinary(nutzdaten)); + } + catch(Exception e){ + e.printStackTrace(); + } + } + + public static void main(String args[]){ + UDPListener testListener = new UDPListener(); + while (true){ + testListener.listen(); + testListener.printData(testListener.getData()); + } + } + + @Override + public void run() { + //System.out.println("UDPListener start!"); + try(DatagramSocket socket = new DatagramSocket(port)){ + socket.setReuseAddress(true); + while (true){ + DatagramPacket incomingData = new DatagramPacket(in, in.length); + socket.receive(incomingData); + in = incomingData.getData(); + if (isAnswer()){ + if (getCommand() == 0x08){ + for (Engine train : Engine.engines){ + if (train.getEngineID() == getAddress()){ + train.engineSpeed = getEngineSpeed(); + //System.out.println("Speed of Engine "+train.getEngineID()+" changed to "+train.getEngineSpeed()); + break; + } + } + } + else if (getCommand() == 0x0A){ + for (Engine train : Engine.engines){ + if (train.getEngineID() == getAddress()){ + train.engineDirection = getEngineDirection(); + //System.out.println("Direction of Engine "+train.getEngineID()+" changed to "+train.getEngineDirection()); + break; + } + } + } + else if (getCommand() == 0x16){ + for (Switch sw : Switch.switches){ + if (sw.getSwitchID() == getAddress()){ + sw.switchDirection = getEngineDirection(); + //System.out.println("Direction of Switch "+sw.getSwitchID()+" changed to "+sw.getSwitchDirection()); + break; + } + } + } + } + } + } + catch (Exception e) { + e.printStackTrace(); + } + } + +}