From f49e30d36d9413c40de464ed6f707958882c467f Mon Sep 17 00:00:00 2001 From: kascade Date: Mon, 20 Aug 2007 13:22:11 +0000 Subject: [PATCH] added alpha version of maf scaler git-svn-id: http://svn.3splooges.com/romraider-arch/trunk@777 d2e2e1cd-ba16-0410-be16-b7c4453c7c2d --- logger.xml | 18 +- src/enginuity/logger/ecu/EcuLogger.java | 151 +++++---- .../ecu/ui/handler/maf/MafUpdateHandler.java | 132 ++++++++ .../ecu/ui/handler/maf/XYTrendline.java | 66 ++++ .../logger/ecu/ui/tab/maf/MafChartPanel.java | 89 +++++ .../ecu/ui/tab/maf/MafControlPanel.java | 315 ++++++++++++++++++ src/enginuity/swing/ECUEditorMenuBar.java | 23 +- 7 files changed, 712 insertions(+), 82 deletions(-) create mode 100644 src/enginuity/logger/ecu/ui/handler/maf/MafUpdateHandler.java create mode 100644 src/enginuity/logger/ecu/ui/handler/maf/XYTrendline.java create mode 100644 src/enginuity/logger/ecu/ui/tab/maf/MafChartPanel.java create mode 100644 src/enginuity/logger/ecu/ui/tab/maf/MafControlPanel.java diff --git a/logger.xml b/logger.xml index 8b4a4a26..d71244d6 100644 --- a/logger.xml +++ b/logger.xml @@ -647,10 +647,10 @@ - - + + @@ -661,10 +661,10 @@ - - + + @@ -674,10 +674,10 @@ - - + + @@ -688,12 +688,12 @@ - - + - + + diff --git a/src/enginuity/logger/ecu/EcuLogger.java b/src/enginuity/logger/ecu/EcuLogger.java index e15ee8be..2a71dc17 100644 --- a/src/enginuity/logger/ecu/EcuLogger.java +++ b/src/enginuity/logger/ecu/EcuLogger.java @@ -21,6 +21,59 @@ package enginuity.logger.ecu; +import java.awt.BorderLayout; +import static java.awt.BorderLayout.CENTER; +import static java.awt.BorderLayout.EAST; +import static java.awt.BorderLayout.NORTH; +import static java.awt.BorderLayout.SOUTH; +import static java.awt.BorderLayout.WEST; +import static java.awt.Color.BLACK; +import static java.awt.Color.RED; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.WindowEvent; +import java.awt.event.WindowListener; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.io.File; +import java.util.ArrayList; +import static java.util.Collections.sort; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Vector; +import static javax.swing.BorderFactory.createLoweredBevelBorder; +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JComponent; +import static javax.swing.JComponent.WHEN_IN_FOCUSED_WINDOW; +import javax.swing.JFrame; +import javax.swing.JLabel; +import static javax.swing.JLabel.RIGHT; +import javax.swing.JMenuBar; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import static javax.swing.JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED; +import static javax.swing.JScrollPane.HORIZONTAL_SCROLLBAR_NEVER; +import static javax.swing.JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED; +import javax.swing.JSeparator; +import static javax.swing.JSeparator.VERTICAL; +import javax.swing.JSplitPane; +import static javax.swing.JSplitPane.HORIZONTAL_SPLIT; +import static javax.swing.JSplitPane.VERTICAL_SPLIT; +import javax.swing.JTabbedPane; +import static javax.swing.JTabbedPane.BOTTOM; +import javax.swing.JTable; +import javax.swing.JToggleButton; +import static javax.swing.KeyStroke.getKeyStroke; +import javax.swing.SwingUtilities; +import javax.swing.table.TableColumn; +import enginuity.ECUEditor; import enginuity.Settings; import enginuity.io.port.SerialPortRefresher; import enginuity.logger.ecu.comms.controller.LoggerController; @@ -62,6 +115,7 @@ import enginuity.logger.ecu.ui.handler.file.FileUpdateHandlerImpl; import enginuity.logger.ecu.ui.handler.graph.GraphUpdateHandler; import enginuity.logger.ecu.ui.handler.livedata.LiveDataTableModel; import enginuity.logger.ecu.ui.handler.livedata.LiveDataUpdateHandler; +import enginuity.logger.ecu.ui.handler.maf.MafUpdateHandler; import enginuity.logger.ecu.ui.handler.table.TableUpdateHandler; import enginuity.logger.ecu.ui.paramlist.ParameterListTable; import enginuity.logger.ecu.ui.paramlist.ParameterListTableModel; @@ -75,59 +129,6 @@ import static enginuity.util.ThreadUtil.runAsDaemon; import static enginuity.util.ThreadUtil.sleep; import org.apache.log4j.Logger; -import static javax.swing.BorderFactory.createLoweredBevelBorder; -import javax.swing.ImageIcon; -import javax.swing.JButton; -import javax.swing.JComponent; -import static javax.swing.JComponent.WHEN_IN_FOCUSED_WINDOW; -import javax.swing.JFrame; -import javax.swing.JLabel; -import static javax.swing.JLabel.RIGHT; -import javax.swing.JMenuBar; -import javax.swing.JPanel; -import javax.swing.JScrollPane; -import static javax.swing.JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED; -import static javax.swing.JScrollPane.HORIZONTAL_SCROLLBAR_NEVER; -import static javax.swing.JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED; -import javax.swing.JSeparator; -import static javax.swing.JSeparator.VERTICAL; -import javax.swing.JSplitPane; -import static javax.swing.JSplitPane.HORIZONTAL_SPLIT; -import static javax.swing.JSplitPane.VERTICAL_SPLIT; -import javax.swing.JTabbedPane; -import static javax.swing.JTabbedPane.BOTTOM; -import javax.swing.JTable; -import javax.swing.JToggleButton; -import static javax.swing.KeyStroke.getKeyStroke; -import javax.swing.SwingUtilities; -import javax.swing.table.TableColumn; -import java.awt.BorderLayout; -import static java.awt.BorderLayout.CENTER; -import static java.awt.BorderLayout.EAST; -import static java.awt.BorderLayout.NORTH; -import static java.awt.BorderLayout.SOUTH; -import static java.awt.BorderLayout.WEST; -import static java.awt.Color.BLACK; -import static java.awt.Color.RED; -import java.awt.Component; -import java.awt.Dimension; -import java.awt.FlowLayout; -import java.awt.GridBagConstraints; -import java.awt.GridBagLayout; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.event.WindowEvent; -import java.awt.event.WindowListener; -import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; -import java.io.File; -import java.util.ArrayList; -import static java.util.Collections.sort; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Vector; - /* TODO: add better debug logging, preferably to a file and switchable (on/off) TODO: Clean up this class! @@ -147,6 +148,7 @@ public final class EcuLogger extends JFrame implements WindowListener, PropertyC private static final String HEADING_EXTERNAL = "External"; private static final String CAL_ID_LABEL = "CAL ID"; private static final String ECU_ID_LABEL = "ECU ID"; + private ECUEditor ecuEditor; private Settings settings; private LoggerController controller; private ResetManager resetManager; @@ -178,12 +180,24 @@ public final class EcuLogger extends JFrame implements WindowListener, PropertyC private GraphUpdateHandler graphUpdateHandler; private JPanel dashboardPanel; private DashboardUpdateHandler dashboardUpdateHandler; + private JPanel mafPanel; + private MafUpdateHandler mafUpdateHandler; private EcuInit ecuInit; private JToggleButton logToFileButton; private List externalDataSources; public EcuLogger(Settings settings) { super(ENGINUITY_ECU_LOGGER_TITLE); + construct(settings); + } + + public EcuLogger(ECUEditor ecuEditor) { + super(ENGINUITY_ECU_LOGGER_TITLE); + this.ecuEditor = ecuEditor; + construct(ecuEditor.getSettings()); + } + + private void construct(Settings settings) { bootstrap(settings); loadEcuDefs(); loadLoggerPlugins(); @@ -229,8 +243,10 @@ public final class EcuLogger extends JFrame implements WindowListener, PropertyC graphUpdateHandler = new GraphUpdateHandler(graphPanel); dashboardPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 3, 3)); dashboardUpdateHandler = new DashboardUpdateHandler(dashboardPanel); + mafPanel = new JPanel(new BorderLayout(2, 2)); + mafUpdateHandler = new MafUpdateHandler(mafPanel, ecuEditor); controller = new LoggerControllerImpl(settings, ecuInitCallback, this, liveDataUpdateHandler, - graphUpdateHandler, dashboardUpdateHandler, fileUpdateHandler, TableUpdateHandler.getInstance()); + graphUpdateHandler, dashboardUpdateHandler, mafUpdateHandler, fileUpdateHandler, TableUpdateHandler.getInstance()); resetManager = new ResetManagerImpl(settings, this); messageLabel = new JLabel(ENGINUITY_ECU_LOGGER_TITLE); calIdLabel = new JLabel(buildEcuInfoLabelText(CAL_ID_LABEL, null)); @@ -565,6 +581,7 @@ public final class EcuLogger extends JFrame implements WindowListener, PropertyC tabbedPane.add("Data", buildSplitPane(buildParamListPane(dataTabParamListTableModel, dataTabSwitchListTableModel, dataTabExternalListTableModel), buildDataTab())); tabbedPane.add("Graph", buildSplitPane(buildParamListPane(graphTabParamListTableModel, graphTabSwitchListTableModel, graphTabExternalListTableModel), buildGraphTab())); tabbedPane.add("Dashboard", buildSplitPane(buildParamListPane(dashboardTabParamListTableModel, dashboardTabSwitchListTableModel, dashboardTabExternalListTableModel), buildDashboardTab())); + tabbedPane.add("MAF", mafPanel); return tabbedPane; } @@ -948,23 +965,36 @@ public final class EcuLogger extends JFrame implements WindowListener, PropertyC //********************************************************************** - public static void startLogger(final int defaultCloseOperation, final Settings settings) { + public static void startLogger(int defaultCloseOperation, ECUEditor ecuEditor) { + // instantiate the controlling class. + final EcuLogger ecuLogger = new EcuLogger(ecuEditor); + createAndShowGui(defaultCloseOperation, ecuLogger); + } + + public static void startLogger(int defaultCloseOperation, Settings settings) { + // instantiate the controlling class. + final EcuLogger ecuLogger = new EcuLogger(settings); + createAndShowGui(defaultCloseOperation, ecuLogger); + } + + private static void createAndShowGui(final int defaultCloseOperation, final EcuLogger ecuLogger) { SwingUtilities.invokeLater(new Runnable() { public void run() { - createAndShowGUI(defaultCloseOperation, settings); + doCreateAndShowGui(defaultCloseOperation, ecuLogger); } }); } - private static void createAndShowGUI(int defaultCloseOperation, Settings settings) { - // instantiate the controlling class. - EcuLogger ecuLogger = new EcuLogger(settings); + private static void doCreateAndShowGui(int defaultCloseOperation, EcuLogger ecuLogger) { + Settings settings = ecuLogger.getSettings(); + + // set default close operation + ecuLogger.setDefaultCloseOperation(defaultCloseOperation); // set remaining window properties ecuLogger.pack(); ecuLogger.setSize(settings.getLoggerWindowSize()); ecuLogger.setIconImage(new ImageIcon("./graphics/enginuity-ico.gif").getImage()); - ecuLogger.setDefaultCloseOperation(defaultCloseOperation); ecuLogger.addWindowListener(ecuLogger); // display the window @@ -974,5 +1004,4 @@ public final class EcuLogger extends JFrame implements WindowListener, PropertyC } ecuLogger.setVisible(true); } - } diff --git a/src/enginuity/logger/ecu/ui/handler/maf/MafUpdateHandler.java b/src/enginuity/logger/ecu/ui/handler/maf/MafUpdateHandler.java new file mode 100644 index 00000000..8dbe914b --- /dev/null +++ b/src/enginuity/logger/ecu/ui/handler/maf/MafUpdateHandler.java @@ -0,0 +1,132 @@ +package enginuity.logger.ecu.ui.handler.maf; + +import static java.awt.BorderLayout.CENTER; +import static java.awt.BorderLayout.WEST; +import java.util.Set; +import javax.swing.JPanel; +import javax.swing.SwingUtilities; +import enginuity.ECUEditor; +import enginuity.logger.ecu.comms.query.Response; +import enginuity.logger.ecu.definition.LoggerData; +import enginuity.logger.ecu.ui.handler.DataUpdateHandler; +import enginuity.logger.ecu.ui.tab.maf.MafChartPanel; +import enginuity.logger.ecu.ui.tab.maf.MafControlPanel; +import org.jfree.data.xy.XYSeries; + +public final class MafUpdateHandler implements DataUpdateHandler { + private static final String MAFV = "P18"; + private static final String AF_LEARNING_1 = "P4"; + private static final String AF_CORRECTION_1 = "P3"; + private final XYSeries series = new XYSeries("MAF Analysis"); + private final XYTrendline trendline = new XYTrendline(); + private final JPanel mafPanel; + private final ECUEditor ecuEditor; + private final MafControlPanel controlPanel; + + public MafUpdateHandler(JPanel mafPanel, ECUEditor ecuEditor) { + this.mafPanel = mafPanel; + this.ecuEditor = ecuEditor; + controlPanel = buildControlPanel(); + mafPanel.add(controlPanel, WEST); + mafPanel.add(buildGraphPanel(), CENTER); + } + + private MafControlPanel buildControlPanel() { + return new MafControlPanel(mafPanel, trendline, series, ecuEditor); + } + + private MafChartPanel buildGraphPanel() { + return new MafChartPanel(trendline, series); + } + + public synchronized void registerData(LoggerData loggerData) { + } + + public synchronized void handleDataUpdate(Response response) { + if (controlPanel.isRecordData() && containsData(response, MAFV, AF_LEARNING_1, AF_CORRECTION_1)) { + boolean valid = true; + + // cl/ol check +// if (valid && (containsData(response, "E3") || containsData(response, "E27"))) { +// double clOl = -1; +// if (containsData(response, "E3")) { +// clOl = (int) findValue(response, "E3"); +// } +// if (containsData(response, "E27")) { +// clOl = (int) findValue(response, "E27"); +// } +// valid = clOl == 8; +// } + + // afr check + if (valid && containsData(response, "P58")) { + double afr = findValue(response, "P58"); + valid = controlPanel.isValidAfr(afr); + } + + // rpm check + if (valid && containsData(response, "P8")) { + double rpm = findValue(response, "P8"); + valid = controlPanel.isValidRpm(rpm); + } + + // maf check + if (valid && containsData(response, "P12")) { + double maf = findValue(response, "P12"); + valid = controlPanel.isValidMaf(maf); + } + + // coolant temp check + if (valid && containsData(response, "P2")) { + double temp = findValue(response, "P2"); + valid = controlPanel.isValidCoolantTemp(temp); + } + + if (valid) { + final double mafv = findValue(response, MAFV); + final double learning = findValue(response, AF_LEARNING_1); + final double correction = findValue(response, AF_CORRECTION_1); + SwingUtilities.invokeLater(new Runnable() { + public void run() { + series.add(mafv, learning + correction); + } + }); + } + } + } + + private boolean containsData(Response response, String... ids) { + Set datas = response.getData(); + for (String id : ids) { + boolean found = false; + for (LoggerData data : datas) { + if (data.getId().equals(id)) { + found = true; + break; + } + } + if (!found) { + return false; + } + } + return true; + } + + private double findValue(Response response, String id) { + for (final LoggerData loggerData : response.getData()) { + if (id.equals(loggerData.getId())) { + return response.getDataValue(loggerData); + } + } + throw new IllegalStateException("Expected data item " + id + " not in response."); + } + + public synchronized void deregisterData(LoggerData loggerData) { + } + + public synchronized void cleanUp() { + } + + public synchronized void reset() { + } +} diff --git a/src/enginuity/logger/ecu/ui/handler/maf/XYTrendline.java b/src/enginuity/logger/ecu/ui/handler/maf/XYTrendline.java new file mode 100644 index 00000000..9244f25f --- /dev/null +++ b/src/enginuity/logger/ecu/ui/handler/maf/XYTrendline.java @@ -0,0 +1,66 @@ +package enginuity.logger.ecu.ui.handler.maf; + +import java.lang.reflect.UndeclaredThrowableException; +import java.util.ArrayList; +import java.util.List; +import jamlab.Polyfit; +import jamlab.Polyval; +import org.jfree.data.xy.AbstractXYDataset; +import org.jfree.data.xy.XYDataItem; +import org.jfree.data.xy.XYSeries; + +public final class XYTrendline extends AbstractXYDataset { + private List items = new ArrayList(); + private double[] xVals = new double[0]; + private double[] yPoly = new double[0]; + private Polyfit polyfit; + + public int getSeriesCount() { + return 1; + } + + public Comparable getSeriesKey(int seriesIndex) { + return "foo"; + } + + public synchronized int getItemCount(int seriesIndex) { + return yPoly.length; + } + + public synchronized Number getY(int seriesIndex, int item) { + return yPoly[item]; + } + + public synchronized Number getX(int seriesIndex, int item) { + return xVals[item]; + } + + public synchronized void update(XYSeries series, int order) { + if (series.getItemCount() <= order) return; + items = new ArrayList(series.getItems()); + xVals = new double[items.size()]; + double[] yVals = new double[items.size()]; + for (int i = 0; i < items.size(); i++) { + XYDataItem dataItem = items.get(i); + xVals[i] = dataItem.getX().doubleValue(); + yVals[i] = dataItem.getY().doubleValue(); + } + try { + polyfit = new Polyfit(xVals, yVals, order); + yPoly = calculate(xVals); + } catch (Exception e) { + throw new UndeclaredThrowableException(e); + } + } + + public synchronized double[] calculate(double[] x) { + Polyval polyval = new Polyval(x, polyfit); + return polyval.getYout(); + } + + public synchronized void clear() { + items.clear(); + xVals = new double[0]; + yPoly = new double[0]; + } +} diff --git a/src/enginuity/logger/ecu/ui/tab/maf/MafChartPanel.java b/src/enginuity/logger/ecu/ui/tab/maf/MafChartPanel.java new file mode 100644 index 00000000..3606ed0b --- /dev/null +++ b/src/enginuity/logger/ecu/ui/tab/maf/MafChartPanel.java @@ -0,0 +1,89 @@ +package enginuity.logger.ecu.ui.tab.maf; + +import java.awt.Color; +import java.awt.Dimension; +import javax.swing.JPanel; +import javax.swing.SpringLayout; +import enginuity.logger.ecu.ui.handler.graph.SpringUtilities; +import enginuity.logger.ecu.ui.handler.maf.XYTrendline; +import static enginuity.util.ParamChecker.checkNotNull; +import org.jfree.chart.ChartFactory; +import org.jfree.chart.ChartPanel; +import org.jfree.chart.JFreeChart; +import static org.jfree.chart.plot.PlotOrientation.VERTICAL; +import org.jfree.chart.plot.XYPlot; +import org.jfree.chart.renderer.xy.StandardXYItemRenderer; +import org.jfree.chart.renderer.xy.XYDotRenderer; +import org.jfree.data.xy.XYDataset; +import org.jfree.data.xy.XYSeries; +import org.jfree.data.xy.XYSeriesCollection; + +public final class MafChartPanel extends JPanel { + private static final Color DARK_GREY = new Color(80, 80, 80); + private static final Color LIGHT_GREY = new Color(110, 110, 110); + private final XYTrendline trendline; + private final XYSeries series; + + public MafChartPanel(XYTrendline trendline, XYSeries series) { + super(new SpringLayout()); + checkNotNull(trendline, series); + this.trendline = trendline; + this.series = series; + addChart(); + } + + private void addChart() { + ChartPanel chartPanel = new ChartPanel(createChart(), false, true, true, true, true); + chartPanel.setMinimumSize(new Dimension(500, 400)); + chartPanel.setPreferredSize(new Dimension(500, 400)); + add(chartPanel); + SpringUtilities.makeCompactGrid(this, 1, 1, 2, 2, 2, 2); + } + + private JFreeChart createChart() { + XYDataset dataset = buildDataset(); + return buildChart(dataset); + } + + private XYSeriesCollection buildDataset() { + return new XYSeriesCollection(series); + } + + private JFreeChart buildChart(XYDataset dataset) { + JFreeChart chart = ChartFactory.createScatterPlot(null, "MAF (v)", "Total Correction (%)", dataset, VERTICAL, false, true, false); + chart.setBackgroundPaint(Color.BLACK); + configurePlot(chart); + addTrendLine(chart); + return chart; + } + + private void configurePlot(JFreeChart chart) { + XYPlot plot = chart.getXYPlot(); + plot.setBackgroundPaint(Color.BLACK); + plot.getDomainAxis().setLabelPaint(Color.WHITE); + plot.getRangeAxis().setLabelPaint(Color.WHITE); + plot.getDomainAxis().setTickLabelPaint(LIGHT_GREY); + plot.getRangeAxis().setTickLabelPaint(LIGHT_GREY); + plot.setDomainGridlinePaint(DARK_GREY); + plot.setRangeGridlinePaint(DARK_GREY); + plot.setOutlinePaint(DARK_GREY); + plot.setRenderer(buildScatterRenderer()); + } + + private XYDotRenderer buildScatterRenderer() { + XYDotRenderer renderer = new XYDotRenderer(); + renderer.setDotHeight(2); + renderer.setDotWidth(2); + return renderer; + } + + private void addTrendLine(JFreeChart chart) { + XYPlot plot = chart.getXYPlot(); + plot.setDataset(1, trendline); + plot.setRenderer(1, buildTrendLineRenderer()); + } + + private StandardXYItemRenderer buildTrendLineRenderer() { + return new StandardXYItemRenderer(); + } +} diff --git a/src/enginuity/logger/ecu/ui/tab/maf/MafControlPanel.java b/src/enginuity/logger/ecu/ui/tab/maf/MafControlPanel.java new file mode 100644 index 00000000..0a902411 --- /dev/null +++ b/src/enginuity/logger/ecu/ui/tab/maf/MafControlPanel.java @@ -0,0 +1,315 @@ +package enginuity.logger.ecu.ui.tab.maf; + +import java.awt.Component; +import java.awt.GridBagConstraints; +import static java.awt.GridBagConstraints.CENTER; +import static java.awt.GridBagConstraints.HORIZONTAL; +import static java.awt.GridBagConstraints.NONE; +import java.awt.GridBagLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import javax.swing.JButton; +import javax.swing.JComboBox; +import javax.swing.JComponent; +import javax.swing.JLabel; +import static javax.swing.JOptionPane.ERROR_MESSAGE; +import static javax.swing.JOptionPane.OK_OPTION; +import static javax.swing.JOptionPane.WARNING_MESSAGE; +import static javax.swing.JOptionPane.YES_NO_OPTION; +import static javax.swing.JOptionPane.showConfirmDialog; +import static javax.swing.JOptionPane.showMessageDialog; +import javax.swing.JPanel; +import javax.swing.JTextField; +import javax.swing.JToggleButton; +import javax.swing.border.TitledBorder; +import enginuity.ECUEditor; +import enginuity.logger.ecu.ui.handler.maf.XYTrendline; +import enginuity.maps.DataCell; +import enginuity.maps.Rom; +import enginuity.maps.Table2D; +import static enginuity.util.ParamChecker.checkNotNull; +import org.jfree.data.xy.XYSeries; + +public final class MafControlPanel extends JPanel { + private final JToggleButton recordDataButton = new JToggleButton("Record Data"); + private final JTextField mafvMin = new JTextField("1.20", 3); + private final JTextField mafvMax = new JTextField("2.60", 3); + private final JTextField afrMin = new JTextField("14.0", 3); + private final JTextField afrMax = new JTextField("16.0", 3); + private final JTextField rpmMin = new JTextField("0", 3); + private final JTextField rpmMax = new JTextField("4500", 3); + private final JTextField mafMin = new JTextField("0", 3); + private final JTextField mafMax = new JTextField("100", 3); + private final JTextField coolantMin = new JTextField("80", 3); + private final Component parent; + private final XYTrendline trendline; + private final XYSeries series; + private final ECUEditor ecuEditor; + + public MafControlPanel(Component parent, XYTrendline trendline, XYSeries series, ECUEditor ecuEditor) { + checkNotNull(parent, trendline, series); + this.parent = parent; + this.trendline = trendline; + this.series = series; + this.ecuEditor = ecuEditor; + addControls(); + } + + public boolean isRecordData() { + return recordDataButton.isSelected(); + } + + public boolean isValidAfr(double value) { + return checkInRange("AFR", afrMin, afrMax, value); + } + + public boolean isValidRpm(double value) { + return checkInRange("RPM", rpmMin, rpmMax, value); + } + + public boolean isValidMaf(double value) { + return checkInRange("MAF", mafMin, mafMax, value); + } + + public boolean isValidMafv(double value) { + return checkInRange("MAFv", mafvMin, mafvMax, value); + } + + public boolean isValidCoolantTemp(double value) { + return checkGreaterThan("Coolant Temp.", coolantMin, value); + } + + private boolean checkInRange(String name, JTextField min, JTextField max, double value) { + if (isValidRange(min, max)) { + return inRange(value, min, max); + } else { + showMessageDialog(parent, "Invalid " + name + " range specified.", "Error", ERROR_MESSAGE); + recordDataButton.setSelected(false); + return false; + } + } + + private boolean checkGreaterThan(String name, JTextField min, double value) { + if (isNumber(min)) { + return value >= parseDouble(min); + } else { + showMessageDialog(parent, "Invalid " + name + " specified.", "Error", ERROR_MESSAGE); + recordDataButton.setSelected(false); + return false; + } + } + + private void addControls() { + JPanel panel = new JPanel(); + + GridBagLayout gridBagLayout = new GridBagLayout(); + panel.setLayout(gridBagLayout); + + add(panel, gridBagLayout, buildFilterPanel(), 0, 0, 1, HORIZONTAL); + add(panel, gridBagLayout, buildInterpolatePanel(), 0, 1, 1, HORIZONTAL); + add(panel, gridBagLayout, buildUpdateMafPanel(), 0, 2, 1, HORIZONTAL); + add(panel, gridBagLayout, buildResetPanel(), 0, 3, 1, HORIZONTAL); + + add(panel); + } + + private void add(JPanel panel, GridBagLayout gridBagLayout, JComponent component, int x, int y, int spanX, int fillType) { + GridBagConstraints constraints = buildBaseConstraints(); + updateConstraints(constraints, x, y, spanX, 1, 1, 1, fillType); + gridBagLayout.setConstraints(component, constraints); + panel.add(component); + } + + private JPanel buildResetPanel() { + JPanel panel = new JPanel(); + panel.setBorder(new TitledBorder("Reset")); + panel.add(buildResetButton()); + return panel; + } + + private JPanel buildUpdateMafPanel() { + JPanel panel = new JPanel(); + panel.setBorder(new TitledBorder("Update MAF")); + + GridBagLayout gridBagLayout = new GridBagLayout(); + panel.setLayout(gridBagLayout); + + addMinMaxFilter(panel, gridBagLayout, "MAFv Range", mafvMin, mafvMax, 0); + addComponent(panel, gridBagLayout, buildUpdateMafButton(), 3); + + return panel; + } + + private JPanel buildInterpolatePanel() { + JPanel panel = new JPanel(); + panel.setBorder(new TitledBorder("Interpolate")); + + GridBagLayout gridBagLayout = new GridBagLayout(); + panel.setLayout(gridBagLayout); + + JComboBox orderComboBox = buildPolyOrderComboBox(); + addLabeledComponent(panel, gridBagLayout, "Poly. order", orderComboBox, 0); + addComponent(panel, gridBagLayout, buildInterpolateButton(orderComboBox), 2); + + return panel; + } + + private void addLabeledComponent(JPanel panel, GridBagLayout gridBagLayout, String name, JComponent component, int y) { + add(panel, gridBagLayout, new JLabel(name), 0, y, 3, HORIZONTAL); + add(panel, gridBagLayout, component, 0, y + 1, 3, NONE); + } + + private JPanel buildFilterPanel() { + JPanel panel = new JPanel(); + panel.setBorder(new TitledBorder("Filter Data")); + + GridBagLayout gridBagLayout = new GridBagLayout(); + panel.setLayout(gridBagLayout); + + addMinMaxFilter(panel, gridBagLayout, "AFR Range", afrMin, afrMax, 0); + addMinMaxFilter(panel, gridBagLayout, "RPM Range", rpmMin, rpmMax, 3); + addMinMaxFilter(panel, gridBagLayout, "MAF Range (g/s)", mafMin, mafMax, 6); + addLabeledComponent(panel, gridBagLayout, "Min. Coolant Temp.", coolantMin, 9); + addComponent(panel, gridBagLayout, recordDataButton, 12); + + return panel; + } + + private void addComponent(JPanel panel, GridBagLayout gridBagLayout, JComponent component, int y) { + add(panel, gridBagLayout, component, 0, y, 3, HORIZONTAL); + } + + private void addMinMaxFilter(JPanel panel, GridBagLayout gridBagLayout, String name, JTextField min, JTextField max, int y) { + add(panel, gridBagLayout, new JLabel(name), 0, y, 3, HORIZONTAL); + y += 1; + add(panel, gridBagLayout, min, 0, y, 1, NONE); + add(panel, gridBagLayout, new JLabel(" - "), 1, y, 1, NONE); + add(panel, gridBagLayout, max, 2, y, 1, NONE); + } + + private GridBagConstraints buildBaseConstraints() { + GridBagConstraints constraints = new GridBagConstraints(); + constraints.anchor = CENTER; + constraints.fill = NONE; + return constraints; + } + + private void updateConstraints(GridBagConstraints constraints, int gridx, int gridy, int gridwidth, int gridheight, int weightx, int weighty, int fill) { + constraints.gridx = gridx; + constraints.gridy = gridy; + constraints.gridwidth = gridwidth; + constraints.gridheight = gridheight; + constraints.weightx = weightx; + constraints.weighty = weighty; + constraints.fill = fill; + } + + private JButton buildResetButton() { + JButton resetButton = new JButton("Reset Data"); + resetButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent actionEvent) { + trendline.clear(); + series.clear(); + parent.repaint(); + } + }); + return resetButton; + } + + private JButton buildInterpolateButton(final JComboBox orderComboBox) { + JButton interpolateButton = new JButton("Interpolate"); + interpolateButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent actionEvent) { + trendline.update(series, (Integer) orderComboBox.getSelectedItem()); + parent.repaint(); + } + }); + return interpolateButton; + } + + private JComboBox buildPolyOrderComboBox() { + final JComboBox orderComboBox = new JComboBox(new Object[]{3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20}); + orderComboBox.setSelectedItem(10); + return orderComboBox; + } + + private JButton buildUpdateMafButton() { + final JButton updateMafButton = new JButton("Update MAF"); + updateMafButton.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent actionEvent) { + Table2D table = getMafTable(ecuEditor); + if (table != null) { + if (showUpdateMafConfirmation() == OK_OPTION) { + if (isValidRange(mafvMin, mafvMax)) { + DataCell[] axisCells = table.getAxis().getData(); + double[] x = new double[axisCells.length]; + for (int i = 0; i < axisCells.length; i++) { + DataCell cell = axisCells[i]; + x[i] = cell.getValue(); + } + double[] percentChange = trendline.calculate(x); + DataCell[] dataCells = table.getData(); + for (int i = 0; i < dataCells.length; i++) { + if (inRange(axisCells[i].getValue(), mafvMin, mafvMax)) { + DataCell cell = dataCells[i]; + double value = cell.getValue(); + cell.setRealValue(String.valueOf(value * (1.0 + percentChange[i] / 100.0))); + } + } + table.colorize(); + } else { + showMessageDialog(parent, "Invalid MAFv range specified.", "Error", ERROR_MESSAGE); + } + } + } + } + }); + return updateMafButton; + } + + private boolean areNumbers(JTextField... textFields) { + for (JTextField field : textFields) { + if (!isNumber(field)) return false; + } + return true; + } + + private boolean isValidRange(JTextField min, JTextField max) { + return areNumbers(min, max) && parseDouble(min) < parseDouble(max); + } + + private boolean isNumber(JTextField textField) { + try { + parseDouble(textField); + return true; + } catch (Exception e) { + return false; + } + } + + private boolean inRange(double val, double min, double max) { + return val >= min && val <= max; + } + + private boolean inRange(double value, JTextField min, JTextField max) { + return inRange(value, parseDouble(min), parseDouble(max)); + } + + private double parseDouble(JTextField field) { + return Double.parseDouble(field.getText().trim()); + } + + private int showUpdateMafConfirmation() { + return showConfirmDialog(parent, "Update MAF Sensor Scaling table?", "Confirm Update", YES_NO_OPTION, WARNING_MESSAGE); + } + + private Table2D getMafTable(ECUEditor ecuEditor) { + try { + Rom rom = ecuEditor.getLastSelectedRom(); + return (Table2D) rom.getTable("MAF Sensor Scaling"); + } catch (Exception e) { + showMessageDialog(parent, "MAF Sensor Scaling table not found.", "Error", ERROR_MESSAGE); + return null; + } + } +} diff --git a/src/enginuity/swing/ECUEditorMenuBar.java b/src/enginuity/swing/ECUEditorMenuBar.java index 59402c42..aaef2e9b 100644 --- a/src/enginuity/swing/ECUEditorMenuBar.java +++ b/src/enginuity/swing/ECUEditorMenuBar.java @@ -21,13 +21,10 @@ package enginuity.swing; -import com.centerkey.utils.BareBonesBrowserLaunch; -import enginuity.ECUEditor; -import enginuity.logger.ecu.EcuLogger; -import enginuity.logger.utec.gui.JutecGUI; -import enginuity.maps.Rom; -import enginuity.ramtune.test.RamTuneTestApp; - +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.io.File; +import java.io.FileOutputStream; import javax.swing.ButtonGroup; import javax.swing.JFileChooser; import static javax.swing.JFrame.DISPOSE_ON_CLOSE; @@ -41,10 +38,12 @@ import static javax.swing.JOptionPane.showConfirmDialog; import static javax.swing.JOptionPane.showMessageDialog; import javax.swing.JRadioButtonMenuItem; import javax.swing.JSeparator; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.io.File; -import java.io.FileOutputStream; +import com.centerkey.utils.BareBonesBrowserLaunch; +import enginuity.ECUEditor; +import enginuity.logger.ecu.EcuLogger; +import enginuity.logger.utec.gui.JutecGUI; +import enginuity.maps.Rom; +import enginuity.ramtune.test.RamTuneTestApp; public class ECUEditorMenuBar extends JMenuBar implements ActionListener { @@ -289,7 +288,7 @@ public class ECUEditorMenuBar extends JMenuBar implements ActionListener { parent.setUserLevel(5); } else if (e.getSource() == openLogger) { - EcuLogger.startLogger(DISPOSE_ON_CLOSE, parent.getSettings()); + EcuLogger.startLogger(DISPOSE_ON_CLOSE, parent); } else if (e.getSource() == utecLogger) { JutecGUI.startLogger(DISPOSE_ON_CLOSE, parent.getSettings());