mirror of https://github.com/rusefi/rusefi.git
311 lines
13 KiB
Java
311 lines
13 KiB
Java
package com.rusefi;
|
|
|
|
import com.devexperts.logging.Logging;
|
|
import com.rusefi.autodetect.PortDetector;
|
|
import com.rusefi.autodetect.SerialAutoChecker;
|
|
import com.rusefi.core.io.BundleUtil;
|
|
import com.rusefi.core.preferences.storage.PersistentConfiguration;
|
|
import com.rusefi.core.ui.FrameHelper;
|
|
import com.rusefi.io.LinkManager;
|
|
import com.rusefi.io.serial.BaudRateHolder;
|
|
import com.rusefi.maintenance.DriverInstall;
|
|
import com.rusefi.maintenance.StLinkFlasher;
|
|
import com.rusefi.maintenance.ProgramSelector;
|
|
import com.rusefi.ui.LogoHelper;
|
|
import com.rusefi.ui.util.HorizontalLine;
|
|
import com.rusefi.ui.util.URLLabel;
|
|
import com.rusefi.ui.util.UiUtils;
|
|
import com.rusefi.ui.widgets.ToolButtons;
|
|
import com.rusefi.util.IoUtils;
|
|
import net.miginfocom.swing.MigLayout;
|
|
import org.jetbrains.annotations.NotNull;
|
|
import org.putgemin.VerticalFlowLayout;
|
|
|
|
import javax.swing.*;
|
|
import javax.swing.border.TitledBorder;
|
|
import java.awt.*;
|
|
import java.awt.event.*;
|
|
import java.util.List;
|
|
|
|
import static com.devexperts.logging.Logging.getLogging;
|
|
import static com.rusefi.core.preferences.storage.PersistentConfiguration.getConfig;
|
|
import static com.rusefi.ui.util.UiUtils.*;
|
|
import static javax.swing.JOptionPane.YES_NO_OPTION;
|
|
|
|
/**
|
|
* This frame is used on startup to select the port we would be using
|
|
*
|
|
* @author Andrey Belomutskiy
|
|
* <p/>
|
|
* 2/14/14
|
|
* @see SimulatorHelper
|
|
* @see StLinkFlasher
|
|
*/
|
|
public class StartupFrame {
|
|
private static final Logging log = getLogging(Launcher.class);
|
|
public static final String ALWAYS_AUTO_PORT = "always_auto_port";
|
|
|
|
// private static final int RUSEFI_ORANGE = 0xff7d03;
|
|
|
|
private final JFrame frame;
|
|
private final JPanel connectPanel = new JPanel(new FlowLayout());
|
|
// todo: move this line to the connectPanel
|
|
private final JComboBox<SerialPortScanner.PortResult> comboPorts = new JComboBox<>();
|
|
private final JPanel leftPanel = new JPanel(new VerticalFlowLayout());
|
|
|
|
private final JPanel realHardwarePanel = new JPanel(new MigLayout());
|
|
private final JPanel miscPanel = new JPanel(new MigLayout()) {
|
|
@Override
|
|
public Dimension getPreferredSize() {
|
|
// want miscPanel and realHardwarePanel to be the same width
|
|
Dimension size = super.getPreferredSize();
|
|
return new Dimension(Math.max(size.width, realHardwarePanel.getPreferredSize().width), size.height);
|
|
}
|
|
};
|
|
/**
|
|
* this flag tells us if we are closing the startup frame in order to proceed with console start or if we are
|
|
* closing the application.
|
|
*/
|
|
private boolean isProceeding;
|
|
private final JLabel noPortsMessage = new JLabel("<html>No ports found!<br>Confirm blue LED is blinking</html>");
|
|
|
|
public StartupFrame() {
|
|
// AudioPlayback.start();
|
|
String title = "rusEFI console version " + Launcher.CONSOLE_VERSION;
|
|
log.info(title);
|
|
frame = FrameHelper.createFrame(title).getFrame();
|
|
frame.addWindowListener(new WindowAdapter() {
|
|
@Override
|
|
public void windowClosed(WindowEvent ev) {
|
|
if (!isProceeding) {
|
|
getConfig().save();
|
|
IoUtils.exit("windowClosed", 0);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
public void chooseSerialPort() {
|
|
realHardwarePanel.setBorder(new TitledBorder(BorderFactory.createLineBorder(Color.darkGray), "Real stm32"));
|
|
miscPanel.setBorder(new TitledBorder(BorderFactory.createLineBorder(Color.darkGray), "Miscellaneous"));
|
|
|
|
if (FileLog.isWindows()) {
|
|
setToolTip(comboPorts, "Use 'Device Manager' icon above to launch Device Manager",
|
|
"In 'Ports' section look for ",
|
|
"'STMicroelectronics Virtual COM Port' for USB port",
|
|
"'USB Serial Port' for TTL port");
|
|
}
|
|
|
|
connectPanel.add(comboPorts);
|
|
final JComboBox<String> comboSpeeds = createSpeedCombo();
|
|
comboSpeeds.setToolTipText("For 'STMicroelectronics Virtual COM Port' device any speed setting would work the same");
|
|
connectPanel.add(comboSpeeds);
|
|
|
|
final JButton connectButton = new JButton("Connect", new ImageIcon(getClass().getResource("/com/rusefi/connect48.png")));
|
|
//connectButton.setBackground(new Color(RUSEFI_ORANGE)); // custom orange
|
|
setToolTip(connectButton, "Connect to real hardware");
|
|
|
|
JCheckBoxMenuItem menuItem = new JCheckBoxMenuItem("Always auto-connect port");
|
|
menuItem.setState(PersistentConfiguration.getBoolProperty(ALWAYS_AUTO_PORT));
|
|
menuItem.addActionListener(e -> PersistentConfiguration.setBoolProperty(ALWAYS_AUTO_PORT, menuItem.getState()));
|
|
|
|
connectButton.addMouseListener(new MouseAdapter() {
|
|
@Override
|
|
public void mouseReleased(MouseEvent e) {
|
|
if (!SwingUtilities.isRightMouseButton(e))
|
|
return;
|
|
JPopupMenu menu = new JPopupMenu();
|
|
menu.add(menuItem);
|
|
menu.show(connectButton, e.getX(), e.getY());
|
|
}
|
|
});
|
|
|
|
connectPanel.add(connectButton);
|
|
connectPanel.setVisible(false);
|
|
|
|
frame.getRootPane().setDefaultButton(connectButton);
|
|
connectButton.addKeyListener(new KeyAdapter() {
|
|
@Override
|
|
public void keyPressed(KeyEvent e) {
|
|
if (e.getKeyCode() == KeyEvent.VK_ENTER) {
|
|
connectButtonAction(comboSpeeds);
|
|
}
|
|
}
|
|
});
|
|
|
|
connectButton.addActionListener(e -> connectButtonAction(comboSpeeds));
|
|
|
|
leftPanel.add(realHardwarePanel);
|
|
leftPanel.add(miscPanel);
|
|
|
|
if (FileLog.isWindows()) {
|
|
JPanel topButtons = new JPanel(new FlowLayout(FlowLayout.CENTER, 5, 0));
|
|
topButtons.add(ToolButtons.createShowDeviceManagerButton());
|
|
topButtons.add(DriverInstall.createButton());
|
|
topButtons.add(ToolButtons.createPcanConnectorButton());
|
|
realHardwarePanel.add(topButtons, "right, wrap");
|
|
}
|
|
realHardwarePanel.add(connectPanel, "right, wrap");
|
|
realHardwarePanel.add(noPortsMessage, "right, wrap");
|
|
noPortsMessage.setToolTipText("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");
|
|
|
|
realHardwarePanel.add(selector.getControl(), "right, wrap");
|
|
|
|
// for F7 builds we just build one file at the moment
|
|
// realHardwarePanel.add(new FirmwareFlasher(FirmwareFlasher.IMAGE_FILE, "ST-LINK Program Firmware", "Default firmware version for most users").getButton());
|
|
JComponent updateHelp = ProgramSelector.createHelpButton();
|
|
|
|
realHardwarePanel.add(updateHelp, "right, wrap");
|
|
|
|
// st-link is pretty advanced use-case, real humans do not have st-link as of 2021
|
|
//realHardwarePanel.add(new EraseChip().getButton(), "right, wrap");
|
|
}
|
|
|
|
SerialPortScanner.INSTANCE.addListener(currentHardware -> SwingUtilities.invokeLater(() -> {
|
|
selector.apply(currentHardware);
|
|
applyKnownPorts(currentHardware);
|
|
frame.pack();
|
|
}));
|
|
|
|
final JButton buttonLogViewer = new JButton();
|
|
buttonLogViewer.setText("Start " + LinkManager.LOG_VIEWER);
|
|
buttonLogViewer.addActionListener(new ActionListener() {
|
|
@Override
|
|
public void actionPerformed(ActionEvent e) {
|
|
disposeFrameAndProceed();
|
|
new ConsoleUI(LinkManager.LOG_VIEWER);
|
|
}
|
|
});
|
|
|
|
miscPanel.add(buttonLogViewer, "wrap");
|
|
miscPanel.add(new HorizontalLine(), "wrap");
|
|
|
|
miscPanel.add(SimulatorHelper.createSimulatorComponent(this));
|
|
|
|
JPanel rightPanel = new JPanel(new VerticalFlowLayout());
|
|
|
|
if (BundleUtil.readBundleFullNameNotNull().contains("proteus_f7")) {
|
|
String text = "WARNING: Proteus F7";
|
|
URLLabel urlLabel = new URLLabel(text, "https://github.com/rusefi/rusefi/wiki/F7-requires-full-erase");
|
|
Color originalColor = urlLabel.getForeground();
|
|
new Timer(500, new ActionListener() {
|
|
int counter;
|
|
@Override
|
|
public void actionPerformed(ActionEvent e) {
|
|
// URL color is hard-coded, let's blink isUnderlined attribute as second best option
|
|
urlLabel.setText(text, counter++ % 2 == 0);
|
|
}
|
|
}).start();
|
|
rightPanel.add(urlLabel);
|
|
}
|
|
|
|
JLabel logo = LogoHelper.createLogoLabel();
|
|
if (logo != null)
|
|
rightPanel.add(logo);
|
|
rightPanel.add(LogoHelper.createUrlLabel());
|
|
rightPanel.add(new JLabel("Version " + Launcher.CONSOLE_VERSION));
|
|
|
|
JPanel content = new JPanel(new BorderLayout());
|
|
content.add(leftPanel, BorderLayout.WEST);
|
|
content.add(rightPanel, BorderLayout.EAST);
|
|
frame.add(content);
|
|
frame.pack();
|
|
setFrameIcon(frame);
|
|
log.info("setVisible");
|
|
frame.setVisible(true);
|
|
UiUtils.centerWindow(frame);
|
|
|
|
KeyListener hwTestEasterEgg = functionalTestEasterEgg();
|
|
|
|
for (Component component : getAllComponents(frame)) {
|
|
component.addKeyListener(hwTestEasterEgg);
|
|
}
|
|
}
|
|
|
|
private void applyKnownPorts(SerialPortScanner.AvailableHardware currentHardware) {
|
|
List<SerialPortScanner.PortResult> ports = currentHardware.getKnownPorts();
|
|
log.info("Rendering available ports: " + ports);
|
|
connectPanel.setVisible(!ports.isEmpty());
|
|
noPortsMessage.setVisible(ports.isEmpty());
|
|
|
|
applyPortSelectionToUIcontrol(ports);
|
|
UiUtils.trueLayout(connectPanel);
|
|
}
|
|
|
|
public static void setFrameIcon(Frame frame) {
|
|
ImageIcon icon = LogoHelper.getBundleIcon();
|
|
if (icon != null)
|
|
frame.setIconImage(icon.getImage());
|
|
}
|
|
|
|
private void connectButtonAction(JComboBox<String> comboSpeeds) {
|
|
BaudRateHolder.INSTANCE.baudRate = Integer.parseInt((String) comboSpeeds.getSelectedItem());
|
|
SerialPortScanner.PortResult selectedPort = ((SerialPortScanner.PortResult)comboPorts.getSelectedItem());
|
|
disposeFrameAndProceed();
|
|
new ConsoleUI(selectedPort.port);
|
|
}
|
|
|
|
/**
|
|
* Here we listen to keystrokes while console start-up frame is being displayed and if magic "test" word is typed
|
|
* we launch a functional test on real hardware, same as Jenkins runs within continuous integration
|
|
*/
|
|
@NotNull
|
|
private KeyListener functionalTestEasterEgg() {
|
|
return new KeyAdapter() {
|
|
private final static String TEST = "test";
|
|
private String recentKeyStrokes = "";
|
|
|
|
@Override
|
|
public void keyTyped(KeyEvent e) {
|
|
recentKeyStrokes = recentKeyStrokes + e.getKeyChar();
|
|
if (recentKeyStrokes.toLowerCase().endsWith(TEST) && showTestConfirmation()) {
|
|
runFunctionalHardwareTest();
|
|
}
|
|
}
|
|
|
|
private boolean showTestConfirmation() {
|
|
return JOptionPane.showConfirmDialog(StartupFrame.this.frame, "Want to run functional test? This would freeze UI for the duration of the test",
|
|
"Better do not run while connected to vehicle!!!", YES_NO_OPTION) == JOptionPane.YES_OPTION;
|
|
}
|
|
|
|
private void runFunctionalHardwareTest() {
|
|
boolean isSuccess = HwCiF4Discovery.runHardwareTest();
|
|
JOptionPane.showMessageDialog(null, "Function test passed: " + isSuccess + "\nSee log folder for details.");
|
|
}
|
|
};
|
|
}
|
|
|
|
public void disposeFrameAndProceed() {
|
|
isProceeding = true;
|
|
frame.dispose();
|
|
SerialPortScanner.INSTANCE.stopTimer();
|
|
}
|
|
|
|
private void applyPortSelectionToUIcontrol(List<SerialPortScanner.PortResult> ports) {
|
|
comboPorts.removeAllItems();
|
|
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);
|
|
}
|
|
|
|
trueLayout(comboPorts);
|
|
}
|
|
|
|
private static JComboBox<String> createSpeedCombo() {
|
|
JComboBox<String> combo = new JComboBox<>();
|
|
String defaultSpeed = getConfig().getRoot().getProperty(ConsoleUI.SPEED_KEY, "115200");
|
|
for (int speed : new int[]{9600, 14400, 19200, 38400, 57600, 115200, 460800, 921600})
|
|
combo.addItem(Integer.toString(speed));
|
|
combo.setSelectedItem(defaultSpeed);
|
|
return combo;
|
|
}
|
|
}
|