rusefi-full/java_console/ui/src/com/rusefi/Launcher.java

346 lines
14 KiB
Java

package com.rusefi;
import com.rusefi.binaryprotocol.BinaryProtocol;
import com.rusefi.config.Fields;
import com.rusefi.core.EngineState;
import com.rusefi.core.MessagesCentral;
import com.rusefi.core.Sensor;
import com.rusefi.core.SensorCentral;
import com.rusefi.io.*;
import com.rusefi.io.serial.PortHolder;
import com.rusefi.io.tcp.BinaryProtocolServer;
import com.rusefi.maintenance.VersionChecker;
import com.rusefi.ui.*;
import com.rusefi.ui.engine.EngineSnifferPanel;
import com.rusefi.ui.logview.LogViewer;
import com.rusefi.ui.storage.Node;
import com.rusefi.ui.util.DefaultExceptionHandler;
import com.rusefi.ui.util.FrameHelper;
import com.rusefi.ui.util.JustOneInstance;
import com.rusefi.ui.util.UiUtils;
import jssc.SerialPortList;
import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import java.awt.*;
import java.awt.event.ActionListener;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.TimeZone;
import java.util.concurrent.atomic.AtomicReference;
import static com.rusefi.ui.storage.PersistentConfiguration.getConfig;
/**
* this is the main entry point of rusEfi ECU console
* <p/>
* <p/>
* 12/25/12
* (c) Andrey Belomutskiy 2013-2017
*
* @see StartupFrame
* @see EngineSnifferPanel
*/
public class Launcher {
public static final int CONSOLE_VERSION = 20170324;
public static final boolean SHOW_STIMULATOR = false;
private static final String TAB_INDEX = "main_tab";
protected static final String PORT_KEY = "port";
protected static final String SPEED_KEY = "speed";
private final String port;
// todo: the logic around 'fatalError' could be implemented nicer
private String fatalError;
public static EngineSnifferPanel engineSnifferPanel;
private static SensorCentral.SensorListener wrongVersionListener;
private final JTabbedPane tabbedPane = new JTabbedPane() {
@Override
public void paint(Graphics g) {
super.paint(g);
paintStatusText(g);
}
private void paintStatusText(Graphics g) {
Font f = g.getFont();
g.setFont(new Font(f.getName(), f.getStyle(), f.getSize() * 4));
Dimension d = getSize();
String text;
switch (ConnectionStatus.INSTANCE.getValue()) {
case NOT_CONNECTED:
text = "Not connected";
break;
case LOADING:
text = "Loading";
break;
default:
text = "";
}
if (fatalError != null) {
text = fatalError;
g.setColor(Color.red);
}
int labelWidth = g.getFontMetrics().stringWidth(text);
g.drawString(text, (d.width - labelWidth) / 2, d.height / 2);
}
};
public static AtomicReference<String> firmwareVersion = new AtomicReference<>("N/A");
private static Frame staticFrame;
private final TableEditorPane tableEditor = new TableEditorPane();
private final SettingsTab settingsTab = new SettingsTab();
private final LogDownloader logsManager = new LogDownloader();
private final FuelTunePane fuelTunePane;
/**
* @see StartupFrame
*/
private FrameHelper mainFrame = new FrameHelper() {
@Override
protected void onWindowOpened() {
super.onWindowOpened();
windowOpenedHandler();
}
@Override
protected void onWindowClosed() {
/**
* here we would close the port and log a message about it
*/
windowClosedHandler();
/**
* here we would close the log file
*/
super.onWindowClosed();
}
};
private final Map<JComponent, ActionListener> tabSelectedListeners = new HashMap<JComponent, ActionListener>();
public Launcher(String port) {
this.port = port;
staticFrame = mainFrame.getFrame();
FileLog.MAIN.logLine("Console " + CONSOLE_VERSION);
getConfig().getRoot().setProperty(PORT_KEY, port);
getConfig().getRoot().setProperty(SPEED_KEY, PortHolder.BAUD_RATE);
LinkManager.start(port);
MessagesCentral.getInstance().addListener(new MessagesCentral.MessageListener() {
@Override
public void onMessage(Class clazz, String message) {
if (message.startsWith(ConnectionStatus.FATAL_MESSAGE_PREFIX))
fatalError = message;
}
});
engineSnifferPanel = new EngineSnifferPanel(getConfig().getRoot().getChild("digital_sniffer"));
if (!LinkManager.isLogViewerMode(port))
engineSnifferPanel.setOutpinListener(LinkManager.engineState);
if (LinkManager.isLogViewerMode(port))
tabbedPane.add("Log Viewer", new LogViewer(engineSnifferPanel));
ConnectionWatchdog.start();
GaugesPanel.DetachedRepository.INSTANCE.init(getConfig().getRoot().getChild("detached"));
GaugesPanel.DetachedRepository.INSTANCE.load();
if (!LinkManager.isLogViewer())
tabbedPane.addTab("Gauges", new GaugesPanel(getConfig().getRoot().getChild("gauges")).getContent());
if (!LinkManager.isLogViewer())
tabbedPane.addTab("Formulas", new FormulasPane().getContent());
tabbedPaneAdd("Engine Sniffer", engineSnifferPanel.getPanel(), engineSnifferPanel.getTabSelectedListener());
if (!LinkManager.isLogViewer()) {
SensorSnifferPane sensorSniffer = new SensorSnifferPane(getConfig().getRoot().getChild("sensor_sniffer"));
tabbedPaneAdd("Sensor Sniffer", sensorSniffer.getPanel(), sensorSniffer.getTabSelectedListener());
}
// tabbedPane.addTab("LE controls", new FlexibleControls().getPanel());
// tabbedPane.addTab("ADC", new AdcPanel(new BooleanInputsModel()).createAdcPanel());
if (SHOW_STIMULATOR && !LinkManager.isStimulationMode && !LinkManager.isLogViewerMode(port)) {
// todo: rethink this UI? special command line key to enable it?
EcuStimulator stimulator = EcuStimulator.getInstance();
tabbedPane.add("ECU stimulation", stimulator.getPanel());
}
// tabbedPane.addTab("live map adjustment", new Live3DReport().getControl());
if (!LinkManager.isLogViewer()) {
MessagesPane messagesPane = new MessagesPane(getConfig().getRoot().getChild("messages"));
tabbedPaneAdd("Messages", messagesPane.getContent(), messagesPane.getTabSelectedListener());
}
if (!LinkManager.isLogViewer())
tabbedPane.addTab("Table Editor", tableEditor);
// tabbedPane.add("Wizards", new Wizard().createPane());
if (!LinkManager.isLogViewer())
tabbedPane.add("Settings", settingsTab.createPane());
if (!LinkManager.isLogViewer())
tabbedPane.add("Bench Test", new BenchTestPane().getContent());
if (!LinkManager.isLogViewer() && false) // todo: fix it & better name?
tabbedPane.add("Logs Manager", logsManager.getContent());
fuelTunePane = new FuelTunePane(getConfig().getRoot().getChild("fueltune"));
if (true)
tabbedPane.add("Fuel Tune", fuelTunePane.getContent());
if (!LinkManager.isLogViewerMode(port)) {
int selectedIndex = getConfig().getRoot().getIntProperty(TAB_INDEX, 2);
if (selectedIndex < tabbedPane.getTabCount())
tabbedPane.setSelectedIndex(selectedIndex);
}
tabbedPane.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
if (e.getSource() instanceof JTabbedPane) {
JTabbedPane pane = (JTabbedPane) e.getSource();
int selectedIndex = pane.getSelectedIndex();
System.out.println("Selected paneNo: " + selectedIndex);
ActionListener actionListener = tabSelectedListeners.get(pane.getComponentAt(selectedIndex));
if (actionListener != null)
actionListener.actionPerformed(null);
}
}
});
StartupFrame.setAppIcon(mainFrame.getFrame());
mainFrame.showFrame(tabbedPane);
}
private void tabbedPaneAdd(String title, JComponent component, ActionListener tabSelectedListener) {
tabSelectedListeners.put(component, tabSelectedListener);
tabbedPane.add(title, component);
}
private void windowOpenedHandler() {
setTitle();
ConnectionStatus.INSTANCE.addListener(new ConnectionStatus.Listener() {
@Override
public void onConnectionStatus(boolean isConnected) {
setTitle();
UiUtils.trueRepaint(tabbedPane); // this would repaint status label
if (ConnectionStatus.INSTANCE.getValue() == ConnectionStatus.Value.CONNECTED) {
long unixTime = System.currentTimeMillis() / 1000L;
long withOffset = unixTime + TimeZone.getDefault().getOffset(System.currentTimeMillis()) / 1000;
CommandQueue.getInstance().write("set date " + withOffset, CommandQueue.DEFAULT_TIMEOUT,
InvocationConfirmationListener.VOID, false);
}
}
});
LinkManager.open(new ConnectionStateListener() {
@Override
public void onConnectionFailed() {
}
@Override
public void onConnectionEstablished() {
tableEditor.showContent();
settingsTab.showContent();
logsManager.showContent();
fuelTunePane.showContent();
BinaryProtocolServer.start();
}
});
LinkManager.engineState.registerStringValueAction(EngineState.RUS_EFI_VERSION_TAG, new EngineState.ValueCallback<String>() {
@Override
public void onUpdate(String firmwareVersion) {
Launcher.firmwareVersion.set(firmwareVersion);
SensorLogger.init();
setTitle();
VersionChecker.getInstance().onFirmwareVersion(firmwareVersion);
}
});
}
private void setTitle() {
String disconnected = ConnectionStatus.INSTANCE.isConnected() ? "" : "DISCONNECTED ";
mainFrame.getFrame().setTitle(disconnected + "Console " + CONSOLE_VERSION + "; firmware=" + Launcher.firmwareVersion.get() + "@" + port);
}
private void windowClosedHandler() {
/**
* looks like reconnectTimer in {@link com.rusefi.ui.RpmPanel} keeps AWT alive. Simplest solution would be to 'exit'
*/
SimulatorHelper.onWindowClosed();
Node root = getConfig().getRoot();
root.setProperty("version", CONSOLE_VERSION);
root.setProperty(TAB_INDEX, tabbedPane.getSelectedIndex());
GaugesPanel.DetachedRepository.INSTANCE.saveConfig();
getConfig().save();
BinaryProtocol bp = BinaryProtocol.instance;
if (bp != null && !bp.isClosed)
bp.close(); // it could be that serial driver wants to be closed explicitly
System.exit(0);
}
public static void main(final String[] args) throws Exception {
String toolName = args.length == 0 ? null : args[0];
if ("compile_fsio_file".equalsIgnoreCase(toolName)) {
CompileTool.run(Arrays.asList(args).subList(1, args.length));
return;
}
FileLog.MAIN.start();
getConfig().load();
FileLog.suspendLogging = getConfig().getRoot().getBoolProperty(GaugesPanel.DISABLE_LOGS);
Thread.setDefaultUncaughtExceptionHandler(new DefaultExceptionHandler());
VersionChecker.start();
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
awtCode(args);
}
});
}
private static void awtCode(String[] args) {
if (JustOneInstance.isAlreadyRunning()) {
int result = JOptionPane.showConfirmDialog(null, "Looks like another instance is already running. Do you really want to start another instance?",
"rusEfi", JOptionPane.YES_NO_OPTION);
if (result == JOptionPane.NO_OPTION)
System.exit(-1);
}
wrongVersionListener = new SensorCentral.SensorListener() {
@Override
public void onSensorUpdate(double value) {
if (value != Fields.TS_FILE_VERSION) {
String message = "This copy of rusEfi console is not compatible with this version of firmware\r\n" +
"Console compatible with " + Fields.TS_FILE_VERSION + " while firmware compatible with " +
(int)value;
JOptionPane.showMessageDialog(Launcher.getFrame(), message);
assert wrongVersionListener != null;
SensorCentral.getInstance().removeListener(Sensor.FIRMWARE_VERSION, wrongVersionListener);
}
}
};
SensorCentral.getInstance().addListener(Sensor.FIRMWARE_VERSION, wrongVersionListener);
JustOneInstance.onStart();
try {
boolean isPortDefined = args.length > 0;
boolean isBaudRateDefined = args.length > 1;
if (isBaudRateDefined)
PortHolder.BAUD_RATE = Integer.parseInt(args[1]);
if (isPortDefined) {
new Launcher(args[0]);
} else {
for (String p : SerialPortList.getPortNames())
MessagesCentral.getInstance().postMessage(Launcher.class, "Available port: " + p);
new StartupFrame().chooseSerialPort();
}
} catch (Throwable e) {
throw new IllegalStateException(e);
}
}
public static Frame getFrame() {
return staticFrame;
}
}