diff --git a/pom.xml b/pom.xml
index fd5943d..e529882 100644
--- a/pom.xml
+++ b/pom.xml
@@ -8,7 +8,7 @@
NS-USBloader
ns-usbloader
- 2.2.1-SNAPSHOT
+ 3.0-SNAPSHOT
https://github.com/developersu/ns-usbloader/
diff --git a/src/main/java/nsusbloader/AppPreferences.java b/src/main/java/nsusbloader/AppPreferences.java
index 4eaca73..3e009b8 100644
--- a/src/main/java/nsusbloader/AppPreferences.java
+++ b/src/main/java/nsusbloader/AppPreferences.java
@@ -152,4 +152,7 @@ public class AppPreferences {
// RCM //
public String getRecentRcm(int num){ return preferences.get(String.format("RCM_%02d", num), ""); }
public void setRecentRcm(int num, String value){ preferences.put(String.format("RCM_%02d", num), value); }
+ // NXDT //
+ public String getNXDTSaveToLocation(){ return preferences.get("nxdt_saveto", System.getProperty("user.home")); }
+ public void setNXDTSaveToLocation(String value){ preferences.put("nxdt_saveto", value); }
}
diff --git a/src/main/java/nsusbloader/Controllers/NSLMainController.java b/src/main/java/nsusbloader/Controllers/NSLMainController.java
index 07c800a..495be84 100644
--- a/src/main/java/nsusbloader/Controllers/NSLMainController.java
+++ b/src/main/java/nsusbloader/Controllers/NSLMainController.java
@@ -48,6 +48,8 @@ public class NSLMainController implements Initializable {
private SplitMergeController SplitMergeTabController;
@FXML
private RcmController RcmTabController;
+ @FXML
+ private NxdtController NXDTabController;
@Override
public void initialize(URL url, ResourceBundle rb) {
@@ -110,6 +112,8 @@ public class NSLMainController implements Initializable {
}
public RcmController getRcmCtrlr(){ return RcmTabController; }
+
+ public NxdtController getNXDTabController(){ return NXDTabController; }
/**
* Save preferences before exit
* */
@@ -135,5 +139,6 @@ public class NSLMainController implements Initializable {
SplitMergeTabController.updatePreferencesOnExit(); // NOTE: This shit above should be re-written to similar pattern
RcmTabController.updatePreferencesOnExit();
+ NXDTabController.updatePreferencesOnExit();
}
}
diff --git a/src/main/java/nsusbloader/Controllers/NxdtController.java b/src/main/java/nsusbloader/Controllers/NxdtController.java
new file mode 100644
index 0000000..ecdc0f8
--- /dev/null
+++ b/src/main/java/nsusbloader/Controllers/NxdtController.java
@@ -0,0 +1,133 @@
+/*
+ Copyright 2019-2020 Dmitry Isaenko
+
+ This file is part of NS-USBloader.
+
+ NS-USBloader 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.
+
+ NS-USBloader 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 NS-USBloader. If not, see .
+*/
+package nsusbloader.Controllers;
+
+import javafx.concurrent.Task;
+import javafx.fxml.FXML;
+import javafx.fxml.Initializable;
+import javafx.scene.control.Button;
+import javafx.scene.control.Label;
+import javafx.scene.layout.Region;
+import javafx.stage.DirectoryChooser;
+import nsusbloader.AppPreferences;
+import nsusbloader.MediatorControl;
+import nsusbloader.NSLDataTypes.EModule;
+import nsusbloader.Utilities.NxdtTask;
+
+import java.io.File;
+import java.net.URL;
+import java.util.ResourceBundle;
+
+public class NxdtController implements Initializable {
+ @FXML
+ private Label saveToLocationLbl, statusLbl;
+
+ @FXML
+ private Button injectPldBtn;
+
+ private ResourceBundle rb;
+
+ private Region btnDumpStopImage;
+
+ private Task NxdtTask;
+ private Thread workThread;
+
+ @Override
+ public void initialize(URL url, ResourceBundle resourceBundle) {
+ this.rb = resourceBundle;
+
+ saveToLocationLbl.setText(AppPreferences.getInstance().getNXDTSaveToLocation());
+
+ btnDumpStopImage = new Region();
+ btnDumpStopImage.getStyleClass().add("regionDump");
+
+ injectPldBtn.getStyleClass().add("buttonUp");
+ injectPldBtn.setGraphic(btnDumpStopImage);
+
+ injectPldBtn.setOnAction(event -> startDumpProcess());
+ }
+
+ @FXML
+ private void bntSelectSaveTo(){
+ DirectoryChooser dc = new DirectoryChooser();
+ dc.setTitle(rb.getString("tabSplMrg_Btn_SelectFolder"));
+ dc.setInitialDirectory(new File(saveToLocationLbl.getText()));
+ File saveToDir = dc.showDialog(saveToLocationLbl.getScene().getWindow());
+ if (saveToDir != null)
+ saveToLocationLbl.setText(saveToDir.getAbsolutePath());
+ }
+ /**
+ * Start reading commands from NXDT button handler
+ * */
+ private void startDumpProcess(){
+ if ((workThread == null || ! workThread.isAlive())){
+ MediatorControl.getInstance().getContoller().logArea.clear();
+
+ NxdtTask = new NxdtTask(saveToLocationLbl.getText());
+ NxdtTask.setOnSucceeded(event -> {
+ if (NxdtTask.getValue())
+ statusLbl.setText(rb.getString("done_txt"));
+ else
+ statusLbl.setText(rb.getString("failure_txt"));
+ });
+
+ workThread = new Thread(NxdtTask);
+ workThread.setDaemon(true);
+ workThread.start();
+ }
+ }
+
+ /**
+ * Interrupt thread NXDT button handler
+ * */
+ private void stopBtnAction(){
+ //TODO
+ }
+
+ public void notifyThreadStarted(boolean isActive, EModule type){
+ if (! type.equals(EModule.NXDT)){
+ injectPldBtn.setDisable(isActive);
+ return;
+ }
+
+ if (isActive) {
+ btnDumpStopImage.getStyleClass().clear();
+ btnDumpStopImage.getStyleClass().add("regionStop");
+
+ injectPldBtn.setOnAction(e-> stopBtnAction());
+ injectPldBtn.setText(rb.getString("btn_Stop"));
+ injectPldBtn.getStyleClass().remove("buttonUp");
+ injectPldBtn.getStyleClass().add("buttonStop");
+ return;
+ }
+ btnDumpStopImage.getStyleClass().clear();
+ btnDumpStopImage.getStyleClass().add("regionDump");
+
+ injectPldBtn.setOnAction(e-> startDumpProcess());
+ injectPldBtn.setText(rb.getString("tabNXDT_Btn_Start"));
+ injectPldBtn.getStyleClass().remove("buttonStop");
+ injectPldBtn.getStyleClass().add("buttonUp");
+ }
+ /**
+ * Save application settings on exit
+ * */
+ public void updatePreferencesOnExit(){
+ AppPreferences.getInstance().setNXDTSaveToLocation(saveToLocationLbl.getText());
+ }
+}
diff --git a/src/main/java/nsusbloader/MediatorControl.java b/src/main/java/nsusbloader/MediatorControl.java
index 6a8ccd6..c0af1ab 100644
--- a/src/main/java/nsusbloader/MediatorControl.java
+++ b/src/main/java/nsusbloader/MediatorControl.java
@@ -44,6 +44,7 @@ public class MediatorControl {
mainCtrler.getFrontCtrlr().notifyTransmThreadStarted(isActive, appModuleType);
mainCtrler.getSmCtrlr().notifySmThreadStarted(isActive, appModuleType);
mainCtrler.getRcmCtrlr().notifySmThreadStarted(isActive, appModuleType);
+ mainCtrler.getNXDTabController().notifyThreadStarted(isActive, appModuleType);
}
public synchronized boolean getTransferActive() { return this.isTransferActive.get(); }
}
diff --git a/src/main/java/nsusbloader/NSLDataTypes/EModule.java b/src/main/java/nsusbloader/NSLDataTypes/EModule.java
index 21360f0..b8331a0 100644
--- a/src/main/java/nsusbloader/NSLDataTypes/EModule.java
+++ b/src/main/java/nsusbloader/NSLDataTypes/EModule.java
@@ -21,5 +21,6 @@ package nsusbloader.NSLDataTypes;
public enum EModule {
USB_NET_TRANSFERS,
SPLIT_MERGE_TOOL,
- RCM
+ RCM,
+ NXDT
}
diff --git a/src/main/java/nsusbloader/NSLMain.java b/src/main/java/nsusbloader/NSLMain.java
index e222ae3..8e2585d 100644
--- a/src/main/java/nsusbloader/NSLMain.java
+++ b/src/main/java/nsusbloader/NSLMain.java
@@ -31,7 +31,7 @@ import java.util.ResourceBundle;
public class NSLMain extends Application {
- public static final String appVersion = "v2.2.1";
+ public static final String appVersion = "v3.0";
@Override
public void start(Stage primaryStage) throws Exception{
diff --git a/src/main/java/nsusbloader/Utilities/NxdtTask.java b/src/main/java/nsusbloader/Utilities/NxdtTask.java
new file mode 100644
index 0000000..4b3907f
--- /dev/null
+++ b/src/main/java/nsusbloader/Utilities/NxdtTask.java
@@ -0,0 +1,60 @@
+/*
+ Copyright 2019-2020 Dmitry Isaenko
+
+ This file is part of NS-USBloader.
+
+ NS-USBloader 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.
+
+ NS-USBloader 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 NS-USBloader. If not, see .
+*/
+package nsusbloader.Utilities;
+
+import javafx.concurrent.Task;
+import nsusbloader.COM.USB.UsbConnect;
+import nsusbloader.ModelControllers.LogPrinter;
+import nsusbloader.NSLDataTypes.EModule;
+import nsusbloader.NSLDataTypes.EMsgType;
+import org.usb4java.DeviceHandle;
+
+public class NxdtTask extends Task {
+
+ private LogPrinter logPrinter;
+ private String saveToLocation;
+
+ public NxdtTask(String saveToLocation){
+ this.logPrinter = new LogPrinter(EModule.NXDT);
+ this.saveToLocation = saveToLocation;
+ }
+
+ @Override
+ protected Boolean call() {
+ logPrinter.print("Save to location: "+ saveToLocation, EMsgType.INFO);
+ logPrinter.print("=============== nxdumptool ===============", EMsgType.INFO);
+
+ UsbConnect usbConnect = UsbConnect.connectHomebrewMode(logPrinter);
+
+ if (! usbConnect.isConnected()){
+ logPrinter.close();
+ return false;
+ }
+
+ DeviceHandle handler = usbConnect.getNsHandler();
+
+ new NxdtUsbAbi1(handler, this, logPrinter, saveToLocation);
+
+ logPrinter.print(".:: Complete ::.", EMsgType.PASS);
+
+ usbConnect.close();
+ logPrinter.close();
+ return true;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/nsusbloader/Utilities/NxdtUsbAbi1.java b/src/main/java/nsusbloader/Utilities/NxdtUsbAbi1.java
new file mode 100644
index 0000000..ceb6af6
--- /dev/null
+++ b/src/main/java/nsusbloader/Utilities/NxdtUsbAbi1.java
@@ -0,0 +1,327 @@
+/*
+ Copyright 2019-2020 Dmitry Isaenko
+
+ This file is part of NS-USBloader.
+
+ NS-USBloader 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.
+
+ NS-USBloader 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 NS-USBloader. If not, see .
+*/
+package nsusbloader.Utilities;
+
+import javafx.concurrent.Task;
+import nsusbloader.COM.USB.UsbErrorCodes;
+import nsusbloader.ModelControllers.LogPrinter;
+import nsusbloader.NSLDataTypes.EMsgType;
+import org.usb4java.DeviceHandle;
+import org.usb4java.LibUsb;
+
+import java.io.*;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.IntBuffer;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+
+class NxdtUsbAbi1 {
+ private LogPrinter logPrinter;
+ private DeviceHandle handlerNS;
+ private Task task;
+ private String saveToPath;
+
+ private boolean isWindows;
+
+ private static final int NXDT_COMMAND_SIZE = 0x1000;
+ private static final int NXDT_FILE_CHUNK_SIZE = 0x800000;
+
+ private static final byte ABI_VERSION = 1;
+ private static final byte[] MAGIC_NXDT = { 0x4e, 0x58, 0x44, 0x54 };
+
+ private static final byte CMD_HANDSHAKE = 0;
+ private static final byte CMD_SEND_FILE_PROPERTIES = 1;
+ private static final byte CMD_ENDSESSION = 3;
+
+ // Standard set of possible replies
+ private static final byte[] USBSTATUS_SUCCESS = { 0x4e, 0x58, 0x44, 0x54,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00 };
+ private static final byte[] USBSTATUS_INVALID_MAGIC = { 0x4e, 0x58, 0x44, 0x54,
+ 0x04, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00 };
+ private static final byte[] USBSTATUS_UNSUPPORTED_ABI = { 0x4e, 0x58, 0x44, 0x54,
+ 0x06, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00 };
+ private static final byte[] USBSTATUS_UNSUPPORTED_CMD = { 0x4e, 0x58, 0x44, 0x54,
+ 0x07, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00 };
+ private static final byte[] USBSTATUS_HOSTIOERROR = { 0x4e, 0x58, 0x44, 0x54,
+ 0x08, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00 };
+
+ public NxdtUsbAbi1(DeviceHandle handler,
+ Task task,
+ LogPrinter logPrinter,
+ String saveToPath
+ ){
+ this.handlerNS = handler;
+ this.task = task;
+ this.logPrinter = logPrinter;
+ this.isWindows = System.getProperty("os.name").toLowerCase().contains("windows");
+
+ if (! saveToPath.endsWith(File.separator))
+ this.saveToPath = saveToPath + File.separator;
+ else
+ this.saveToPath = saveToPath;
+
+ readLoop();
+ }
+
+ private void readLoop(){
+ logPrinter.print("Awaiting for handshake", EMsgType.INFO);
+ try {
+ byte[] deviceCommand;
+
+ while (true){
+ deviceCommand = readUsbCmd();
+
+ if (isInvalidCommand(deviceCommand))
+ continue;
+
+ switch (deviceCommand[4]){
+ case CMD_HANDSHAKE:
+ performHandshake(deviceCommand);
+ break;
+ case CMD_SEND_FILE_PROPERTIES:
+ handleSendFileProperties(deviceCommand);
+ break;
+ case CMD_ENDSESSION:
+ logPrinter.print("Session successfully ended", EMsgType.PASS);
+ return;
+ }
+ }
+ }
+ catch (InterruptedException ioe){
+ logPrinter.print("Execution interrupted", EMsgType.INFO);
+ }
+ catch (Exception e){
+ e.printStackTrace();
+ logPrinter.print(e.getMessage(), EMsgType.INFO);
+ logPrinter.print("Terminating now", EMsgType.FAIL);
+ }
+ };
+
+ private boolean isInvalidCommand(byte[] message) throws Exception{
+ boolean returnValue = false;
+ if (! Arrays.equals(Arrays.copyOfRange(message, 0,4), MAGIC_NXDT)){
+ writeUsb(USBSTATUS_INVALID_MAGIC);
+ logPrinter.print("Invalid magic command", EMsgType.INFO);
+ returnValue = true;
+ }
+ if (message.length != NXDT_COMMAND_SIZE){
+ writeUsb(USBSTATUS_UNSUPPORTED_CMD);
+ logPrinter.print("Invalid command size. Expected size is 4096 while received is "+message.length, EMsgType.INFO);
+ returnValue = true;
+ }
+ return returnValue;
+ }
+
+ private void performHandshake(byte[] message) throws Exception{
+ logPrinter.print("nxdumptool v"+message[8]+"."+message[9]+"."+message[10]+" ABI v"+message[11], EMsgType.INFO);
+
+ if (ABI_VERSION != message[11]){
+ writeUsb(USBSTATUS_UNSUPPORTED_ABI);
+ throw new Exception("ABI v"+message[11]+" is not supported in current version.");
+ }
+ writeUsb(USBSTATUS_SUCCESS);
+ // consider refactoring: create sub-classes for various ABI versions and check if it's supported or not
+ }
+
+ private void handleSendFileProperties(byte[] message) throws Exception{
+ long fileSize = getLElong(message, 8);
+ int fileNameLen = getLEint(message, 12);
+ String filename = new String(Arrays.copyOfRange(message, 16, fileNameLen), StandardCharsets.UTF_8);
+
+ // TODO: In here should be also a field with NSP Header size that would be transmitted after the end of main data transfer; NOTE: Handle with RandomAccessFile.
+
+ logPrinter.print("Write request for: '"+filename+"' ("+fileSize+" bytes)", EMsgType.INFO);
+ // If RomFs related
+ if (filename.startsWith("/")) {
+ if (isWindows)
+ filename = saveToPath + filename.replaceAll("/", "\\\\");
+ else
+ filename = saveToPath + filename;
+
+ try {
+ createPath(filename);
+ }
+ catch (Exception e){
+ writeUsb(USBSTATUS_HOSTIOERROR);
+ logPrinter.print("Unable to create dir(s) for file in "+filename+
+ "\n Returned: "+e.getMessage(), EMsgType.FAIL);
+ return;
+ }
+
+ }
+ else
+ filename = saveToPath + filename;
+
+ File fileToDump = new File(filename);
+
+ // Check if enough space
+ if (fileToDump.getFreeSpace() <= fileSize){
+ writeUsb(USBSTATUS_HOSTIOERROR);
+ logPrinter.print("Not enough space on selected volume. Need: "+fileSize+" while available: "+fileToDump.getFreeSpace(), EMsgType.FAIL);
+ return;
+ }
+ // Check if FS is NOT read-only
+ if (! fileToDump.canWrite()){
+ writeUsb(USBSTATUS_HOSTIOERROR);
+ logPrinter.print("Unable to write into selected volume: "+fileToDump.getAbsolutePath(), EMsgType.FAIL);
+ return;
+ }
+
+ dumpFile(fileToDump, fileSize);
+
+ writeUsb(USBSTATUS_SUCCESS);
+
+ // TODO: check if NSP_SIZE != 0 then go dump header
+ }
+
+ private void createPath(String path) throws Exception{
+ File resultingFile = new File(path);
+ File folderForTheFile = resultingFile.getParentFile();
+ folderForTheFile.mkdirs();
+ }
+
+ private void dumpFile(File file, long size) throws Exception{
+ BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file, false));
+
+ byte[] readBuffer;
+ long received = 0;
+ int bufferSize;
+
+ while (received < size){
+ readBuffer = readUsbFile();
+ bos.write(readBuffer);
+ bufferSize = readBuffer.length;
+ received += bufferSize;
+
+ logPrinter.updateProgress((received + bufferSize) / (size / 100.0) / 100.0);
+ }
+
+ logPrinter.updateProgress(1.0);
+ bos.close();
+ }
+
+
+ public static int getLEint(byte[] bytes, int fromOffset){
+ return ByteBuffer.wrap(bytes, fromOffset, 0x4).order(ByteOrder.LITTLE_ENDIAN).getInt();
+ }
+
+ public static long getLElong(byte[] bytes, int fromOffset){
+ return ByteBuffer.wrap(bytes, fromOffset, 0x8).order(ByteOrder.LITTLE_ENDIAN).getLong();
+ }
+
+ /**
+ * Sending any byte array to USB device
+ * @return 'false' if no issues
+ * 'true' if errors happened
+ * */
+ private void writeUsb(byte[] message) throws Exception{
+ ByteBuffer writeBuffer = ByteBuffer.allocateDirect(message.length);
+ writeBuffer.put(message);
+ IntBuffer writeBufTransferred = IntBuffer.allocate(1);
+ int result;
+
+ while (! task.isCancelled()) {
+ result = LibUsb.bulkTransfer(handlerNS, (byte) 0x01, writeBuffer, writeBufTransferred, 5050);
+
+ switch (result){
+ case LibUsb.SUCCESS:
+ if (writeBufTransferred.get() == message.length)
+ return;
+ throw new Exception("Data transfer issue [write]" +
+ "\n Requested: "+message.length+
+ "\n Transferred: "+writeBufTransferred.get());
+ case LibUsb.ERROR_TIMEOUT:
+ continue;
+ default:
+ throw new Exception("Data transfer issue [write]" +
+ "\n Returned: "+ UsbErrorCodes.getErrCode(result) +
+ "\n (execution stopped)");
+ }
+ }
+ throw new InterruptedException("Execution interrupted");
+ }
+ /**
+ * Reading what USB device responded (command).
+ * @return byte array if data read successful
+ * 'null' if read failed
+ * */
+ private byte[] readUsbCmd() throws Exception{
+ ByteBuffer readBuffer = ByteBuffer.allocateDirect(NXDT_COMMAND_SIZE);
+ // 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 command]" +
+ "\n Returned: " + UsbErrorCodes.getErrCode(result)+
+ "\n (execution stopped)");
+ }
+ }
+ throw new InterruptedException();
+ }
+ /**
+ * Reading what USB device responded (file).
+ * @return byte array if data read successful
+ * 'null' if read failed
+ * */
+ private byte[] readUsbFile() throws Exception{
+ ByteBuffer readBuffer = ByteBuffer.allocateDirect(NXDT_FILE_CHUNK_SIZE);
+ IntBuffer readBufTransferred = IntBuffer.allocate(1);
+ int result;
+ while (! task.isCancelled()) {
+ result = LibUsb.bulkTransfer(handlerNS, (byte) 0x81, readBuffer, readBufTransferred, 1000);
+
+ 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 file]" +
+ "\n Returned: " + UsbErrorCodes.getErrCode(result)+
+ "\n (execution stopped)");
+ }
+ }
+ throw new InterruptedException();
+ }
+}
diff --git a/src/main/resources/NSLMain.fxml b/src/main/resources/NSLMain.fxml
index 017fe2f..6fb2355 100644
--- a/src/main/resources/NSLMain.fxml
+++ b/src/main/resources/NSLMain.fxml
@@ -31,6 +31,14 @@
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/NXDTab.fxml b/src/main/resources/NXDTab.fxml
new file mode 100644
index 0000000..dd720f0
--- /dev/null
+++ b/src/main/resources/NXDTab.fxml
@@ -0,0 +1,78 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/locale.properties b/src/main/resources/locale.properties
index ed11486..2f19a59 100644
--- a/src/main/resources/locale.properties
+++ b/src/main/resources/locale.properties
@@ -62,3 +62,4 @@ done_txt=Done!
failure_txt=Failed
btn_Select=Select
btn_InjectPayloader=Inject payload
+tabNXDT_Btn_Start=Start!
diff --git a/src/main/resources/locale_rus.properties b/src/main/resources/locale_rus.properties
index 2395d66..cf7070a 100644
--- a/src/main/resources/locale_rus.properties
+++ b/src/main/resources/locale_rus.properties
@@ -62,4 +62,5 @@ done_txt=\u0413\u043E\u0442\u043E\u0432\u043E!
failure_txt=\u041D\u0435\u0443\u0434\u0430\u0447\u0430
btn_Select=\u0412\u044B\u0431\u0440\u0430\u0442\u044C
btn_InjectPayloader=\u0417\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044C payload
+tabNXDT_Btn_Start=\u0421\u0442\u0430\u0440\u0442!
diff --git a/src/main/resources/locale_ukr.properties b/src/main/resources/locale_ukr.properties
index 643a9f9..7e1054f 100644
--- a/src/main/resources/locale_ukr.properties
+++ b/src/main/resources/locale_ukr.properties
@@ -61,4 +61,5 @@ windowBodyPleaseFinishTransfersFirst=\u041D\u0435\u043C\u043E\u0436\u043B\u0438\
done_txt=\u0413\u043E\u0442\u043E\u0432\u043E!
failure_txt=\u041D\u0435\u0432\u0434\u0430\u0447\u0430
btn_Select=\u0412\u0438\u0431\u0440\u0430\u0442\u0438
-btn_InjectPayloader=\u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0438\u0442\u0438 payload
\ No newline at end of file
+btn_InjectPayloader=\u0417\u0430\u0432\u0430\u043D\u0442\u0430\u0436\u0438\u0442\u0438 payload
+tabNXDT_Btn_Start=\u0421\u0442\u0430\u0440\u0442!
\ No newline at end of file
diff --git a/src/main/resources/res/app_dark.css b/src/main/resources/res/app_dark.css
index 027aa20..1f04ca0 100644
--- a/src/main/resources/res/app_dark.css
+++ b/src/main/resources/res/app_dark.css
@@ -373,6 +373,12 @@
-fx-min-height: 24;
-fx-min-width: 36;
}
+.regionDump{
+ -fx-shape: "M 4.0078125 0 C 1.5078125 0 0 1.4882812 0 3.984375 L 0 15.988281 C 0 18.417969 1.4927148 20 4.0078125 20 L 6.5 20 L 6.5 0 L 4.0078125 0 z M 23.5 0 L 23.5 20 C 24.504057 19.999294 25.159942 20 25.992188 20 C 28.414062 20 30 18.496094 30 15.996094 L 30 3.9765625 C 30 1.5195311 28.508726 0 26.003906 0 L 23.5 0 z M 11.990234 2.8886719 L 11.990234 9.9003906 L 6.9902344 9.9003906 L 14.990234 20 L 22.990234 9.9003906 L 17.990234 9.9003906 C 17.990234 8.2387016 17.9999 3.6538029 18 2.8886719 L 11.990234 2.8886719 z M 3.1015625 2.9570312 C 4.1485235 2.9562481 4.9977514 3.8046013 4.9980469 4.8515625 C 4.998831 5.8992865 4.1492865 6.7488309 3.1015625 6.7480469 C 2.0546013 6.7477509 1.2062483 5.8985235 1.2070312 4.8515625 C 1.2073268 3.8053642 2.0553642 2.9573267 3.1015625 2.9570312 z M 26.865234 11.148438 C 27.912958 11.147652 28.762503 11.997198 28.761719 13.044922 C 28.761423 14.091883 27.912195 14.940236 26.865234 14.939453 C 25.819036 14.939158 24.970999 14.09112 24.970703 13.044922 C 24.96992 11.997961 25.818273 11.148733 26.865234 11.148438 z ";
+ -fx-background-color: #71e016;
+ -fx-min-height: 24;
+ -fx-min-width: 36;
+}
.regionStop{
-fx-shape: "M12,2C17.53,2 22,6.47 22,12C22,17.53 17.53,22 12,22C6.47,22 2,17.53 2,12C2,6.47 6.47,2 12,2M15.59,7L12,10.59L8.41,7L7,8.41L10.59,12L7,15.59L8.41,17L12,13.41L15.59,17L17,15.59L13.41,12L17,8.41L15.59,7Z";
-fx-background-color: #fb582c;
@@ -394,6 +400,9 @@
-size: 17.5;
-fx-min-width: 20;
}
+.nxdt.label .text {
+ -fx-fill: #cb0010;
+}
//
//.lineGradient {
// -fx-background-color: linear-gradient(from 41px 34px to 50px 50px, reflect, #00c8fc 30%, transparent 45%);
diff --git a/src/main/resources/res/app_light.css b/src/main/resources/res/app_light.css
index a0e6c9c..030667e 100644
--- a/src/main/resources/res/app_light.css
+++ b/src/main/resources/res/app_light.css
@@ -291,7 +291,12 @@
-fx-min-height: 24;
-fx-min-width: 36;
}
-
+.regionDump{
+ -fx-shape: "M 4.0078125 0 C 1.5078125 0 0 1.4882812 0 3.984375 L 0 15.988281 C 0 18.417969 1.4927148 20 4.0078125 20 L 6.5 20 L 6.5 0 L 4.0078125 0 z M 23.5 0 L 23.5 20 C 24.504057 19.999294 25.159942 20 25.992188 20 C 28.414062 20 30 18.496094 30 15.996094 L 30 3.9765625 C 30 1.5195311 28.508726 0 26.003906 0 L 23.5 0 z M 11.990234 2.8886719 L 11.990234 9.9003906 L 6.9902344 9.9003906 L 14.990234 20 L 22.990234 9.9003906 L 17.990234 9.9003906 C 17.990234 8.2387016 17.9999 3.6538029 18 2.8886719 L 11.990234 2.8886719 z M 3.1015625 2.9570312 C 4.1485235 2.9562481 4.9977514 3.8046013 4.9980469 4.8515625 C 4.998831 5.8992865 4.1492865 6.7488309 3.1015625 6.7480469 C 2.0546013 6.7477509 1.2062483 5.8985235 1.2070312 4.8515625 C 1.2073268 3.8053642 2.0553642 2.9573267 3.1015625 2.9570312 z M 26.865234 11.148438 C 27.912958 11.147652 28.762503 11.997198 28.761719 13.044922 C 28.761423 14.091883 27.912195 14.940236 26.865234 14.939453 C 25.819036 14.939158 24.970999 14.09112 24.970703 13.044922 C 24.96992 11.997961 25.818273 11.148733 26.865234 11.148438 z ";
+ -fx-background-color: #71e016;
+ -fx-min-height: 24;
+ -fx-min-width: 36;
+}
.regionStop{
-fx-shape: "M12,2C17.53,2 22,6.47 22,12C22,17.53 17.53,22 12,22C6.47,22 2,17.53 2,12C2,6.47 6.47,2 12,2M15.59,7L12,10.59L8.41,7L7,8.41L10.59,12L7,15.59L8.41,17L12,13.41L15.59,17L17,15.59L13.41,12L17,8.41L15.59,7Z";
-fx-background-color: #fb582c;
@@ -312,4 +317,7 @@
-fx-background-color: #2c2c2c;
-size: 17.5;
-fx-min-width: 20;
+}
+.nxdt.label .text {
+ -fx-fill: #9d010e;
}
\ No newline at end of file
diff --git a/src/main/resources/res/nxdt_icon.jpg b/src/main/resources/res/nxdt_icon.jpg
new file mode 100644
index 0000000..f4d2627
Binary files /dev/null and b/src/main/resources/res/nxdt_icon.jpg differ