NXDT-related updates

This commit is contained in:
Dmitry Isaenko 2020-08-27 13:13:28 +03:00
parent ab1b5b1820
commit ba4afa0046
8 changed files with 400 additions and 45 deletions

View file

@ -18,6 +18,7 @@
*/
package nsusbloader.COM.USB;
import nsusbloader.COM.USB.common.DeviceInformation;
import nsusbloader.ModelControllers.ILogPrinter;
import nsusbloader.NSLDataTypes.EMsgType;
import org.usb4java.*;
@ -88,6 +89,7 @@ public class UsbConnect {
usbConnect.connected = true;
}
catch (Exception e){
e.printStackTrace();
logPrinter.print(e.getMessage(), EMsgType.FAIL);
usbConnect.close();
}
@ -193,12 +195,10 @@ public class UsbConnect {
throw new Exception("Unable to set active configuration on device: "+UsbErrorCodes.getErrCode(returningValue));
}
private void claimInterface() throws Exception{
// Claim interface
returningValue = LibUsb.claimInterface(handlerNS, DEFAULT_INTERFACE);
if (returningValue != LibUsb.SUCCESS)
throw new Exception("Claim interface failure: "+UsbErrorCodes.getErrCode(returningValue));
}
/**
* Get USB status
* @return status of connection

View file

@ -0,0 +1,95 @@
/*
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 <https://www.gnu.org/licenses/>.
*/
package nsusbloader.COM.USB.common;
import nsusbloader.COM.USB.UsbErrorCodes;
import org.usb4java.*;
import java.util.ArrayList;
import java.util.List;
public class DeviceInformation {
private static final byte DEFAULT_IN_EP_ADDRESS = -127; // 0x81
private static final byte DEFAULT_OUT_EP_ADDRESS = 1;
private Device device;
private ConfigDescriptor configDescriptor;
private List<NsUsbInterface> interfacesInformation = new ArrayList<>();
private DeviceInformation(){}
public static DeviceInformation build(DeviceHandle handler) throws Exception{
Device device = LibUsb.getDevice(handler);
return DeviceInformation.build(device);
}
public static DeviceInformation build(Device device) throws Exception{
DeviceInformation deviceInformation = new DeviceInformation();
deviceInformation.device = device;
deviceInformation.claimConfigurationDescriptor();
deviceInformation.collectInterfaces();
deviceInformation.freeConfigurationDescriptor();
return deviceInformation;
}
private void claimConfigurationDescriptor() throws Exception{
configDescriptor = new ConfigDescriptor();
int returningValue = LibUsb.getActiveConfigDescriptor(device, configDescriptor);
if (returningValue != LibUsb.SUCCESS)
throw new Exception("Get Active config descriptor failed: "+ UsbErrorCodes.getErrCode(returningValue));
}
private void collectInterfaces(){
for (Interface intrface : configDescriptor.iface())
interfacesInformation.add(new NsUsbInterface(intrface));
}
private void freeConfigurationDescriptor(){
LibUsb.freeConfigDescriptor(configDescriptor);
}
/** Bulk transfer endpoint IN */
public NsUsbEndpointDescriptor getSimplifiedDefaultEndpointDescriptorIn() throws Exception{
return getSimplifiedDefaultEndpointDescriptor(true);
}
/** Bulk transfer endpoint OUT */
public NsUsbEndpointDescriptor getSimplifiedDefaultEndpointDescriptorOut() throws Exception{
return getSimplifiedDefaultEndpointDescriptor(false);
}
private NsUsbEndpointDescriptor getSimplifiedDefaultEndpointDescriptor(boolean isDescriptorIN) throws Exception{
byte endpointAddress;
if (isDescriptorIN)
endpointAddress = DEFAULT_IN_EP_ADDRESS;
else
endpointAddress = DEFAULT_OUT_EP_ADDRESS;
NsUsbInterface nsUsbInterface = interfacesInformation.get(0);
NsUsbInterfaceDescriptor firstInterfaceDescriptor = nsUsbInterface.getInterfaceDescriptors()[0];
NsUsbEndpointDescriptor[] endpointDescriptors = firstInterfaceDescriptor.getEndpointDescriptors();
for (NsUsbEndpointDescriptor epDescriptor : endpointDescriptors){
if (epDescriptor.getbEndpointAddress() == endpointAddress)
return epDescriptor;
}
throw new Exception("No "+(isDescriptorIN?"IN":"OUT")+" endpoint descriptors found on default interface");
}
}

View file

@ -0,0 +1,64 @@
/*
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 <https://www.gnu.org/licenses/>.
*/
package nsusbloader.COM.USB.common;
import org.usb4java.EndpointDescriptor;
public class NsUsbEndpointDescriptor {
private final byte bLength;
private final byte bDescriptorType;
private final byte bEndpointAddress;
private final byte bmAttributes;
//Ignoring: Transfer Type, Synch Type, Usage Type
private final short wMaxPacketSize;
private final byte bInterval;
NsUsbEndpointDescriptor(EndpointDescriptor endpointDescriptor){
this.bLength = endpointDescriptor.bLength();
this.bDescriptorType = endpointDescriptor.bDescriptorType();
this.bEndpointAddress = endpointDescriptor.bEndpointAddress();
this.bmAttributes = endpointDescriptor.bmAttributes();
this.wMaxPacketSize = endpointDescriptor.wMaxPacketSize();
this.bInterval = endpointDescriptor.bInterval();
}
public byte getbLength() {
return bLength;
}
public byte getbDescriptorType() {
return bDescriptorType;
}
public byte getbEndpointAddress() {
return bEndpointAddress;
}
public byte getBmAttributes() {
return bmAttributes;
}
public short getwMaxPacketSize() {
return wMaxPacketSize;
}
public byte getbInterval() {
return bInterval;
}
}

View file

@ -0,0 +1,32 @@
/*
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 <https://www.gnu.org/licenses/>.
*/
package nsusbloader.COM.USB.common;
import org.usb4java.EndpointDescriptor;
public class NsUsbEndpointDescriptorUtils {
static NsUsbEndpointDescriptor[] convertFromNatives(EndpointDescriptor[] nativeEpDescriptors){
int descriptorsCount = nativeEpDescriptors.length;
NsUsbEndpointDescriptor[] nsUsbEpDescriptors = new NsUsbEndpointDescriptor[descriptorsCount];
for (int i = 0; i < descriptorsCount; i++) {
nsUsbEpDescriptors[i] = new NsUsbEndpointDescriptor(nativeEpDescriptors[i]);
}
return nsUsbEpDescriptors;
}
}

View file

@ -0,0 +1,50 @@
/*
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 <https://www.gnu.org/licenses/>.
*/
package nsusbloader.COM.USB.common;
import org.usb4java.Interface;
import org.usb4java.InterfaceDescriptor;
import java.util.LinkedList;
/**
* Adapter for easier access to USB devices which has only one interface with one interface descriptor (BULK)
*
* After few JVM failed to core few 'holders' were added: such as NsUsbEndpoint descriptor and NsUsbInterfaceDescriptor
* */
public class NsUsbInterface {
private final Interface iface;
private final LinkedList<NsUsbInterfaceDescriptor> interfaceDescriptors;
public NsUsbInterface(Interface iface){
this.iface = iface;
this.interfaceDescriptors = new LinkedList<>();
collectDescriptors();
}
private void collectDescriptors(){
for (InterfaceDescriptor ifaceDescriptor : iface.altsetting()){
interfaceDescriptors.add(new NsUsbInterfaceDescriptor(ifaceDescriptor));
}
}
public NsUsbInterfaceDescriptor[] getInterfaceDescriptors(){
return interfaceDescriptors.toArray(new NsUsbInterfaceDescriptor[0]);
}
}

View file

@ -0,0 +1,93 @@
/*
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 <https://www.gnu.org/licenses/>.
*/
package nsusbloader.COM.USB.common;
import org.usb4java.EndpointDescriptor;
import org.usb4java.InterfaceDescriptor;
import java.nio.ByteBuffer;
public class NsUsbInterfaceDescriptor {
private final byte bLength;
private final byte bDescriptorType;
private final byte bInterfaceNumber;
private final byte bAlternateSetting;
private final byte bNumEndpoints;
private final byte bInterfaceClass;
private final byte bInterfaceSubClass;
private final byte bInterfaceProtocol;
private final byte iInterface;
//private final int extralen;
//private final ByteBuffer extra;
private final NsUsbEndpointDescriptor[] endpointDescriptors;
NsUsbInterfaceDescriptor(InterfaceDescriptor interfaceDescriptor){
this.bLength = interfaceDescriptor.bLength();
this.bDescriptorType = interfaceDescriptor.bDescriptorType();
this.bInterfaceNumber = interfaceDescriptor.bInterfaceNumber();
this.bAlternateSetting = interfaceDescriptor.bAlternateSetting();
this.bNumEndpoints = interfaceDescriptor.bNumEndpoints();
this.bInterfaceClass = interfaceDescriptor.bInterfaceClass();
this.bInterfaceSubClass = interfaceDescriptor.bInterfaceSubClass();
this.bInterfaceProtocol = interfaceDescriptor.bInterfaceProtocol();
this.iInterface = interfaceDescriptor.iInterface();
this.endpointDescriptors = NsUsbEndpointDescriptorUtils.convertFromNatives(interfaceDescriptor.endpoint());
}
public byte getbLength() {
return bLength;
}
public byte getbDescriptorType() {
return bDescriptorType;
}
public byte getbInterfaceNumber() {
return bInterfaceNumber;
}
public byte getbAlternateSetting() {
return bAlternateSetting;
}
public byte getbNumEndpoints() {
return bNumEndpoints;
}
public byte getbInterfaceClass() {
return bInterfaceClass;
}
public byte getbInterfaceSubClass() {
return bInterfaceSubClass;
}
public byte getbInterfaceProtocol() {
return bInterfaceProtocol;
}
public byte getiInterface() {
return iInterface;
}
public NsUsbEndpointDescriptor[] getEndpointDescriptors() {
return endpointDescriptors;
}
}

View file

@ -50,7 +50,12 @@ public class NxdtTask extends CancellableRunnable {
DeviceHandle handler = usbConnect.getNsHandler();
new NxdtUsbAbi1(handler, logPrinter, saveToLocation, this);
try {
new NxdtUsbAbi1(handler, logPrinter, saveToLocation, this);
}
catch (Exception e){
logPrinter.print(e.getMessage(), EMsgType.FAIL);
}
logPrinter.print(".:: Complete ::.", EMsgType.PASS);

View file

@ -19,6 +19,8 @@
package nsusbloader.Utilities.nxdumptool;
import nsusbloader.COM.USB.UsbErrorCodes;
import nsusbloader.COM.USB.common.DeviceInformation;
import nsusbloader.COM.USB.common.NsUsbEndpointDescriptor;
import nsusbloader.ModelControllers.ILogPrinter;
import nsusbloader.NSLDataTypes.EMsgType;
import org.usb4java.DeviceHandle;
@ -77,14 +79,17 @@ class NxdtUsbAbi1 {
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00 };
private static final long W_MAX_PACKET_SIZE = 0x200;
private short endpointMaxPacketSize;
private static final int NXDT_USB_TIMEOUT = 5000;
public NxdtUsbAbi1(DeviceHandle handler,
ILogPrinter logPrinter,
String saveToPath,
NxdtTask parent
){
)throws Exception{
this.handlerNS = handler;
//this.endpointMaxPacketSize = wMaxPacketSize;
this.logPrinter = logPrinter;
this.parent = parent;
this.isWindows = System.getProperty("os.name").toLowerCase().contains("windows");
@ -97,9 +102,17 @@ class NxdtUsbAbi1 {
else
this.saveToPath = saveToPath;
resolveEndpointMaxPacketSize();
readLoop();
}
private void resolveEndpointMaxPacketSize() throws Exception{
DeviceInformation deviceInformation = DeviceInformation.build(handlerNS);
NsUsbEndpointDescriptor endpointInDescriptor = deviceInformation.getSimplifiedDefaultEndpointDescriptorIn();
this.endpointMaxPacketSize = endpointInDescriptor.getwMaxPacketSize();
}
private void readLoop(){
logPrinter.print("Awaiting for handshake", EMsgType.INFO);
try {
@ -174,7 +187,16 @@ class NxdtUsbAbi1 {
writeUsb(USBSTATUS_UNSUPPORTED_ABI);
throw new Exception("ABI v"+versionABI+" is not supported in current version.");
}
writeUsb(USBSTATUS_SUCCESS);
replyToHandshake();
}
private void replyToHandshake() throws Exception{
// Send status response + endpoint max packet size
ByteBuffer buffer = ByteBuffer.allocate(USBSTATUS_SUCCESS.length + 2).order(ByteOrder.LITTLE_ENDIAN);
buffer.put(USBSTATUS_SUCCESS);
buffer.putShort(endpointMaxPacketSize);
byte[] response = buffer.array();
writeUsb(response);
}
private void handleSendFileProperties(byte[] message) throws Exception{
@ -187,7 +209,8 @@ class NxdtUsbAbi1 {
logPrinter.print("Invalid filename length!", EMsgType.FAIL);
return;
}
// TODO: Note, in case of a big amount of small files performace decreses dramatically. It's better to handle this only in case of 1-big-file-transfer
logPrinter.print("Receiving: '"+filename+"' ("+fileSize+" b)", EMsgType.INFO);
// If RomFs related
if (isRomFs(filename)) {
if (isWindows)
@ -198,7 +221,7 @@ class NxdtUsbAbi1 {
createPath(filename);
}
else {
logPrinter.print("Receiving: '"+filename+"' ("+fileSize+" b)", EMsgType.INFO);
//logPrinter.print("Receiving: '"+filename+"' ("+fileSize+" b)", EMsgType.INFO); // TODO: see above
filename = saveToPath + filename;
}
@ -222,10 +245,7 @@ class NxdtUsbAbi1 {
if (fileSize == 0)
return;
if (isWindows10)
dumpFileOnWindowsTen(fileToDump, fileSize);
else
dumpFile(fileToDump, fileSize);
dumpFile(fileToDump, fileSize);
writeUsb(USBSTATUS_SUCCESS);
@ -257,33 +277,8 @@ class NxdtUsbAbi1 {
throw new Exception("Unable to create dir(s) for file in "+folderForTheFile);
}
private void dumpFile(File file, long size) throws Exception{
try (BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file, false))) {
byte[] readBuffer;
long received = 0;
int bufferSize;
boolean zlt_expected = isAligned(size);
while (received < size) {
readBuffer = readUsbFile();
bos.write(readBuffer);
bufferSize = readBuffer.length;
received += bufferSize;
logPrinter.updateProgress((received + bufferSize) / (size / 100.0) / 100.0);
}
if (zlt_expected) {
logPrinter.print("Finishing with ZLT packet request", EMsgType.INFO);
readUsbFile();
}
} finally {
logPrinter.updateProgress(1.0);
}
}
// @see https://bugs.openjdk.java.net/browse/JDK-8146538
private void dumpFileOnWindowsTen(File file, long size) throws Exception{
private void dumpFile(File file, long size) throws Exception{
FileOutputStream fos = new FileOutputStream(file, true);
try (BufferedOutputStream bos = new BufferedOutputStream(fos)) {
@ -295,18 +290,21 @@ class NxdtUsbAbi1 {
boolean zlt_expected = isAligned(size);
while (received < size) {
readBuffer = readUsbFile();
//readBuffer = readUsbFile();
readBuffer = readUsbFileDebug();
bos.write(readBuffer);
fd.sync(); // Fixes flushing under Windows (unharmful for other OS)
if (isWindows10)
fd.sync();
bufferSize = readBuffer.length;
received += bufferSize;
logPrinter.updateProgress((received + bufferSize) / (size / 100.0) / 100.0);
logPrinter.updateProgress((double)received / (double)size);
}
if (zlt_expected) {
logPrinter.print("Finishing with ZLT packet request", EMsgType.INFO);
readUsbFile();
//readUsbFile();
readUsbFileDebug();
}
} finally {
logPrinter.updateProgress(1.0);
@ -314,7 +312,7 @@ class NxdtUsbAbi1 {
}
/** Handle Zero-length terminator **/
private boolean isAligned(long size){
return ((size & (W_MAX_PACKET_SIZE - 1)) == 0);
return ((size & (endpointMaxPacketSize - 1)) == 0);
}
/** Sending any byte array to USB device **/
@ -326,7 +324,7 @@ class NxdtUsbAbi1 {
if ( parent.isCancelled() )
throw new InterruptedException("Execution interrupted");
int result = LibUsb.bulkTransfer(handlerNS, (byte) 0x01, writeBuffer, writeBufTransferred, 5050);
int result = LibUsb.bulkTransfer(handlerNS, (byte) 0x01, writeBuffer, writeBufTransferred, NXDT_USB_TIMEOUT);
if (result == LibUsb.SUCCESS) {
if (writeBufTransferred.get() == message.length)
@ -338,7 +336,6 @@ class NxdtUsbAbi1 {
throw new Exception("Data transfer issue [write]" +
"\n Returned: " + UsbErrorCodes.getErrCode(result) +
"\n (execution stopped)");
}
/**
* Reading what USB device responded (command).
@ -399,4 +396,23 @@ class NxdtUsbAbi1 {
}
throw new InterruptedException();
}
private byte[] readUsbFileDebug() throws Exception {
ByteBuffer readBuffer = ByteBuffer.allocateDirect(NXDT_FILE_CHUNK_SIZE);
IntBuffer readBufTransferred = IntBuffer.allocate(1);
if (parent.isCancelled())
throw new InterruptedException();
int result = LibUsb.bulkTransfer(handlerNS, (byte) 0x81, readBuffer, readBufTransferred, NXDT_USB_TIMEOUT);
if (result == LibUsb.SUCCESS) {
int trans = readBufTransferred.get();
byte[] receivedBytes = new byte[trans];
readBuffer.get(receivedBytes);
return receivedBytes;
}
throw new Exception("Data transfer issue [read file]" +
"\n Returned: " + UsbErrorCodes.getErrCode(result) +
"\n (execution stopped)");
}
}