remote SD card access
This commit is contained in:
parent
609fe10a93
commit
70e23dafbf
|
@ -36,11 +36,17 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||
import static com.devexperts.logging.Logging.getLogging;
|
||||
import static com.rusefi.binaryprotocol.BinaryProtocol.sleep;
|
||||
|
||||
/**
|
||||
* Remote user process which facilitates connection between local tuning application and real ECU via rusEFI proxy service
|
||||
*/
|
||||
public class LocalApplicationProxy implements Closeable {
|
||||
private static final ThreadFactory THREAD_FACTORY = new NamedThreadFactory("gauge poking");
|
||||
private static final Logging log = getLogging(LocalApplicationProxy.class);
|
||||
public static final int SERVER_PORT_FOR_APPLICATIONS = HttpUtil.getIntProperty("applications.port", 8002);
|
||||
private final ApplicationRequest applicationRequest;
|
||||
/**
|
||||
* local TCP server socket which local tuning application connects to
|
||||
*/
|
||||
private final ServerSocketReference serverHolder;
|
||||
private final IoStream authenticatorToProxyStream;
|
||||
|
||||
|
@ -50,6 +56,10 @@ public class LocalApplicationProxy implements Closeable {
|
|||
this.authenticatorToProxyStream = authenticatorToProxyStream;
|
||||
}
|
||||
|
||||
public IoStream getAuthenticatorToProxyStream() {
|
||||
return authenticatorToProxyStream;
|
||||
}
|
||||
|
||||
public static HttpResponse requestSoftwareUpdate(int httpPort, ApplicationRequest applicationRequest, UpdateType type) throws IOException {
|
||||
HttpPost httpPost = new HttpPost(ProxyClient.getHttpAddress(httpPort) + ProxyClient.UPDATE_CONNECTOR_SOFTWARE);
|
||||
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
package com.rusefi.ts_plugin;
|
||||
|
||||
import com.efiAnalytics.plugin.ecu.ControllerAccess;
|
||||
import com.rusefi.io.ConnectionStateListener;
|
||||
import com.rusefi.io.IoStream;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class LocalSdCardReader {
|
||||
private final JPanel content = new JPanel(new BorderLayout());
|
||||
|
||||
private final SdCardReaderPanel sdCardReaderPanel;
|
||||
|
||||
public LocalSdCardReader(Supplier<ControllerAccess> controllerAccessSupplier) {
|
||||
JPanel topPanel = new JPanel(new BorderLayout());
|
||||
|
||||
ConnectPanel connectPanel = new ConnectPanel(new ConnectionStateListener() {
|
||||
public void onConnectionEstablished() {
|
||||
sdCardReaderPanel.onConnectionEstablished();
|
||||
}
|
||||
|
||||
public void onConnectionFailed() {
|
||||
}
|
||||
});
|
||||
topPanel.add(connectPanel.getContent(), BorderLayout.NORTH);
|
||||
sdCardReaderPanel = new SdCardReaderPanel(controllerAccessSupplier, new Supplier<IoStream>() {
|
||||
@Override
|
||||
public IoStream get() {
|
||||
return connectPanel.getControllerConnector().getConnector().getBinaryProtocol().getStream();
|
||||
}
|
||||
}, content.getParent());
|
||||
|
||||
content.add(topPanel, BorderLayout.NORTH);
|
||||
content.add(sdCardReaderPanel.getContent(), BorderLayout.CENTER);
|
||||
|
||||
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() {
|
||||
return new JScrollPane(content, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
|
||||
}
|
||||
}
|
|
@ -20,10 +20,13 @@ import java.util.function.Supplier;
|
|||
* @see PluginBodySandbox
|
||||
*/
|
||||
public class PluginEntry implements TsPluginBody {
|
||||
private static final String LOCAL_SD_CARD = "Local SD Card";
|
||||
private static final String REMOTE_SD_CARD = "Remote SD Card";
|
||||
private final JPanel content = new JPanel(new BorderLayout());
|
||||
|
||||
static final ImageIcon LOGO = AutoupdateUtil.loadIcon("/rusefi_online_color_300.png");
|
||||
|
||||
private final JTabbedPane tabbedPane = new JTabbedPane();
|
||||
|
||||
/**
|
||||
* the real constructor - this one is invoked via reflection
|
||||
|
@ -45,15 +48,32 @@ public class PluginEntry implements TsPluginBody {
|
|||
TuneUploadTab tuneUploadTab = new TuneUploadTab(controllerAccessSupplier);
|
||||
LogUploadSelector logUploadTab = new LogUploadSelector(controllerAccessSupplier);
|
||||
BroadcastTab broadcastTab = new BroadcastTab();
|
||||
RemoteTab remoteTab = new RemoteTab();
|
||||
Component localSdCard = new LocalSdCardReader(controllerAccessSupplier).getContent();
|
||||
Component remoteSdCard = new RemoteSdCardReader(controllerAccessSupplier).getContent();
|
||||
RemoteTab remoteTab = new RemoteTab(new RemoteTab.Listener() {
|
||||
@Override
|
||||
public void onConnected() {
|
||||
tabbedPane.remove(localSdCard);
|
||||
tabbedPane.addTab(REMOTE_SD_CARD, remoteSdCard);
|
||||
}
|
||||
});
|
||||
|
||||
RemoteTabController.INSTANCE.listeners.add(new RemoteTabController.Listener() {
|
||||
@Override
|
||||
public void onChange(RemoteTabController.State state) {
|
||||
if (state == RemoteTabController.State.NOT_CONNECTED) {
|
||||
tabbedPane.remove(remoteSdCard);
|
||||
tabbedPane.addTab(LOCAL_SD_CARD, localSdCard);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
JTabbedPane tabbedPane = new JTabbedPane();
|
||||
tabbedPane.addTab("Tune Upload", tuneUploadTab.getContent());
|
||||
tabbedPane.addTab("Log Upload", logUploadTab.getContent());
|
||||
tabbedPane.addTab("Broadcast", broadcastTab.getContent());
|
||||
tabbedPane.addTab("Remote ECU", remoteTab.getContent());
|
||||
tabbedPane.addTab("Read SD Card", new SdCardReader(controllerAccessSupplier).getContent());
|
||||
content.add(tabbedPane);
|
||||
tabbedPane.addTab(LOCAL_SD_CARD, localSdCard);
|
||||
this.content.add(tabbedPane);
|
||||
|
||||
InstanceAuthContext.startup();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
package com.rusefi.ts_plugin;
|
||||
|
||||
import com.efiAnalytics.plugin.ecu.ControllerAccess;
|
||||
import com.rusefi.io.IoStream;
|
||||
import com.rusefi.proxy.client.LocalApplicationProxy;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class RemoteSdCardReader {
|
||||
private final JPanel content = new JPanel(new BorderLayout());
|
||||
|
||||
private final SdCardReaderPanel sdCardReaderPanel;
|
||||
|
||||
public RemoteSdCardReader(Supplier<ControllerAccess> controllerAccessSupplier) {
|
||||
|
||||
sdCardReaderPanel = new SdCardReaderPanel(controllerAccessSupplier, new Supplier<IoStream>() {
|
||||
@Override
|
||||
public IoStream get() {
|
||||
LocalApplicationProxy localApplicationProxy = RemoteTabController.INSTANCE.getLocalApplicationProxy();
|
||||
if (localApplicationProxy == null)
|
||||
throw new NullPointerException("Not connected");
|
||||
return localApplicationProxy.getAuthenticatorToProxyStream();
|
||||
}
|
||||
}, content.getParent());
|
||||
|
||||
content.add(sdCardReaderPanel.getContent(), BorderLayout.CENTER);
|
||||
}
|
||||
|
||||
public Component getContent() {
|
||||
return new JScrollPane(content, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -61,6 +61,7 @@ public class RemoteTab {
|
|||
return new Dimension(100, size.height);
|
||||
}
|
||||
};
|
||||
private final Listener listener;
|
||||
|
||||
|
||||
private StreamStatusControl streamStatusControl = null;
|
||||
|
@ -69,7 +70,8 @@ public class RemoteTab {
|
|||
|
||||
private final Executor listDownloadExecutor = Executors.newSingleThreadExecutor(new NamedThreadFactory("online list downloader", true));
|
||||
|
||||
public RemoteTab() {
|
||||
public RemoteTab(Listener listener) {
|
||||
this.listener = listener;
|
||||
JButton refresh = new JButton("Refresh Remote Controllers List");
|
||||
refresh.addActionListener(e -> requestControllersList());
|
||||
|
||||
|
@ -259,6 +261,7 @@ public class RemoteTab {
|
|||
streamStatusControl = new StreamStatusControl(authenticatorToProxyStream);
|
||||
}
|
||||
|
||||
listener.onConnected();
|
||||
setStatus("Connected to " + userDetails.getUserName(),
|
||||
new JLabel("You can now connect your TunerStudio to IP address localhost and port " + getLocalPort()),
|
||||
new URLLabel(SignatureHelper.getUrl(controllerInfo.getSignature()).first),
|
||||
|
@ -319,4 +322,8 @@ public class RemoteTab {
|
|||
public JComponent getContent() {
|
||||
return scroll;
|
||||
}
|
||||
|
||||
interface Listener {
|
||||
void onConnected();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,8 @@ package com.rusefi.ts_plugin;
|
|||
|
||||
import com.rusefi.proxy.client.LocalApplicationProxy;
|
||||
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
public enum RemoteTabController {
|
||||
/**
|
||||
* TunerStudio likes to close plugin panel, we need a singleton to preserve the state
|
||||
|
@ -11,9 +13,15 @@ public enum RemoteTabController {
|
|||
private State state = State.NOT_CONNECTED;
|
||||
private LocalApplicationProxy localApplicationProxy;
|
||||
|
||||
public final CopyOnWriteArrayList<Listener> listeners = new CopyOnWriteArrayList<>();
|
||||
|
||||
public synchronized void setState(State state) {
|
||||
this.state = state;
|
||||
localApplicationProxy = null;
|
||||
if (state != this.state) {
|
||||
this.state = state;
|
||||
for (Listener listener : listeners)
|
||||
listener.onChange(state);
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized State getState() {
|
||||
|
@ -34,4 +42,8 @@ public enum RemoteTabController {
|
|||
CONNECTING,
|
||||
CONNECTED
|
||||
}
|
||||
|
||||
interface Listener {
|
||||
void onChange(State state);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,6 @@ import com.devexperts.logging.Logging;
|
|||
import com.efiAnalytics.plugin.ecu.ControllerAccess;
|
||||
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;
|
||||
|
@ -25,66 +24,199 @@ 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);
|
||||
public class SdCardReaderPanel {
|
||||
private final static int TRANSFER_HEADER_SIZE = 3;
|
||||
private final JPanel content = new JPanel(new BorderLayout());
|
||||
private static final Logging log = getLogging(SdCardReaderPanel.class);
|
||||
|
||||
private final JPanel fileList = new JPanel(new VerticalFlowLayout());
|
||||
private final JLabel status = new JLabel();
|
||||
|
||||
private final ConnectPanel connectPanel = new ConnectPanel(new ConnectionStateListener() {
|
||||
public void onConnectionEstablished() {
|
||||
ConnectPanel.IO_THREAD.execute(() -> requestFileList());
|
||||
}
|
||||
|
||||
public void onConnectionFailed() {
|
||||
}
|
||||
});
|
||||
private final Supplier<ControllerAccess> controllerAccessSupplier;
|
||||
private final Supplier<IoStream> ioStreamSupplier;
|
||||
private final Container parent;
|
||||
|
||||
public SdCardReader(Supplier<ControllerAccess> controllerAccessSupplier) {
|
||||
private final JPanel content = new JPanel(new BorderLayout());
|
||||
|
||||
public SdCardReaderPanel(Supplier<ControllerAccess> controllerAccessSupplier,
|
||||
Supplier<IoStream> ioStreamSupplier, Container parent) {
|
||||
this.controllerAccessSupplier = controllerAccessSupplier;
|
||||
this.ioStreamSupplier = ioStreamSupplier;
|
||||
this.parent = parent;
|
||||
JButton refresh = new JButton("Refresh");
|
||||
refresh.addActionListener(e -> ConnectPanel.IO_THREAD.execute(this::requestFileList));
|
||||
|
||||
JPanel topPanel = new JPanel(new BorderLayout());
|
||||
JPanel lowPanel = new JPanel(new FlowLayout());
|
||||
|
||||
JButton open = new JButton("Open Destination Folder");
|
||||
JPanel lowPanel = new JPanel(new FlowLayout());
|
||||
lowPanel.add(refresh);
|
||||
lowPanel.add(open);
|
||||
|
||||
JPanel topPanel = new JPanel(new BorderLayout());
|
||||
topPanel.add(status, BorderLayout.CENTER);
|
||||
topPanel.add(lowPanel, BorderLayout.SOUTH);
|
||||
|
||||
content.add(topPanel, BorderLayout.NORTH);
|
||||
content.add(fileList, BorderLayout.CENTER);
|
||||
|
||||
open.addActionListener(new AbstractAction() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
try {
|
||||
String folder = getDestinationFolder(controllerAccessSupplier);
|
||||
String folder = getDestinationFolder();
|
||||
Runtime.getRuntime().exec("explorer.exe /select," + folder + File.separator);
|
||||
} catch (IOException ex) {
|
||||
log.error("Error", ex);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
topPanel.add(connectPanel.getContent(), BorderLayout.NORTH);
|
||||
topPanel.add(status, BorderLayout.CENTER);
|
||||
topPanel.add(lowPanel, BorderLayout.SOUTH);
|
||||
|
||||
content.add(topPanel, BorderLayout.NORTH);
|
||||
|
||||
content.add(fileList, BorderLayout.CENTER);
|
||||
|
||||
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 JPanel getContent() {
|
||||
return content;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private String getDestinationFolder(Supplier<ControllerAccess> controllerAccessSupplier) {
|
||||
private byte[] getDirContent() throws IOException {
|
||||
byte[] packet;
|
||||
byte[] response;
|
||||
IoStream stream = ioStreamSupplier.get();
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getDestinationFolder() {
|
||||
return LogUploadSelector.getLogsFolderDir(controllerAccessSupplier.get().getEcuConfigurationNames()[0]);
|
||||
}
|
||||
|
||||
public Component getContent() {
|
||||
return new JScrollPane(content, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
|
||||
private void downloadFile(String fileName) {
|
||||
String lastFour = ConnectPanel.getLastFour(fileName);
|
||||
|
||||
byte[] packet = new byte[17];
|
||||
packet[0] = Fields.TS_SD_W_COMMAND;
|
||||
packet[2] = TS_SD_PROTOCOL_FETCH_INFO;
|
||||
packet[6] = Fields.TS_SD_PROTOCOL_FETCH_COMPRESSED;
|
||||
applyLastFour(lastFour, packet);
|
||||
|
||||
IoStream stream = ioStreamSupplier.get();
|
||||
|
||||
FileOutputStream fos = null;
|
||||
try {
|
||||
stream.sendPacket(packet);
|
||||
byte[] response = stream.getDataBuffer().getPacket("Download file");
|
||||
log.info("Download file " + IoStream.printHexBinary(response));
|
||||
setStatus("Downloading " + fileName);
|
||||
|
||||
fos = new FileOutputStream(getDestinationFolder() + File.separator + 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;
|
||||
packet[2] = Fields.TS_SD_PROTOCOL_FETCH_DATA;
|
||||
packet[3] = (byte) chunk;
|
||||
packet[4] = (byte) (chunk >> 8);
|
||||
|
||||
stream.sendPacket(packet);
|
||||
response = stream.getDataBuffer().getPacket("Get file", true);
|
||||
|
||||
if (response == null) {
|
||||
log.info("No content response");
|
||||
break;
|
||||
}
|
||||
|
||||
int dataBytes = response.length - TRANSFER_HEADER_SIZE;
|
||||
totalSize += dataBytes;
|
||||
|
||||
if (chunk % 10 == 0)
|
||||
log.info("Got content package size " + response.length + "/total=" + totalSize);
|
||||
|
||||
fos.write(response, TRANSFER_HEADER_SIZE, dataBytes);
|
||||
|
||||
if (dataBytes != 2048) {
|
||||
log.info(response.length + " must be the last packet");
|
||||
long duration = System.currentTimeMillis() - start;
|
||||
setStatus(fileName + " downloaded " + humanReadableByteCountBin(totalSize) + " in " + duration + " ms");
|
||||
break;
|
||||
}
|
||||
if (chunk % 10 == 0)
|
||||
setStatus(humanReadableByteCountBin(totalSize) + " so far");
|
||||
chunk++;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new IllegalStateException(e);
|
||||
} finally {
|
||||
close(fos);
|
||||
}
|
||||
}
|
||||
|
||||
private void applyLastFour(String lastFour, byte[] packet) {
|
||||
for (int i = 0; i < 4; i++)
|
||||
packet[7 + i] = (byte) lastFour.charAt(i);
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
private void deleteFile(String fileName) {
|
||||
String lastFour = ConnectPanel.getLastFour(fileName);
|
||||
|
||||
byte[] packet = new byte[17];
|
||||
packet[0] = Fields.TS_SD_W_COMMAND;
|
||||
packet[2] = TS_SD_PROTOCOL_FETCH_INFO;
|
||||
packet[6] = Fields.TS_SD_PROTOCOL_REMOVE_FILE;
|
||||
applyLastFour(lastFour, packet);
|
||||
|
||||
IoStream stream = ioStreamSupplier.get();
|
||||
|
||||
try {
|
||||
stream.sendPacket(packet);
|
||||
byte[] response = stream.getDataBuffer().getPacket("delete file");
|
||||
log.info("Delete file " + IoStream.printHexBinary(response));
|
||||
} catch (IOException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void requestFileList() {
|
||||
|
@ -135,7 +267,7 @@ public class SdCardReader {
|
|||
|
||||
log.info("Filename " + fileName + " size " + fileSize);
|
||||
|
||||
AutoupdateUtil.trueLayout(content.getParent());
|
||||
AutoupdateUtil.trueLayout(parent);
|
||||
}
|
||||
|
||||
} catch (IOException ioException) {
|
||||
|
@ -147,148 +279,11 @@ 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);
|
||||
|
||||
byte[] packet = new byte[17];
|
||||
packet[0] = Fields.TS_SD_W_COMMAND;
|
||||
packet[2] = TS_SD_PROTOCOL_FETCH_INFO;
|
||||
packet[6] = Fields.TS_SD_PROTOCOL_FETCH_COMPRESSED;
|
||||
applyLastFour(lastFour, packet);
|
||||
|
||||
IoStream stream = connectPanel.getControllerConnector().getConnector().getBinaryProtocol().getStream();
|
||||
|
||||
FileOutputStream fos = null;
|
||||
try {
|
||||
stream.sendPacket(packet);
|
||||
byte[] response = stream.getDataBuffer().getPacket("Download file");
|
||||
log.info("Download file " + IoStream.printHexBinary(response));
|
||||
setStatus("Downloading " + fileName);
|
||||
|
||||
fos = new FileOutputStream(getDestinationFolder(controllerAccessSupplier) + File.separator + 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;
|
||||
packet[2] = Fields.TS_SD_PROTOCOL_FETCH_DATA;
|
||||
packet[3] = (byte) chunk;
|
||||
packet[4] = (byte) (chunk >> 8);
|
||||
|
||||
stream.sendPacket(packet);
|
||||
response = stream.getDataBuffer().getPacket("Get file", true);
|
||||
|
||||
if (response == null) {
|
||||
log.info("No content response");
|
||||
break;
|
||||
}
|
||||
|
||||
int dataBytes = response.length - TRANSFER_HEADER_SIZE;
|
||||
totalSize += dataBytes;
|
||||
|
||||
if (chunk % 10 == 0)
|
||||
log.info("Got content package size " + response.length + "/total=" + totalSize);
|
||||
|
||||
fos.write(response, TRANSFER_HEADER_SIZE, dataBytes);
|
||||
|
||||
if (dataBytes != 2048) {
|
||||
log.info(response.length + " must be the last packet");
|
||||
long duration = System.currentTimeMillis() - start;
|
||||
setStatus(fileName + " downloaded " + humanReadableByteCountBin(totalSize) + " in " + duration + " ms");
|
||||
break;
|
||||
}
|
||||
if (chunk % 10 == 0)
|
||||
setStatus(humanReadableByteCountBin(totalSize) + " so far");
|
||||
chunk++;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new IllegalStateException(e);
|
||||
} finally {
|
||||
close(fos);
|
||||
}
|
||||
}
|
||||
|
||||
private void deleteFile(String fileName) {
|
||||
String lastFour = ConnectPanel.getLastFour(fileName);
|
||||
|
||||
byte[] packet = new byte[17];
|
||||
packet[0] = Fields.TS_SD_W_COMMAND;
|
||||
packet[2] = TS_SD_PROTOCOL_FETCH_INFO;
|
||||
packet[6] = Fields.TS_SD_PROTOCOL_REMOVE_FILE;
|
||||
applyLastFour(lastFour, packet);
|
||||
|
||||
IoStream stream = connectPanel.getControllerConnector().getConnector().getBinaryProtocol().getStream();
|
||||
|
||||
try {
|
||||
stream.sendPacket(packet);
|
||||
byte[] response = stream.getDataBuffer().getPacket("delete file");
|
||||
log.info("Delete file " + IoStream.printHexBinary(response));
|
||||
} catch (IOException e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void applyLastFour(String lastFour, byte[] packet) {
|
||||
for (int i = 0; i < 4; i++)
|
||||
packet[7 + i] = (byte) lastFour.charAt(i);
|
||||
}
|
||||
|
||||
private void setStatus(String message) {
|
||||
public 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());
|
||||
public void onConnectionEstablished() {
|
||||
ConnectPanel.IO_THREAD.execute(this::requestFileList);
|
||||
}
|
||||
}
|
|
@ -7,6 +7,9 @@ import com.rusefi.ui.util.FrameHelper;
|
|||
*/
|
||||
public class RemoteTabSandbox {
|
||||
public static void main(String[] args) {
|
||||
new FrameHelper().showFrame(new RemoteTab().getContent());
|
||||
RemoteTab.Listener listener = () -> {
|
||||
|
||||
};
|
||||
new FrameHelper().showFrame(new RemoteTab(listener).getContent());
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue