diff --git a/java_console/autoupdate/src/com/rusefi/autoupdate/AutoupdateUtil.java b/java_console/autoupdate/src/com/rusefi/autoupdate/AutoupdateUtil.java index 43144fa039..f8d6aeb1ac 100644 --- a/java_console/autoupdate/src/com/rusefi/autoupdate/AutoupdateUtil.java +++ b/java_console/autoupdate/src/com/rusefi/autoupdate/AutoupdateUtil.java @@ -19,6 +19,12 @@ public class AutoupdateUtil { // todo: figure out a better way to work with absolute path 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 { FrameHelper frameHelper = null; final AtomicReference jProgressBarAtomicReference = new AtomicReference<>(); diff --git a/java_console/ui/src/main/java/com/rusefi/ui/util/UiUtils.java b/java_console/ui/src/main/java/com/rusefi/ui/util/UiUtils.java index 5fc930d18a..c1669e5696 100644 --- a/java_console/ui/src/main/java/com/rusefi/ui/util/UiUtils.java +++ b/java_console/ui/src/main/java/com/rusefi/ui/util/UiUtils.java @@ -113,9 +113,7 @@ public class UiUtils { } public static JComponent wrap(JComponent component) { - JPanel result = new JPanel(); - result.add(component); - return result; + return AutoupdateUtil.wrap(component); } public static JButton createSaveImageButton() { diff --git a/java_tools/ts_plugin/src/main/java/com/rusefi/ts_plugin/ConnectPanel.java b/java_tools/ts_plugin/src/main/java/com/rusefi/ts_plugin/ConnectPanel.java index 9e8411ff36..d56369a064 100644 --- a/java_tools/ts_plugin/src/main/java/com/rusefi/ts_plugin/ConnectPanel.java +++ b/java_tools/ts_plugin/src/main/java/com/rusefi/ts_plugin/ConnectPanel.java @@ -51,12 +51,13 @@ public class ConnectPanel { //String port = ":29001"; controllerConnector.startAndConnect(autoDetectedPort, new ConnectionStateListener() { public void onConnectionEstablished() { - status.setText("Connected to rusEFI"); - disconnect.setEnabled(true); - connectionStateListener.onConnectionEstablished(); + SwingUtilities.invokeLater(() -> { + status.setText("Connected to rusEFI"); + disconnect.setEnabled(true); + connectionStateListener.onConnectionEstablished(); + }); } - public void onConnectionFailed() { } }); diff --git a/java_tools/ts_plugin/src/main/java/com/rusefi/ts_plugin/SdCardReader.java b/java_tools/ts_plugin/src/main/java/com/rusefi/ts_plugin/SdCardReader.java index 07108f96d1..18315818bc 100644 --- a/java_tools/ts_plugin/src/main/java/com/rusefi/ts_plugin/SdCardReader.java +++ b/java_tools/ts_plugin/src/main/java/com/rusefi/ts_plugin/SdCardReader.java @@ -1,9 +1,11 @@ package com.rusefi.ts_plugin; +import com.devexperts.logging.Logging; import com.rusefi.autoupdate.AutoupdateUtil; import com.rusefi.config.generated.Fields; import com.rusefi.io.ConnectionStateListener; import com.rusefi.io.IoStream; +import org.jetbrains.annotations.NotNull; import org.putgemin.VerticalFlowLayout; import javax.swing.*; @@ -12,20 +14,28 @@ import java.io.FileOutputStream; import java.io.IOException; import java.nio.ByteBuffer; 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.shared.FileUtil.close; public class SdCardReader { + private static final Logging log = getLogging(SdCardReader.class); private final static int TRANSFER_HEADER_SIZE = 3; private final JPanel content = new JPanel(new BorderLayout()); private final JPanel fileList = new JPanel(new VerticalFlowLayout()); private final JLabel status = new JLabel(); + private static final Executor IO_THREAD = Executors.newSingleThreadExecutor(); + private final ConnectPanel connectPanel = new ConnectPanel(new ConnectionStateListener() { public void onConnectionEstablished() { - requestFileList(); + IO_THREAD.execute(() -> requestFileList()); } public void onConnectionFailed() { @@ -34,15 +44,17 @@ public class SdCardReader { public SdCardReader() { JButton refresh = new JButton("Refresh"); - refresh.addActionListener(e -> requestFileList()); + refresh.addActionListener(e -> IO_THREAD.execute(this::requestFileList)); JPanel topPanel = new JPanel(new BorderLayout()); topPanel.add(connectPanel.getContent(), BorderLayout.NORTH); topPanel.add(status, BorderLayout.CENTER); + topPanel.add(AutoupdateUtil.wrap(refresh), BorderLayout.SOUTH); content.add(topPanel, BorderLayout.NORTH); content.add(fileList, BorderLayout.CENTER); - content.add(refresh, BorderLayout.SOUTH); + + content.add(new JLabel("This tab allows direct access to SD card
Please be sure to disconnect Tuner Studio from ECU while downloading files using this tab"), BorderLayout.SOUTH); } public Component getContent() { @@ -53,40 +65,7 @@ public class SdCardReader { int fileCount = 0; try { - 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"); - 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)); + byte[] response = getDirContent(); fileList.removeAll(); @@ -101,14 +80,14 @@ public class SdCardReader { ByteBuffer bb = ByteBuffer.wrap(response, 1 + offset + 28, 4); bb.order(ByteOrder.LITTLE_ENDIAN); - int size = bb.getInt(); + int fileSize = bb.getInt(); 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"); - download.addActionListener(e -> downloadFile(fileName)); + download.addActionListener(e -> IO_THREAD.execute(() -> downloadFile(fileName))); filePanel.add(download); 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, "rusEfi", JOptionPane.YES_NO_OPTION); if (result == JOptionPane.YES_OPTION) { - deleteFile(fileName); - status.setText("Deleted " + fileName); - requestFileList(); + + IO_THREAD.execute(() -> { + deleteFile(fileName); + setStatus("Deleted " + fileName); + requestFileList(); + }); } }); filePanel.add(delete); fileList.add(filePanel); - System.out.println("Filename " + fileName + " size " + size); + log.info("Filename " + fileName + " size " + fileSize); 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) { String lastFour = ConnectPanel.getLastFour(fileName); @@ -154,19 +175,13 @@ public class SdCardReader { try { stream.sendPacket(packet); byte[] response = stream.getDataBuffer().getPacket("Download file"); - System.out.println("Download file " + IoStream.printHexBinary(response)); - - status.setText("Downloading " + fileName); - + log.info("Download file " + IoStream.printHexBinary(response)); + setStatus("Downloading " + fileName); fos = new FileOutputStream("downloaded_" + fileName, false); - int chunk = 0; - int totalSize = 0; - long start = System.currentTimeMillis(); - while (true) { packet = new byte[17]; packet[0] = Fields.TS_SD_R_COMMAND; @@ -178,23 +193,26 @@ public class SdCardReader { response = stream.getDataBuffer().getPacket("Get file", true); if (response == null) { - System.out.println("No content response"); + log.info("No content response"); break; } int dataBytes = response.length - TRANSFER_HEADER_SIZE; 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); 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; - status.setText(fileName + " downloaded " + totalSize + " byte(s) in " + duration); + setStatus(fileName + " downloaded " + humanReadableByteCountBin(totalSize) + " in " + duration + " ms"); break; } + if (chunk % 10 == 0) + setStatus(humanReadableByteCountBin(totalSize) + " so far"); chunk++; } } catch (IOException e) { @@ -218,7 +236,7 @@ public class SdCardReader { try { stream.sendPacket(packet); 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) { throw new IllegalStateException(e); } @@ -228,4 +246,23 @@ public class SdCardReader { for (int i = 0; i < 4; 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()); + } }