v0.8 Fix for interrupt process issue; Refactoring.
This commit is contained in:
parent
9b73a4d19d
commit
6f1700fbab
9 changed files with 1655 additions and 1515 deletions
6
pom.xml
6
pom.xml
|
@ -8,7 +8,7 @@
|
||||||
<name>NS-USBloader</name>
|
<name>NS-USBloader</name>
|
||||||
|
|
||||||
<artifactId>ns-usbloader</artifactId>
|
<artifactId>ns-usbloader</artifactId>
|
||||||
<version>0.7-SNAPSHOT</version>
|
<version>0.8-SNAPSHOT</version>
|
||||||
|
|
||||||
<url>https://github.com/developersu/ns-usbloader/</url>
|
<url>https://github.com/developersu/ns-usbloader/</url>
|
||||||
<description>
|
<description>
|
||||||
|
@ -218,11 +218,11 @@
|
||||||
<minVersion>1.8</minVersion>
|
<minVersion>1.8</minVersion>
|
||||||
</jre>
|
</jre>
|
||||||
<versionInfo>
|
<versionInfo>
|
||||||
<fileVersion>0.7.0.0</fileVersion>
|
<fileVersion>0.8.0.0</fileVersion>
|
||||||
<txtFileVersion>${project.version}</txtFileVersion>
|
<txtFileVersion>${project.version}</txtFileVersion>
|
||||||
<fileDescription>TinFoil and GoldLeaf installer for your NS</fileDescription>
|
<fileDescription>TinFoil and GoldLeaf installer for your NS</fileDescription>
|
||||||
<copyright>GNU General Public License v3, 2019 ${organization.name}. Russia/LPR.</copyright>
|
<copyright>GNU General Public License v3, 2019 ${organization.name}. Russia/LPR.</copyright>
|
||||||
<productVersion>0.7.0.0</productVersion>
|
<productVersion>0.8.0.0</productVersion>
|
||||||
<txtProductVersion>${project.version}</txtProductVersion>
|
<txtProductVersion>${project.version}</txtProductVersion>
|
||||||
<companyName>${organization.name}</companyName>
|
<companyName>${organization.name}</companyName>
|
||||||
<productName>${project.name}</productName>
|
<productName>${project.name}</productName>
|
||||||
|
|
|
@ -49,9 +49,12 @@ public class LogPrinter {
|
||||||
/**
|
/**
|
||||||
* Update progress for progress bar
|
* Update progress for progress bar
|
||||||
* */
|
* */
|
||||||
public void updateProgress(Double value) throws InterruptedException{
|
public void updateProgress(Double value) {
|
||||||
|
try {
|
||||||
progressQueue.put(value);
|
progressQueue.put(value);
|
||||||
}
|
}
|
||||||
|
catch (InterruptedException ignored){} // TODO: Do something with this
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* When we're done - update status
|
* When we're done - update status
|
||||||
* */
|
* */
|
||||||
|
|
|
@ -374,23 +374,14 @@ public class NETCommunications extends Task<Void> { // todo: thows IOException?
|
||||||
}
|
}
|
||||||
currSockOS.write(byteBuf);
|
currSockOS.write(byteBuf);
|
||||||
//-----------------------------------------/
|
//-----------------------------------------/
|
||||||
try {
|
|
||||||
logPrinter.updateProgress((currentOffset+readPice)/(count/100.0) / 100.0);
|
logPrinter.updateProgress((currentOffset+readPice)/(count/100.0) / 100.0);
|
||||||
}catch (InterruptedException ie){
|
|
||||||
getException().printStackTrace(); // TODO: Do something with this
|
|
||||||
}
|
|
||||||
//-----------------------------------------/
|
//-----------------------------------------/
|
||||||
currentOffset += readPice;
|
currentOffset += readPice;
|
||||||
}
|
}
|
||||||
currSockOS.flush(); // TODO: check if this really needed.
|
currSockOS.flush(); // TODO: check if this really needed.
|
||||||
bis.close();
|
bis.close();
|
||||||
//-----------------------------------------/
|
//-----------------------------------------/
|
||||||
try{
|
|
||||||
logPrinter.updateProgress(1.0);
|
logPrinter.updateProgress(1.0);
|
||||||
}
|
|
||||||
catch (InterruptedException ie){
|
|
||||||
getException().printStackTrace(); // TODO: Do something with this
|
|
||||||
}
|
|
||||||
//-----------------------------------------/
|
//-----------------------------------------/
|
||||||
}
|
}
|
||||||
catch (IOException ioe){
|
catch (IOException ioe){
|
||||||
|
|
|
@ -12,7 +12,7 @@ import java.util.Locale;
|
||||||
import java.util.ResourceBundle;
|
import java.util.ResourceBundle;
|
||||||
|
|
||||||
public class NSLMain extends Application {
|
public class NSLMain extends Application {
|
||||||
public static final String appVersion = "v0.7";
|
public static final String appVersion = "v0.8";
|
||||||
@Override
|
@Override
|
||||||
public void start(Stage primaryStage) throws Exception{
|
public void start(Stage primaryStage) throws Exception{
|
||||||
FXMLLoader loader = new FXMLLoader(getClass().getResource("/NSLMain.fxml"));
|
FXMLLoader loader = new FXMLLoader(getClass().getResource("/NSLMain.fxml"));
|
||||||
|
|
1115
src/main/java/nsusbloader/USB/GoldLeaf.java
Normal file
1115
src/main/java/nsusbloader/USB/GoldLeaf.java
Normal file
File diff suppressed because it is too large
Load diff
7
src/main/java/nsusbloader/USB/ITransferModule.java
Normal file
7
src/main/java/nsusbloader/USB/ITransferModule.java
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
package nsusbloader.USB;
|
||||||
|
|
||||||
|
import nsusbloader.NSLDataTypes.EFileStatus;
|
||||||
|
|
||||||
|
public interface ITransferModule {
|
||||||
|
EFileStatus getStatus();
|
||||||
|
}
|
321
src/main/java/nsusbloader/USB/TinFoil.java
Normal file
321
src/main/java/nsusbloader/USB/TinFoil.java
Normal file
|
@ -0,0 +1,321 @@
|
||||||
|
package nsusbloader.USB;
|
||||||
|
|
||||||
|
import javafx.concurrent.Task;
|
||||||
|
import nsusbloader.ModelControllers.LogPrinter;
|
||||||
|
import nsusbloader.NSLDataTypes.EFileStatus;
|
||||||
|
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;
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tinfoil processing
|
||||||
|
* */
|
||||||
|
class TinFoil implements ITransferModule {
|
||||||
|
private LogPrinter logPrinter;
|
||||||
|
private DeviceHandle handlerNS;
|
||||||
|
private LinkedHashMap<String, File> nspMap;
|
||||||
|
private EFileStatus status = EFileStatus.FAILED;
|
||||||
|
private Task<Void> task;
|
||||||
|
|
||||||
|
TinFoil(DeviceHandle handler, LinkedHashMap<String, File> nspMap, Task<Void> task, LogPrinter logPrinter){
|
||||||
|
this.handlerNS = handler;
|
||||||
|
this.nspMap = nspMap;
|
||||||
|
this.task = task;
|
||||||
|
this.logPrinter = logPrinter;
|
||||||
|
|
||||||
|
logPrinter.print("============= TinFoil =============", EMsgType.INFO);
|
||||||
|
|
||||||
|
if (!sendListOfNSP())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (proceedCommands()) // REPORT SUCCESS
|
||||||
|
status = EFileStatus.UPLOADED; // Don't change status that is already set to FAILED
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Send what NSP will be transferred
|
||||||
|
* */
|
||||||
|
private boolean sendListOfNSP(){
|
||||||
|
// Send list of NSP files:
|
||||||
|
// Proceed "TUL0"
|
||||||
|
if (writeUsb("TUL0".getBytes(StandardCharsets.US_ASCII))) { // new byte[]{(byte) 0x54, (byte) 0x55, (byte) 0x76, (byte) 0x30}
|
||||||
|
logPrinter.print("TF Send list of files: handshake", EMsgType.FAIL);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
logPrinter.print("TF Send list of files: handshake", EMsgType.PASS);
|
||||||
|
//Collect file names
|
||||||
|
StringBuilder nspListNamesBuilder = new StringBuilder(); // Add every title to one stringBuilder
|
||||||
|
for(String nspFileName: nspMap.keySet()) {
|
||||||
|
nspListNamesBuilder.append(nspFileName); // And here we come with java string default encoding (UTF-16)
|
||||||
|
nspListNamesBuilder.append('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] nspListNames = nspListNamesBuilder.toString().getBytes(StandardCharsets.UTF_8);
|
||||||
|
ByteBuffer byteBuffer = ByteBuffer.allocate(Integer.BYTES).order(ByteOrder.LITTLE_ENDIAN); // integer = 4 bytes; BTW Java is stored in big-endian format
|
||||||
|
byteBuffer.putInt(nspListNames.length); // This way we obtain length in int converted to byte array in correct Big-endian order. Trust me.
|
||||||
|
byte[] nspListSize = byteBuffer.array(); // TODO: rewind? not sure..
|
||||||
|
//byteBuffer.reset();
|
||||||
|
|
||||||
|
// Sending NSP list
|
||||||
|
logPrinter.print("TF Send list of files", EMsgType.INFO);
|
||||||
|
if (writeUsb(nspListSize)) { // size of the list we're going to transfer goes...
|
||||||
|
logPrinter.print(" [send list length]", EMsgType.FAIL);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
logPrinter.print(" [send list length]", EMsgType.PASS);
|
||||||
|
|
||||||
|
if (writeUsb(new byte[8])) { // 8 zero bytes goes...
|
||||||
|
logPrinter.print(" [send padding]", EMsgType.FAIL);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
logPrinter.print(" [send padding]", EMsgType.PASS);
|
||||||
|
|
||||||
|
if (writeUsb(nspListNames)) { // list of the names goes...
|
||||||
|
logPrinter.print(" [send list itself]", EMsgType.FAIL);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
logPrinter.print(" [send list itself]", EMsgType.PASS);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* After we sent commands to NS, this chain starts
|
||||||
|
* */
|
||||||
|
private boolean proceedCommands(){
|
||||||
|
logPrinter.print("TF Awaiting for NS commands.", EMsgType.INFO);
|
||||||
|
|
||||||
|
/* byte[] magic = new byte[4];
|
||||||
|
ByteBuffer bb = StandardCharsets.UTF_8.encode("TUC0").rewind().get(magic); // Let's rephrase this 'string'
|
||||||
|
*/
|
||||||
|
final byte[] magic = new byte[]{(byte) 0x54, (byte) 0x55, (byte) 0x43, (byte) 0x30}; // eq. 'TUC0' @ UTF-8 (actually ASCII lol, u know what I mean)
|
||||||
|
|
||||||
|
byte[] receivedArray;
|
||||||
|
|
||||||
|
while (true){ // Check if user interrupted process.
|
||||||
|
|
||||||
|
receivedArray = readUsb();
|
||||||
|
|
||||||
|
if (receivedArray == null) // catches error
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!Arrays.equals(Arrays.copyOfRange(receivedArray, 0,4), magic)) // Bytes from 0 to 3 should contain 'magic' TUC0, so must be verified like this
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// 8th to 12th(explicits) bytes in returned data stands for command ID as unsigned integer (Little-endian). Actually, we have to compare arrays here, but in real world it can't be greater then 0/1/2, thus:
|
||||||
|
// BTW also protocol specifies 4th byte to be 0x00 kinda indicating that that this command is valid. But, as you may see, never happens other situation when it's not = 0.
|
||||||
|
if (receivedArray[8] == 0x00){ //0x00 - exit
|
||||||
|
logPrinter.print("TF Received 'EXIT' command. Terminating.", EMsgType.PASS);
|
||||||
|
return true; // All interaction with USB device should be ended (expected);
|
||||||
|
}
|
||||||
|
else if ((receivedArray[8] == 0x01) || (receivedArray[8] == 0x02)){ //0x01 - file range; 0x02 unknown bug on backend side (dirty hack).
|
||||||
|
logPrinter.print("TF Received 'FILE RANGE' command. Proceeding: [0x0"+receivedArray[8]+"]", EMsgType.PASS);
|
||||||
|
/*// We can get in this pocket a length of file name (+32). Why +32? I dunno man.. Do we need this? Definitely not. This app can live without it.
|
||||||
|
long receivedSize = ByteBuffer.wrap(Arrays.copyOfRange(receivedArray, 12,20)).order(ByteOrder.LITTLE_ENDIAN).getLong();
|
||||||
|
logsArea.appendText("[V] Received FILE_RANGE command. Size: "+Long.toUnsignedString(receivedSize)+"\n"); // this shit returns string that will be chosen next '+32'. And, BTW, can't be greater then 512
|
||||||
|
*/
|
||||||
|
if (! fileRangeCmd())
|
||||||
|
return false; // catches exception
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* This is what returns requested file (files)
|
||||||
|
* Executes multiple times
|
||||||
|
* @return 'true' if everything is ok
|
||||||
|
* 'false' is error/exception occurs
|
||||||
|
* */
|
||||||
|
private boolean fileRangeCmd(){
|
||||||
|
byte[] receivedArray;
|
||||||
|
// Here we take information of what other side wants
|
||||||
|
receivedArray = readUsb();
|
||||||
|
if (receivedArray == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// range_offset of the requested file. In the begining it will be 0x10.
|
||||||
|
long receivedRangeSize = ByteBuffer.wrap(Arrays.copyOfRange(receivedArray, 0,8)).order(ByteOrder.LITTLE_ENDIAN).getLong(); // Note - it could be unsigned long. Unfortunately, this app won't support files greater then 8796093022208 Gb
|
||||||
|
byte[] receivedRangeSizeRAW = Arrays.copyOfRange(receivedArray, 0,8); // used (only) when we use sendResponse(). It's just simply.
|
||||||
|
long receivedRangeOffset = ByteBuffer.wrap(Arrays.copyOfRange(receivedArray, 8,16)).order(ByteOrder.LITTLE_ENDIAN).getLong(); // Note - it could be unsigned long. Unfortunately, this app won't support files greater then 8796093022208 Gb
|
||||||
|
/* Below, it's REAL NSP file name length that we sent before among others (WITHOUT +32 byes). It can't be greater then... see what is written in the beginning of this code.
|
||||||
|
We don't need this since in next pocket we'll get name itself UTF-8 encoded. Could be used to double-checks or something like that.
|
||||||
|
long receivedNspNameLen = ByteBuffer.wrap(Arrays.copyOfRange(receivedArray, 16,24)).order(ByteOrder.LITTLE_ENDIAN).getLong(); */
|
||||||
|
|
||||||
|
// Requesting UTF-8 file name required:
|
||||||
|
receivedArray = readUsb();
|
||||||
|
if (receivedArray == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
String receivedRequestedNSP = new String(receivedArray, StandardCharsets.UTF_8);
|
||||||
|
logPrinter.print("TF Reply to requested file: "+receivedRequestedNSP
|
||||||
|
+"\n Range Size: "+receivedRangeSize
|
||||||
|
+"\n Range Offset: "+receivedRangeOffset, EMsgType.INFO);
|
||||||
|
|
||||||
|
// Sending response header
|
||||||
|
if (!sendResponse(receivedRangeSizeRAW)) // Get receivedRangeSize in 'RAW' format exactly as it has been received. It's simply.
|
||||||
|
return false;
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
BufferedInputStream bufferedInStream = new BufferedInputStream(new FileInputStream(nspMap.get(receivedRequestedNSP))); // TODO: refactor?
|
||||||
|
byte[] bufferCurrent ;//= new byte[1048576]; // eq. Allocate 1mb
|
||||||
|
|
||||||
|
if (bufferedInStream.skip(receivedRangeOffset) != receivedRangeOffset){
|
||||||
|
logPrinter.print("TF Requested skip is out of file size. Nothing to transmit.", EMsgType.FAIL);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
long currentOffset = 0;
|
||||||
|
// 'End Offset' equal to receivedRangeSize.
|
||||||
|
int readPice = 8388608; // = 8Mb
|
||||||
|
|
||||||
|
while (currentOffset < receivedRangeSize){
|
||||||
|
if ((currentOffset + readPice) >= receivedRangeSize )
|
||||||
|
readPice = Math.toIntExact(receivedRangeSize - currentOffset);
|
||||||
|
//System.out.println("CO: "+currentOffset+"\t\tEO: "+receivedRangeSize+"\t\tRP: "+readPice); // NOTE: DEBUG
|
||||||
|
// updating progress bar (if a lot of data requested) START BLOCK
|
||||||
|
//-----------------------------------------/
|
||||||
|
logPrinter.updateProgress((currentOffset+readPice)/(receivedRangeSize/100.0) / 100.0);
|
||||||
|
//-----------------------------------------/
|
||||||
|
bufferCurrent = new byte[readPice]; // TODO: not perfect moment, consider refactoring.
|
||||||
|
|
||||||
|
if (bufferedInStream.read(bufferCurrent) != readPice) { // changed since @ v0.3.2
|
||||||
|
logPrinter.print("TF Reading of stream suddenly ended.", EMsgType.WARNING);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
//write to USB
|
||||||
|
if (writeUsb(bufferCurrent)) {
|
||||||
|
logPrinter.print("TF Failure during NSP transmission.", EMsgType.FAIL);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
currentOffset += readPice;
|
||||||
|
}
|
||||||
|
bufferedInStream.close();
|
||||||
|
//-----------------------------------------/
|
||||||
|
logPrinter.updateProgress(1.0);
|
||||||
|
//-----------------------------------------/
|
||||||
|
} catch (FileNotFoundException fnfe){
|
||||||
|
logPrinter.print("TF FileNotFoundException:\n "+fnfe.getMessage(), EMsgType.FAIL);
|
||||||
|
fnfe.printStackTrace();
|
||||||
|
return false;
|
||||||
|
} catch (IOException ioe){
|
||||||
|
logPrinter.print("TF IOException:\n "+ioe.getMessage(), EMsgType.FAIL);
|
||||||
|
ioe.printStackTrace();
|
||||||
|
return false;
|
||||||
|
} catch (ArithmeticException ae){
|
||||||
|
logPrinter.print("TF ArithmeticException (can't cast 'offset end' - 'offsets current' to 'integer'):\n "+ae.getMessage(), EMsgType.FAIL);
|
||||||
|
ae.printStackTrace();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Send response header.
|
||||||
|
* @return true if everything OK
|
||||||
|
* false if failed
|
||||||
|
* */
|
||||||
|
private boolean sendResponse(byte[] rangeSize){ // This method as separate function itself for application needed as a cookie in the middle of desert.
|
||||||
|
logPrinter.print("TF Sending response", EMsgType.INFO);
|
||||||
|
if (writeUsb(new byte[] { (byte) 0x54, (byte) 0x55, (byte) 0x43, (byte) 0x30, // 'TUC0'
|
||||||
|
(byte) 0x01, // CMD_TYPE_RESPONSE = 1
|
||||||
|
(byte) 0x00, (byte) 0x00, (byte) 0x00, // kinda padding. Guys, didn't you want to use integer value for CMD semantic?
|
||||||
|
(byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00} ) // Send integer value of '1' in Little-endian format.
|
||||||
|
){
|
||||||
|
logPrinter.print(" [1/3]", EMsgType.FAIL);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
logPrinter.print(" [1/3]", EMsgType.PASS);
|
||||||
|
if(writeUsb(rangeSize)) { // Send EXACTLY what has been received
|
||||||
|
logPrinter.print(" [2/3]", EMsgType.FAIL);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
logPrinter.print(" [2/3]", EMsgType.PASS);
|
||||||
|
if(writeUsb(new byte[12])) { // kinda another one padding
|
||||||
|
logPrinter.print(" [3/3]", EMsgType.FAIL);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
logPrinter.print(" [3/3]", EMsgType.PASS);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
while (! task.isCancelled()) {
|
||||||
|
result = LibUsb.bulkTransfer(handlerNS, (byte) 0x01, writeBuffer, writeBufTransferred, 1000); // last one is TIMEOUT. 0 stands for unlimited. Endpoint OUT = 0x01
|
||||||
|
|
||||||
|
switch (result){
|
||||||
|
case LibUsb.SUCCESS:
|
||||||
|
if (writeBufTransferred.get() == message.length)
|
||||||
|
return false;
|
||||||
|
else {
|
||||||
|
logPrinter.print("TF Data transfer issue [write]\n Requested: "+message.length+"\n Transferred: "+writeBufTransferred.get(), EMsgType.FAIL);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case LibUsb.ERROR_TIMEOUT:
|
||||||
|
continue;
|
||||||
|
default:
|
||||||
|
logPrinter.print("TF Data transfer issue [write]\n Returned: "+ UsbErrorCodes.getErrCode(result), EMsgType.FAIL);
|
||||||
|
logPrinter.print("TF Execution stopped", EMsgType.FAIL);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
logPrinter.print("TF Execution interrupted", EMsgType.INFO);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Reading what USB device responded.
|
||||||
|
* @return byte array if data read successful
|
||||||
|
* 'null' if read failed
|
||||||
|
* */
|
||||||
|
private byte[] readUsb(){
|
||||||
|
ByteBuffer readBuffer = ByteBuffer.allocateDirect(512);
|
||||||
|
// 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:
|
||||||
|
logPrinter.print("TF Data transfer issue [read]\n Returned: " + UsbErrorCodes.getErrCode(result), EMsgType.FAIL);
|
||||||
|
logPrinter.print("TF Execution stopped", EMsgType.FAIL);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
logPrinter.print("TF Execution interrupted", EMsgType.INFO);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Status getter
|
||||||
|
* @return status
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public EFileStatus getStatus() {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load diff
183
src/main/java/nsusbloader/USB/UsbConnect.java
Normal file
183
src/main/java/nsusbloader/USB/UsbConnect.java
Normal file
|
@ -0,0 +1,183 @@
|
||||||
|
package nsusbloader.USB;
|
||||||
|
|
||||||
|
import nsusbloader.ModelControllers.LogPrinter;
|
||||||
|
import nsusbloader.NSLDataTypes.EMsgType;
|
||||||
|
import org.usb4java.*;
|
||||||
|
|
||||||
|
class UsbConnect {
|
||||||
|
private final int DEFAULT_INTERFACE = 0;
|
||||||
|
|
||||||
|
private Context contextNS;
|
||||||
|
private DeviceHandle handlerNS;
|
||||||
|
|
||||||
|
private LogPrinter logPrinter;
|
||||||
|
|
||||||
|
private boolean connected;
|
||||||
|
|
||||||
|
UsbConnect(LogPrinter logPrinter){
|
||||||
|
this.logPrinter = logPrinter;
|
||||||
|
this.connected = false;
|
||||||
|
|
||||||
|
int result;
|
||||||
|
|
||||||
|
// Creating Context required by libusb. Optional. TODO: Consider removing.
|
||||||
|
contextNS = new Context();
|
||||||
|
result = LibUsb.init(contextNS);
|
||||||
|
if (result != LibUsb.SUCCESS) {
|
||||||
|
logPrinter.print("libusb initialization\n Returned: "+result, EMsgType.FAIL);
|
||||||
|
close();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
logPrinter.print("libusb initialization", EMsgType.PASS);
|
||||||
|
|
||||||
|
// Searching for NS in devices: obtain list of all devices
|
||||||
|
DeviceList deviceList = new DeviceList();
|
||||||
|
result = LibUsb.getDeviceList(contextNS, deviceList);
|
||||||
|
if (result < 0) {
|
||||||
|
logPrinter.print("Get device list\n Returned: "+result, EMsgType.FAIL);
|
||||||
|
close();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
logPrinter.print("Get device list", EMsgType.PASS);
|
||||||
|
// Searching for NS in devices: looking for NS
|
||||||
|
DeviceDescriptor descriptor;
|
||||||
|
Device deviceNS = null;
|
||||||
|
for (Device device: deviceList){
|
||||||
|
descriptor = new DeviceDescriptor(); // mmm.. leave it as is.
|
||||||
|
result = LibUsb.getDeviceDescriptor(device, descriptor);
|
||||||
|
if (result != LibUsb.SUCCESS){
|
||||||
|
logPrinter.print("Read file descriptors for USB devices\n Returned: "+result, EMsgType.FAIL);
|
||||||
|
LibUsb.freeDeviceList(deviceList, true);
|
||||||
|
close();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ((descriptor.idVendor() == 0x057E) && descriptor.idProduct() == 0x3000){
|
||||||
|
deviceNS = device;
|
||||||
|
logPrinter.print("Read file descriptors for USB devices", EMsgType.PASS);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Free device list.
|
||||||
|
if (deviceNS != null){
|
||||||
|
logPrinter.print("NS in connected USB devices found", EMsgType.PASS);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
logPrinter.print("NS in connected USB devices not found", EMsgType.FAIL);
|
||||||
|
close();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Handle NS device
|
||||||
|
handlerNS = new DeviceHandle();
|
||||||
|
result = LibUsb.open(deviceNS, handlerNS);
|
||||||
|
if (result != LibUsb.SUCCESS) {
|
||||||
|
logPrinter.print("Open NS USB device\n Returned: "+UsbErrorCodes.getErrCode(result), EMsgType.FAIL);
|
||||||
|
if (result == LibUsb.ERROR_ACCESS)
|
||||||
|
logPrinter.print("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}==\"057e\", ATTRS{idProduct}==\"3000\", GROUP=\"plugdev\"\n" +
|
||||||
|
"root # udevadm control --reload-rules && udevadm trigger\n", EMsgType.INFO);
|
||||||
|
// Let's make a bit dirty workaround since such shit happened
|
||||||
|
logPrinter.print("Requested context close", EMsgType.INFO);
|
||||||
|
LibUsb.exit(contextNS);
|
||||||
|
return; // And close
|
||||||
|
}
|
||||||
|
else
|
||||||
|
logPrinter.print("Open NS USB device", EMsgType.PASS);
|
||||||
|
|
||||||
|
logPrinter.print("Free device list", EMsgType.INFO);
|
||||||
|
LibUsb.freeDeviceList(deviceList, true);
|
||||||
|
|
||||||
|
// DO some stuff to connected NS
|
||||||
|
// Check if this device uses kernel driver and detach if possible:
|
||||||
|
boolean canDetach = LibUsb.hasCapability(LibUsb.CAP_SUPPORTS_DETACH_KERNEL_DRIVER); // if cant, it's windows ot old lib
|
||||||
|
if (canDetach){
|
||||||
|
int usedByKernel = LibUsb.kernelDriverActive(handlerNS, DEFAULT_INTERFACE);
|
||||||
|
if (usedByKernel == LibUsb.SUCCESS)
|
||||||
|
logPrinter.print("Can proceed with libusb driver", EMsgType.PASS); // we're good
|
||||||
|
else if (usedByKernel == 1) { // used by kernel
|
||||||
|
result = LibUsb.detachKernelDriver(handlerNS, DEFAULT_INTERFACE);
|
||||||
|
logPrinter.print("Detach kernel required", EMsgType.INFO);
|
||||||
|
if (result != 0) {
|
||||||
|
logPrinter.print("Detach kernel\n Returned: " + UsbErrorCodes.getErrCode(result), EMsgType.FAIL);
|
||||||
|
close();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
logPrinter.print("Detach kernel", EMsgType.PASS);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
logPrinter.print("Can't proceed with libusb driver\n Returned: "+UsbErrorCodes.getErrCode(usedByKernel), EMsgType.FAIL);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
logPrinter.print("libusb doesn't support function 'CAP_SUPPORTS_DETACH_KERNEL_DRIVER'. It's normal. Proceeding.", EMsgType.WARNING);
|
||||||
|
/*
|
||||||
|
// Reset device
|
||||||
|
result = LibUsb.resetDevice(handlerNS);
|
||||||
|
if (result == 0)
|
||||||
|
logPrinter.print("Reset device", EMsgType.PASS);
|
||||||
|
else {
|
||||||
|
logPrinter.print("Reset device returned: " + result, EMsgType.FAIL);
|
||||||
|
updateAndClose();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
// Set configuration (soft reset if needed)
|
||||||
|
result = LibUsb.setConfiguration(handlerNS, 1); // 1 - configuration all we need
|
||||||
|
if (result != LibUsb.SUCCESS){
|
||||||
|
logPrinter.print("Set active configuration to device\n Returned: "+UsbErrorCodes.getErrCode(result), EMsgType.FAIL);
|
||||||
|
close();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
logPrinter.print("Set active configuration to device.", EMsgType.PASS);
|
||||||
|
|
||||||
|
// Claim interface
|
||||||
|
result = LibUsb.claimInterface(handlerNS, DEFAULT_INTERFACE);
|
||||||
|
if (result != LibUsb.SUCCESS) {
|
||||||
|
logPrinter.print("Claim interface\n Returned: "+UsbErrorCodes.getErrCode(result), EMsgType.FAIL);
|
||||||
|
close();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
logPrinter.print("Claim interface", EMsgType.PASS);
|
||||||
|
|
||||||
|
this.connected = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get USB status
|
||||||
|
* @return status of connection
|
||||||
|
*/
|
||||||
|
boolean isConnected() { return connected; }
|
||||||
|
/**
|
||||||
|
* Getter for handler
|
||||||
|
* @return DeviceHandle of NS
|
||||||
|
*/
|
||||||
|
DeviceHandle getHandlerNS(){ return handlerNS; }
|
||||||
|
/**
|
||||||
|
* Correct exit
|
||||||
|
* */
|
||||||
|
void close(){
|
||||||
|
// Close handler in the end
|
||||||
|
if (handlerNS != null) {
|
||||||
|
// Try to release interface
|
||||||
|
int result = LibUsb.releaseInterface(handlerNS, DEFAULT_INTERFACE);
|
||||||
|
|
||||||
|
if (result != LibUsb.SUCCESS)
|
||||||
|
logPrinter.print("Release interface\n Returned: "+result+" (sometimes it's not an issue)", EMsgType.WARNING);
|
||||||
|
else
|
||||||
|
logPrinter.print("Release interface", EMsgType.PASS);
|
||||||
|
|
||||||
|
LibUsb.close(handlerNS);
|
||||||
|
logPrinter.print("Requested handler close", EMsgType.INFO);
|
||||||
|
}
|
||||||
|
// Close context in the end
|
||||||
|
if (contextNS != null) {
|
||||||
|
LibUsb.exit(contextNS);
|
||||||
|
logPrinter.print("Requested context close", EMsgType.INFO);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue