580 lines
18 KiB
Java
580 lines
18 KiB
Java
package fabrik.simulator.pic16f84;
|
||
|
||
|
||
import fabrik.simulator.pic16f84.frontendspecifics.FrontendSpecificToggleButtonGroup;
|
||
import fabrik.simulator.pic16f84.frontendspecifics.ToggleButtonGroup;
|
||
|
||
import fabrik.simulator.pic16f84.interfaces.*;
|
||
import javafx.application.Platform;
|
||
import javafx.collections.FXCollections;
|
||
import javafx.collections.ObservableList;
|
||
import javafx.event.ActionEvent;
|
||
import javafx.fxml.FXML;
|
||
|
||
import javafx.scene.Scene;
|
||
import javafx.scene.control.*;
|
||
import javafx.scene.layout.VBox;
|
||
import javafx.scene.shape.Circle;
|
||
import javafx.stage.FileChooser;
|
||
|
||
import java.io.File;
|
||
import java.io.IOException;
|
||
|
||
import java.io.BufferedReader;
|
||
|
||
import java.io.FileReader;
|
||
|
||
import javafx.scene.control.Label;
|
||
import javafx.scene.control.TableView;
|
||
|
||
import javafx.stage.Stage;
|
||
import javafx.util.Callback;
|
||
|
||
|
||
import java.util.Arrays;
|
||
import java.util.HashSet;
|
||
import java.util.List;
|
||
import java.util.Set;
|
||
|
||
import static java.lang.Math.max;
|
||
|
||
public class Controller_Frontend extends PICComponent implements FrontendControllerInterface, ExecutionTimeObserver {
|
||
|
||
private int [] prog;
|
||
private int [][] read;
|
||
private int [] ind;
|
||
private PICComponentLocator picComponents;
|
||
|
||
private boolean isBreakpointReached = false;
|
||
|
||
private boolean continueExecutionAfterBreakpoint = false;
|
||
|
||
@FXML
|
||
private ComboBox<String> executionTimeComboBox;
|
||
|
||
|
||
@FXML
|
||
private Button stepintoButton;
|
||
|
||
@FXML
|
||
private TableView<Table.DataEntry> tableView;
|
||
|
||
@FXML
|
||
private ListView<String> lstContentListView;
|
||
|
||
@FXML
|
||
private Button autoRunGUI;
|
||
|
||
@FXML
|
||
private Button stopButton;
|
||
|
||
@FXML
|
||
private Label totalExecutionTimeLabel;
|
||
|
||
@FXML
|
||
private CheckBox wdtCheck;
|
||
|
||
|
||
|
||
public Controller_Frontend() {
|
||
super();
|
||
System.out.println(this);
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
//Refactoring
|
||
|
||
public void stopRunFromBackend(String message) {
|
||
ExecutionState.setAutoRunActive(false);
|
||
|
||
handleSleepOrReset();
|
||
showStopDialog(message);
|
||
|
||
}
|
||
private void handleSleepOrReset() {
|
||
if (ExecutionState.isSleeping()) {
|
||
ExecutionState.wakeUp();
|
||
} else {
|
||
dataRegister.resetPC();
|
||
}
|
||
}
|
||
|
||
private static void showStopDialog(String message) {
|
||
Stage stoppedStage = new Stage();
|
||
stoppedStage.setTitle("Programm unterbrochen!");
|
||
|
||
VBox vbox = new VBox();
|
||
vbox.setAlignment(javafx.geometry.Pos.CENTER);
|
||
|
||
Label grundlabel = new Label("Grund: " + message);
|
||
grundlabel.setStyle("-fx-font-size: 16px; -fx-font-weight: bold;");
|
||
|
||
Label ueberlabel = new Label("Programm unterbrochen!");
|
||
vbox.getChildren().addAll(ueberlabel, grundlabel);
|
||
VBox.setMargin(grundlabel, new javafx.geometry.Insets(10, 10, 10, 10));
|
||
|
||
Scene scene = new Scene(vbox, 300, 90);
|
||
stoppedStage.setAlwaysOnTop(true);
|
||
stoppedStage.setScene(scene);
|
||
stoppedStage.show();
|
||
}
|
||
|
||
|
||
|
||
//Refactoring Ende
|
||
|
||
|
||
|
||
@FXML
|
||
private void stopAutoRun(ActionEvent event) {
|
||
ExecutionState.setAutoRunActive(false);
|
||
}
|
||
|
||
|
||
@FXML
|
||
public void autoRunGUI(ActionEvent event) {
|
||
if (!ExecutionState.isAutoRunActive()) {
|
||
ExecutionState.setAutoRunActive(true) ;
|
||
}
|
||
|
||
Thread autoRunThread = new Thread(() -> {
|
||
try {
|
||
while (dataRegister.getPC() < prog.length && ExecutionState.isAutoRunActive()){
|
||
|
||
Platform.runLater(() -> {
|
||
try {
|
||
stepintoButton(null);
|
||
} catch (IOException e) {
|
||
e.printStackTrace();
|
||
}
|
||
});
|
||
Thread.sleep(80); //Verzögerungszeit in Millisekunden
|
||
}
|
||
} catch (InterruptedException e) {
|
||
e.printStackTrace();
|
||
}
|
||
});
|
||
autoRunThread.setDaemon(true);
|
||
autoRunThread.start();
|
||
}
|
||
|
||
|
||
|
||
private void updateExecutionTimeMultiplier() {
|
||
String selectedOption = executionTimeComboBox.getValue();
|
||
executionTime.setExecutionTimeMultiplier(selectedOption);
|
||
}
|
||
|
||
@FXML
|
||
public void stepintoButton(ActionEvent event) throws IOException {
|
||
if (lstContentListView.getItems().isEmpty()) {
|
||
// Datei ist nicht geladen oder leer
|
||
return;
|
||
}
|
||
|
||
int currentIndex;
|
||
// Aktuelle Zeile abrufen
|
||
if (!ExecutionState.isSleeping())
|
||
currentIndex = ind[dataRegister.getPC()];
|
||
else
|
||
currentIndex = ind[dataRegister.getPC()]-1;
|
||
|
||
// Überprüfung ob ein Breakpoint gesetzt ist testte
|
||
|
||
if (breakpoints.contains(currentIndex)) {
|
||
if (!continueExecutionAfterBreakpoint){
|
||
isBreakpointReached = true;
|
||
stopAutoRun(null);
|
||
System.out.println("Breakpoint erreicht bei Zeile: " + currentIndex);
|
||
continueExecutionAfterBreakpoint = true;
|
||
return;
|
||
}
|
||
}
|
||
else {
|
||
isBreakpointReached = false;
|
||
continueExecutionAfterBreakpoint = false;
|
||
}
|
||
|
||
// Scrollen zur ausgewählten Zeile
|
||
lstContentListView.scrollTo(currentIndex -2);
|
||
|
||
// Zeile auswählen
|
||
lstContentListView.getSelectionModel().clearSelection();
|
||
lstContentListView.getSelectionModel().select(currentIndex);
|
||
|
||
String selectedRowStyle;
|
||
if (!ExecutionState.isSleeping())
|
||
selectedRowStyle = "-fx-background-color: red; -fx-text-fill: white;";
|
||
else
|
||
selectedRowStyle = "-fx-background-color: teal; -fx-text-fill: white;";
|
||
|
||
markSelectedRow(currentIndex, selectedRowStyle);
|
||
|
||
if (!ExecutionState.isSleeping()) {
|
||
commands.decode(prog[dataRegister.getPC()]);
|
||
dataRegister.increasePC();
|
||
}
|
||
else {
|
||
commands.decode(0);
|
||
}
|
||
watchdogTimer.testAndTrigger();
|
||
table.refresh();
|
||
CreateWindow.refreshTable();
|
||
ioPorts.refreshUI(getTRISbuttons(), getPORTbuttons());
|
||
updateStack();
|
||
updateWatchdog();
|
||
}
|
||
|
||
|
||
private void markSelectedRow(int currentIndex, String selectedRowStyle) {
|
||
lstContentListView.setCellFactory(column -> new ListCell<String>() {
|
||
@Override
|
||
protected void updateItem(String item, boolean empty) {
|
||
super.updateItem(item, empty);
|
||
setText(item);
|
||
if (getIndex() == currentIndex) {
|
||
setStyle(selectedRowStyle);
|
||
} else {
|
||
setStyle("");
|
||
}
|
||
CheckBox breakpointCheckBox = new CheckBox();
|
||
breakpointCheckBox.setOnAction(event -> {
|
||
int index = getIndex();
|
||
if (breakpointCheckBox.isSelected()) {
|
||
breakpoints.add(index);
|
||
} else {
|
||
breakpoints.remove(index);
|
||
}
|
||
});
|
||
breakpointCheckBox.setSelected(breakpoints.contains(getIndex()));
|
||
setGraphic(breakpointCheckBox);
|
||
}
|
||
});
|
||
}
|
||
|
||
private Set<Integer> breakpoints = new HashSet<>();
|
||
|
||
|
||
|
||
@FXML
|
||
protected void selectFileLST(ActionEvent event) throws IOException {
|
||
File selectedFile = chooseLSTFile();
|
||
stopAutoRun(null);
|
||
if(selectedFile != null){
|
||
String fileAddress = selectedFile.getAbsolutePath();
|
||
System.out.println(dataRegister);
|
||
if (null == dataRegister) dataRegister = (DataRegisterInterface) picComponents.getComponent(DataRegisterInterface.class);
|
||
dataRegister.initDataRegister();
|
||
dataRegister.resetPC();
|
||
toggleLEDs(null);
|
||
ioPorts.reset();
|
||
|
||
for (ToggleButtonGroup toggleButtonGroup : allPORTbuttons) {
|
||
try {
|
||
toggleButtonGroup.getToggles().get(0).setSelected(true);
|
||
toggleButtonGroup.getToggles().get(1).setSelected(false);
|
||
ioPorts.setPORTfromUI(toggleButtonGroup);
|
||
} catch (NullPointerException ignored) {}
|
||
}
|
||
programStack.reset();
|
||
ExecutionState.wakeUp();
|
||
breakpoints.clear();
|
||
ioPorts.refreshUI(getTRISbuttons(), getPORTbuttons());
|
||
executionTime.resetTotalExecutionTime();
|
||
watchdogTimer.reset();
|
||
wdtCheck.setSelected(false);
|
||
table.refresh();
|
||
read = ParseFile.parseDatei(fileAddress);
|
||
prog = read [0];
|
||
ind = read[1];
|
||
updateStack();
|
||
System.out.println(Arrays.toString(Arrays.stream(prog).toArray()));
|
||
displayLSTFileContent(selectedFile);
|
||
markSelectedRow(0, "-fx-background-color: red; -fx-text-fill: white;");
|
||
initializeBreakpoints();
|
||
int lastSlash = max (fileAddress.lastIndexOf('/'), fileAddress.lastIndexOf('\\'));
|
||
int lastDot = fileAddress.lastIndexOf('.');
|
||
String stageTitle;
|
||
if (lastDot > lastSlash)
|
||
stageTitle = "Simulator - " + fileAddress.substring(lastSlash + 1, lastDot);
|
||
else {
|
||
stageTitle = "Simulator - " + fileAddress.substring(lastSlash + 1);
|
||
}
|
||
Stage stage = (Stage) stepintoButton.getScene().getWindow();
|
||
stage.setTitle(stageTitle);
|
||
}
|
||
}
|
||
|
||
private void initializeBreakpoints() {
|
||
lstContentListView.setCellFactory(createBreakpointCell());
|
||
}
|
||
|
||
private boolean checkBreakpoint(int pc) {
|
||
// Hier wird überprüft, ob ein Breakpoint am angegebenen Programmzähler gesetzt ist
|
||
return breakpoints.contains(pc);
|
||
}
|
||
|
||
|
||
private Callback<ListView<String>, ListCell<String>> createBreakpointCell() {
|
||
return listView -> new ListCell<String>() {
|
||
private final CheckBox breakpointCheckBox = new CheckBox();
|
||
{
|
||
breakpointCheckBox.setOnAction(event -> {
|
||
int index = getIndex();
|
||
if (breakpointCheckBox.isSelected()) {
|
||
breakpoints.add(index);
|
||
} else {
|
||
breakpoints.remove(index);
|
||
}
|
||
});
|
||
}
|
||
|
||
@Override
|
||
protected void updateItem(String item, boolean empty) {
|
||
super.updateItem(item, empty);
|
||
if (empty || item == null) {
|
||
setGraphic(null);
|
||
} else {
|
||
setText(item);
|
||
setGraphic(breakpointCheckBox);
|
||
breakpointCheckBox.setSelected(breakpoints.contains(getIndex()));
|
||
}
|
||
}
|
||
};
|
||
}
|
||
|
||
@FXML
|
||
protected void loadLSTFileContent(String fileContent) {
|
||
ObservableList<String> items = FXCollections.observableArrayList(fileContent.split("\n"));
|
||
lstContentListView.setItems(items);
|
||
}
|
||
|
||
|
||
private File chooseLSTFile() {
|
||
FileChooser fileChooser = new FileChooser();
|
||
fileChooser.getExtensionFilters().addAll(
|
||
new FileChooser.ExtensionFilter("LST Files", "*.lst", "*.LST"),
|
||
new FileChooser.ExtensionFilter("All Files", "*.*"));
|
||
return fileChooser.showOpenDialog(null);
|
||
}
|
||
|
||
@FXML
|
||
private void displayLSTFileContent(File selectedFile) {
|
||
try (BufferedReader reader = new BufferedReader(new FileReader(selectedFile))) {
|
||
ObservableList<String> contentList = FXCollections.observableArrayList();
|
||
String line;
|
||
while ((line = reader.readLine()) != null) {
|
||
contentList.add(line);
|
||
}
|
||
lstContentListView.setItems(contentList);
|
||
} catch (IOException e) {
|
||
e.printStackTrace();
|
||
}
|
||
}
|
||
|
||
@FXML
|
||
public void toggleWatchdog(ActionEvent actionEvent) {
|
||
if (wdtCheck.isSelected()){
|
||
watchdogTimer.enable();
|
||
|
||
}
|
||
else{
|
||
watchdogTimer.disable();
|
||
}
|
||
}
|
||
|
||
@FXML
|
||
private ToggleButtonGroup bgTRISA0;
|
||
@FXML
|
||
private ToggleButtonGroup bgTRISA1;
|
||
@FXML
|
||
private ToggleButtonGroup bgTRISA2;
|
||
@FXML
|
||
private ToggleButtonGroup bgTRISA3;
|
||
@FXML
|
||
private ToggleButtonGroup bgTRISA4;
|
||
@FXML
|
||
private ToggleButtonGroup bgTRISB0;
|
||
@FXML
|
||
private ToggleButtonGroup bgTRISB1;
|
||
@FXML
|
||
private ToggleButtonGroup bgTRISB2;
|
||
@FXML
|
||
private ToggleButtonGroup bgTRISB3;
|
||
@FXML
|
||
private ToggleButtonGroup bgTRISB4;
|
||
@FXML
|
||
private ToggleButtonGroup bgTRISB5;
|
||
@FXML
|
||
private ToggleButtonGroup bgTRISB6;
|
||
@FXML
|
||
private ToggleButtonGroup bgTRISB7;
|
||
@FXML
|
||
private ToggleButtonGroup bgPORTA0;
|
||
@FXML
|
||
private ToggleButtonGroup bgPORTA1;
|
||
@FXML
|
||
private ToggleButtonGroup bgPORTA2;
|
||
@FXML
|
||
private ToggleButtonGroup bgPORTA3;
|
||
@FXML
|
||
private ToggleButtonGroup bgPORTA4;
|
||
@FXML
|
||
private ToggleButtonGroup bgPORTB0;
|
||
@FXML
|
||
private ToggleButtonGroup bgPORTB1;
|
||
@FXML
|
||
private ToggleButtonGroup bgPORTB2;
|
||
@FXML
|
||
private ToggleButtonGroup bgPORTB3;
|
||
@FXML
|
||
private ToggleButtonGroup bgPORTB4;
|
||
@FXML
|
||
private ToggleButtonGroup bgPORTB5;
|
||
@FXML
|
||
private ToggleButtonGroup bgPORTB6;
|
||
@FXML
|
||
private ToggleButtonGroup bgPORTB7;
|
||
|
||
private static ToggleButtonGroup[] allTRISbuttons;
|
||
private static ToggleButtonGroup[] allPORTbuttons;
|
||
private static Circle[] allLEDsA;
|
||
private static Circle[] allLEDsB;
|
||
private static ToggleButtonGroup dummy = new ToggleButtonGroup(new ToggleButton(), new ToggleButton());
|
||
|
||
public void initialize() {
|
||
ToggleButtonGroup [] allTRISButtons = {bgTRISA0, bgTRISA1, bgTRISA2, bgTRISA3, bgTRISA4, dummy, dummy, dummy, bgTRISB0, bgTRISB1, bgTRISB2, bgTRISB3, bgTRISB4, bgTRISB5, bgTRISB6, bgTRISB7};
|
||
ToggleButtonGroup [] allPORTButtons = {bgPORTA0, bgPORTA1, bgPORTA2, bgPORTA3, bgPORTA4, dummy, dummy, dummy, bgPORTB0, bgPORTB1, bgPORTB2, bgPORTB3, bgPORTB4, bgPORTB5, bgPORTB6, bgPORTB7};
|
||
Circle[] allLEDsA = {ledA0, ledA1, ledA2, ledA3, ledA4};
|
||
Circle[] allLEDsB = {ledB0, ledB1, ledB2, ledB3, ledB4, ledB5, ledB6, ledB7};
|
||
for (int i = 0; i<allPORTButtons.length; i++) {
|
||
allTRISButtons[i].getToggles().get(0).setSelected(true);
|
||
allPORTButtons[i].getToggles().get(0).setSelected(true);
|
||
allTRISButtons[i].getToggles().get(1).setSelected(false);
|
||
allPORTButtons[i].getToggles().get(1).setSelected(false);
|
||
toggleButtonExt.addAlwaysOneSelectedSupport(allTRISButtons[i]);
|
||
toggleButtonExt.addAlwaysOneSelectedSupport(allPORTButtons[i]);
|
||
}
|
||
|
||
ledCheckA.setSelected(false);
|
||
ledCheckB.setSelected(false);
|
||
setTRISbuttons(allTRISButtons);
|
||
setPORTbuttons(allPORTButtons);
|
||
ioPorts.setLEDs(allLEDsA, allLEDsB);
|
||
|
||
lstContentListView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
|
||
|
||
autoRunGUI.setOnAction(this::autoRunGUI);
|
||
stopButton.setOnAction(this::stopAutoRun);
|
||
|
||
initializeBreakpoints();
|
||
executionTimeComboBox.setItems(FXCollections.observableArrayList("8 MHZ", "4 MHZ", "1 MHZ", "500 HZ", "100 HZ", "32 HZ"));
|
||
executionTimeComboBox.setValue("4 MHZ");
|
||
executionTimeComboBox.setOnAction(event -> updateExecutionTimeMultiplier());
|
||
}
|
||
|
||
|
||
|
||
private void setTRISbuttons(ToggleButtonGroup[] allButtons) {
|
||
allTRISbuttons = allButtons;
|
||
}
|
||
|
||
public FrontendSpecificToggleButtonGroup [] getTRISbuttons() {
|
||
return allTRISbuttons;
|
||
}
|
||
|
||
private void setPORTbuttons(ToggleButtonGroup[] allButtons) {
|
||
allPORTbuttons = allButtons;
|
||
}
|
||
|
||
public ToggleButtonGroup [] getPORTbuttons() {
|
||
return allPORTbuttons;
|
||
}
|
||
|
||
public Circle[] getLEDsA() {
|
||
return allLEDsA;
|
||
}
|
||
|
||
public Circle[] getLEDsB() {
|
||
return allLEDsB;
|
||
}
|
||
|
||
|
||
@FXML
|
||
private CheckBox ledCheckA;
|
||
@FXML
|
||
private CheckBox ledCheckB;
|
||
@FXML
|
||
private Circle ledA0;
|
||
@FXML
|
||
private Circle ledA1;
|
||
@FXML
|
||
private Circle ledA2;
|
||
@FXML
|
||
private Circle ledA3;
|
||
@FXML
|
||
private Circle ledA4;
|
||
@FXML
|
||
private Circle ledB0;
|
||
@FXML
|
||
private Circle ledB1;
|
||
@FXML
|
||
private Circle ledB2;
|
||
@FXML
|
||
private Circle ledB3;
|
||
@FXML
|
||
private Circle ledB4;
|
||
@FXML
|
||
private Circle ledB5;
|
||
@FXML
|
||
private Circle ledB6;
|
||
@FXML
|
||
private Circle ledB7;
|
||
|
||
@FXML
|
||
public void toggleLEDs (ActionEvent actionEvent) {
|
||
ioPorts.setLEDs(new boolean[]{ledCheckA.isSelected(), ledCheckB.isSelected()});
|
||
}
|
||
|
||
@FXML
|
||
private Label stackIndex;
|
||
|
||
@FXML
|
||
private ListView<String> stackVisual;
|
||
|
||
private static String format (String s) {
|
||
return (s.length() == 1) ? "0" + s : s;
|
||
}
|
||
|
||
private void updateStack (){
|
||
stackIndex.setText("Stack-Pointer: " + programStack.getStackPointer());
|
||
ObservableList<String> observedList = FXCollections.observableArrayList();
|
||
List<Integer> stackList = programStack.getStack();
|
||
for (Integer integer : stackList) {
|
||
observedList.add("0x" + format(Integer.toHexString(integer).toUpperCase()));
|
||
}
|
||
stackVisual.setItems(observedList);
|
||
}
|
||
|
||
private void updateWatchdog (){
|
||
wdtCheck.setText("Watchdog-Timer: " + watchdogTimer.get() + "µs");
|
||
}
|
||
|
||
@Override
|
||
public void initialize(PICComponentLocator locator) {
|
||
super.initialize(locator);
|
||
executionTime.registerObserver(this);
|
||
this.picComponents = locator;
|
||
System.out.println("Frontend");
|
||
}
|
||
|
||
@Override
|
||
public void executionTimeChanged() {
|
||
totalExecutionTimeLabel.setText("Total Execution Time: " + executionTime.getTotalExecutionTime() + "µs");
|
||
}
|
||
}
|
||
|