master
Dmitry Isaenko 2020-05-02 17:30:15 +03:00
commit ba92bee6e6
21 changed files with 1945 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
# Project exclude paths
/target/

39
JavaUSBTool.iml Normal file
View File

@ -0,0 +1,39 @@
<?xml version="1.0" encoding="UTF-8"?>
<module org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule="true" type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8">
<output url="file://$MODULE_DIR$/target/classes" />
<output-test url="file://$MODULE_DIR$/target/test-classes" />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
<excludeFolder url="file://$MODULE_DIR$/target" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="Maven: org.openjfx:javafx-controls:linux:11" level="project" />
<orderEntry type="library" name="Maven: org.openjfx:javafx-graphics:11" level="project" />
<orderEntry type="library" name="Maven: org.openjfx:javafx-media:linux:11" level="project" />
<orderEntry type="library" name="Maven: org.openjfx:javafx-fxml:linux:11" level="project" />
<orderEntry type="library" name="Maven: org.openjfx:javafx-controls:11" level="project" />
<orderEntry type="library" name="Maven: org.openjfx:javafx-graphics:linux:11" level="project" />
<orderEntry type="library" name="Maven: org.openjfx:javafx-base:11" level="project" />
<orderEntry type="library" name="Maven: org.openjfx:javafx-base:linux:11" level="project" />
<orderEntry type="library" name="Maven: org.openjfx:javafx-controls:win:11" level="project" />
<orderEntry type="library" name="Maven: org.openjfx:javafx-media:win:11" level="project" />
<orderEntry type="library" name="Maven: org.openjfx:javafx-fxml:win:11" level="project" />
<orderEntry type="library" name="Maven: org.openjfx:javafx-graphics:win:11" level="project" />
<orderEntry type="library" name="Maven: org.openjfx:javafx-controls:mac:11" level="project" />
<orderEntry type="library" name="Maven: org.openjfx:javafx-media:mac:11" level="project" />
<orderEntry type="library" name="Maven: org.openjfx:javafx-fxml:mac:11" level="project" />
<orderEntry type="library" name="Maven: org.openjfx:javafx-graphics:mac:11" level="project" />
<orderEntry type="library" name="Maven: org.usb4java:usb4java:1.3.0" level="project" />
<orderEntry type="library" name="Maven: org.usb4java:libusb4java:linux-x86:1.3.0" level="project" />
<orderEntry type="library" name="Maven: org.usb4java:libusb4java:linux-x86-64:1.3.0" level="project" />
<orderEntry type="library" name="Maven: org.usb4java:libusb4java:win32-x86:1.3.0" level="project" />
<orderEntry type="library" name="Maven: org.usb4java:libusb4java:win32-x86-64:1.3.0" level="project" />
<orderEntry type="library" name="Maven: org.usb4java:libusb4java:darwin-x86-64:1.3.0" level="project" />
<orderEntry type="library" name="Maven: org.usb4java:libusb4java:linux-arm:1.3.0" level="project" />
<orderEntry type="library" name="Maven: org.usb4java:libusb4java:linux-aarch64:1.3.0" level="project" />
<orderEntry type="library" name="Maven: org.apache.commons:commons-lang3:3.8.1" level="project" />
</component>
</module>

196
pom.xml Normal file
View File

@ -0,0 +1,196 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>loper</groupId>
<name>JavaUSBTool</name>
<artifactId>javausbtool</artifactId>
<version>0.1-SNAPSHOT</version>
<url>https://github.com/developersu/javausbtool/</url>
<description>
Java USB Tool for prototyping and/or debug
</description>
<inceptionYear>2019</inceptionYear>
<organization>
<name>Dmitry Isaenko</name>
<url>https://developersu.blogspot.com/</url>
</organization>
<licenses>
<license>
<name>GNU General Public License v3</name>
<url>http://www.gnu.org/licenses/gpl.txt</url>
<distribution>manual</distribution>
</license>
</licenses>
<developers>
<developer>
<id>developer.su</id>
<name>Dmitry Isaenko</name>
<roles>
<role>Developer</role>
</roles>
<timezone>+3</timezone>
<url>https://developersu.blogspot.com/</url>
</developer>
</developers>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<issueManagement>
<system>GitHub</system>
<url>https://github.com/developer_su/${project.artifactId}/issues</url>
</issueManagement>
<!-- openJFX Linux -->
<dependencies>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>11</version>
<classifier>linux</classifier>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-media</artifactId>
<version>11</version>
<classifier>linux</classifier>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-fxml</artifactId>
<version>11</version>
<classifier>linux</classifier>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-graphics</artifactId>
<version>11</version>
<classifier>linux</classifier>
<scope>compile</scope>
</dependency>
<!-- openJFX Windows -->
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>11</version>
<classifier>win</classifier>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-media</artifactId>
<version>11</version>
<classifier>win</classifier>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-fxml</artifactId>
<version>11</version>
<classifier>win</classifier>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-graphics</artifactId>
<version>11</version>
<classifier>win</classifier>
<scope>compile</scope>
</dependency>
<!-- openJFX MAC -->
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>11</version>
<classifier>mac</classifier>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-media</artifactId>
<version>11</version>
<classifier>mac</classifier>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-fxml</artifactId>
<version>11</version>
<classifier>mac</classifier>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-graphics</artifactId>
<version>11</version>
<classifier>mac</classifier>
<scope>compile</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.usb4java/usb4java -->
<dependency>
<groupId>org.usb4java</groupId>
<artifactId>usb4java</artifactId>
<version>1.3.0</version> <!-- Must be 1.2.0 for macOS lower than Mojave -->
<scope>compile</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<!-- Don't generate default JAR without dependencies -->
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>2.4</version>
<executions>
<execution>
<id>default-jar</id>
<phase>none</phase>
</execution>
</executions>
</plugin>
<!-- Generate JAR with dependencies -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.1.0</version>
<configuration>
<archive>
<manifest>
<mainClass>javausbtool.Main</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<id>make-assembly</id> <!-- this is used for inheritance merges -->
<phase>package</phase> <!-- bind to the packaging phase -->
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,66 @@
/*
Copyright 2020 Dmitry Isaenko
This file is part of JavaUSBTool.
JavaUSBTool is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
JavaUSBTool is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with JavaUSBTool. If not, see <https://www.gnu.org/licenses/>.
*/
package javausbtool;
import java.util.prefs.Preferences;
public class AppPreferences {
private static final AppPreferences INSTANCE = new AppPreferences();
public static AppPreferences getInstance() { return INSTANCE; }
private Preferences preferences;
private AppPreferences(){
preferences = Preferences.userRoot().node("javausbtool");
}
public void setSaveTo(String path){preferences.put("save_to_path", path);}
public String getSaveTo(){return preferences.get("save_to_path", System.getProperty("user.dir"));}
public String getRecentPath(){return preferences.get("recent_path", System.getProperty("user.home"));}
public void setRecentPath(String path){preferences.put("recent_path", path);}
public double getSceneWidth(){ return preferences.getDouble("window_width", 850.0); }
public void setSceneWidth(double value){ preferences.putDouble("window_width", value); }
public double getSceneHeight(){ return preferences.getDouble("window_height", 525.0); }
public void setSceneHeight(double value){ preferences.putDouble("window_height", value); }
// Usb setup
public short getVid(){ return (short) preferences.getInt("vid", 0x057E); }
public void setVid(short value){ preferences.putInt("vid", value); }
public short getPid(){ return (short) preferences.getInt("pid", 0x3000); }
public void setPid(short value){ preferences.putInt("pid", value); }
public int getInterface(){ return preferences.getInt("interface", 1); }
public void setInterface(int value){ preferences.putInt("interface", value); }
public int getDeviceConfiguration(){ return preferences.getInt("devconfiguration", 0); }
public void setDeviceConfiguration(int value){ preferences.putInt("devconfiguration", value); }
public boolean getHandleKernelDrvAutoDetach(){ return preferences.getBoolean("handle_kernel_driver", true); }
public void setHandleKernelDrvAutoDetach(boolean value){preferences.putBoolean("handle_kernel_driver", value);}
public boolean getSoftResetOnHandle(){ return preferences.getBoolean("soft_reset_on_handle", false); }
public void setSoftResetOnHandle(boolean value){preferences.putBoolean("soft_reset_on_handle", value);}
public int getReadBufferSize(){ return preferences.getInt("read_buffer_size", 512); }
public void setReadBufferSize(int value){ preferences.putInt("read_buffer_size", value); }
}

View File

@ -0,0 +1,76 @@
/*
Copyright 2020 Dmitry Isaenko
This file is part of JavaUSBTool.
JavaUSBTool is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
JavaUSBTool is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with JavaUSBTool. If not, see <https://www.gnu.org/licenses/>.
*/
package javausbtool;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.stage.Stage;
import javausbtool.controllers.LandingPageController;
import java.util.Locale;
import java.util.ResourceBundle;
public class JFXMain extends Application {
public static final String appVersion = "v0.1";
@Override
public void start(Stage primaryStage) throws Exception{
FXMLLoader loader = new FXMLLoader(getClass().getResource("/landingPage.fxml"));
Parent root = loader.load();
primaryStage.getIcons().addAll(
new Image(getClass().getResourceAsStream("/res/app_icon32x32.png")),
new Image(getClass().getResourceAsStream("/res/app_icon48x48.png")),
new Image(getClass().getResourceAsStream("/res/app_icon64x64.png")),
new Image(getClass().getResourceAsStream("/res/app_icon128x128.png"))
);
primaryStage.setTitle("JavaUSBTool "+appVersion);
primaryStage.setMinWidth(650);
primaryStage.setMinHeight(450);
Scene mainScene = new Scene(root,
AppPreferences.getInstance().getSceneWidth(),
AppPreferences.getInstance().getSceneHeight()
);
mainScene.getStylesheets().add("/res/app_light.css");
primaryStage.setScene(mainScene);
primaryStage.show();
LandingPageController controller = loader.getController();
primaryStage.setOnHidden(e-> {
AppPreferences.getInstance().setSceneHeight(mainScene.getHeight());
AppPreferences.getInstance().setSceneWidth(mainScene.getWidth());
controller.exit();
});
}
public static void main(String[] args) {
if ((args.length == 1) && (args[0].equals("-v") || args[0].equals("--version")))
System.out.println("JavaUSBTool "+JFXMain.appVersion);
else
launch(args);
}
}

View File

@ -0,0 +1,26 @@
/*
Copyright 2020 Dmitry Isaenko
This file is part of JavaUSBTool.
JavaUSBTool is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
JavaUSBTool is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with JavaUSBTool. If not, see <https://www.gnu.org/licenses/>.
*/
package javausbtool;
/**
* It's a workaround to execute JavaFX application.
* */
public class Main {
public static void main(String[] args){ JFXMain.main(args); }
}

View File

@ -0,0 +1,37 @@
/*
Copyright 2020 Dmitry Isaenko
This file is part of JavaUSBTool.
JavaUSBTool is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
JavaUSBTool is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with JavaUSBTool. If not, see <https://www.gnu.org/licenses/>.
*/
package javausbtool;
import javausbtool.controllers.LandingPageController;
public class MediatorControl {
private LandingPageController applicationController;
public static MediatorControl getInstance(){
return MediatorControlHold.INSTANCE;
}
private static class MediatorControlHold {
private static final MediatorControl INSTANCE = new MediatorControl();
}
public void setController(LandingPageController controller){
this.applicationController = controller;
}
public LandingPageController getContoller(){ return this.applicationController; }
}

View File

@ -0,0 +1,219 @@
/*
Copyright 2020 Dmitry Isaenko
This file is part of JavaUSBTool.
JavaUSBTool is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
JavaUSBTool is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with JavaUSBTool. If not, see <https://www.gnu.org/licenses/>.
*/
package javausbtool.controllers;
import javafx.concurrent.Task;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.*;
import javafx.stage.DirectoryChooser;
import javafx.stage.FileChooser;
import javausbtool.AppPreferences;
import javausbtool.MediatorControl;
import javausbtool.usb.UsbCommunications;
import java.io.File;
import java.net.URL;
import java.util.ResourceBundle;
public class LandingPageController implements Initializable {
@FXML
public TextArea logArea;
@FXML
public ProgressBar progressBar;
@FXML
private TextField vidTf,
pidTf,
devInterfaceTf,
devConfigurationTf,
readBufferSizeTf;
@FXML
private Label saveToLbl, sendFileLbl;
@FXML
private CheckBox handleKernelDrvDetachCb,
mandatorySoftResetCb;
@FXML
private Button changeSaveToBtn, fileToSendBtn, startBtn, stopBtn;
@FXML
private RadioButton readOnStartRb,
writeOnStartRb;
private String previouslyOpenedPath;
private File writeOnStartFile;
private Task<Void> usbCommunications;
private Thread workThread;
@Override
public void initialize(URL url, ResourceBundle resourceBundle) {
MediatorControl.getInstance().setController(this);
AppPreferences pref = AppPreferences.getInstance();
vidTf.setText(Short.toString(pref.getVid()));
pidTf.setText(Short.toString(pref.getPid()));
devInterfaceTf.setText(Integer.toString(pref.getInterface()));
devConfigurationTf.setText(Integer.toString(pref.getDeviceConfiguration()));
handleKernelDrvDetachCb.setSelected(pref.getHandleKernelDrvAutoDetach());
mandatorySoftResetCb.setSelected(pref.getSoftResetOnHandle());
readBufferSizeTf.setText(Integer.toString(pref.getReadBufferSize()));
vidTf.setTextFormatter(getNumericTextFormatter());
pidTf.setTextFormatter(getNumericTextFormatter());
devConfigurationTf.setTextFormatter(getNumericTextFormatter());
devConfigurationTf.setTextFormatter(getNumericTextFormatter());
readBufferSizeTf.setTextFormatter(getNumericTextFormatter());
saveToLbl.setText(pref.getSaveTo());
changeSaveToBtn.setOnAction(event -> setSaveToFolder());
ToggleGroup readWriteToggleGrp = new ToggleGroup();
readWriteToggleGrp.getToggles().addAll(readOnStartRb, writeOnStartRb);
readOnStartRb.setSelected(true);
previouslyOpenedPath = System.getProperty("user.home");
fileToSendBtn.setOnAction(event -> selectFileToSendInitially());
startBtn.setOnAction(event -> startProcess());
stopBtn.setOnAction(event -> stopProcess());
}
private TextFormatter getNumericTextFormatter(){
return new TextFormatter<>(change -> {
if (change.getControlNewText().matches("^[0-9]{0,}$"))
return change;
return null;
});
}
private void setSaveToFolder() {
DirectoryChooser dirChooser = new DirectoryChooser();
dirChooser.setTitle("Save files to...");
dirChooser.setInitialDirectory(new File(System.getProperty("user.home")));
File dir = dirChooser.showDialog(progressBar.getScene().getWindow());
if (dir != null && dir.exists())
saveToLbl.setText(dir.getAbsolutePath());
}
private void selectFileToSendInitially(){
File file;
FileChooser fileChooser = new FileChooser();
fileChooser.setTitle("Select file");
File validator = new File(previouslyOpenedPath);
if (validator.exists() && validator.isDirectory())
fileChooser.setInitialDirectory(validator);
else
return;
fileChooser.getExtensionFilters().add(new FileChooser.ExtensionFilter("Any", "*.*"));
file = fileChooser.showOpenDialog(sendFileLbl.getScene().getWindow());
if (file != null) {
sendFileLbl.setText(file.getName());
previouslyOpenedPath = file.getParent();
writeOnStartFile = file;
}
}
private void startProcess(){
logArea.clear();
if (writeOnStartRb.isSelected() && writeOnStartFile == null){
logArea.appendText("'Write on start' option selected but no file defined\n");
return;
}
if ((workThread != null && workThread.isAlive())){
logArea.appendText("Something still running\n");
return;
}
usbCommunications = new UsbCommunications(
(short) Integer.parseInt(vidTf.getText()),
(short) Integer.parseInt(pidTf.getText()),
Integer.parseInt(devInterfaceTf.getText()),
Integer.parseInt(devConfigurationTf.getText()),
handleKernelDrvDetachCb.isSelected(),
mandatorySoftResetCb.isSelected(),
Integer.parseInt(readBufferSizeTf.getText()),
saveToLbl.getText(),
readOnStartRb.isSelected(),
writeOnStartFile
);
workThread = new Thread(usbCommunications);
workThread.setDaemon(true);
workThread.start();
}
private void stopProcess(){
if (workThread != null && workThread.isAlive()){
usbCommunications.cancel(false);
logArea.appendText("Stop request sent\n");
}
else
logArea.appendText("Nothing to stop\n");
}
/**
* Save any changes made on settings on app
* */
public void exit() {
AppPreferences pref = AppPreferences.getInstance();
short shortValue;
try{
if ((shortValue = Short.parseShort(vidTf.getText())) > 0)
pref.setVid(shortValue);
}
catch (NumberFormatException e){ e.printStackTrace(); }
try{
if ((shortValue = Short.parseShort(pidTf.getText())) > 0)
pref.setPid(shortValue);
}
catch (NumberFormatException e){ e.printStackTrace(); }
int intValue;
try {
if ((intValue = Integer.parseInt(devInterfaceTf.getText())) > 0)
pref.setInterface(intValue);
}
catch (NumberFormatException e){ e.printStackTrace(); }
try {
if ((intValue = Integer.parseInt(devConfigurationTf.getText())) > 0)
pref.setDeviceConfiguration(intValue);
}
catch (NumberFormatException e){ e.printStackTrace(); }
pref.setHandleKernelDrvAutoDetach(handleKernelDrvDetachCb.isSelected());
pref.setSoftResetOnHandle(mandatorySoftResetCb.isSelected());
pref.setSaveTo(saveToLbl.getText());
try {
if ((intValue = Integer.parseInt(readBufferSizeTf.getText())) > 0)
pref.setReadBufferSize(intValue);
}
catch (NumberFormatException e){ e.printStackTrace(); }
}
}

View File

@ -0,0 +1,63 @@
/*
Copyright 2020 Dmitry Isaenko
This file is part of JavaUSBTool.
JavaUSBTool is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
JavaUSBTool is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with JavaUSBTool. If not, see <https://www.gnu.org/licenses/>.
*/
package javausbtool.misc;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
public class LogPrinter {
private MessagesConsumer msgConsumer;
private BlockingQueue<String> msgQueue;
private BlockingQueue<Double> progressQueue;
public LogPrinter(){
this.msgQueue = new LinkedBlockingQueue<>();
this.progressQueue = new LinkedBlockingQueue<>();
this.msgConsumer = new MessagesConsumer(this.msgQueue, this.progressQueue);
this.msgConsumer.start();
}
/**
* This is what will print to textArea of the application.
* */
public void print(String message){
try {
msgQueue.put(message+"\n");
}
catch (Exception e){
e.printStackTrace();
}
}
/**
* Update progress for progress bar
* */
public void updateProgress(Double value) {
try {
progressQueue.put(value);
}
catch (InterruptedException e){
e.printStackTrace();
}
}
/**
* When we're done - close it
* */
public void close(){
msgConsumer.interrupt();
}
}

View File

@ -0,0 +1,80 @@
/*
Copyright 2020 Dmitry Isaenko
This file is part of JavaUSBTool.
JavaUSBTool is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
JavaUSBTool is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with JavaUSBTool. If not, see <https://www.gnu.org/licenses/>.
*/
package javausbtool.misc;
import javafx.animation.AnimationTimer;
import javafx.scene.control.ProgressBar;
import javafx.scene.control.ProgressIndicator;
import javafx.scene.control.TextArea;
import javausbtool.MediatorControl;
import java.util.ArrayList;
import java.util.concurrent.BlockingQueue;
public class MessagesConsumer extends AnimationTimer {
private final BlockingQueue<String> msgQueue;
private final TextArea logsArea;
private final BlockingQueue<Double> progressQueue;
private final ProgressBar progressBar;
private boolean isInterrupted;
MessagesConsumer(BlockingQueue<String> msgQueue, BlockingQueue<Double> progressQueue){
this.isInterrupted = false;
this.msgQueue = msgQueue;
this.logsArea = MediatorControl.getInstance().getContoller().logArea;
this.progressQueue = progressQueue;
this.progressBar = MediatorControl.getInstance().getContoller().progressBar;
progressBar.setProgress(0.0);
progressBar.setProgress(ProgressIndicator.INDETERMINATE_PROGRESS);
}
@Override
public void handle(long l) {
ArrayList<String> messages = new ArrayList<>();
int msgRecieved = msgQueue.drainTo(messages);
if (msgRecieved > 0)
messages.forEach(logsArea::appendText);
ArrayList<Double> progress = new ArrayList<>();
int progressRecieved = progressQueue.drainTo(progress);
if (progressRecieved > 0) {
progress.forEach(prg -> {
if (prg != 1.0)
progressBar.setProgress(prg);
else
progressBar.setProgress(ProgressIndicator.INDETERMINATE_PROGRESS);
});
}
if (isInterrupted) {
progressBar.setProgress(0.0);
this.stop();
}
}
public void interrupt(){
this.isInterrupted = true;
}
}

View File

@ -0,0 +1,105 @@
/*
Copyright 2020 Dmitry Isaenko
This file is part of JavaUSBTool.
JavaUSBTool is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
JavaUSBTool is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with JavaUSBTool. If not, see <https://www.gnu.org/licenses/>.
*/
package javausbtool.usb;
import javafx.concurrent.Task;
import javausbtool.misc.LogPrinter;
import org.usb4java.DeviceHandle;
import java.io.File;
public class UsbCommunications extends Task<Void> {
private LogPrinter logPrinter;
private short vid;
private short pid;
private int interfaceNumber;
private int configurationNumber;
private boolean handleAutoKernelDriverDetach;
private boolean mandatoryDeviceReset;
private boolean shouldRead;
private File writeOnStartFile;
private int readBufferCapacity;
private String saveRepliesTo;
public UsbCommunications(
short vid,
short pid,
int interfaceNumber,
int configurationNumber,
boolean handleAutoKernelDriverDetach,
boolean mandatoryDeviceReset,
int readBufferCapacity,
String saveRepliesTo,
boolean shouldRead,
File writeOnStartFile
)
{
this.logPrinter = new LogPrinter();
this.vid = vid;
this.pid = pid;
this.interfaceNumber = interfaceNumber;
this.configurationNumber = configurationNumber;
this.handleAutoKernelDriverDetach = handleAutoKernelDriverDetach;
this.mandatoryDeviceReset = mandatoryDeviceReset;
this.readBufferCapacity = readBufferCapacity;
this.saveRepliesTo = saveRepliesTo;
this.shouldRead = shouldRead;
this.writeOnStartFile = writeOnStartFile;
}
@Override
protected Void call() {
logPrinter.print("\tStart UsbCommunications()");
UsbConnect usbConnect = UsbConnect.connect(logPrinter,
vid,
pid,
interfaceNumber,
configurationNumber,
handleAutoKernelDriverDetach,
mandatoryDeviceReset);
if (! usbConnect.isConnected()){
logPrinter.close();
return null;
}
DeviceHandle handler = usbConnect.getNsHandler();
new UsbLoop(handler,
readBufferCapacity,
writeOnStartFile,
this,
logPrinter,
saveRepliesTo,
shouldRead
);
usbConnect.close();
logPrinter.close();
return null;
}
}

View File

@ -0,0 +1,219 @@
/*
Copyright 2020 Dmitry Isaenko
This file is part of JavaUSBTool.
JavaUSBTool is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
JavaUSBTool is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with JavaUSBTool. If not, see <https://www.gnu.org/licenses/>.
*/
package javausbtool.usb;
import javausbtool.misc.LogPrinter;
import org.usb4java.*;
public class UsbConnect {
private Context contextNS;
private DeviceHandle handlerNS;
private Device deviceNS;
private LogPrinter logPrinter;
private boolean connected;
private short VENDOR_ID;
private short PRODUCT_ID;
private int INTERFACE_NUMBER;
private int returningValue;
private DeviceList deviceList;
public static UsbConnect connect(LogPrinter logPrinter,
short vid,
short pid,
int interfaceNumber,
int configurationNumber,
boolean handleAutoKernelDriverDetach,
boolean mandatoryDeviceReset){
UsbConnect usbConnect = new UsbConnect(logPrinter);
usbConnect.VENDOR_ID = vid;
usbConnect.PRODUCT_ID = pid;
usbConnect.INTERFACE_NUMBER = interfaceNumber;
try {
usbConnect.createContextAndInitLibUSB();
usbConnect.getDeviceList();
usbConnect.findDevice();
usbConnect.openDevice();
usbConnect.freeDeviceList();
if (handleAutoKernelDriverDetach)
usbConnect.setAutoDetachKernelDriver();
if (mandatoryDeviceReset)
usbConnect.resetDevice();
usbConnect.setConfiguration(configurationNumber);
usbConnect.claimInterface();
usbConnect.connected = true;
}
catch (Exception e){
logPrinter.print(e.getMessage());
usbConnect.close();
}
return usbConnect;
}
private UsbConnect(){}
private UsbConnect(LogPrinter logPrinter){
this.logPrinter = logPrinter;
this.connected = false;
};
private void createContextAndInitLibUSB() throws Exception{
// Creating Context required by libusb. Optional? Consider removing.
contextNS = new Context();
returningValue = LibUsb.init(contextNS);
if (returningValue != LibUsb.SUCCESS)
throw new Exception("LibUSB initialization failed: "+UsbErrorCodes.getErrCode(returningValue));
}
private void getDeviceList() throws Exception{
deviceList = new DeviceList();
returningValue = LibUsb.getDeviceList(contextNS, deviceList);
if (returningValue < 0)
throw new Exception("Can't get device list: "+UsbErrorCodes.getErrCode(returningValue));
}
private void findDevice() throws Exception{
// Searching for NS in devices: looking for NS
DeviceDescriptor descriptor;
for (Device device: deviceList){
descriptor = getDeviceDescriptor(device);
if ((descriptor.idVendor() == VENDOR_ID) && descriptor.idProduct() == PRODUCT_ID){
deviceNS = device;
break;
}
}
if (deviceNS == null) {
this.freeDeviceList();
throw new Exception("NS not found in connected USB devices");
}
}
private DeviceDescriptor getDeviceDescriptor(Device device) throws Exception{
DeviceDescriptor descriptor = new DeviceDescriptor();
returningValue = LibUsb.getDeviceDescriptor(device, descriptor);
if (returningValue != LibUsb.SUCCESS){
this.freeDeviceList();
throw new Exception("Get USB device descriptor failure: "+UsbErrorCodes.getErrCode(returningValue));
}
return descriptor;
}
private void openDevice() throws Exception{
// Handle NS device
handlerNS = new DeviceHandle();
returningValue = LibUsb.open(deviceNS, handlerNS);
if (returningValue == LibUsb.SUCCESS)
return;
handlerNS = null; // Avoid issue on close();
if (returningValue == LibUsb.ERROR_ACCESS) {
throw new Exception(String.format(
"Can't open NS USB device: %s\n" +
"Double check that you have administrator privileges (you're 'root') or check 'udev' rules set for this user (linux only)!\n\n" +
"Steps to set 'udev' rules:\n" +
"root # vim /etc/udev/rules.d/99-NS.rules\n" +
"SUBSYSTEM==\"usb\", ATTRS{idVendor}==\"%04x\", ATTRS{idProduct}==\"%04x\", GROUP=\"plugdev\"\n" +
"root # udevadm control --reload-rules && udevadm trigger\n", UsbErrorCodes.getErrCode(returningValue), VENDOR_ID, PRODUCT_ID));
}
else
throw new Exception("Can't open NS USB device: "+UsbErrorCodes.getErrCode(returningValue));
}
private void freeDeviceList(){
LibUsb.freeDeviceList(deviceList, true);
}
private void setAutoDetachKernelDriver(){
// Actually, there are no drivers in Linux kernel which uses this device.
returningValue = LibUsb.setAutoDetachKernelDriver(handlerNS, true);
if (returningValue != LibUsb.SUCCESS)
logPrinter.print("Skip kernel driver attach & detach ("+UsbErrorCodes.getErrCode(returningValue)+")");
}
private void resetDevice() throws Exception{
returningValue = LibUsb.resetDevice(handlerNS);
if (returningValue != LibUsb.SUCCESS)
throw new Exception("Reset device\n Returned: "+UsbErrorCodes.getErrCode(returningValue));
}
private void setConfiguration(int configuration) throws Exception{
returningValue = LibUsb.setConfiguration(handlerNS, configuration);
if (returningValue != LibUsb.SUCCESS)
throw new Exception("Unable to set active configuration on device: "+UsbErrorCodes.getErrCode(returningValue));
}
private void claimInterface() throws Exception{
// Claim interface
returningValue = LibUsb.claimInterface(handlerNS, INTERFACE_NUMBER);
if (returningValue != LibUsb.SUCCESS)
throw new Exception("Claim interface failure: "+UsbErrorCodes.getErrCode(returningValue));
}
/**
* Get USB status
* @return status of connection
*/
public boolean isConnected() { return connected; }
/**
* Getter for handler
* @return DeviceHandle of NS
*/
public DeviceHandle getNsHandler(){ return handlerNS; }
/**
* Getter for 'Bus ID' where NS located found
*/
public int getNsBus(){
return LibUsb.getBusNumber(deviceNS);
}
/**
* Getter for 'Device address' where NS located at
*/
public int getNsAddress(){
return LibUsb.getDeviceAddress(deviceNS);
}
/**
* Correct exit
* */
public void close(){
// Close handler in the end
if (handlerNS != null) {
// Try to release interface
returningValue = LibUsb.releaseInterface(handlerNS, INTERFACE_NUMBER);
if (returningValue != LibUsb.SUCCESS) {
logPrinter.print("Release interface failure: " +
UsbErrorCodes.getErrCode(returningValue) +
" (sometimes it's not an issue)");
}
LibUsb.close(handlerNS);
}
// Close context in the end
if (contextNS != null)
LibUsb.exit(contextNS);
}
}

View File

@ -0,0 +1,56 @@
/*
Copyright 2020 Dmitry Isaenko
This file is part of JavaUSBTool.
JavaUSBTool is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
JavaUSBTool is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with JavaUSBTool. If not, see <https://www.gnu.org/licenses/>.
*/
package javausbtool.usb;
import org.usb4java.LibUsb;
public class UsbErrorCodes {
public static String getErrCode(int value){
switch (value){
case LibUsb.ERROR_ACCESS:
return "ERROR_ACCESS";
case LibUsb.ERROR_BUSY:
return "ERROR_BUSY";
case LibUsb.ERROR_INTERRUPTED:
return "ERROR_INTERRUPTED";
case LibUsb.ERROR_INVALID_PARAM:
return "ERROR_INVALID_PARAM";
case LibUsb.ERROR_IO:
return "ERROR_IO";
case LibUsb.ERROR_NO_DEVICE:
return "ERROR_NO_DEVICE";
case LibUsb.ERROR_NO_MEM:
return "ERROR_NO_MEM";
case LibUsb.ERROR_NOT_FOUND:
return "ERROR_NOT_FOUND";
case LibUsb.ERROR_NOT_SUPPORTED:
return "ERROR_NOT_SUPPORTED";
case LibUsb.ERROR_OTHER:
return "ERROR_OTHER";
case LibUsb.ERROR_OVERFLOW:
return "ERROR_OVERFLOW";
case LibUsb.ERROR_PIPE:
return "ERROR_PIPE";
case LibUsb.ERROR_TIMEOUT:
return "ERROR_TIMEOUT";
default:
return Integer.toString(value);
}
}
}

View File

@ -0,0 +1,202 @@
/*
Copyright 2020 Dmitry Isaenko
This file is part of JavaUSBTool.
JavaUSBTool is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
JavaUSBTool is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with JavaUSBTool. If not, see <https://www.gnu.org/licenses/>.
*/
package javausbtool.usb;
import javafx.concurrent.Task;
import javausbtool.misc.LogPrinter;
import org.usb4java.DeviceHandle;
import org.usb4java.LibUsb;
import java.io.*;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
/**
* Tinfoil processing
* */
class UsbLoop {
private LogPrinter logPrinter;
private DeviceHandle handlerNS;
private Task<Void> task;
private int readBufferCapacity;
private long readCounter;
private File saveRepliesFolder;
public UsbLoop(DeviceHandle handler,
int readBufferCapacity,
File fileToSendOnStart,
Task<Void> task,
LogPrinter logPrinter,
String saveRepliesTo,
boolean shouldRead
){
this.handlerNS = handler;
this.task = task;
this.logPrinter = logPrinter;
this.readBufferCapacity = readBufferCapacity;
this.readCounter = 0;
logPrinter.print("============= UsbProtocol =============");
this.saveRepliesFolder = new File(saveRepliesTo+ LocalTime.now().format(DateTimeFormatter.ofPattern("HH:mm:ss")));
saveRepliesFolder.mkdirs();
logPrinter.print("Save replies to dir: "+saveRepliesFolder.getName());
if (! shouldRead) {
try {
writeFile(fileToSendOnStart);
}
catch (Exception e){
e.printStackTrace();
logPrinter.print(e.getMessage());
logPrinter.print("Terminating now");
return;
}
}
readLoop();
}
private void readLoop(){
while (true){
try {
dumpData(readUsb());
}
catch (InterruptedException ioe){
logPrinter.print("Execution interrupted");
return;
}
catch (Exception e){
e.printStackTrace();
logPrinter.print(e.getMessage());
logPrinter.print("Terminating now");
return;
}
}
};
void writeFile(File file) throws IOException, NullPointerException, ArithmeticException {
byte[] readBuffer;
long currentOffset = 0;
int chunk = 8388608;
long size = file.length();
BufferedInputStream bufferedInStream = new BufferedInputStream(new FileInputStream(file));
while (currentOffset < size) {
if ((currentOffset + chunk) >= size)
chunk = Math.toIntExact(size - currentOffset);
logPrinter.updateProgress((currentOffset + chunk) / (size / 100.0) / 100.0);
readBuffer = new byte[chunk];
if (bufferedInStream.read(readBuffer) != chunk)
throw new IOException("Reading from file stream suddenly ended.");
if (writeUsb(readBuffer))
throw new IOException("Failure during file transfer.");
currentOffset += chunk;
}
bufferedInStream.close();
logPrinter.updateProgress(1.0);
}
private void dumpData(byte[] data) throws Exception{
this.readCounter++;
File chunkFile = new File(saveRepliesFolder.getAbsolutePath()+File.separator+readCounter+".bin");
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(chunkFile, false));
bos.write(data);
bos.close();
}
/**
* Sending any byte array to USB device
* @return 'false' if no issues
* 'true' if errors happened
* */
private boolean writeUsb(byte[] message) {
ByteBuffer writeBuffer = ByteBuffer.allocateDirect(message.length); //writeBuffer.order() equals BIG_ENDIAN;
writeBuffer.put(message); // Don't do writeBuffer.rewind();
IntBuffer writeBufTransferred = IntBuffer.allocate(1);
int result;
//int varVar = 0; //todo:remove
while (! task.isCancelled()) {
/*
if (varVar != 0)
logPrinter.print("writeUsb() retry cnt: "+varVar, EMsgType.INFO); //NOTE: DEBUG
varVar++;
*/
result = LibUsb.bulkTransfer(handlerNS, (byte) 0x01, writeBuffer, writeBufTransferred, 5050); // last one is TIMEOUT. 0 stands for unlimited. Endpoint OUT = 0x01
switch (result){
case LibUsb.SUCCESS:
if (writeBufTransferred.get() == message.length)
return false;
logPrinter.print("TF Data transfer issue [write]" +
"\n Requested: "+message.length+
"\n Transferred: "+writeBufTransferred.get());
return true;
case LibUsb.ERROR_TIMEOUT:
//System.out.println("writeBuffer position: "+writeBuffer.position()+" "+writeBufTransferred.get());
//writeBufTransferred.clear(); // MUST BE HERE IF WE 'GET()' IT
continue;
default:
logPrinter.print("TF Data transfer issue [write]" +
"\n Returned: "+ UsbErrorCodes.getErrCode(result) +
"\n (execution stopped)");
return true;
}
}
logPrinter.print("INFO TF Execution interrupted");
return true;
}
/**
* Reading what USB device responded.
* @return byte array if data read successful
* 'null' if read failed
* */
private byte[] readUsb() throws Exception{
ByteBuffer readBuffer = ByteBuffer.allocateDirect(readBufferCapacity);
// We can limit it to 32 bytes, but there is a non-zero chance to got OVERFLOW from libusb.
IntBuffer readBufTransferred = IntBuffer.allocate(1);
int result;
while (! task.isCancelled()) {
result = LibUsb.bulkTransfer(handlerNS, (byte) 0x81, readBuffer, readBufTransferred, 1000); // last one is TIMEOUT. 0 stands for unlimited. Endpoint IN = 0x81
switch (result) {
case LibUsb.SUCCESS:
int trans = readBufTransferred.get();
byte[] receivedBytes = new byte[trans];
readBuffer.get(receivedBytes);
return receivedBytes;
case LibUsb.ERROR_TIMEOUT:
continue;
default:
throw new Exception("Data transfer issue [read]" +
"\n Returned: " + UsbErrorCodes.getErrCode(result)+
"\n (execution stopped)");
}
}
throw new InterruptedException("Execution interrupted");
}
}

View File

@ -0,0 +1,117 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.CheckBox?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.ProgressBar?>
<?import javafx.scene.control.RadioButton?>
<?import javafx.scene.control.Separator?>
<?import javafx.scene.control.SplitPane?>
<?import javafx.scene.control.TextArea?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.control.TitledPane?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.shape.SVGPath?>
<AnchorPane minHeight="400.0" minWidth="400.0" xmlns="http://javafx.com/javafx/8.0.141" xmlns:fx="http://javafx.com/fxml/1" fx:controller="javausbtool.controllers.LandingPageController">
<children>
<VBox AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<children>
<SplitPane dividerPositions="0.5" VBox.vgrow="ALWAYS">
<items>
<VBox spacing="5.0">
<children>
<TitledPane expanded="false" text="USB Connection configuration">
<content>
<VBox spacing="5.0">
<children>
<HBox alignment="CENTER_LEFT" spacing="5.0">
<children>
<Label minWidth="100.0" text="VID" />
<TextField fx:id="vidTf" />
</children>
</HBox>
<HBox alignment="CENTER_LEFT" spacing="5.0">
<children>
<Label minWidth="100.0" text="PID" />
<TextField fx:id="pidTf" />
</children>
</HBox>
<HBox alignment="CENTER_LEFT" spacing="5.0">
<children>
<Label minWidth="100.0" text="Interface" />
<TextField fx:id="devInterfaceTf" />
</children>
</HBox>
<HBox alignment="CENTER_LEFT" spacing="5.0">
<children>
<Label minWidth="100.0" text="Configuration" />
<TextField fx:id="devConfigurationTf" />
</children>
</HBox>
<CheckBox fx:id="handleKernelDrvDetachCb" mnemonicParsing="false" text="Automatically handle kernel driver detach" />
<CheckBox fx:id="mandatorySoftResetCb" mnemonicParsing="false" text="Perform soft-reset device once handle" />
</children>
</VBox>
</content>
</TitledPane>
<HBox alignment="CENTER_LEFT" spacing="5.0">
<children>
<Button fx:id="changeSaveToBtn" mnemonicParsing="false">
<graphic>
<SVGPath content="M3,4C1.89,4 1,4.89 1,6V18A2,2 0 0,0 3,20H11V18.11L21,8.11V8C21,6.89 20.1,6 19,6H11L9,4H3M21.04,11.13C20.9,11.13 20.76,11.19 20.65,11.3L19.65,12.3L21.7,14.35L22.7,13.35C22.92,13.14 22.92,12.79 22.7,12.58L21.42,11.3C21.31,11.19 21.18,11.13 21.04,11.13M19.07,12.88L13,18.94V21H15.06L21.12,14.93L19.07,12.88Z" />
</graphic>
</Button>
<Label text="Save recieved to:" />
<Label fx:id="saveToLbl" />
</children>
</HBox>
<Separator prefWidth="200.0" />
<HBox alignment="CENTER_LEFT" spacing="5.0">
<children>
<Label text="NS read buffer size:" />
<TextField fx:id="readBufferSizeTf" />
<Label text="(e.g. 512 or 4096)" />
</children>
</HBox>
<RadioButton fx:id="readOnStartRb" mnemonicParsing="false" text="Read on start" />
<HBox alignment="CENTER_LEFT" spacing="5.0">
<children>
<RadioButton fx:id="writeOnStartRb" mnemonicParsing="false" text="Write on start" />
<Button fx:id="fileToSendBtn" mnemonicParsing="false">
<graphic>
<SVGPath content="M3,4C1.89,4 1,4.89 1,6V18A2,2 0 0,0 3,20H11V18.11L21,8.11V8C21,6.89 20.1,6 19,6H11L9,4H3M21.04,11.13C20.9,11.13 20.76,11.19 20.65,11.3L19.65,12.3L21.7,14.35L22.7,13.35C22.92,13.14 22.92,12.79 22.7,12.58L21.42,11.3C21.31,11.19 21.18,11.13 21.04,11.13M19.07,12.88L13,18.94V21H15.06L21.12,14.93L19.07,12.88Z" />
</graphic>
</Button>
<Label fx:id="sendFileLbl" text="?" />
</children>
</HBox>
<HBox alignment="CENTER" spacing="5.0">
<children>
<Button fx:id="startBtn" mnemonicParsing="false" text="Start" />
<Button fx:id="stopBtn" mnemonicParsing="false" text="Stop" />
</children>
</HBox>
</children>
<padding>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</padding>
</VBox>
<TextArea fx:id="logArea" editable="false" />
</items>
</SplitPane>
<AnchorPane>
<children>
<ProgressBar fx:id="progressBar" progress="0.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
</children>
</AnchorPane>
</children>
</VBox>
</children>
<padding>
<Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
</padding>
</AnchorPane>

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View File

@ -0,0 +1,442 @@
@font-face {
src: url("NotoMono-Regular.ttf");
}
.root{
-fx-background: #f5f5f5;
}
.button SVGPath{
-fx-fill: #2c2c2c;
}
.button:hover SVGPath, .choice-box:hover SVGPath, .button:focused:hover SVGPath, .choice-box:focused:hover SVGPath, .button:pressed SVGPath, .button:pressed:hover SVGPath{
-fx-fill: #ffffff;
}
.button{
-fx-background-color: #ffffff;
-fx-border-color: #0d98ba;
-fx-background-radius: 5;
-fx-border-radius: 5;
-fx-border-width: 1;
-fx-text-fill: #2c2c2c;
}
.button:disabled SVGPath{
-fx-fill: #bbbbbb;
}
.button:disabled {
-fx-opacity: 1.0 ;
-fx-background-color: #959595;
-fx-border-color: #959595;
-fx-background-radius: 5;
-fx-border-radius: 5;
-fx-border-width: 1;
-fx-text-fill: #bbbbbb;
}
.button:hover, .choice-box:hover, .button:focused:hover, .choice-box:focused:hover{
-fx-background-color: #0d98ba;
-fx-border-color: #0d98ba;
-fx-background-radius: 5;
-fx-border-radius: 5;
-fx-border-width: 1;
-fx-text-fill: #ffffff;
}
.button:focused, .choice-box:focused{
-fx-background-color: #d0d0d0;
-fx-border-color: #0d98ba;
-fx-background-radius: 5;
-fx-border-radius: 5;
-fx-border-width: 1;
-fx-text-fill: #2c2c2c;
}
.button:pressed, .button:pressed:hover{
-fx-background-color: #007cad;
-fx-border-color: #007cad;
-fx-background-radius: 5;
-fx-border-radius: 5;
-fx-border-width: 1;
-fx-text-fill: #ffffff;
}
// -========================+ Button RED =====================-
.buttonRed SVGPath{
-fx-fill: #e34234;
}
.buttonRed{
-fx-background-color: #ffffff;
-fx-border-color: #e34234;
-fx-background-radius: 5;
-fx-border-radius: 5;
-fx-border-width: 1;
-fx-text-fill: #2c2c2c;
}
.buttonRed:hover, .buttonRed:focused:hover{
-fx-background-color: #e34234;
-fx-border-color: #e34234;
-fx-background-radius: 5;
-fx-border-radius: 5;
-fx-border-width: 1;
-fx-text-fill: #ffffff;
}
.buttonRed:focused{
-fx-background-color: #d0d0d0;
-fx-border-color: #cc0605;
-fx-background-radius: 5;
-fx-border-radius: 5;
-fx-border-width: 1;
-fx-text-fill: #2c2c2c;
}
.buttonRed:pressed, .buttonRed:pressed:hover{
-fx-background-color: #cc0605;
-fx-border-color: #cc0605;
-fx-background-radius: 5;
-fx-border-radius: 5;
-fx-border-width: 1;
-fx-text-fill: #ffffff;
}
// -========================+ TextArea =====================-
.text-area{
-fx-background-color: transparent;
-fx-control-inner-background: #fefefe;
-fx-font-family: "Noto Mono";
-fx-background-radius: 3;
-fx-border-color: #0d98ba;
-fx-border-radius: 3;
-fx-border-width: 2;
-fx-text-fill: #2c2c2c;
}
.progress-bar {
-fx-fit-to-width: true;
-fx-background-color: transparent;
-fx-box-border: transparent;
}
.progress-bar > .track {
-fx-background-color: transparent;
-fx-box-border: transparent;
}
.progress-bar > .bar {
-fx-background-color: linear-gradient(to right, #00bce4, #ff5f53);
-fx-background-radius: 2;
-fx-background-insets: 1 1 2 1;
-fx-padding: 0.23em;
}
.dialog-pane {
-fx-background-color: #fefefe;
}
.dialog-pane > .button-bar > .container{
-fx-background-color: #f5f5f5;
}
.dialog-pane > .label{
-fx-padding: 10 5 10 5;
}
.tool-bar{
-fx-background-color: transparent;
}
.special-pane-as-border{
-fx-background-color: #2c2c2c;
-fx-min-height: 1;
}
// -======================== Choice box =========================-
.choice-box {
-fx-background-color: #fefefe;
-fx-border-color: #fefefe;
-fx-border-radius: 3;
-fx-border-width: 2;
-fx-mark-color: #eea11e;
-fx-effect: dropshadow(three-pass-box, #414a4c, 2, 0, 0, 0);
}
.choice-box > .label {
-fx-text-fill: #2c2c2c;
}
.choice-box:pressed, .choice-box:pressed:hover{
-fx-background-color: #fefefe;
-fx-border-color: #eea11e;
-fx-border-radius: 3;
-fx-border-width: 2;
-fx-text-fill: #2c2c2c;
}
// Background color of the whole context menu
.choice-box .context-menu {
-fx-background-color: #fefefe;
}
// Focused item background color in the list
.choice-box .context-menu .menu-item:focused {
-fx-background-color: #eea11e;
}
.choice-box .context-menu .menu-item:focused .label {
-fx-text-fill: #2c2c2c;
}
// -======================== TAB PANE =========================-
/*
.tab-pane .tab SVGPath{
-fx-fill: #2c2c2c; // OK
}
.tab-pane .tab:selected SVGPath{
-fx-fill: #1dacd6; // OK
}
.tab-pane .tab{
-fx-background-color: #fefefe; //ok
-fx-focus-color: transparent;
-fx-faint-focus-color: transparent;
-fx-border-radius: 0 0 0 0;
-fx-border-width: 0 0 1 0;
-fx-border-color: #fefefe; //OK
}
.tab-pane .tab:selected{
-fx-background-color: #ffefd5; // OK
-fx-focus-color: transparent;
-fx-faint-focus-color: transparent;
-fx-border-radius: 0 0 0 0;
-fx-border-width: 0 0 1 0;
-fx-border-color: #9aceeb; // OK
}
.tab-pane > .tab-header-area {
-fx-background-insets: 0.0;
-fx-padding: 5 5 5 5 ;
}
.tab-pane > .tab-header-area > .tab-header-background
{
-fx-background-color: #fefefe; // OK
}
.tab-pane > .tab-header-area > .headers-region > .tab {
-fx-padding: 10;
}
*/
// -======================== TAB PANE =========================-
.tab-pane .tab SVGPath{
-fx-fill: #2c2c2c;
}
.tab-pane .tab:selected SVGPath, .tab-pane .tab:hover SVGPath{
-fx-fill: #ffffff;
}
.tab-pane .tab .label{
-fx-text-fill: #2c2c2c;
}
.tab-pane .tab{
-fx-background-color: #f5f5f5;
-fx-focus-color: transparent;
-fx-faint-focus-color: transparent;
-fx-background-radius: 5;
}
.tab-pane .tab:selected .label{
-fx-text-fill: #ffffff;
}
.tab-pane .tab:selected{
-fx-background-color: #007cad;
-fx-focus-color: transparent;
-fx-faint-focus-color: transparent;
-fx-background-radius: 5;
}
.tab-pane .tab:hover .label{
-fx-text-fill: #ffffff;
}
.tab-pane .tab:hover{
-fx-background-color: #0d98ba;
-fx-focus-color: transparent;
-fx-faint-focus-color: transparent;
-fx-background-radius: 5;
}
.tab-pane > .tab-header-area {
-fx-background-insets: 0.0;
-fx-padding: 5 5 5 5 ;
}
.tab-pane > .tab-header-area > .tab-header-background
{
-fx-background-color: #f5f5f5;
-fx-border-width: 0 0 1 0;
-fx-border-color: #959595;
}
.tab-pane > .tab-header-area > .headers-region > .tab {
-fx-padding: 10;
}
// Special colors for in-file sub-files
.tab-pane .tab-sub:selected{
-fx-background-color: #b90078;
-fx-focus-color: transparent;
-fx-faint-focus-color: transparent;
-fx-background-radius: 5;
}
.tab-pane .tab-sub:hover{
-fx-background-color: #df0091;
-fx-focus-color: transparent;
-fx-faint-focus-color: transparent;
-fx-background-radius: 5;
}
// -=========================== TABLE ======================-
.table-view {
-fx-background-color: #fefefe;
-fx-background-image: url(app_logo.png);
-fx-background-position: center;
-fx-background-repeat: no-repeat;
-fx-background-radius: 3;
-fx-border-color: #0d98ba;
-fx-border-radius: 3;
-fx-border-width: 2;
}
.table-view .arrow {
-fx-mark-color: #2c2c2c ;
}
.table-view .column-header {
-fx-background-color: transparent;
-fx-border-width: 0 1 2 0;
-fx-border-color: #b0b0b0;
}
.table-view .column-header-background .label{
-fx-background-color: transparent;
-fx-text-fill: #2c2c2c;
}
.table-view .column-header-background, .table-view .filler{
-fx-background-color: #fefefe;
}
.table-view .table-cell{
-fx-text-fill: #2c2c2c;
}
.table-row-cell, .table-row-cell:filled:selected, .table-row-cell:selected{
-fx-background-color: -fx-table-cell-border-color, #f0fff0;
-fx-background-insets: 0, 0 0 1 0;
-fx-padding: 0.0em; /* 0 */
-fx-table-cell-border-color: #b0b0b0;
}
.table-row-cell .text, .table-row-cell:odd .text {
-fx-fill: #2c2c2c;
}
.table-row-cell:filled:selected .text, .table-row-cell:odd:filled:selected .text{
-fx-fill: #2c2c2c;
-fx-font-weight: bold
}
.table-row-cell:odd, .table-row-cell:odd:filled:selected, .table-row-cell:odd:selected{
-fx-background-color: -fx-table-cell-border-color, #fefefe;
-fx-background-insets: 0, 0 0 1 0;
-fx-padding: 0.0em; /* 0 */
-fx-table-cell-border-color: #b0b0b0;
}
// -========================== Context menu =====================-
.context-menu {
-fx-background-color: #fefefe;
-fx-cursor: hand;
}
.context-menu .menu-item .label {
-fx-text-fill: #2c2c2c;
}
.context-menu .menu-item:focused .label {
-fx-text-fill: white;
}
// -========================== Text Field =====================-
.text-field {
-fx-border-color: #289de8;
-fx-border-width: 0 0 1 0;
-fx-background-color: transparent;
-fx-text-fill: #2c2c2c;
}
.text-field:focused {
-fx-border-color: #e82382;
-fx-border-width: 0 0 1 0;
-fx-background-color: transparent;
-fx-text-fill: #e82382;
}
.customMainGrid {
-fx-border-color: #191919;
-fx-border-width: 1;
}
.customTitleGrid {
-fx-background-color: #191919, #f0fff0;
-fx-background-insets: 0, 1;
}
.customGrid {
-fx-background-color: #191919, #f0f0f0;
-fx-background-insets: 0, 1;
}
// -======================== Titiled Pane ========================-
.titled-pane
{
-fx-text-fill: #000000;
}
.titled-pane:focused
{
-fx-text-fill: white;
}
.titled-pane > .title
{
-fx-background-color: #efebe6;
-fx-background-insets: 0, 1, 2;
-fx-background-radius: 5 5 0 0, 4 4 0 0, 3 3 0 0;
-fx-padding: 3 11 5 11;
-fx-border-width: 1;
-fx-border-radius: 5 5 0 0, 4 4 0 0, 3 3 0 0;
-fx-border-color: #c8c8c8;
}
.titled-pane:focused > .title
{
-fx-background-color: #d5713f;
-fx-background-insets: 0, 1, 2;
-fx-background-radius: 5 5 0 0, 4 4 0 0, 3 3 0 0;
-fx-padding: 3 11 5 11;
-fx-border-width: 1;
-fx-border-radius: 5 5 0 0, 4 4 0 0, 3 3 0 0;
-fx-border-color: #c8c8c8;
}
.titled-pane > .title > .arrow-button
{
-fx-background-color: transparent;
-fx-background-insets: 0;
-fx-background-radius: 0;
-fx-padding: 0 3 0 0;
}
.titled-pane > .title > .arrow-button .arrow
{
-fx-background-color: #575757, #575757;
-fx-background-insets: 1 0 -1 0, 0;
-fx-padding: 3 3.75 3 3.75;
-fx-shape: "M 0 0 h 7 l -3.5 4 z";
}
.titled-pane:collapsed > .title > .arrow-button .arrow
{
-fx-rotate: -90;
}
.titled-pane:focused > .title > .arrow-button .arrow
{
-fx-background-color: white, white;
}
.regionFolder {
-fx-shape: "M10,4H4C2.89,4 2,4.89 2,6V18A2,2 0 0,0 4,20H20A2,2 0 0,0 22,18V8C22,6.89 21.1,6 20,6H12L10,4Z";
-fx-background-color: #ffbf00;
-fx-min-height: 17.0;
-fx-min-width: 17.5;
}
.regionFile {
-fx-shape: "M13,9V3.5L18.5,9M6,2C4.89,2 4,2.89 4,4V20A2,2 0 0,0 6,22H18A2,2 0 0,0 20,20V8L14,2H6Z";
-fx-background-color: #e54d1e;
-fx-min-height: 17.0;
-fx-min-width: 13;
}