mirror of https://github.com/rusefi/dfu_java.git
Does not work yet but getting closer?
This commit is contained in:
parent
32d17463fc
commit
00ff85c536
|
@ -8,11 +8,7 @@ public enum DfuCommmand {
|
|||
CLRSTATUS(4),
|
||||
GETSTATE(5),
|
||||
ABORT(6),
|
||||
|
||||
/**
|
||||
* http://dfu-util.sourceforge.net/dfuse.html
|
||||
*/
|
||||
SE_SET_ADDRESS(0x21);
|
||||
;
|
||||
|
||||
private final byte value;
|
||||
|
||||
|
|
|
@ -1,16 +1,38 @@
|
|||
package com.rusefi.dfu;
|
||||
|
||||
import com.rusefi.dfu.commands.DfuCommandGetStatus;
|
||||
import com.rusefi.dfu.usb4java.USBDfuConnection;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
public interface DfuConnection {
|
||||
int SECOND = 1000;
|
||||
int DFU_TIMEOUT = 10 * DfuConnection.SECOND;
|
||||
|
||||
static void waitStatus(USBDfuConnection device) {
|
||||
DfuCommandGetStatus.State state = DfuCommandGetStatus.read(device);
|
||||
System.out.println(" state " + state);
|
||||
while (state == DfuCommandGetStatus.State.DFU_DOWNLOAD_BUSY || state == DfuCommandGetStatus.State.DFU_ERROR) {
|
||||
sleep(106);
|
||||
state = DfuCommandGetStatus.read(device);
|
||||
System.out.println(" state " + state);
|
||||
}
|
||||
}
|
||||
|
||||
static void sleep(int millis) {
|
||||
System.out.println("Sleep " + millis);
|
||||
try {
|
||||
Thread.sleep(millis);
|
||||
} catch (InterruptedException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
|
||||
FlashRange getFlashRange();
|
||||
|
||||
int getTransferSize();
|
||||
|
||||
int receiveData(DfuCommmand command, short value, ByteBuffer data);
|
||||
int receiveData(DfuCommmand command, short wValue, ByteBuffer data);
|
||||
|
||||
int sendData(DfuCommmand command, short value, ByteBuffer data);
|
||||
int sendData(DfuCommmand command, short wValue, ByteBuffer data);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
package com.rusefi.dfu;
|
||||
|
||||
public class DfuSeCommand {
|
||||
public static final short W_SPECIAL = 0;
|
||||
public static final short W_DNLOAD = 2;
|
||||
/**
|
||||
* http://dfu-util.sourceforge.net/dfuse.html
|
||||
*/
|
||||
public static byte SE_SET_ADDRESS = 0x21;
|
||||
public static byte SE_ERASE_PAGE = 0x41;
|
||||
|
||||
|
||||
}
|
|
@ -11,6 +11,8 @@ public class DfuCommandGetStatus {
|
|||
public static State read(USBDfuConnection session) {
|
||||
ByteBuffer buffer = ByteBuffer.allocateDirect(PACKET_SIZE);
|
||||
int count = session.receiveData(DfuCommmand.GETSTATUS, (short) 0, buffer);
|
||||
if (count == 0)
|
||||
return State.DFU_ERROR;
|
||||
if (count != PACKET_SIZE)
|
||||
throw new IllegalStateException("Got " + count);
|
||||
buffer.rewind();
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
package com.rusefi.dfu.commands;
|
||||
|
||||
import com.rusefi.dfu.DfuCommmand;
|
||||
import com.rusefi.dfu.DfuConnection;
|
||||
import com.rusefi.dfu.DfuSeCommand;
|
||||
import com.rusefi.dfu.usb4java.LogUtil;
|
||||
import com.rusefi.dfu.usb4java.USBDfuConnection;
|
||||
import org.apache.commons.logging.Log;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
public class DfuSeCommandErasePage {
|
||||
private static final Log log = LogUtil.getLog(DfuSeCommandErasePage.class);
|
||||
|
||||
public static void execute(USBDfuConnection session, int address) {
|
||||
log.info(String.format("SetAddress %x", address));
|
||||
ByteBuffer buffer = DfuSeCommandSetAddress.createSpecialCommandBuffer(DfuSeCommand.SE_ERASE_PAGE, address);
|
||||
session.sendData(DfuCommmand.DNLOAD, DfuSeCommand.W_SPECIAL, buffer);
|
||||
DfuConnection.waitStatus(session);
|
||||
}
|
||||
}
|
|
@ -1,14 +1,35 @@
|
|||
package com.rusefi.dfu.commands;
|
||||
|
||||
import com.rusefi.dfu.DfuCommmand;
|
||||
import com.rusefi.dfu.DfuSeCommand;
|
||||
import com.rusefi.dfu.usb4java.LogUtil;
|
||||
import com.rusefi.dfu.usb4java.USBDfuConnection;
|
||||
import org.apache.commons.logging.Log;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
|
||||
public class DfuSeCommandSetAddress {
|
||||
private static final Log log = LogUtil.getLog(DfuSeCommandSetAddress.class);
|
||||
|
||||
public static void execute(USBDfuConnection session, int address) {
|
||||
ByteBuffer buffer = ByteBuffer.allocateDirect(4);
|
||||
log.info(String.format("SetAddress %x", address));
|
||||
ByteBuffer buffer = createSpecialCommandBuffer(DfuSeCommand.SE_SET_ADDRESS, address);
|
||||
buffer.putInt(address);
|
||||
session.sendData(DfuCommmand.CLRSTATUS, (short) 0, buffer);
|
||||
session.sendData(DfuCommmand.DNLOAD, DfuSeCommand.W_SPECIAL, buffer);
|
||||
}
|
||||
|
||||
protected static ByteBuffer createSpecialCommandBuffer(byte command, int address) {
|
||||
ByteBuffer buffer = createBuffer(5);
|
||||
buffer.put(command);
|
||||
// buffer.rewind();
|
||||
// byte[] t = new byte[4];
|
||||
// buffer.get(t);
|
||||
buffer.putInt(address);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
protected static ByteBuffer createBuffer(int capacity) {
|
||||
return ByteBuffer.allocateDirect(capacity).order(ByteOrder.LITTLE_ENDIAN);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,21 +34,21 @@ public class USBDfuConnection implements DfuConnection {
|
|||
}
|
||||
|
||||
@Override
|
||||
public int receiveData(DfuCommmand command, short value, ByteBuffer data) {
|
||||
return transfer(command, value, data, LibUsb.ENDPOINT_IN);
|
||||
public int receiveData(DfuCommmand command, short wValue, ByteBuffer data) {
|
||||
return transfer(command, wValue, data, LibUsb.ENDPOINT_IN);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int sendData(DfuCommmand command, short value, ByteBuffer data) {
|
||||
return transfer(command, value, data, LibUsb.ENDPOINT_OUT);
|
||||
public int sendData(DfuCommmand command, short wValue, ByteBuffer data) {
|
||||
return transfer(command, wValue, data, LibUsb.ENDPOINT_OUT);
|
||||
}
|
||||
|
||||
private int transfer(DfuCommmand command, short value, ByteBuffer data, byte mode) {
|
||||
private int transfer(DfuCommmand command, short wValue, ByteBuffer data, byte mode) {
|
||||
return LibUsb.controlTransfer(
|
||||
deviceHandle,
|
||||
(byte) (mode | LibUsb.REQUEST_TYPE_CLASS | LibUsb.RECIPIENT_INTERFACE),
|
||||
command.getValue(),
|
||||
value,
|
||||
wValue,
|
||||
interfaceNumber,
|
||||
data,
|
||||
DFU_TIMEOUT);
|
||||
|
|
|
@ -10,11 +10,15 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||
|
||||
public class HexImage extends AtomicInteger {
|
||||
private final byte[] image;
|
||||
private final FlashRange range;
|
||||
private final int totalBytes;
|
||||
private final int maxOffset;
|
||||
|
||||
public HexImage(byte[] image, int totalBytes) {
|
||||
public HexImage(byte[] image, FlashRange range, int totalBytes, int maxOffset) {
|
||||
this.image = image;
|
||||
this.range = range;
|
||||
this.totalBytes = totalBytes;
|
||||
this.maxOffset = maxOffset;
|
||||
}
|
||||
|
||||
static HexImage loadHexToBuffer(InputStream is, FlashRange range) throws IntelHexException, IOException {
|
||||
|
@ -24,6 +28,8 @@ public class HexImage extends AtomicInteger {
|
|||
Parser ihp = new Parser(is);
|
||||
|
||||
AtomicInteger totalBytesReceived = new AtomicInteger();
|
||||
|
||||
AtomicInteger maxOffset = new AtomicInteger();
|
||||
// register parser listener
|
||||
ihp.setDataListener(new DataListener() {
|
||||
@Override
|
||||
|
@ -31,6 +37,8 @@ public class HexImage extends AtomicInteger {
|
|||
// System.out.printf("Address %x size %x\n", address, data.length);
|
||||
totalBytesReceived.addAndGet(data.length);
|
||||
|
||||
maxOffset.set((int) Math.max(maxOffset.get(), address + 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,
|
||||
|
@ -46,7 +54,9 @@ public class HexImage extends AtomicInteger {
|
|||
});
|
||||
ihp.parse();
|
||||
|
||||
return new HexImage(image, totalBytesReceived.get());
|
||||
maxOffset.set(range.getBaseAddress() + 16 * 1024);
|
||||
|
||||
return new HexImage(image, range, totalBytesReceived.get(), maxOffset.get());
|
||||
}
|
||||
|
||||
public byte[] getImage() {
|
||||
|
@ -56,4 +66,22 @@ public class HexImage extends AtomicInteger {
|
|||
public int getTotalBytes() {
|
||||
return totalBytes;
|
||||
}
|
||||
|
||||
public int getMaxOffset() {
|
||||
return maxOffset;
|
||||
}
|
||||
|
||||
public FlashRange getRange() {
|
||||
return range;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "HexImage{" +
|
||||
"image=" + image.length +
|
||||
", range=" + range +
|
||||
", totalBytes=" + totalBytes +
|
||||
", maxOffset=" + maxOffset +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ public class HexReaderSandbox {
|
|||
|
||||
HexImage image = HexImage.loadHexToBuffer(new FileInputStream("rusefi.hex"), range);
|
||||
|
||||
System.out.println("Total received " + image.getTotalBytes());
|
||||
System.out.println("Total received " + image);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package com.rusefi.dfu;
|
||||
|
||||
import com.rusefi.dfu.commands.DfuCommandGetStatus;
|
||||
import com.rusefi.dfu.commands.DfuSeCommandErasePage;
|
||||
import com.rusefi.dfu.commands.DfuSeCommandSetAddress;
|
||||
import com.rusefi.dfu.usb4java.DfuDeviceLocator;
|
||||
import com.rusefi.dfu.usb4java.LogUtil;
|
||||
|
@ -26,37 +26,29 @@ public class Sandbox {
|
|||
|
||||
HexImage image = HexImage.loadHexToBuffer(new FileInputStream("rusefi.hex"), device.getFlashRange());
|
||||
|
||||
for (int offset = 0; offset < device.getFlashRange().getTotalLength(); offset += device.getTransferSize()) {
|
||||
System.out.println("Handing offset " + offset);
|
||||
|
||||
DfuSeCommandErasePage.execute(device, 0x08000000);
|
||||
DfuSeCommandErasePage.execute(device, 0x08004000);
|
||||
DfuSeCommandErasePage.execute(device, 0x08008000);
|
||||
DfuSeCommandErasePage.execute(device, 0x0800C000);
|
||||
DfuSeCommandErasePage.execute(device, 0x08010000);
|
||||
DfuSeCommandErasePage.execute(device, 0x08020000);
|
||||
DfuSeCommandErasePage.execute(device, 0x08040000);
|
||||
|
||||
for (int offset = 0; offset < image.getMaxOffset() - image.getRange().getBaseAddress(); offset += device.getTransferSize()) {
|
||||
System.out.println("Handling offset " + offset);
|
||||
DfuSeCommandSetAddress.execute(device, device.getFlashRange().getBaseAddress() + offset);
|
||||
waitStatus(device);
|
||||
DfuConnection.waitStatus(device);
|
||||
|
||||
ByteBuffer buffer = ByteBuffer.allocateDirect(device.getTransferSize());
|
||||
buffer.put(image.getImage(), offset, device.getTransferSize());
|
||||
device.sendData(DfuCommmand.DNLOAD, (short) 2, buffer);
|
||||
waitStatus(device);
|
||||
device.sendData(DfuCommmand.DNLOAD, DfuSeCommand.W_DNLOAD, buffer);
|
||||
// AN3156 USB DFU protocol used in the STM32 bootloader
|
||||
// "The Write memory operation is effectively executed only when a DFU_GETSTATUS request is issued by the host. "
|
||||
DfuConnection.waitStatus(device);
|
||||
}
|
||||
|
||||
|
||||
log.info("STM32 DFU " + device);
|
||||
}
|
||||
|
||||
private static void waitStatus(USBDfuConnection device) {
|
||||
DfuCommandGetStatus.State state = DfuCommandGetStatus.read(device);
|
||||
System.out.println(" state " + state);
|
||||
while (state == DfuCommandGetStatus.State.DFU_DOWNLOAD_BUSY) {
|
||||
sleep(106);
|
||||
state = DfuCommandGetStatus.read(device);
|
||||
System.out.println(" state " + state);
|
||||
}
|
||||
}
|
||||
|
||||
private static void sleep(int millis) {
|
||||
System.out.println("Sleep " + millis);
|
||||
try {
|
||||
Thread.sleep(millis);
|
||||
} catch (InterruptedException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue