diff --git a/java_console/.idea/runConfigurations/Launcher_Auto.xml b/java_console/.idea/runConfigurations/Launcher_Auto.xml
new file mode 100644
index 0000000000..c46a03e234
--- /dev/null
+++ b/java_console/.idea/runConfigurations/Launcher_Auto.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/java_console/ui/src/com/rusefi/Launcher.java b/java_console/ui/src/com/rusefi/Launcher.java
index dd933b2987..5b18329197 100644
--- a/java_console/ui/src/com/rusefi/Launcher.java
+++ b/java_console/ui/src/com/rusefi/Launcher.java
@@ -1,6 +1,7 @@
package com.rusefi;
import com.fathzer.soft.javaluator.DoubleEvaluator;
+import com.rusefi.autodetect.PortDetector;
import com.rusefi.binaryprotocol.BinaryProtocol;
import com.rusefi.binaryprotocol.BinaryProtocolHolder;
import com.rusefi.config.generated.Fields;
@@ -47,7 +48,7 @@ import static com.rusefi.ui.storage.PersistentConfiguration.getConfig;
* @see EngineSnifferPanel
*/
public class Launcher {
- public static final int CONSOLE_VERSION = 20190809;
+ public static final int CONSOLE_VERSION = 20190814;
public static final String INPUT_FILES_PATH = "..";
private static final String TAB_INDEX = "main_tab";
protected static final String PORT_KEY = "port";
@@ -301,6 +302,10 @@ public class Launcher {
System.exit(0);
}
+ /**
+ * rusEfi console entry point
+ * @see StartupFrame if no parameters specified
+ */
public static void main(final String[] args) throws Exception {
String toolName = args.length == 0 ? null : args[0];
if (TOOL_NAME_COMPILE_FSIO_FILE.equalsIgnoreCase(toolName)) {
@@ -364,8 +369,23 @@ public class Launcher {
boolean isBaudRateDefined = args.length > 1;
if (isBaudRateDefined)
PortHolder.BAUD_RATE = Integer.parseInt(args[1]);
+
+ String port = null;
+ if (isPortDefined)
+ port = args[0];
+
+
+ if (isPortDefined && port.toLowerCase().startsWith("auto")) {
+ String autoDetectedPort = PortDetector.autoDetectSerial();
+ if (autoDetectedPort == null) {
+ isPortDefined = false;
+ } else {
+ port = autoDetectedPort;
+ }
+ }
+
if (isPortDefined) {
- new Launcher(args[0]);
+ new Launcher(port);
} else {
for (String p : SerialPortList.getPortNames())
MessagesCentral.getInstance().postMessage(Launcher.class, "Available port: " + p);
diff --git a/java_console/ui/src/com/rusefi/StartupFrame.java b/java_console/ui/src/com/rusefi/StartupFrame.java
index 91a25536a6..45435d2921 100644
--- a/java_console/ui/src/com/rusefi/StartupFrame.java
+++ b/java_console/ui/src/com/rusefi/StartupFrame.java
@@ -1,5 +1,6 @@
package com.rusefi;
+import com.rusefi.autodetect.PortDetector;
import com.rusefi.io.LinkManager;
import com.rusefi.io.serial.PortHolder;
import com.rusefi.io.tcp.TcpConnector;
@@ -45,6 +46,7 @@ public class StartupFrame {
private static final String LOGO = "logo.gif";
public static final String LINK_TEXT = "rusEfi (c) 2012-2019";
private static final String URI = "http://rusefi.com/?java_console";
+ private static final String AUTO_SERIAL = "Auto Serial";
private final JFrame frame;
private final Timer scanPortsTimes = new Timer(1000, new ActionListener() {
@@ -122,9 +124,16 @@ public class StartupFrame {
connect.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
- disposeFrameAndProceed();
PortHolder.BAUD_RATE = Integer.parseInt((String) comboSpeeds.getSelectedItem());
- new Launcher(comboPorts.getSelectedItem().toString());
+ String selectedPort = comboPorts.getSelectedItem().toString();
+ if (AUTO_SERIAL.equals(selectedPort)) {
+ String autoDetectedPort = PortDetector.autoDetectPort(StartupFrame.this.frame);
+ if (autoDetectedPort == null)
+ return;
+ selectedPort = autoDetectedPort;
+ }
+ disposeFrameAndProceed();
+ new Launcher(selectedPort);
}
});
@@ -230,7 +239,10 @@ public class StartupFrame {
@NotNull
private List findAllAvailablePorts() {
List ports = new ArrayList<>();
- ports.addAll(Arrays.asList(SerialPortList.getPortNames()));
+ String[] serialPorts = SerialPortList.getPortNames();
+ if (serialPorts.length > 0 || serialPorts.length < 15)
+ ports.add(AUTO_SERIAL);
+ ports.addAll(Arrays.asList(serialPorts));
ports.addAll(TcpConnector.getAvailablePorts());
return ports;
}
diff --git a/java_console/ui/src/com/rusefi/autodetect/PortDetector.java b/java_console/ui/src/com/rusefi/autodetect/PortDetector.java
new file mode 100644
index 0000000000..224564a1cb
--- /dev/null
+++ b/java_console/ui/src/com/rusefi/autodetect/PortDetector.java
@@ -0,0 +1,49 @@
+package com.rusefi.autodetect;
+
+import jssc.SerialPortList;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
+
+/**
+ * (c) Andrey Belomutskiy 2013-2019
+ */
+public class PortDetector {
+ /**
+ * Connect to all serial ports and find out which one respond first
+ */
+ public static String autoDetectSerial() {
+ String[] serialPorts = SerialPortList.getPortNames();
+ List serialFinder = new ArrayList<>();
+ CountDownLatch portFound = new CountDownLatch(1);
+ AtomicReference result = new AtomicReference<>();
+ for (String serialPort : serialPorts) {
+ Thread thread = new Thread(new SerialAutoChecker(serialPort, portFound, result));
+ serialFinder.add(thread);
+ thread.start();
+ }
+ try {
+ portFound.await(5, TimeUnit.SECONDS);
+ } catch (InterruptedException e) {
+ throw new IllegalStateException(e);
+ }
+ for (Thread thread : serialFinder)
+ thread.interrupt();
+ return result.get();
+ }
+
+ @Nullable
+ public static String autoDetectPort(JFrame parent) {
+ String autoDetectedPort = autoDetectSerial();
+ if (autoDetectedPort == null) {
+ JOptionPane.showMessageDialog(parent, "Failed to located device");
+ return null;
+ }
+ return autoDetectedPort;
+ }
+}
diff --git a/java_console/ui/src/com/rusefi/autodetect/SerialAutoChecker.java b/java_console/ui/src/com/rusefi/autodetect/SerialAutoChecker.java
new file mode 100644
index 0000000000..36e71fd148
--- /dev/null
+++ b/java_console/ui/src/com/rusefi/autodetect/SerialAutoChecker.java
@@ -0,0 +1,56 @@
+package com.rusefi.autodetect;
+
+import com.opensr5.Logger;
+import com.rusefi.FileLog;
+import com.rusefi.binaryprotocol.BinaryProtocol;
+import com.rusefi.binaryprotocol.BinaryProtocolCommands;
+import com.rusefi.binaryprotocol.IncomingDataBuffer;
+import com.rusefi.config.generated.Fields;
+import com.rusefi.io.IoStream;
+import com.rusefi.io.serial.PortHolder;
+
+import java.io.IOException;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.atomic.AtomicReference;
+
+import static com.rusefi.binaryprotocol.IoHelper.checkResponseCode;
+
+class SerialAutoChecker implements Runnable {
+ private final String serialPort;
+ private final CountDownLatch portFound;
+ private final AtomicReference result;
+
+ public SerialAutoChecker(String serialPort, CountDownLatch portFound, AtomicReference result) {
+ this.serialPort = serialPort;
+ this.portFound = portFound;
+ this.result = result;
+ }
+
+ @Override
+ public void run() {
+ PortHolder.EstablishConnection establishConnection = new PortHolder.EstablishConnection(serialPort).invoke();
+ if (!establishConnection.isConnected())
+ return;
+ IoStream stream = establishConnection.getStream();
+ Logger logger = FileLog.LOGGER;
+ IncomingDataBuffer incomingData = new IncomingDataBuffer(logger);
+ stream.setInputListener(incomingData::addData);
+ try {
+ BinaryProtocol.sendPacket(new byte[]{BinaryProtocolCommands.COMMAND_HELLO}, logger, stream);
+ byte[] response = incomingData.getPacket(logger, "", false, System.currentTimeMillis());
+ if (!checkResponseCode(response, BinaryProtocolCommands.RESPONSE_OK))
+ return;
+ String message = new String(response, 1, response.length - 1);
+ System.out.println("Got " + message + " from " + serialPort);
+ if (message.startsWith(Fields.TS_SIGNATURE)) {
+ result.set(serialPort);
+ portFound.countDown();
+ }
+ } catch (IOException | InterruptedException ignore) {
+ return;
+ } finally {
+ stream.close();
+ }
+
+ }
+}