TS SD integration #1653
This commit is contained in:
parent
20ec569e46
commit
51b8da5b3d
|
@ -19,6 +19,12 @@ public class AutoupdateUtil {
|
||||||
// todo: figure out a better way to work with absolute path
|
// todo: figure out a better way to work with absolute path
|
||||||
private static final String APPICON = "/appicon.png";
|
private static final String APPICON = "/appicon.png";
|
||||||
|
|
||||||
|
public static JComponent wrap(JComponent component) {
|
||||||
|
JPanel result = new JPanel();
|
||||||
|
result.add(component);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
public static void downloadAutoupdateFile(String localZipFileName, ConnectionAndMeta connectionAndMeta, String title) throws IOException {
|
public static void downloadAutoupdateFile(String localZipFileName, ConnectionAndMeta connectionAndMeta, String title) throws IOException {
|
||||||
FrameHelper frameHelper = null;
|
FrameHelper frameHelper = null;
|
||||||
final AtomicReference<JProgressBar> jProgressBarAtomicReference = new AtomicReference<>();
|
final AtomicReference<JProgressBar> jProgressBarAtomicReference = new AtomicReference<>();
|
||||||
|
|
|
@ -113,9 +113,7 @@ public class UiUtils {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static JComponent wrap(JComponent component) {
|
public static JComponent wrap(JComponent component) {
|
||||||
JPanel result = new JPanel();
|
return AutoupdateUtil.wrap(component);
|
||||||
result.add(component);
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static JButton createSaveImageButton() {
|
public static JButton createSaveImageButton() {
|
||||||
|
|
|
@ -51,12 +51,13 @@ public class ConnectPanel {
|
||||||
//String port = ":29001";
|
//String port = ":29001";
|
||||||
controllerConnector.startAndConnect(autoDetectedPort, new ConnectionStateListener() {
|
controllerConnector.startAndConnect(autoDetectedPort, new ConnectionStateListener() {
|
||||||
public void onConnectionEstablished() {
|
public void onConnectionEstablished() {
|
||||||
status.setText("Connected to rusEFI");
|
SwingUtilities.invokeLater(() -> {
|
||||||
disconnect.setEnabled(true);
|
status.setText("Connected to rusEFI");
|
||||||
connectionStateListener.onConnectionEstablished();
|
disconnect.setEnabled(true);
|
||||||
|
connectionStateListener.onConnectionEstablished();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void onConnectionFailed() {
|
public void onConnectionFailed() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
package com.rusefi.ts_plugin;
|
package com.rusefi.ts_plugin;
|
||||||
|
|
||||||
|
import com.devexperts.logging.Logging;
|
||||||
import com.rusefi.autoupdate.AutoupdateUtil;
|
import com.rusefi.autoupdate.AutoupdateUtil;
|
||||||
import com.rusefi.config.generated.Fields;
|
import com.rusefi.config.generated.Fields;
|
||||||
import com.rusefi.io.ConnectionStateListener;
|
import com.rusefi.io.ConnectionStateListener;
|
||||||
import com.rusefi.io.IoStream;
|
import com.rusefi.io.IoStream;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.putgemin.VerticalFlowLayout;
|
import org.putgemin.VerticalFlowLayout;
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
|
@ -12,20 +14,28 @@ import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.ByteOrder;
|
import java.nio.ByteOrder;
|
||||||
|
import java.text.CharacterIterator;
|
||||||
|
import java.text.StringCharacterIterator;
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
|
||||||
|
import static com.devexperts.logging.Logging.getLogging;
|
||||||
import static com.rusefi.config.generated.Fields.TS_SD_PROTOCOL_FETCH_INFO;
|
import static com.rusefi.config.generated.Fields.TS_SD_PROTOCOL_FETCH_INFO;
|
||||||
import static com.rusefi.shared.FileUtil.close;
|
import static com.rusefi.shared.FileUtil.close;
|
||||||
|
|
||||||
public class SdCardReader {
|
public class SdCardReader {
|
||||||
|
private static final Logging log = getLogging(SdCardReader.class);
|
||||||
private final static int TRANSFER_HEADER_SIZE = 3;
|
private final static int TRANSFER_HEADER_SIZE = 3;
|
||||||
private final JPanel content = new JPanel(new BorderLayout());
|
private final JPanel content = new JPanel(new BorderLayout());
|
||||||
|
|
||||||
private final JPanel fileList = new JPanel(new VerticalFlowLayout());
|
private final JPanel fileList = new JPanel(new VerticalFlowLayout());
|
||||||
private final JLabel status = new JLabel();
|
private final JLabel status = new JLabel();
|
||||||
|
|
||||||
|
private static final Executor IO_THREAD = Executors.newSingleThreadExecutor();
|
||||||
|
|
||||||
private final ConnectPanel connectPanel = new ConnectPanel(new ConnectionStateListener() {
|
private final ConnectPanel connectPanel = new ConnectPanel(new ConnectionStateListener() {
|
||||||
public void onConnectionEstablished() {
|
public void onConnectionEstablished() {
|
||||||
requestFileList();
|
IO_THREAD.execute(() -> requestFileList());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void onConnectionFailed() {
|
public void onConnectionFailed() {
|
||||||
|
@ -34,15 +44,17 @@ public class SdCardReader {
|
||||||
|
|
||||||
public SdCardReader() {
|
public SdCardReader() {
|
||||||
JButton refresh = new JButton("Refresh");
|
JButton refresh = new JButton("Refresh");
|
||||||
refresh.addActionListener(e -> requestFileList());
|
refresh.addActionListener(e -> IO_THREAD.execute(this::requestFileList));
|
||||||
|
|
||||||
JPanel topPanel = new JPanel(new BorderLayout());
|
JPanel topPanel = new JPanel(new BorderLayout());
|
||||||
topPanel.add(connectPanel.getContent(), BorderLayout.NORTH);
|
topPanel.add(connectPanel.getContent(), BorderLayout.NORTH);
|
||||||
topPanel.add(status, BorderLayout.CENTER);
|
topPanel.add(status, BorderLayout.CENTER);
|
||||||
|
topPanel.add(AutoupdateUtil.wrap(refresh), BorderLayout.SOUTH);
|
||||||
|
|
||||||
content.add(topPanel, BorderLayout.NORTH);
|
content.add(topPanel, BorderLayout.NORTH);
|
||||||
content.add(fileList, BorderLayout.CENTER);
|
content.add(fileList, BorderLayout.CENTER);
|
||||||
content.add(refresh, BorderLayout.SOUTH);
|
|
||||||
|
content.add(new JLabel("<html>This tab allows direct access to SD card<br/>Please be sure to disconnect Tuner Studio from ECU while downloading files using this tab"), BorderLayout.SOUTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Component getContent() {
|
public Component getContent() {
|
||||||
|
@ -53,40 +65,7 @@ public class SdCardReader {
|
||||||
int fileCount = 0;
|
int fileCount = 0;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
byte[] packet;
|
byte[] response = getDirContent();
|
||||||
byte[] response;
|
|
||||||
IoStream stream = connectPanel.getControllerConnector().getConnector().getBinaryProtocol().getStream();
|
|
||||||
|
|
||||||
packet = new byte[3];
|
|
||||||
packet[0] = Fields.TS_SD_R_COMMAND;
|
|
||||||
packet[2] = Fields.TS_SD_PROTOCOL_RTC;
|
|
||||||
stream.sendPacket(packet);
|
|
||||||
response = stream.getDataBuffer().getPacket("RTC status");
|
|
||||||
System.out.println("RTC response " + IoStream.printHexBinary(response));
|
|
||||||
if (response == null)
|
|
||||||
throw new IOException("RTC No packet");
|
|
||||||
|
|
||||||
packet = new byte[17];
|
|
||||||
packet[0] = Fields.TS_SD_W_COMMAND;
|
|
||||||
packet[2] = TS_SD_PROTOCOL_FETCH_INFO;
|
|
||||||
packet[6] = Fields.TS_SD_PROTOCOL_READ_DIR;
|
|
||||||
stream.sendPacket(packet);
|
|
||||||
response = stream.getDataBuffer().getPacket("read dir command");
|
|
||||||
if (response == null)
|
|
||||||
throw new IOException("Read Dir No packet");
|
|
||||||
System.out.println("read dir command " + IoStream.printHexBinary(response));
|
|
||||||
|
|
||||||
packet = new byte[8];
|
|
||||||
packet[0] = Fields.TS_SD_R_COMMAND;
|
|
||||||
packet[1] = 0;
|
|
||||||
packet[2] = TS_SD_PROTOCOL_FETCH_INFO;
|
|
||||||
packet[5] = 0x02;
|
|
||||||
packet[6] = 0x02;
|
|
||||||
stream.sendPacket(packet);
|
|
||||||
response = stream.getDataBuffer().getPacket("read command", true);
|
|
||||||
if (response == null)
|
|
||||||
throw new IOException("No packet");
|
|
||||||
System.out.println("read command " + IoStream.printHexBinary(response));
|
|
||||||
|
|
||||||
fileList.removeAll();
|
fileList.removeAll();
|
||||||
|
|
||||||
|
@ -101,14 +80,14 @@ public class SdCardReader {
|
||||||
|
|
||||||
ByteBuffer bb = ByteBuffer.wrap(response, 1 + offset + 28, 4);
|
ByteBuffer bb = ByteBuffer.wrap(response, 1 + offset + 28, 4);
|
||||||
bb.order(ByteOrder.LITTLE_ENDIAN);
|
bb.order(ByteOrder.LITTLE_ENDIAN);
|
||||||
int size = bb.getInt();
|
int fileSize = bb.getInt();
|
||||||
|
|
||||||
JPanel filePanel = new JPanel(new FlowLayout());
|
JPanel filePanel = new JPanel(new FlowLayout());
|
||||||
|
|
||||||
filePanel.add(new JLabel(fileName + " " + size + " byte(s)"));
|
filePanel.add(new JLabel(fileName + " " + humanReadableByteCountBin(fileSize)));
|
||||||
|
|
||||||
JButton download = new JButton("Download");
|
JButton download = new JButton("Download");
|
||||||
download.addActionListener(e -> downloadFile(fileName));
|
download.addActionListener(e -> IO_THREAD.execute(() -> downloadFile(fileName)));
|
||||||
|
|
||||||
filePanel.add(download);
|
filePanel.add(download);
|
||||||
JButton delete = new JButton("Delete");
|
JButton delete = new JButton("Delete");
|
||||||
|
@ -116,16 +95,19 @@ public class SdCardReader {
|
||||||
int result = JOptionPane.showConfirmDialog(null, "Are you sure you want to remove " + fileName,
|
int result = JOptionPane.showConfirmDialog(null, "Are you sure you want to remove " + fileName,
|
||||||
"rusEfi", JOptionPane.YES_NO_OPTION);
|
"rusEfi", JOptionPane.YES_NO_OPTION);
|
||||||
if (result == JOptionPane.YES_OPTION) {
|
if (result == JOptionPane.YES_OPTION) {
|
||||||
deleteFile(fileName);
|
|
||||||
status.setText("Deleted " + fileName);
|
IO_THREAD.execute(() -> {
|
||||||
requestFileList();
|
deleteFile(fileName);
|
||||||
|
setStatus("Deleted " + fileName);
|
||||||
|
requestFileList();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
filePanel.add(delete);
|
filePanel.add(delete);
|
||||||
|
|
||||||
fileList.add(filePanel);
|
fileList.add(filePanel);
|
||||||
|
|
||||||
System.out.println("Filename " + fileName + " size " + size);
|
log.info("Filename " + fileName + " size " + fileSize);
|
||||||
|
|
||||||
AutoupdateUtil.trueLayout(content.getParent());
|
AutoupdateUtil.trueLayout(content.getParent());
|
||||||
}
|
}
|
||||||
|
@ -139,6 +121,45 @@ public class SdCardReader {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private byte[] getDirContent() throws IOException {
|
||||||
|
byte[] packet;
|
||||||
|
byte[] response;
|
||||||
|
IoStream stream = connectPanel.getControllerConnector().getConnector().getBinaryProtocol().getStream();
|
||||||
|
|
||||||
|
packet = new byte[3];
|
||||||
|
packet[0] = Fields.TS_SD_R_COMMAND;
|
||||||
|
packet[2] = Fields.TS_SD_PROTOCOL_RTC;
|
||||||
|
stream.sendPacket(packet);
|
||||||
|
response = stream.getDataBuffer().getPacket("RTC status");
|
||||||
|
log.info("RTC response " + IoStream.printHexBinary(response));
|
||||||
|
if (response == null)
|
||||||
|
throw new IOException("RTC No packet");
|
||||||
|
|
||||||
|
packet = new byte[17];
|
||||||
|
packet[0] = Fields.TS_SD_W_COMMAND;
|
||||||
|
packet[2] = TS_SD_PROTOCOL_FETCH_INFO;
|
||||||
|
packet[6] = Fields.TS_SD_PROTOCOL_READ_DIR;
|
||||||
|
stream.sendPacket(packet);
|
||||||
|
response = stream.getDataBuffer().getPacket("read dir command");
|
||||||
|
if (response == null)
|
||||||
|
throw new IOException("Read Dir No packet");
|
||||||
|
log.info("read dir command " + IoStream.printHexBinary(response));
|
||||||
|
|
||||||
|
packet = new byte[8];
|
||||||
|
packet[0] = Fields.TS_SD_R_COMMAND;
|
||||||
|
packet[1] = 0;
|
||||||
|
packet[2] = TS_SD_PROTOCOL_FETCH_INFO;
|
||||||
|
packet[5] = 0x02;
|
||||||
|
packet[6] = 0x02;
|
||||||
|
stream.sendPacket(packet);
|
||||||
|
response = stream.getDataBuffer().getPacket("read command", true);
|
||||||
|
if (response == null)
|
||||||
|
throw new IOException("No packet");
|
||||||
|
log.info("read command " + IoStream.printHexBinary(response));
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
private void downloadFile(String fileName) {
|
private void downloadFile(String fileName) {
|
||||||
String lastFour = ConnectPanel.getLastFour(fileName);
|
String lastFour = ConnectPanel.getLastFour(fileName);
|
||||||
|
|
||||||
|
@ -154,19 +175,13 @@ public class SdCardReader {
|
||||||
try {
|
try {
|
||||||
stream.sendPacket(packet);
|
stream.sendPacket(packet);
|
||||||
byte[] response = stream.getDataBuffer().getPacket("Download file");
|
byte[] response = stream.getDataBuffer().getPacket("Download file");
|
||||||
System.out.println("Download file " + IoStream.printHexBinary(response));
|
log.info("Download file " + IoStream.printHexBinary(response));
|
||||||
|
setStatus("Downloading " + fileName);
|
||||||
status.setText("Downloading " + fileName);
|
|
||||||
|
|
||||||
|
|
||||||
fos = new FileOutputStream("downloaded_" + fileName, false);
|
fos = new FileOutputStream("downloaded_" + fileName, false);
|
||||||
|
|
||||||
int chunk = 0;
|
int chunk = 0;
|
||||||
|
|
||||||
int totalSize = 0;
|
int totalSize = 0;
|
||||||
|
|
||||||
long start = System.currentTimeMillis();
|
long start = System.currentTimeMillis();
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
packet = new byte[17];
|
packet = new byte[17];
|
||||||
packet[0] = Fields.TS_SD_R_COMMAND;
|
packet[0] = Fields.TS_SD_R_COMMAND;
|
||||||
|
@ -178,23 +193,26 @@ public class SdCardReader {
|
||||||
response = stream.getDataBuffer().getPacket("Get file", true);
|
response = stream.getDataBuffer().getPacket("Get file", true);
|
||||||
|
|
||||||
if (response == null) {
|
if (response == null) {
|
||||||
System.out.println("No content response");
|
log.info("No content response");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
int dataBytes = response.length - TRANSFER_HEADER_SIZE;
|
int dataBytes = response.length - TRANSFER_HEADER_SIZE;
|
||||||
totalSize += dataBytes;
|
totalSize += dataBytes;
|
||||||
|
|
||||||
System.out.println("Got content package size " + response.length + "/total=" + totalSize);
|
if (chunk % 10 == 0)
|
||||||
|
log.info("Got content package size " + response.length + "/total=" + totalSize);
|
||||||
|
|
||||||
fos.write(response, TRANSFER_HEADER_SIZE, dataBytes);
|
fos.write(response, TRANSFER_HEADER_SIZE, dataBytes);
|
||||||
|
|
||||||
if (dataBytes != 2048) {
|
if (dataBytes != 2048) {
|
||||||
System.out.println(response.length + " must be the last packet");
|
log.info(response.length + " must be the last packet");
|
||||||
long duration = System.currentTimeMillis() - start;
|
long duration = System.currentTimeMillis() - start;
|
||||||
status.setText(fileName + " downloaded " + totalSize + " byte(s) in " + duration);
|
setStatus(fileName + " downloaded " + humanReadableByteCountBin(totalSize) + " in " + duration + " ms");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (chunk % 10 == 0)
|
||||||
|
setStatus(humanReadableByteCountBin(totalSize) + " so far");
|
||||||
chunk++;
|
chunk++;
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
@ -218,7 +236,7 @@ public class SdCardReader {
|
||||||
try {
|
try {
|
||||||
stream.sendPacket(packet);
|
stream.sendPacket(packet);
|
||||||
byte[] response = stream.getDataBuffer().getPacket("delete file");
|
byte[] response = stream.getDataBuffer().getPacket("delete file");
|
||||||
System.out.println("Delete file " + IoStream.printHexBinary(response));
|
log.info("Delete file " + IoStream.printHexBinary(response));
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new IllegalStateException(e);
|
throw new IllegalStateException(e);
|
||||||
}
|
}
|
||||||
|
@ -228,4 +246,23 @@ public class SdCardReader {
|
||||||
for (int i = 0; i < 4; i++)
|
for (int i = 0; i < 4; i++)
|
||||||
packet[7 + i] = (byte) lastFour.charAt(i);
|
packet[7 + i] = (byte) lastFour.charAt(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setStatus(String message) {
|
||||||
|
SwingUtilities.invokeLater(() -> status.setText(message));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String humanReadableByteCountBin(long bytes) {
|
||||||
|
long absB = bytes == Long.MIN_VALUE ? Long.MAX_VALUE : Math.abs(bytes);
|
||||||
|
if (absB < 1024) {
|
||||||
|
return bytes + " B";
|
||||||
|
}
|
||||||
|
long value = absB;
|
||||||
|
CharacterIterator ci = new StringCharacterIterator("KMGTPE");
|
||||||
|
for (int i = 40; i >= 0 && absB > 0xfffccccccccccccL >> i; i -= 10) {
|
||||||
|
value >>= 10;
|
||||||
|
ci.next();
|
||||||
|
}
|
||||||
|
value *= Long.signum(bytes);
|
||||||
|
return String.format("%.1f %ciB", value / 1024.0, ci.current());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue