From 771b907156d66b44200c0a075382ad3fe1203da8 Mon Sep 17 00:00:00 2001 From: rusefillc Date: Mon, 3 Oct 2022 23:00:26 -0400 Subject: [PATCH] Startup Frame should scan for available hardware fix #4633 --- .../java/com/rusefi/SerialPortScanner.java | 94 ++++++++++++++----- .../main/java/com/rusefi/StartupFrame.java | 23 ++--- .../rusefi/maintenance/ProgramSelector.java | 45 ++++++--- 3 files changed, 114 insertions(+), 48 deletions(-) diff --git a/java_console/ui/src/main/java/com/rusefi/SerialPortScanner.java b/java_console/ui/src/main/java/com/rusefi/SerialPortScanner.java index 07b88fdd50..84fc9c40a2 100644 --- a/java_console/ui/src/main/java/com/rusefi/SerialPortScanner.java +++ b/java_console/ui/src/main/java/com/rusefi/SerialPortScanner.java @@ -2,11 +2,11 @@ package com.rusefi; import com.rusefi.io.LinkManager; import com.rusefi.io.tcp.TcpConnector; +import com.rusefi.maintenance.DfuFlasher; +import com.rusefi.ui.StatusConsumer; import org.jetbrains.annotations.NotNull; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; +import java.util.*; import java.util.concurrent.CopyOnWriteArrayList; import static com.rusefi.FileLog.isLinux; @@ -23,54 +23,66 @@ public enum SerialPortScanner { private static final boolean SHOW_SOCKETCAN = isLinux(); static final String AUTO_SERIAL = "Auto Serial"; - @NotNull - private final List knownPorts = new ArrayList<>(); - public List listeners = new CopyOnWriteArrayList<>(); + private final Object lock = new Object(); + @NotNull + private AvailableHardware knownHardware = new AvailableHardware(Collections.emptyList(), false, false); + + private final List listeners = new CopyOnWriteArrayList<>(); + + public void addListener(Listener listener) { + boolean shouldStart = listeners.isEmpty(); + listeners.add(listener); + if (shouldStart) + startTimer(); + } /** * Find all available serial ports and checks if simulator local TCP port is available */ private void findAllAvailablePorts(boolean includeSlowTcpLookup) { List ports = new ArrayList<>(); + boolean dfuConnected; + boolean stLinkConnected; + String[] serialPorts = LinkManager.getCommPorts(); if (serialPorts.length > 0) ports.add(AUTO_SERIAL); ports.addAll(Arrays.asList(serialPorts)); - if (includeSlowTcpLookup) + + if (includeSlowTcpLookup) { ports.addAll(TcpConnector.getAvailablePorts()); + dfuConnected = DfuFlasher.detectSTM32BootloaderDriverState(StatusConsumer.VOID); + stLinkConnected = DfuFlasher.detectStLink(StatusConsumer.VOID); + } else { + dfuConnected = false; + stLinkConnected = false; + } if (SHOW_PCAN) ports.add(LinkManager.PCAN); if (SHOW_SOCKETCAN) ports.add(LinkManager.SOCKET_CAN); boolean isListUpdated; - synchronized (knownPorts) { - isListUpdated = knownPorts.equals(ports); - knownPorts.clear(); - knownPorts.addAll(ports); + AvailableHardware currentHardware = new AvailableHardware(ports, dfuConnected, stLinkConnected); + synchronized (lock) { + isListUpdated = !knownHardware.equals(currentHardware); + knownHardware = currentHardware; } if (isListUpdated) { for (Listener listener : listeners) - listener.onChange(); + listener.onChange(currentHardware); } } - @NotNull - public List getKnownPorts() { - synchronized (knownPorts) { - return new ArrayList<>(knownPorts); - } - } - - public void startTimer() { + private void startTimer() { Thread portsScanner = new Thread(() -> { boolean isFirstTime = true; while (isRunning) { findAllAvailablePorts(!isFirstTime); isFirstTime = false; try { - Thread.sleep(1000); + Thread.sleep(300); } catch (InterruptedException e) { throw new IllegalStateException(e); } @@ -86,6 +98,44 @@ public enum SerialPortScanner { } interface Listener { - void onChange(); + void onChange(AvailableHardware currentHardware); + } + + public static class AvailableHardware { + + private final List ports; + private final boolean dfuFound; + private final boolean stLinkConnected; + + public AvailableHardware(List ports, boolean dfuFound, boolean stLinkConnected) { + this.ports = ports; + this.dfuFound = dfuFound; + this.stLinkConnected = stLinkConnected; + } + + @NotNull + public List getKnownPorts() { + return new ArrayList<>(ports); + } + + public boolean isDfuFound() { + return dfuFound; + } + + public boolean isStLinkConnected() { + return stLinkConnected; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + AvailableHardware that = (AvailableHardware) o; + return dfuFound == that.dfuFound && stLinkConnected == that.stLinkConnected && ports.equals(that.ports); + } + + public boolean isEmpty() { + return !dfuFound && !stLinkConnected && ports.isEmpty(); + } } } diff --git a/java_console/ui/src/main/java/com/rusefi/StartupFrame.java b/java_console/ui/src/main/java/com/rusefi/StartupFrame.java index 499ba8f405..c147b4ae44 100644 --- a/java_console/ui/src/main/java/com/rusefi/StartupFrame.java +++ b/java_console/ui/src/main/java/com/rusefi/StartupFrame.java @@ -57,9 +57,6 @@ public class StartupFrame { private final JPanel connectPanel = new JPanel(new FlowLayout()); // todo: move this line to the connectPanel private final JComboBox comboPorts = new JComboBox<>(); - @NotNull - private List currentlyDisplayedPorts = new ArrayList<>(); - private boolean isFirstTimeApplyingPorts = true; private final JPanel leftPanel = new JPanel(new VerticalFlowLayout()); private final JPanel realHardwarePanel = new JPanel(new MigLayout()); @@ -93,7 +90,6 @@ public class StartupFrame { } }); AutoupdateUtil.setAppIcon(frame); - SerialPortScanner.INSTANCE.startTimer(); } @NotNull @@ -122,6 +118,7 @@ public class StartupFrame { //connectButton.setBackground(new Color(RUSEFI_ORANGE)); // custom orange setToolTip(connectButton, "Connect to real hardware"); connectPanel.add(connectButton); + connectPanel.setVisible(false); frame.getRootPane().setDefaultButton(connectButton); connectButton.addKeyListener(new KeyAdapter() { @@ -149,10 +146,11 @@ public class StartupFrame { realHardwarePanel.add(noPortsMessage, "right, wrap"); installMessage(noPortsMessage, "Check you cables. Check your drivers. Do you want to start simulator maybe?"); + ProgramSelector selector = new ProgramSelector(comboPorts); + if (FileLog.isWindows()) { realHardwarePanel.add(new HorizontalLine(), "right, wrap"); - ProgramSelector selector = new ProgramSelector(comboPorts); realHardwarePanel.add(selector.getControl(), "right, wrap"); // for F7 builds we just build one file at the moment @@ -170,7 +168,11 @@ public class StartupFrame { //realHardwarePanel.add(new EraseChip().getButton(), "right, wrap"); } - SerialPortScanner.INSTANCE.listeners.add(() -> SwingUtilities.invokeLater(this::applyKnownPorts)); + SerialPortScanner.INSTANCE.addListener(currentHardware -> SwingUtilities.invokeLater(() -> { + selector.apply(currentHardware); + applyKnownPorts(currentHardware); + frame.pack(); + })); final JButton buttonLogViewer = new JButton(); buttonLogViewer.setText("Start " + LinkManager.LOG_VIEWER); @@ -226,19 +228,14 @@ public class StartupFrame { } } - private void applyKnownPorts() { - List ports = SerialPortScanner.INSTANCE.getKnownPorts(); - if (!currentlyDisplayedPorts.equals(ports) || isFirstTimeApplyingPorts) { + private void applyKnownPorts(SerialPortScanner.AvailableHardware currentHardware) { + List ports = currentHardware.getKnownPorts(); log.info("Rendering available ports: " + ports); - isFirstTimeApplyingPorts = false; connectPanel.setVisible(!ports.isEmpty()); noPortsMessage.setVisible(ports.isEmpty()); applyPortSelectionToUIcontrol(ports); - currentlyDisplayedPorts = ports; UiUtils.trueLayout(connectPanel); - frame.pack(); - } } public static void setFrameIcon(Frame frame) { diff --git a/java_console/ui/src/main/java/com/rusefi/maintenance/ProgramSelector.java b/java_console/ui/src/main/java/com/rusefi/maintenance/ProgramSelector.java index 5fb1bdfaca..b408cd7f01 100644 --- a/java_console/ui/src/main/java/com/rusefi/maintenance/ProgramSelector.java +++ b/java_console/ui/src/main/java/com/rusefi/maintenance/ProgramSelector.java @@ -1,10 +1,12 @@ package com.rusefi.maintenance; import com.rusefi.Launcher; +import com.rusefi.SerialPortScanner; import com.rusefi.autodetect.PortDetector; import com.rusefi.autoupdate.AutoupdateUtil; import com.rusefi.ui.StatusWindow; import com.rusefi.ui.util.URLLabel; +import com.rusefi.ui.util.UiUtils; import org.jetbrains.annotations.NotNull; import javax.swing.*; @@ -17,6 +19,7 @@ import java.util.Objects; import static com.rusefi.StartupFrame.appendBundleName; import static com.rusefi.ui.storage.PersistentConfiguration.getConfig; +import static com.rusefi.ui.util.UiUtils.trueLayout; public class ProgramSelector { @@ -33,22 +36,16 @@ public class ProgramSelector { public static final String BOOT_COMMANDER_EXE = "BootCommander.exe"; public static final String OPENBLT_BINARY_LOCATION = Launcher.TOOLS_PATH + File.separator + "openblt"; + + private final JPanel content = new JPanel(new BorderLayout()); + private final JLabel noHardware = new JLabel("Nothing detected"); private final JPanel controls = new JPanel(new FlowLayout()); private final JComboBox mode = new JComboBox<>(); public ProgramSelector(JComboBox comboPorts) { - /* - * todo: add FULL AUTO mode which would fire up DFU and ST-LINK in parallel hoping that one of those would work? - */ - if (IS_WIN) { - mode.addItem(AUTO_DFU); - mode.addItem(MANUAL_DFU); - mode.addItem(DFU_ERASE); - mode.addItem(ST_LINK); - mode.addItem(OPENBLT_CAN); - } - mode.addItem(DFU_SWITCH); - + content.add(controls, BorderLayout.NORTH); + content.add(noHardware, BorderLayout.SOUTH); + controls.setVisible(false); controls.add(mode); String persistedMode = getConfig().getRoot().getProperty(getClass().getSimpleName()); @@ -117,6 +114,28 @@ public class ProgramSelector { } public JPanel getControl() { - return controls; + return content; + } + + public void apply(SerialPortScanner.AvailableHardware currentHardware) { + noHardware.setVisible(currentHardware.isEmpty()); + controls.setVisible(!currentHardware.isEmpty()); + + mode.removeAllItems(); + if (IS_WIN) { + if (!currentHardware.getKnownPorts().isEmpty()) + mode.addItem(AUTO_DFU); + if (currentHardware.isDfuFound()) { + mode.addItem(MANUAL_DFU); + mode.addItem(DFU_ERASE); + } + if (currentHardware.isStLinkConnected()) + mode.addItem(ST_LINK); + // todo: detect PCAN mode.addItem(OPENBLT_CAN); + } + if (!currentHardware.getKnownPorts().isEmpty()) + mode.addItem(DFU_SWITCH); + trueLayout(mode); + UiUtils.trueLayout(content); } }