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.devexperts.logging.Logging.getLogging;
|
||||||
import static com.rusefi.binaryprotocol.BinaryProtocol.sleep;
|
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 {
|
public class LocalApplicationProxy implements Closeable {
|
||||||
private static final ThreadFactory THREAD_FACTORY = new NamedThreadFactory("gauge poking");
|
private static final ThreadFactory THREAD_FACTORY = new NamedThreadFactory("gauge poking");
|
||||||
private static final Logging log = getLogging(LocalApplicationProxy.class);
|
private static final Logging log = getLogging(LocalApplicationProxy.class);
|
||||||
public static final int SERVER_PORT_FOR_APPLICATIONS = HttpUtil.getIntProperty("applications.port", 8002);
|
public static final int SERVER_PORT_FOR_APPLICATIONS = HttpUtil.getIntProperty("applications.port", 8002);
|
||||||
private final ApplicationRequest applicationRequest;
|
private final ApplicationRequest applicationRequest;
|
||||||
|
/**
|
||||||
|
* local TCP server socket which local tuning application connects to
|
||||||
|
*/
|
||||||
private final ServerSocketReference serverHolder;
|
private final ServerSocketReference serverHolder;
|
||||||
private final IoStream authenticatorToProxyStream;
|
private final IoStream authenticatorToProxyStream;
|
||||||
|
|
||||||
|
@ -50,6 +56,10 @@ public class LocalApplicationProxy implements Closeable {
|
||||||
this.authenticatorToProxyStream = authenticatorToProxyStream;
|
this.authenticatorToProxyStream = authenticatorToProxyStream;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IoStream getAuthenticatorToProxyStream() {
|
||||||
|
return authenticatorToProxyStream;
|
||||||
|
}
|
||||||
|
|
||||||
public static HttpResponse requestSoftwareUpdate(int httpPort, ApplicationRequest applicationRequest, UpdateType type) throws IOException {
|
public static HttpResponse requestSoftwareUpdate(int httpPort, ApplicationRequest applicationRequest, UpdateType type) throws IOException {
|
||||||
HttpPost httpPost = new HttpPost(ProxyClient.getHttpAddress(httpPort) + ProxyClient.UPDATE_CONNECTOR_SOFTWARE);
|
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
|
* @see PluginBodySandbox
|
||||||
*/
|
*/
|
||||||
public class PluginEntry implements TsPluginBody {
|
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());
|
private final JPanel content = new JPanel(new BorderLayout());
|
||||||
|
|
||||||
static final ImageIcon LOGO = AutoupdateUtil.loadIcon("/rusefi_online_color_300.png");
|
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
|
* the real constructor - this one is invoked via reflection
|
||||||
|
@ -45,15 +48,32 @@ public class PluginEntry implements TsPluginBody {
|
||||||
TuneUploadTab tuneUploadTab = new TuneUploadTab(controllerAccessSupplier);
|
TuneUploadTab tuneUploadTab = new TuneUploadTab(controllerAccessSupplier);
|
||||||
LogUploadSelector logUploadTab = new LogUploadSelector(controllerAccessSupplier);
|
LogUploadSelector logUploadTab = new LogUploadSelector(controllerAccessSupplier);
|
||||||
BroadcastTab broadcastTab = new BroadcastTab();
|
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("Tune Upload", tuneUploadTab.getContent());
|
||||||
tabbedPane.addTab("Log Upload", logUploadTab.getContent());
|
tabbedPane.addTab("Log Upload", logUploadTab.getContent());
|
||||||
tabbedPane.addTab("Broadcast", broadcastTab.getContent());
|
tabbedPane.addTab("Broadcast", broadcastTab.getContent());
|
||||||
tabbedPane.addTab("Remote ECU", remoteTab.getContent());
|
tabbedPane.addTab("Remote ECU", remoteTab.getContent());
|
||||||
tabbedPane.addTab("Read SD Card", new SdCardReader(controllerAccessSupplier).getContent());
|
tabbedPane.addTab(LOCAL_SD_CARD, localSdCard);
|
||||||
content.add(tabbedPane);
|
this.content.add(tabbedPane);
|
||||||
|
|
||||||
InstanceAuthContext.startup();
|
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);
|
return new Dimension(100, size.height);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
private final Listener listener;
|
||||||
|
|
||||||
|
|
||||||
private StreamStatusControl streamStatusControl = null;
|
private StreamStatusControl streamStatusControl = null;
|
||||||
|
@ -69,7 +70,8 @@ public class RemoteTab {
|
||||||
|
|
||||||
private final Executor listDownloadExecutor = Executors.newSingleThreadExecutor(new NamedThreadFactory("online list downloader", true));
|
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");
|
JButton refresh = new JButton("Refresh Remote Controllers List");
|
||||||
refresh.addActionListener(e -> requestControllersList());
|
refresh.addActionListener(e -> requestControllersList());
|
||||||
|
|
||||||
|
@ -259,6 +261,7 @@ public class RemoteTab {
|
||||||
streamStatusControl = new StreamStatusControl(authenticatorToProxyStream);
|
streamStatusControl = new StreamStatusControl(authenticatorToProxyStream);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
listener.onConnected();
|
||||||
setStatus("Connected to " + userDetails.getUserName(),
|
setStatus("Connected to " + userDetails.getUserName(),
|
||||||
new JLabel("You can now connect your TunerStudio to IP address localhost and port " + getLocalPort()),
|
new JLabel("You can now connect your TunerStudio to IP address localhost and port " + getLocalPort()),
|
||||||
new URLLabel(SignatureHelper.getUrl(controllerInfo.getSignature()).first),
|
new URLLabel(SignatureHelper.getUrl(controllerInfo.getSignature()).first),
|
||||||
|
@ -319,4 +322,8 @@ public class RemoteTab {
|
||||||
public JComponent getContent() {
|
public JComponent getContent() {
|
||||||
return scroll;
|
return scroll;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface Listener {
|
||||||
|
void onConnected();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,8 @@ package com.rusefi.ts_plugin;
|
||||||
|
|
||||||
import com.rusefi.proxy.client.LocalApplicationProxy;
|
import com.rusefi.proxy.client.LocalApplicationProxy;
|
||||||
|
|
||||||
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
|
|
||||||
public enum RemoteTabController {
|
public enum RemoteTabController {
|
||||||
/**
|
/**
|
||||||
* TunerStudio likes to close plugin panel, we need a singleton to preserve the state
|
* 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 State state = State.NOT_CONNECTED;
|
||||||
private LocalApplicationProxy localApplicationProxy;
|
private LocalApplicationProxy localApplicationProxy;
|
||||||
|
|
||||||
|
public final CopyOnWriteArrayList<Listener> listeners = new CopyOnWriteArrayList<>();
|
||||||
|
|
||||||
public synchronized void setState(State state) {
|
public synchronized void setState(State state) {
|
||||||
this.state = state;
|
|
||||||
localApplicationProxy = null;
|
localApplicationProxy = null;
|
||||||
|
if (state != this.state) {
|
||||||
|
this.state = state;
|
||||||
|
for (Listener listener : listeners)
|
||||||
|
listener.onChange(state);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized State getState() {
|
public synchronized State getState() {
|
||||||
|
@ -34,4 +42,8 @@ public enum RemoteTabController {
|
||||||
CONNECTING,
|
CONNECTING,
|
||||||
CONNECTED
|
CONNECTED
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface Listener {
|
||||||
|
void onChange(State state);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,6 @@ import com.devexperts.logging.Logging;
|
||||||
import com.efiAnalytics.plugin.ecu.ControllerAccess;
|
import com.efiAnalytics.plugin.ecu.ControllerAccess;
|
||||||
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.IoStream;
|
import com.rusefi.io.IoStream;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.putgemin.VerticalFlowLayout;
|
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.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 SdCardReaderPanel {
|
||||||
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 static final Logging log = getLogging(SdCardReaderPanel.class);
|
||||||
|
|
||||||
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 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<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.controllerAccessSupplier = controllerAccessSupplier;
|
||||||
|
this.ioStreamSupplier = ioStreamSupplier;
|
||||||
|
this.parent = parent;
|
||||||
JButton refresh = new JButton("Refresh");
|
JButton refresh = new JButton("Refresh");
|
||||||
refresh.addActionListener(e -> ConnectPanel.IO_THREAD.execute(this::requestFileList));
|
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");
|
JButton open = new JButton("Open Destination Folder");
|
||||||
|
JPanel lowPanel = new JPanel(new FlowLayout());
|
||||||
lowPanel.add(refresh);
|
lowPanel.add(refresh);
|
||||||
lowPanel.add(open);
|
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() {
|
open.addActionListener(new AbstractAction() {
|
||||||
@Override
|
@Override
|
||||||
public void actionPerformed(ActionEvent e) {
|
public void actionPerformed(ActionEvent e) {
|
||||||
try {
|
try {
|
||||||
String folder = getDestinationFolder(controllerAccessSupplier);
|
String folder = getDestinationFolder();
|
||||||
Runtime.getRuntime().exec("explorer.exe /select," + folder + File.separator);
|
Runtime.getRuntime().exec("explorer.exe /select," + folder + File.separator);
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
log.error("Error", ex);
|
log.error("Error", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
topPanel.add(connectPanel.getContent(), BorderLayout.NORTH);
|
public JPanel getContent() {
|
||||||
topPanel.add(status, BorderLayout.CENTER);
|
return content;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@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]);
|
return LogUploadSelector.getLogsFolderDir(controllerAccessSupplier.get().getEcuConfigurationNames()[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Component getContent() {
|
private void downloadFile(String fileName) {
|
||||||
return new JScrollPane(content, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
|
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() {
|
private void requestFileList() {
|
||||||
|
@ -135,7 +267,7 @@ public class SdCardReader {
|
||||||
|
|
||||||
log.info("Filename " + fileName + " size " + fileSize);
|
log.info("Filename " + fileName + " size " + fileSize);
|
||||||
|
|
||||||
AutoupdateUtil.trueLayout(content.getParent());
|
AutoupdateUtil.trueLayout(parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (IOException ioException) {
|
} catch (IOException ioException) {
|
||||||
|
@ -147,148 +279,11 @@ public class SdCardReader {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
public void setStatus(String message) {
|
||||||
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) {
|
|
||||||
SwingUtilities.invokeLater(() -> status.setText(message));
|
SwingUtilities.invokeLater(() -> status.setText(message));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String humanReadableByteCountBin(long bytes) {
|
public void onConnectionEstablished() {
|
||||||
long absB = bytes == Long.MIN_VALUE ? Long.MAX_VALUE : Math.abs(bytes);
|
ConnectPanel.IO_THREAD.execute(this::requestFileList);
|
||||||
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());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -7,6 +7,9 @@ import com.rusefi.ui.util.FrameHelper;
|
||||||
*/
|
*/
|
||||||
public class RemoteTabSandbox {
|
public class RemoteTabSandbox {
|
||||||
public static void main(String[] args) {
|
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