mirror of https://github.com/rusefi/rusefi.git
integration
This commit is contained in:
parent
ad4aa4f0de
commit
0f7e444944
|
@ -18,6 +18,8 @@ import org.jetbrains.annotations.NotNull;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.CopyOnWriteArrayList;
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Andrey Belomutskiy
|
* @author Andrey Belomutskiy
|
||||||
|
@ -111,30 +113,158 @@ public enum SerialPortScanner {
|
||||||
startTimer();
|
startTimer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static PortResult inspectPort(String serialPort) {
|
||||||
|
log.info("Determining type of serial port: " + serialPort);
|
||||||
|
|
||||||
|
boolean isOpenblt = isPortOpenblt(serialPort);
|
||||||
|
log.info("Port " + serialPort + (isOpenblt ? " looks like" : " does not look like") + " an OpenBLT bootloader");
|
||||||
|
if (isOpenblt) {
|
||||||
|
return new PortResult(serialPort, SerialPortType.OpenBlt);
|
||||||
|
} else {
|
||||||
|
// See if this looks like an ECU
|
||||||
|
String signature = getEcuSignature(serialPort);
|
||||||
|
boolean isEcu = signature != null;
|
||||||
|
log.info("Port " + serialPort + (isEcu ? " looks like" : " does not look like") + " an ECU");
|
||||||
|
if (isEcu) {
|
||||||
|
boolean ecuHasOpenblt = ecuHasOpenblt(serialPort);
|
||||||
|
log.info("ECU at " + serialPort + (ecuHasOpenblt ? " has" : " does not have") + " an OpenBLT bootloader");
|
||||||
|
return new PortResult(serialPort, ecuHasOpenblt ? SerialPortType.EcuWithOpenblt : SerialPortType.Ecu, signature);
|
||||||
|
} else {
|
||||||
|
// Dunno what this is, leave it in the list anyway
|
||||||
|
return new PortResult(serialPort, SerialPortType.Unknown);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<PortResult> inspectPorts(final List<String> ports) {
|
||||||
|
if (ports.isEmpty()) {
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
final Object resultsLock = new Object();
|
||||||
|
final Map<String, PortResult> results = new HashMap<>();
|
||||||
|
|
||||||
|
// When the last port is found, we need to cancel the timeout
|
||||||
|
final Thread callingThread = Thread.currentThread();
|
||||||
|
|
||||||
|
// One thread per port to check
|
||||||
|
final List<Thread> threads = ports.stream().map(p -> {
|
||||||
|
Thread t = new Thread(() -> {
|
||||||
|
PortResult r = inspectPort(p);
|
||||||
|
|
||||||
|
// Record the result under lock
|
||||||
|
synchronized (resultsLock) {
|
||||||
|
if (Thread.currentThread().isInterrupted()) {
|
||||||
|
// If interrupted, don't try to write our result
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
results.put(p, r);
|
||||||
|
|
||||||
|
if (results.size() == ports.size()) {
|
||||||
|
// We now have all the results - interrupt the calling thread
|
||||||
|
callingThread.interrupt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
t.setName("SerialPortScanner inspectPort " + p);
|
||||||
|
t.setDaemon(true);
|
||||||
|
t.start();
|
||||||
|
|
||||||
|
return t;
|
||||||
|
}).collect(Collectors.toList());
|
||||||
|
|
||||||
|
// Give everyone a chance to finish
|
||||||
|
try {
|
||||||
|
Thread.sleep(5000);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
// We got interrupted because the last port got found, nothing to do
|
||||||
|
}
|
||||||
|
|
||||||
|
// Interrupt all threads under lock to ensure no more objects are added to results
|
||||||
|
synchronized (resultsLock) {
|
||||||
|
for (Thread t : threads) {
|
||||||
|
t.interrupt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now check that we got everything - if any timed out, register them as unknown
|
||||||
|
for (String port : ports) {
|
||||||
|
if (!results.containsKey(port)) {
|
||||||
|
log.info("Port " + port + " timed out, adding as Unknown.");
|
||||||
|
results.put(port, new PortResult(port, SerialPortType.Unknown));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ArrayList<>(results.values());
|
||||||
|
}
|
||||||
|
|
||||||
|
private final static Map<String, PortResult> portCache = new HashMap<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find all available serial ports and checks if simulator local TCP port is available
|
* Find all available serial ports and checks if simulator local TCP port is available
|
||||||
*/
|
*/
|
||||||
private void findAllAvailablePorts(boolean includeSlowLookup) {
|
private void findAllAvailablePorts(boolean includeSlowLookup) {
|
||||||
List<String> ports = new ArrayList<>();
|
List<PortResult> ports = new ArrayList<>();
|
||||||
boolean dfuConnected;
|
boolean dfuConnected;
|
||||||
boolean stLinkConnected;
|
boolean stLinkConnected;
|
||||||
boolean PCANConnected;
|
boolean PCANConnected;
|
||||||
|
|
||||||
String[] serialPorts = LinkManager.getCommPorts();
|
String[] serialPorts = LinkManager.getCommPorts();
|
||||||
if (serialPorts.length > 0)
|
|
||||||
ports.add(AUTO_SERIAL);
|
List<String> portsToInspect = new ArrayList<>();
|
||||||
|
|
||||||
for (String serialPort : serialPorts) {
|
for (String serialPort : serialPorts) {
|
||||||
// Filter out some macOS trash
|
// First, check the port cache
|
||||||
if (serialPort.contains("wlan-debug") ||
|
if (portCache.containsKey(serialPort)) {
|
||||||
serialPort.contains("Bluetooth-Incoming-Port") ||
|
// We've already probed this port - don't re-probe it again
|
||||||
serialPort.startsWith("cu.")) {
|
PortResult cached = portCache.get(serialPort);
|
||||||
continue;
|
|
||||||
|
ports.add(cached);
|
||||||
|
} else {
|
||||||
|
portsToInspect.add(serialPort);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (PortResult p : inspectPorts(portsToInspect)) {
|
||||||
|
log.info("Port " + p.port + " detected as: " + p.type.friendlyString);
|
||||||
|
|
||||||
|
ports.add(p);
|
||||||
|
portCache.put(p.port, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
// Clean the port cache of any entries that no longer exist
|
||||||
|
// If the same port appears later, we want to re-probe it at that time
|
||||||
|
// In any other scenario, auto could have unexpected behavior for the user
|
||||||
|
List<String> toRemove = new ArrayList<>();
|
||||||
|
for (String x : portCache.keySet()) {
|
||||||
|
if (Arrays.stream(serialPorts).noneMatch(x::equals)) {
|
||||||
|
toRemove.add(x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// two steps to avoid ConcurrentModificationException
|
||||||
|
toRemove.forEach(p -> {
|
||||||
|
portCache.remove(p);
|
||||||
|
log.info("Removing port " + p);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort ports by their type to put your ECU at the top
|
||||||
|
ports.sort(Comparator.comparingInt(a -> a.type.sortOrder));
|
||||||
|
|
||||||
|
if (includeSlowLookup) {
|
||||||
|
for (String tcpPort : TcpConnector.getAvailablePorts()) {
|
||||||
|
ports.add(new PortResult(tcpPort, SerialPortType.Ecu));
|
||||||
}
|
}
|
||||||
ports.add(serialPort);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (includeSlowLookup) {
|
if (includeSlowLookup) {
|
||||||
ports.addAll(TcpConnector.getAvailablePorts());
|
for (String tcpPort : TcpConnector.getAvailablePorts()) {
|
||||||
|
ports.add(new PortResult(tcpPort, SerialPortType.Ecu));
|
||||||
|
}
|
||||||
dfuConnected = DfuFlasher.detectSTM32BootloaderDriverState(UpdateOperationCallbacks.DUMMY);
|
dfuConnected = DfuFlasher.detectSTM32BootloaderDriverState(UpdateOperationCallbacks.DUMMY);
|
||||||
stLinkConnected = DfuFlasher.detectStLink(UpdateOperationCallbacks.DUMMY);
|
stLinkConnected = DfuFlasher.detectStLink(UpdateOperationCallbacks.DUMMY);
|
||||||
PCANConnected = DfuFlasher.detectPcan(UpdateOperationCallbacks.DUMMY);
|
PCANConnected = DfuFlasher.detectPcan(UpdateOperationCallbacks.DUMMY);
|
||||||
|
@ -144,9 +274,9 @@ public enum SerialPortScanner {
|
||||||
PCANConnected = false;
|
PCANConnected = false;
|
||||||
}
|
}
|
||||||
if (PCANConnected)
|
if (PCANConnected)
|
||||||
ports.add(LinkManager.PCAN);
|
ports.add(new PortResult(LinkManager.PCAN, SerialPortType.CAN));
|
||||||
if (SHOW_SOCKETCAN)
|
if (SHOW_SOCKETCAN)
|
||||||
ports.add(LinkManager.SOCKET_CAN);
|
ports.add(new PortResult(LinkManager.SOCKET_CAN, SerialPortType.CAN));
|
||||||
|
|
||||||
boolean isListUpdated;
|
boolean isListUpdated;
|
||||||
AvailableHardware currentHardware = new AvailableHardware(ports, dfuConnected, stLinkConnected, PCANConnected);
|
AvailableHardware currentHardware = new AvailableHardware(ports, dfuConnected, stLinkConnected, PCANConnected);
|
||||||
|
@ -188,12 +318,12 @@ public enum SerialPortScanner {
|
||||||
|
|
||||||
public static class AvailableHardware {
|
public static class AvailableHardware {
|
||||||
|
|
||||||
private final List<String> ports;
|
private final List<PortResult> ports;
|
||||||
private final boolean dfuFound;
|
private final boolean dfuFound;
|
||||||
private final boolean stLinkConnected;
|
private final boolean stLinkConnected;
|
||||||
private final boolean PCANConnected;
|
private final boolean PCANConnected;
|
||||||
|
|
||||||
public <T> AvailableHardware(List<String> ports, boolean dfuFound, boolean stLinkConnected, boolean PCANConnected) {
|
public <T> AvailableHardware(List<PortResult> ports, boolean dfuFound, boolean stLinkConnected, boolean PCANConnected) {
|
||||||
this.ports = ports;
|
this.ports = ports;
|
||||||
this.dfuFound = dfuFound;
|
this.dfuFound = dfuFound;
|
||||||
this.stLinkConnected = stLinkConnected;
|
this.stLinkConnected = stLinkConnected;
|
||||||
|
@ -201,7 +331,7 @@ public enum SerialPortScanner {
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public List<String> getKnownPorts() {return new ArrayList<>(ports);}
|
public List<PortResult> getKnownPorts() {return new ArrayList<>(ports);}
|
||||||
|
|
||||||
public boolean isDfuFound() {
|
public boolean isDfuFound() {
|
||||||
return dfuFound;
|
return dfuFound;
|
||||||
|
|
|
@ -51,7 +51,7 @@ public class StartupFrame {
|
||||||
private final JFrame frame;
|
private final JFrame frame;
|
||||||
private final JPanel connectPanel = new JPanel(new FlowLayout());
|
private final JPanel connectPanel = new JPanel(new FlowLayout());
|
||||||
// todo: move this line to the connectPanel
|
// todo: move this line to the connectPanel
|
||||||
private final JComboBox<String> comboPorts = new JComboBox<>();
|
private final JComboBox<SerialPortScanner.PortResult> comboPorts = new JComboBox<>();
|
||||||
private final JPanel leftPanel = new JPanel(new VerticalFlowLayout());
|
private final JPanel leftPanel = new JPanel(new VerticalFlowLayout());
|
||||||
|
|
||||||
private final JPanel realHardwarePanel = new JPanel(new MigLayout());
|
private final JPanel realHardwarePanel = new JPanel(new MigLayout());
|
||||||
|
@ -234,7 +234,7 @@ public class StartupFrame {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void applyKnownPorts(SerialPortScanner.AvailableHardware currentHardware) {
|
private void applyKnownPorts(SerialPortScanner.AvailableHardware currentHardware) {
|
||||||
List<String> ports = currentHardware.getKnownPorts();
|
List<SerialPortScanner.PortResult> ports = currentHardware.getKnownPorts();
|
||||||
log.info("Rendering available ports: " + ports);
|
log.info("Rendering available ports: " + ports);
|
||||||
connectPanel.setVisible(!ports.isEmpty());
|
connectPanel.setVisible(!ports.isEmpty());
|
||||||
noPortsMessage.setVisible(ports.isEmpty());
|
noPortsMessage.setVisible(ports.isEmpty());
|
||||||
|
@ -299,10 +299,11 @@ public class StartupFrame {
|
||||||
SerialPortScanner.INSTANCE.stopTimer();
|
SerialPortScanner.INSTANCE.stopTimer();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void applyPortSelectionToUIcontrol(List<String> ports) {
|
private void applyPortSelectionToUIcontrol(List<SerialPortScanner.PortResult> ports) {
|
||||||
comboPorts.removeAllItems();
|
comboPorts.removeAllItems();
|
||||||
for (final String port : ports)
|
for (final SerialPortScanner.PortResult port : ports) {
|
||||||
comboPorts.addItem(port);
|
comboPorts.addItem(port);
|
||||||
|
}
|
||||||
String defaultPort = getConfig().getRoot().getProperty(ConsoleUI.PORT_KEY);
|
String defaultPort = getConfig().getRoot().getProperty(ConsoleUI.PORT_KEY);
|
||||||
if (!PersistentConfiguration.getBoolProperty(ALWAYS_AUTO_PORT)) {
|
if (!PersistentConfiguration.getBoolProperty(ALWAYS_AUTO_PORT)) {
|
||||||
comboPorts.setSelectedItem(defaultPort);
|
comboPorts.setSelectedItem(defaultPort);
|
||||||
|
|
|
@ -44,7 +44,7 @@ public class ProgramSelector {
|
||||||
private final JPanel controls = new JPanel(new FlowLayout());
|
private final JPanel controls = new JPanel(new FlowLayout());
|
||||||
private final JComboBox<String> mode = new JComboBox<>();
|
private final JComboBox<String> mode = new JComboBox<>();
|
||||||
|
|
||||||
public ProgramSelector(JComboBox<String> comboPorts) {
|
public ProgramSelector(JComboBox<SerialPortScanner.PortResult> comboPorts) {
|
||||||
content.add(controls, BorderLayout.NORTH);
|
content.add(controls, BorderLayout.NORTH);
|
||||||
content.add(noHardware, BorderLayout.SOUTH);
|
content.add(noHardware, BorderLayout.SOUTH);
|
||||||
controls.setVisible(false);
|
controls.setVisible(false);
|
||||||
|
@ -61,7 +61,7 @@ public class ProgramSelector {
|
||||||
@Override
|
@Override
|
||||||
public void actionPerformed(ActionEvent e) {
|
public void actionPerformed(ActionEvent e) {
|
||||||
final String selectedMode = (String) mode.getSelectedItem();
|
final String selectedMode = (String) mode.getSelectedItem();
|
||||||
final String selectedPort = (String) comboPorts.getSelectedItem();
|
final SerialPortScanner.PortResult selectedPort = ((SerialPortScanner.PortResult) comboPorts.getSelectedItem());
|
||||||
|
|
||||||
getConfig().getRoot().setProperty(getClass().getSimpleName(), selectedMode);
|
getConfig().getRoot().setProperty(getClass().getSimpleName(), selectedMode);
|
||||||
|
|
||||||
|
@ -72,7 +72,7 @@ public class ProgramSelector {
|
||||||
switch (selectedMode) {
|
switch (selectedMode) {
|
||||||
case AUTO_DFU:
|
case AUTO_DFU:
|
||||||
jobName = "DFU update";
|
jobName = "DFU update";
|
||||||
job = (callbacks) -> DfuFlasher.doAutoDfu(comboPorts, selectedPort, callbacks);
|
job = (callbacks) -> DfuFlasher.doAutoDfu(comboPorts, selectedPort.port, callbacks);
|
||||||
break;
|
break;
|
||||||
case MANUAL_DFU:
|
case MANUAL_DFU:
|
||||||
jobName = "DFU update";
|
jobName = "DFU update";
|
||||||
|
@ -86,11 +86,11 @@ public class ProgramSelector {
|
||||||
break;
|
break;
|
||||||
case DFU_SWITCH:
|
case DFU_SWITCH:
|
||||||
jobName = "DFU switch";
|
jobName = "DFU switch";
|
||||||
job = (callbacks) -> rebootToDfu(comboPorts, selectedPort, callbacks);
|
job = (callbacks) -> rebootToDfu(comboPorts, selectedPort.port, callbacks);
|
||||||
break;
|
break;
|
||||||
case OPENBLT_SWITCH:
|
case OPENBLT_SWITCH:
|
||||||
jobName = "OpenBLT switch";
|
jobName = "OpenBLT switch";
|
||||||
job = (callbacks) -> rebootToOpenblt(comboPorts, selectedPort, callbacks);
|
job = (callbacks) -> rebootToOpenblt(comboPorts, selectedPort.port, callbacks);
|
||||||
break;
|
break;
|
||||||
case OPENBLT_CAN:
|
case OPENBLT_CAN:
|
||||||
jobName = "OpenBLT via CAN";
|
jobName = "OpenBLT via CAN";
|
||||||
|
@ -98,11 +98,11 @@ public class ProgramSelector {
|
||||||
break;
|
break;
|
||||||
case OPENBLT_MANUAL:
|
case OPENBLT_MANUAL:
|
||||||
jobName = "OpenBLT via Serial";
|
jobName = "OpenBLT via Serial";
|
||||||
job = (callbacks) -> flashOpenbltSerialJni(selectedPort, callbacks);
|
job = (callbacks) -> flashOpenbltSerialJni(selectedPort.port, callbacks);
|
||||||
break;
|
break;
|
||||||
case OPENBLT_AUTO:
|
case OPENBLT_AUTO:
|
||||||
jobName = "OpenBLT via Serial";
|
jobName = "OpenBLT via Serial";
|
||||||
job = (callbacks) -> flashOpenbltSerialAutomatic(comboPorts, selectedPort, callbacks);
|
job = (callbacks) -> flashOpenbltSerialAutomatic(comboPorts, selectedPort.port, callbacks);
|
||||||
break;
|
break;
|
||||||
case DFU_ERASE:
|
case DFU_ERASE:
|
||||||
jobName = "DFU erase";
|
jobName = "DFU erase";
|
||||||
|
|
Loading…
Reference in New Issue