diff --git a/.gitignore b/.gitignore index e9891c7..b0405f2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ .gradle build -sample.hex +*.hex diff --git a/src/main/java/com/rusefi/dfu/DfuConnection.java b/src/main/java/com/rusefi/dfu/DfuConnection.java index 43a25eb..dbab461 100644 --- a/src/main/java/com/rusefi/dfu/DfuConnection.java +++ b/src/main/java/com/rusefi/dfu/DfuConnection.java @@ -6,6 +6,10 @@ public interface DfuConnection { int SECOND = 1000; int DFU_TIMEOUT = 10 * DfuConnection.SECOND; + FlashRange getFlashRange(); + + int getTransferSize(); + int receiveData(DfuCommmand command, short value, ByteBuffer data); int sendData(DfuCommmand command, short value, ByteBuffer data); diff --git a/src/main/java/com/rusefi/dfu/FlashRange.java b/src/main/java/com/rusefi/dfu/FlashRange.java index 0813cd9..f456fa9 100644 --- a/src/main/java/com/rusefi/dfu/FlashRange.java +++ b/src/main/java/com/rusefi/dfu/FlashRange.java @@ -16,4 +16,12 @@ public class FlashRange { public int getTotalLength() { return totalLength; } + + @Override + public String toString() { + return "FlashRange{" + + "baseAddress=" + baseAddress + + ", totalLength=" + totalLength + + '}'; + } } diff --git a/src/main/java/com/rusefi/dfu/usb4java/DfuDeviceLocator.java b/src/main/java/com/rusefi/dfu/usb4java/DfuDeviceLocator.java index d3271e9..33f83bf 100644 --- a/src/main/java/com/rusefi/dfu/usb4java/DfuDeviceLocator.java +++ b/src/main/java/com/rusefi/dfu/usb4java/DfuDeviceLocator.java @@ -1,16 +1,21 @@ package com.rusefi.dfu.usb4java; +import com.rusefi.dfu.DfuSeFlashDescriptor; +import com.rusefi.dfu.FlashRange; import com.rusefi.dfu.commands.DfuCommandClearStatus; import com.rusefi.dfu.commands.DfuCommandGetStatus; import org.apache.commons.logging.Log; import org.usb4java.*; +import java.nio.ByteBuffer; + public class DfuDeviceLocator { private static final short ST_VENDOR = 0x0483; private static final short ST_DFU_PRODUCT = (short) 0xdf11; private static final byte USB_CLASS_APP_SPECIFIC = (byte) 0xfe; private static final byte DFU_SUBCLASS = 0x01; + private static final byte USB_DT_DFU = 0x21; private static final Log log = LogUtil.getLog(DfuDeviceLocator.class); @@ -56,9 +61,18 @@ public class DfuDeviceLocator { return null; } + public static int swap16(int x) { + return (((x & 0xff) << 8) | ((x >> 8) & 0xff)); + } + public static USBDfuConnection findDfuInterface(Device device, DeviceDescriptor deviceDescriptor) { byte numConfigurations = deviceDescriptor.bNumConfigurations(); log.info(numConfigurations + " configuration(s)"); + + DeviceHandle deviceHandle = open(device); + int transferSize = 0; + FlashRange flashRange = null; + for (int configurationIndex = 0; configurationIndex < numConfigurations; configurationIndex++) { ConfigDescriptor config = new ConfigDescriptor(); int result = LibUsb.getConfigDescriptor(device, (byte) configurationIndex, config); @@ -66,6 +80,9 @@ public class DfuDeviceLocator { throw new LibUsbException("getConfigDescriptor", result); } + System.out.println("Config " + config); + System.out.println("Config Done"); + byte numInterfaces = config.bNumInterfaces(); log.info(numInterfaces + " interface(s)"); @@ -74,7 +91,32 @@ public class DfuDeviceLocator { for (int s = 0; s < iface.numAltsetting(); s++) { InterfaceDescriptor setting = iface.altsetting()[s]; - log.info("Set " + setting); + System.out.println("setting " + setting); + + ByteBuffer extra = setting.extra(); + + if (extra.limit() > 2) { + int len = extra.get(); + byte type = extra.get(); + if (type == USB_DT_DFU) { + System.out.println(len + " " + type); + extra.get(); // bmAttributes + extra.get(); // wDetachTimeOut + extra.get(); + transferSize = swap16(extra.getShort()); + System.out.println("transferSize " + transferSize); + } + } + } + } + + for (int interfaceIndex = 0; interfaceIndex < numInterfaces; interfaceIndex++) { + Interface iface = config.iface()[interfaceIndex]; + + for (int s = 0; s < iface.numAltsetting(); s++) { + InterfaceDescriptor setting = iface.altsetting()[s]; + + log.info("Settings " + setting); byte interfaceNumber = setting.bInterfaceNumber(); log.info(String.format("Setting %d: %x %x class %x, subclass %x, protocol: %x", s, interfaceNumber, @@ -83,23 +125,21 @@ public class DfuDeviceLocator { setting.bInterfaceProtocol() )); - - if (setting.bInterfaceClass() == USB_CLASS_APP_SPECIFIC && setting.bInterfaceSubClass() == DFU_SUBCLASS) { log.debug(String.format("Found DFU interface: %d", interfaceNumber)); - DeviceHandle deviceHandle = open(device); - String stringDescriptor = LibUsb.getStringDescriptor(deviceHandle, setting.iInterface()); log.info("StringDescriptor: " + stringDescriptor); + if (stringDescriptor.contains("Flash")) + flashRange = DfuSeFlashDescriptor.parse(stringDescriptor); result = LibUsb.claimInterface(deviceHandle, interfaceNumber); if (result != LibUsb.SUCCESS) { throw new LibUsbException("claimInterface", result); } - USBDfuConnection session = new USBDfuConnection(deviceHandle, interfaceNumber); + USBDfuConnection session = new USBDfuConnection(deviceHandle, interfaceNumber, transferSize, flashRange); DfuCommandGetStatus.State state = DfuCommandGetStatus.read(session); log.info("DFU state: " + state); diff --git a/src/main/java/com/rusefi/dfu/usb4java/USBDfuConnection.java b/src/main/java/com/rusefi/dfu/usb4java/USBDfuConnection.java index 3086336..888edcb 100644 --- a/src/main/java/com/rusefi/dfu/usb4java/USBDfuConnection.java +++ b/src/main/java/com/rusefi/dfu/usb4java/USBDfuConnection.java @@ -2,6 +2,7 @@ package com.rusefi.dfu.usb4java; import com.rusefi.dfu.DfuCommmand; import com.rusefi.dfu.DfuConnection; +import com.rusefi.dfu.FlashRange; import org.usb4java.DeviceHandle; import org.usb4java.LibUsb; @@ -10,10 +11,24 @@ import java.nio.ByteBuffer; public class USBDfuConnection implements DfuConnection { private final DeviceHandle deviceHandle; private final byte interfaceNumber; + private final int transferSize; + private final FlashRange flashRange; - public USBDfuConnection(DeviceHandle deviceHandle, byte interfaceNumber) { + public USBDfuConnection(DeviceHandle deviceHandle, byte interfaceNumber, int transferSize, FlashRange flashRange) { this.deviceHandle = deviceHandle; this.interfaceNumber = interfaceNumber; + this.transferSize = transferSize; + this.flashRange = flashRange; + } + + @Override + public FlashRange getFlashRange() { + return flashRange; + } + + @Override + public int getTransferSize() { + return transferSize; } @Override diff --git a/src/test/java/com/rusefi/dfu/HexImage.java b/src/test/java/com/rusefi/dfu/HexImage.java new file mode 100644 index 0000000..fd155ed --- /dev/null +++ b/src/test/java/com/rusefi/dfu/HexImage.java @@ -0,0 +1,59 @@ +package com.rusefi.dfu; + +import cz.jaybee.intelhex.DataListener; +import cz.jaybee.intelhex.IntelHexException; +import cz.jaybee.intelhex.Parser; + +import java.io.IOException; +import java.io.InputStream; +import java.util.concurrent.atomic.AtomicInteger; + +public class HexImage extends AtomicInteger { + private final byte[] image; + private final int totalBytes; + + public HexImage(byte[] image, int totalBytes) { + this.image = image; + this.totalBytes = totalBytes; + } + + static HexImage loadHexToBuffer(InputStream is, FlashRange range) throws IntelHexException, IOException { + byte[] image = new byte[range.getTotalLength()]; + + // create IntelHexParserObject + Parser ihp = new Parser(is); + + AtomicInteger totalBytesReceived = new AtomicInteger(); + // register parser listener + ihp.setDataListener(new DataListener() { + @Override + public void data(long address, byte[] data) { +// System.out.printf("Address %x size %x\n", address, data.length); + totalBytesReceived.addAndGet(data.length); + + if (address < range.getBaseAddress() || address + data.length > range.getBaseAddress() + range.getTotalLength()) + throw new IllegalStateException(String.format("Image data out of range: %x@%x not withiin %s", + data.length, + address, + range.toString())); + System.arraycopy(data, 0, image, (int) (address - range.getBaseAddress()), data.length); + } + + @Override + public void eof() { + // do some action + } + }); + ihp.parse(); + + return new HexImage(image, totalBytesReceived.get()); + } + + public byte[] getImage() { + return image; + } + + public int getTotalBytes() { + return totalBytes; + } +} diff --git a/src/test/java/com/rusefi/dfu/HexReaderSandbox.java b/src/test/java/com/rusefi/dfu/HexReaderSandbox.java index 46d4bd7..470273a 100644 --- a/src/test/java/com/rusefi/dfu/HexReaderSandbox.java +++ b/src/test/java/com/rusefi/dfu/HexReaderSandbox.java @@ -1,32 +1,18 @@ package com.rusefi.dfu; -import cz.jaybee.intelhex.DataListener; import cz.jaybee.intelhex.IntelHexException; -import cz.jaybee.intelhex.Parser; import java.io.FileInputStream; import java.io.IOException; -import java.io.InputStream; public class HexReaderSandbox { public static void main(String[] args) throws IOException, IntelHexException { - InputStream is = new FileInputStream("sample.hex"); - // create IntelHexParserObject - Parser ihp = new Parser(is); + FlashRange range = new FlashRange(0x8000000, 0x100000); - // register parser listener - ihp.setDataListener(new DataListener() { - @Override - public void data(long address, byte[] data) { - System.out.printf("Address %x size %x\n", address, data.length); - } + HexImage image = HexImage.loadHexToBuffer(new FileInputStream("rusefi.hex"), range); - @Override - public void eof() { - // do some action - } - }); - ihp.parse(); + System.out.println("Total received " + image.getTotalBytes()); } + } diff --git a/src/test/java/com/rusefi/dfu/Sandbox.java b/src/test/java/com/rusefi/dfu/Sandbox.java index bcac499..deb58f2 100644 --- a/src/test/java/com/rusefi/dfu/Sandbox.java +++ b/src/test/java/com/rusefi/dfu/Sandbox.java @@ -3,15 +3,26 @@ package com.rusefi.dfu; import com.rusefi.dfu.usb4java.DfuDeviceLocator; import com.rusefi.dfu.usb4java.LogUtil; import com.rusefi.dfu.usb4java.USBDfuConnection; +import cz.jaybee.intelhex.IntelHexException; import org.apache.commons.logging.Log; +import java.io.FileInputStream; +import java.io.IOException; + public class Sandbox { private static final Log log = LogUtil.getLog(Sandbox.class); - public static void main(String[] args) { + public static void main(String[] args) throws IOException, IntelHexException { log.info("Hello sandbox"); USBDfuConnection device = DfuDeviceLocator.findDevice(); + if (device == null) { + System.err.println("No DFU devices found"); + return; + } + + HexImage image = HexImage.loadHexToBuffer(new FileInputStream("rusefi.hex"), device.getFlashRange()); + log.info("STM32 DFU " + device); }