Add `Update Calibrations` button #6864
This commit is contained in:
parent
0fe5649794
commit
6fd13d446a
|
@ -0,0 +1,86 @@
|
||||||
|
package com.rusefi.maintenance;
|
||||||
|
|
||||||
|
import com.devexperts.logging.Logging;
|
||||||
|
import com.opensr5.ConfigurationImage;
|
||||||
|
import com.rusefi.io.LinkManager;
|
||||||
|
import com.rusefi.io.UpdateOperationCallbacks;
|
||||||
|
|
||||||
|
import javax.swing.*;
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import static com.devexperts.logging.Logging.getLogging;
|
||||||
|
|
||||||
|
public enum CalibrationsUpdater {
|
||||||
|
INSTANCE;
|
||||||
|
|
||||||
|
private static final Logging log = getLogging(CalibrationsUpdater.class);
|
||||||
|
|
||||||
|
private volatile ConfigurationImage calibrationsToUpload = null;
|
||||||
|
|
||||||
|
public void setCalibrationsToUpload(final ConfigurationImage calibrations) {
|
||||||
|
calibrationsToUpload = calibrations;
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void updateCalibrations(
|
||||||
|
final String port,
|
||||||
|
final UpdateOperationCallbacks callbacks
|
||||||
|
) {
|
||||||
|
final ConfigurationImage calibrationsImage = calibrationsToUpload;
|
||||||
|
if (calibrationsImage != null) {
|
||||||
|
final int calibrationsImageSize = calibrationsImage.getSize();
|
||||||
|
try (LinkManager linkManager = new LinkManager()
|
||||||
|
.setNeedPullText(false)
|
||||||
|
.setNeedPullLiveData(true)) {
|
||||||
|
|
||||||
|
callbacks.logLine(String.format("Connecting to port %s...", port));
|
||||||
|
try {
|
||||||
|
linkManager.connect(port).await(60, TimeUnit.SECONDS);
|
||||||
|
} catch (final InterruptedException e) {
|
||||||
|
final String errorMsg = String.format("Failed to connect to port %s", port);
|
||||||
|
log.error(errorMsg, e);
|
||||||
|
callbacks.logLine(errorMsg);
|
||||||
|
callbacks.error();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
callbacks.logLine(String.format(
|
||||||
|
"Updating configuration image (%d bytes) to port %s...",
|
||||||
|
calibrationsImageSize,
|
||||||
|
port
|
||||||
|
));
|
||||||
|
final CountDownLatch latch = new CountDownLatch(1);
|
||||||
|
linkManager.execute(() -> {
|
||||||
|
linkManager.getBinaryProtocol().uploadChanges(calibrationsImage);
|
||||||
|
latch.countDown();
|
||||||
|
});
|
||||||
|
try {
|
||||||
|
if (!latch.await(1, TimeUnit.MINUTES)) {
|
||||||
|
callbacks.logLine(String.format(
|
||||||
|
"Failed to update configuration image (%d bytes) to port %s in a minute",
|
||||||
|
calibrationsImageSize,
|
||||||
|
port
|
||||||
|
));
|
||||||
|
callbacks.error();
|
||||||
|
} else {
|
||||||
|
callbacks.logLine(String.format(
|
||||||
|
"Configuration image (%d bytes) has been uploaded to port %s",
|
||||||
|
calibrationsImageSize,
|
||||||
|
port
|
||||||
|
));
|
||||||
|
callbacks.done();
|
||||||
|
}
|
||||||
|
} catch (final InterruptedException e) {
|
||||||
|
final String errorMsg = String.format(
|
||||||
|
"Updating calibrations to port %s was interrupted",
|
||||||
|
port
|
||||||
|
);
|
||||||
|
log.error(errorMsg, e);
|
||||||
|
callbacks.logLine(errorMsg);
|
||||||
|
callbacks.error();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
callbacks.logLine("ERROR: Calibrations to update are undefined");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -52,6 +52,7 @@ public class ProgramSelector {
|
||||||
private static final String INSTALL_OPENBLT = "Install OpenBLT";
|
private static final String INSTALL_OPENBLT = "Install OpenBLT";
|
||||||
private static final String OPENBLT_CAN = "OpenBLT via CAN";
|
private static final String OPENBLT_CAN = "OpenBLT via CAN";
|
||||||
|
|
||||||
|
public static final String UPDATE_CALIBRATIONS = "Update Calibrations";
|
||||||
|
|
||||||
private final JPanel content = new JPanel(new BorderLayout());
|
private final JPanel content = new JPanel(new BorderLayout());
|
||||||
private final JLabel noHardware = new JLabel("Nothing detected");
|
private final JLabel noHardware = new JLabel("Nothing detected");
|
||||||
|
@ -133,6 +134,13 @@ public class ProgramSelector {
|
||||||
jobName = "DFU erase";
|
jobName = "DFU erase";
|
||||||
job = DfuFlasher::runDfuEraseAsync;
|
job = DfuFlasher::runDfuEraseAsync;
|
||||||
break;
|
break;
|
||||||
|
case UPDATE_CALIBRATIONS:
|
||||||
|
jobName = "Update calibrations";
|
||||||
|
job = (callbacks) -> CalibrationsUpdater.INSTANCE.updateCalibrations(
|
||||||
|
selectedPort.port,
|
||||||
|
callbacks
|
||||||
|
);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
throw new IllegalArgumentException("How did you " + selectedMode);
|
throw new IllegalArgumentException("How did you " + selectedMode);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
package com.rusefi.ui.basic;
|
package com.rusefi.ui.basic;
|
||||||
|
|
||||||
import com.devexperts.logging.Logging;
|
import com.devexperts.logging.Logging;
|
||||||
|
|
||||||
|
import com.opensr5.ConfigurationImage;
|
||||||
|
import com.opensr5.io.ConfigurationImageFile;
|
||||||
import com.rusefi.AvailableHardware;
|
import com.rusefi.AvailableHardware;
|
||||||
import com.rusefi.Launcher;
|
import com.rusefi.Launcher;
|
||||||
import com.rusefi.SerialPortScanner;
|
import com.rusefi.SerialPortScanner;
|
||||||
|
@ -8,11 +11,10 @@ import com.rusefi.StartupFrame;
|
||||||
import com.rusefi.autodetect.PortDetector;
|
import com.rusefi.autodetect.PortDetector;
|
||||||
import com.rusefi.core.FindFileHelper;
|
import com.rusefi.core.FindFileHelper;
|
||||||
import com.rusefi.core.net.ConnectionAndMeta;
|
import com.rusefi.core.net.ConnectionAndMeta;
|
||||||
|
import com.rusefi.core.preferences.storage.PersistentConfiguration;
|
||||||
|
import com.rusefi.core.ui.AutoupdateUtil;
|
||||||
import com.rusefi.core.ui.FrameHelper;
|
import com.rusefi.core.ui.FrameHelper;
|
||||||
import com.rusefi.maintenance.DfuFlasher;
|
import com.rusefi.maintenance.*;
|
||||||
import com.rusefi.maintenance.ProgramSelector;
|
|
||||||
import com.rusefi.maintenance.StatusAnimation;
|
|
||||||
import com.rusefi.maintenance.UpdateStatusWindow;
|
|
||||||
import com.rusefi.ui.LogoHelper;
|
import com.rusefi.ui.LogoHelper;
|
||||||
import com.rusefi.ui.util.DefaultExceptionHandler;
|
import com.rusefi.ui.util.DefaultExceptionHandler;
|
||||||
import com.rusefi.ui.util.HorizontalLine;
|
import com.rusefi.ui.util.HorizontalLine;
|
||||||
|
@ -21,14 +23,16 @@ import com.rusefi.ui.widgets.ToolButtons;
|
||||||
import org.putgemin.VerticalFlowLayout;
|
import org.putgemin.VerticalFlowLayout;
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
|
import javax.swing.filechooser.FileNameExtensionFilter;
|
||||||
|
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
import java.awt.event.ActionEvent;
|
import java.awt.event.ActionEvent;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
import static com.devexperts.logging.Logging.getLogging;
|
import static com.devexperts.logging.Logging.getLogging;
|
||||||
import static com.rusefi.FileLog.isWindows;
|
import static com.rusefi.FileLog.isWindows;
|
||||||
|
@ -40,6 +44,8 @@ import static com.rusefi.FileLog.isWindows;
|
||||||
public class BasicStartupFrame {
|
public class BasicStartupFrame {
|
||||||
private static final Logging log = getLogging(BasicStartupFrame.class);
|
private static final Logging log = getLogging(BasicStartupFrame.class);
|
||||||
|
|
||||||
|
private static final String BINARY_IMAGE_DEFAULT_DIRECTORY_PROPERTY_NAME = "binary_image_default_directory";
|
||||||
|
|
||||||
private final String whiteLabel = ConnectionAndMeta.getWhiteLabel(ConnectionAndMeta.getProperties());
|
private final String whiteLabel = ConnectionAndMeta.getWhiteLabel(ConnectionAndMeta.getProperties());
|
||||||
private final FrameHelper frame = FrameHelper.createFrame(
|
private final FrameHelper frame = FrameHelper.createFrame(
|
||||||
whiteLabel + " basic console " + Launcher.CONSOLE_VERSION
|
whiteLabel + " basic console " + Launcher.CONSOLE_VERSION
|
||||||
|
@ -49,8 +55,14 @@ public class BasicStartupFrame {
|
||||||
private final JLabel statusMessage = new JLabel();
|
private final JLabel statusMessage = new JLabel();
|
||||||
private final StatusAnimation status = new StatusAnimation(this::updateStatus, StartupFrame.SCANNING_PORTS);
|
private final StatusAnimation status = new StatusAnimation(this::updateStatus, StartupFrame.SCANNING_PORTS);
|
||||||
private final JButton updateFirmwareButton = ProgramSelector.createUpdateFirmwareButton();
|
private final JButton updateFirmwareButton = ProgramSelector.createUpdateFirmwareButton();
|
||||||
|
private final JButton updateCalibrationsButton = new JButton(
|
||||||
|
"Update Calibrations",
|
||||||
|
AutoupdateUtil.loadIcon("writeconfig48.png")
|
||||||
|
);
|
||||||
|
private final JFileChooser calibrationsFileChooser = createConfigurationImageFileChooser();
|
||||||
|
|
||||||
private volatile Optional<SerialPortScanner.PortResult> portToUpdateObfuscatedFirmware = Optional.empty();
|
private volatile Optional<SerialPortScanner.PortResult> portToUpdateObfuscatedFirmware = Optional.empty();
|
||||||
|
private volatile Optional<SerialPortScanner.PortResult> portToUpdateCalibrations = Optional.empty();
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
runTool(null);
|
runTool(null);
|
||||||
|
@ -75,12 +87,12 @@ public class BasicStartupFrame {
|
||||||
panel.add(statusMessage);
|
panel.add(statusMessage);
|
||||||
}
|
}
|
||||||
panel.add(updateFirmwareButton);
|
panel.add(updateFirmwareButton);
|
||||||
SerialPortScanner.INSTANCE.addListener(currentHardware -> SwingUtilities.invokeLater(() -> {
|
|
||||||
onHardwareUpdated(currentHardware);
|
|
||||||
}));
|
|
||||||
} else {
|
} else {
|
||||||
panel.add(new JLabel("Sorry only works on Windows"));
|
panel.add(new JLabel("Sorry only works on Windows"));
|
||||||
}
|
}
|
||||||
|
SerialPortScanner.INSTANCE.addListener(currentHardware -> SwingUtilities.invokeLater(() -> {
|
||||||
|
onHardwareUpdated(currentHardware);
|
||||||
|
}));
|
||||||
|
|
||||||
panel.add(new HorizontalLine());
|
panel.add(new HorizontalLine());
|
||||||
JLabel logoLabel = LogoHelper.createLogoLabel();
|
JLabel logoLabel = LogoHelper.createLogoLabel();
|
||||||
|
@ -89,6 +101,10 @@ public class BasicStartupFrame {
|
||||||
if (ConnectionAndMeta.isDefaultWhitelabel(whiteLabel))
|
if (ConnectionAndMeta.isDefaultWhitelabel(whiteLabel))
|
||||||
panel.add(LogoHelper.createUrlLabel());
|
panel.add(LogoHelper.createUrlLabel());
|
||||||
|
|
||||||
|
updateCalibrationsButton.addActionListener(this::onUpdateCalibrationsButtonClicked);
|
||||||
|
updateCalibrationsButton.setEnabled(false);
|
||||||
|
panel.add(updateCalibrationsButton);
|
||||||
|
|
||||||
frame.showFrame(panel, false);
|
frame.showFrame(panel, false);
|
||||||
UiUtils.centerWindow(frame.getFrame());
|
UiUtils.centerWindow(frame.getFrame());
|
||||||
packFrame();
|
packFrame();
|
||||||
|
@ -120,6 +136,7 @@ public class BasicStartupFrame {
|
||||||
if (isObfusacted) {
|
if (isObfusacted) {
|
||||||
updatePortToUpdateObfuscatedFirmware(currentHardware);
|
updatePortToUpdateObfuscatedFirmware(currentHardware);
|
||||||
}
|
}
|
||||||
|
updatePortToUpdateCalibrations(currentHardware);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updatePortToUpdateObfuscatedFirmware(final AvailableHardware currentHardware) {
|
private void updatePortToUpdateObfuscatedFirmware(final AvailableHardware currentHardware) {
|
||||||
|
@ -175,7 +192,46 @@ public class BasicStartupFrame {
|
||||||
statusMessage.setText(reason);
|
statusMessage.setText(reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onUpdateFirmwareButtonClicked(final ActionEvent e) {
|
private void updatePortToUpdateCalibrations(final AvailableHardware currentHardware) {
|
||||||
|
final List<SerialPortScanner.PortResult> ecuPortsToUpdateCalibrations = currentHardware.getKnownPorts(Set.of(
|
||||||
|
SerialPortScanner.SerialPortType.Ecu,
|
||||||
|
SerialPortScanner.SerialPortType.EcuWithOpenblt
|
||||||
|
));
|
||||||
|
|
||||||
|
switch (ecuPortsToUpdateCalibrations.size()) {
|
||||||
|
case 0: {
|
||||||
|
resetPortToUpdateCalibrations();
|
||||||
|
log.info("No ECU ports to update calibrations found");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 1: {
|
||||||
|
setPortToUpdateCalibrations(ecuPortsToUpdateCalibrations.get(0));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
resetPortToUpdateCalibrations();
|
||||||
|
log.info(String.format(
|
||||||
|
"Multiple ECU ports to update calibrations found on: %s",
|
||||||
|
ecuPortsToUpdateCalibrations.stream()
|
||||||
|
.map(portResult -> portResult.port)
|
||||||
|
.collect(Collectors.joining(", "))
|
||||||
|
));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setPortToUpdateCalibrations(final SerialPortScanner.PortResult port) {
|
||||||
|
portToUpdateCalibrations = Optional.of(port);
|
||||||
|
updateCalibrationsButton.setEnabled(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void resetPortToUpdateCalibrations() {
|
||||||
|
portToUpdateCalibrations = Optional.empty();
|
||||||
|
updateCalibrationsButton.setEnabled(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onUpdateFirmwareButtonClicked(final ActionEvent actionEvent) {
|
||||||
if (isObfusacted) {
|
if (isObfusacted) {
|
||||||
portToUpdateObfuscatedFirmware.ifPresentOrElse(port -> {
|
portToUpdateObfuscatedFirmware.ifPresentOrElse(port -> {
|
||||||
switch (port.type) {
|
switch (port.type) {
|
||||||
|
@ -201,6 +257,76 @@ public class BasicStartupFrame {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void onUpdateCalibrationsButtonClicked(final ActionEvent actionEvent) {
|
||||||
|
portToUpdateCalibrations.ifPresentOrElse(
|
||||||
|
port -> {
|
||||||
|
final int selectedOption = calibrationsFileChooser.showOpenDialog(updateCalibrationsButton);
|
||||||
|
if (selectedOption == JFileChooser.APPROVE_OPTION) {
|
||||||
|
final File selectedFile = calibrationsFileChooser.getSelectedFile();
|
||||||
|
saveBinaryImageDefaultDirectory(selectedFile.getParent());
|
||||||
|
try {
|
||||||
|
final ConfigurationImage calibrationsImage = ConfigurationImageFile.readFromFile(
|
||||||
|
selectedFile.getAbsolutePath()
|
||||||
|
);
|
||||||
|
CalibrationsUpdater.INSTANCE.setCalibrationsToUpload(calibrationsImage);
|
||||||
|
ProgramSelector.executeJob(
|
||||||
|
updateCalibrationsButton,
|
||||||
|
ProgramSelector.UPDATE_CALIBRATIONS,
|
||||||
|
port
|
||||||
|
);
|
||||||
|
} catch (final IOException e) {
|
||||||
|
final String errorMsg = String.format(
|
||||||
|
"Failed to load calibrations from file %s",
|
||||||
|
selectedFile.getAbsolutePath()
|
||||||
|
);
|
||||||
|
log.error(errorMsg, e);
|
||||||
|
JOptionPane.showMessageDialog(
|
||||||
|
updateCalibrationsButton,
|
||||||
|
errorMsg,
|
||||||
|
"Error",
|
||||||
|
JOptionPane.ERROR_MESSAGE
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, () -> {
|
||||||
|
JOptionPane.showMessageDialog(
|
||||||
|
updateCalibrationsButton,
|
||||||
|
"Device is not connected",
|
||||||
|
"Error",
|
||||||
|
JOptionPane.ERROR_MESSAGE
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void saveBinaryImageDefaultDirectory(final String path) {
|
||||||
|
PersistentConfiguration.getConfig().getRoot().setProperty(
|
||||||
|
BINARY_IMAGE_DEFAULT_DIRECTORY_PROPERTY_NAME,
|
||||||
|
path
|
||||||
|
);
|
||||||
|
PersistentConfiguration.getConfig().save();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String loadBinaryImageDefaultDirectory() {
|
||||||
|
return PersistentConfiguration.getConfig().getRoot().getProperty(
|
||||||
|
BINARY_IMAGE_DEFAULT_DIRECTORY_PROPERTY_NAME,
|
||||||
|
""
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
private void runTool() {
|
private void runTool() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private JFileChooser createConfigurationImageFileChooser() {
|
||||||
|
final JFileChooser fc = new JFileChooser();
|
||||||
|
fc.setFileSelectionMode(JFileChooser.FILES_ONLY);
|
||||||
|
fc.setFileFilter(new FileNameExtensionFilter("Binary image files (.binary_image)", "binary_image"));
|
||||||
|
|
||||||
|
final String currentDirectory = loadBinaryImageDefaultDirectory();
|
||||||
|
if (currentDirectory != null) {
|
||||||
|
fc.setCurrentDirectory(new File(currentDirectory));
|
||||||
|
}
|
||||||
|
|
||||||
|
return fc;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue