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.util.*;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @author Andrey Belomutskiy
|
||||
|
@ -111,30 +113,158 @@ public enum SerialPortScanner {
|
|||
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
|
||||
*/
|
||||
private void findAllAvailablePorts(boolean includeSlowLookup) {
|
||||
List<String> ports = new ArrayList<>();
|
||||
List<PortResult> ports = new ArrayList<>();
|
||||
boolean dfuConnected;
|
||||
boolean stLinkConnected;
|
||||
boolean PCANConnected;
|
||||
|
||||
String[] serialPorts = LinkManager.getCommPorts();
|
||||
if (serialPorts.length > 0)
|
||||
ports.add(AUTO_SERIAL);
|
||||
|
||||
List<String> portsToInspect = new ArrayList<>();
|
||||
|
||||
for (String serialPort : serialPorts) {
|
||||
// Filter out some macOS trash
|
||||
if (serialPort.contains("wlan-debug") ||
|
||||
serialPort.contains("Bluetooth-Incoming-Port") ||
|
||||
serialPort.startsWith("cu.")) {
|
||||
continue;
|
||||
// First, check the port cache
|
||||
if (portCache.containsKey(serialPort)) {
|
||||
// We've already probed this port - don't re-probe it again
|
||||
PortResult cached = portCache.get(serialPort);
|
||||
|
||||
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) {
|
||||
ports.addAll(TcpConnector.getAvailablePorts());
|
||||
for (String tcpPort : TcpConnector.getAvailablePorts()) {
|
||||
ports.add(new PortResult(tcpPort, SerialPortType.Ecu));
|
||||
}
|
||||
dfuConnected = DfuFlasher.detectSTM32BootloaderDriverState(UpdateOperationCallbacks.DUMMY);
|
||||
stLinkConnected = DfuFlasher.detectStLink(UpdateOperationCallbacks.DUMMY);
|
||||
PCANConnected = DfuFlasher.detectPcan(UpdateOperationCallbacks.DUMMY);
|
||||
|
@ -144,9 +274,9 @@ public enum SerialPortScanner {
|
|||
PCANConnected = false;
|
||||
}
|
||||
if (PCANConnected)
|
||||
ports.add(LinkManager.PCAN);
|
||||
ports.add(new PortResult(LinkManager.PCAN, SerialPortType.CAN));
|
||||
if (SHOW_SOCKETCAN)
|
||||
ports.add(LinkManager.SOCKET_CAN);
|
||||
ports.add(new PortResult(LinkManager.SOCKET_CAN, SerialPortType.CAN));
|
||||
|
||||
boolean isListUpdated;
|
||||
AvailableHardware currentHardware = new AvailableHardware(ports, dfuConnected, stLinkConnected, PCANConnected);
|
||||
|
@ -188,12 +318,12 @@ public enum SerialPortScanner {
|
|||
|
||||
public static class AvailableHardware {
|
||||
|
||||
private final List<String> ports;
|
||||
private final List<PortResult> ports;
|
||||
private final boolean dfuFound;
|
||||
private final boolean stLinkConnected;
|
||||
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.dfuFound = dfuFound;
|
||||
this.stLinkConnected = stLinkConnected;
|
||||
|
@ -201,7 +331,7 @@ public enum SerialPortScanner {
|
|||
}
|
||||
|
||||
@NotNull
|
||||
public List<String> getKnownPorts() {return new ArrayList<>(ports);}
|
||||
public List<PortResult> getKnownPorts() {return new ArrayList<>(ports);}
|
||||
|
||||
public boolean isDfuFound() {
|
||||
return dfuFound;
|
||||
|
|
|
@ -51,7 +51,7 @@ public class StartupFrame {
|
|||
private final JFrame frame;
|
||||
private final JPanel connectPanel = new JPanel(new FlowLayout());
|
||||
// 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 realHardwarePanel = new JPanel(new MigLayout());
|
||||
|
@ -234,7 +234,7 @@ public class StartupFrame {
|
|||
}
|
||||
|
||||
private void applyKnownPorts(SerialPortScanner.AvailableHardware currentHardware) {
|
||||
List<String> ports = currentHardware.getKnownPorts();
|
||||
List<SerialPortScanner.PortResult> ports = currentHardware.getKnownPorts();
|
||||
log.info("Rendering available ports: " + ports);
|
||||
connectPanel.setVisible(!ports.isEmpty());
|
||||
noPortsMessage.setVisible(ports.isEmpty());
|
||||
|
@ -299,10 +299,11 @@ public class StartupFrame {
|
|||
SerialPortScanner.INSTANCE.stopTimer();
|
||||
}
|
||||
|
||||
private void applyPortSelectionToUIcontrol(List<String> ports) {
|
||||
private void applyPortSelectionToUIcontrol(List<SerialPortScanner.PortResult> ports) {
|
||||
comboPorts.removeAllItems();
|
||||
for (final String port : ports)
|
||||
for (final SerialPortScanner.PortResult port : ports) {
|
||||
comboPorts.addItem(port);
|
||||
}
|
||||
String defaultPort = getConfig().getRoot().getProperty(ConsoleUI.PORT_KEY);
|
||||
if (!PersistentConfiguration.getBoolProperty(ALWAYS_AUTO_PORT)) {
|
||||
comboPorts.setSelectedItem(defaultPort);
|
||||
|
|
|
@ -44,7 +44,7 @@ public class ProgramSelector {
|
|||
private final JPanel controls = new JPanel(new FlowLayout());
|
||||
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(noHardware, BorderLayout.SOUTH);
|
||||
controls.setVisible(false);
|
||||
|
@ -61,7 +61,7 @@ public class ProgramSelector {
|
|||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
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);
|
||||
|
||||
|
@ -72,7 +72,7 @@ public class ProgramSelector {
|
|||
switch (selectedMode) {
|
||||
case AUTO_DFU:
|
||||
jobName = "DFU update";
|
||||
job = (callbacks) -> DfuFlasher.doAutoDfu(comboPorts, selectedPort, callbacks);
|
||||
job = (callbacks) -> DfuFlasher.doAutoDfu(comboPorts, selectedPort.port, callbacks);
|
||||
break;
|
||||
case MANUAL_DFU:
|
||||
jobName = "DFU update";
|
||||
|
@ -86,11 +86,11 @@ public class ProgramSelector {
|
|||
break;
|
||||
case DFU_SWITCH:
|
||||
jobName = "DFU switch";
|
||||
job = (callbacks) -> rebootToDfu(comboPorts, selectedPort, callbacks);
|
||||
job = (callbacks) -> rebootToDfu(comboPorts, selectedPort.port, callbacks);
|
||||
break;
|
||||
case OPENBLT_SWITCH:
|
||||
jobName = "OpenBLT switch";
|
||||
job = (callbacks) -> rebootToOpenblt(comboPorts, selectedPort, callbacks);
|
||||
job = (callbacks) -> rebootToOpenblt(comboPorts, selectedPort.port, callbacks);
|
||||
break;
|
||||
case OPENBLT_CAN:
|
||||
jobName = "OpenBLT via CAN";
|
||||
|
@ -98,11 +98,11 @@ public class ProgramSelector {
|
|||
break;
|
||||
case OPENBLT_MANUAL:
|
||||
jobName = "OpenBLT via Serial";
|
||||
job = (callbacks) -> flashOpenbltSerialJni(selectedPort, callbacks);
|
||||
job = (callbacks) -> flashOpenbltSerialJni(selectedPort.port, callbacks);
|
||||
break;
|
||||
case OPENBLT_AUTO:
|
||||
jobName = "OpenBLT via Serial";
|
||||
job = (callbacks) -> flashOpenbltSerialAutomatic(comboPorts, selectedPort, callbacks);
|
||||
job = (callbacks) -> flashOpenbltSerialAutomatic(comboPorts, selectedPort.port, callbacks);
|
||||
break;
|
||||
case DFU_ERASE:
|
||||
jobName = "DFU erase";
|
||||
|
|
Loading…
Reference in New Issue