diff --git a/lib/logger/jcommon-1.0.0.jar b/lib/logger/jcommon-1.0.0.jar new file mode 100644 index 00000000..c5d23f4a Binary files /dev/null and b/lib/logger/jcommon-1.0.0.jar differ diff --git a/lib/logger/jfreechart-1.0.1.jar b/lib/logger/jfreechart-1.0.1.jar new file mode 100644 index 00000000..6a015249 Binary files /dev/null and b/lib/logger/jfreechart-1.0.1.jar differ diff --git a/lib/rxtx/INSTALL b/lib/logger/rxtx/INSTALL similarity index 100% rename from lib/rxtx/INSTALL rename to lib/logger/rxtx/INSTALL diff --git a/lib/rxtx/RXTXcomm.jar b/lib/logger/rxtx/RXTXcomm.jar similarity index 100% rename from lib/rxtx/RXTXcomm.jar rename to lib/logger/rxtx/RXTXcomm.jar diff --git a/lib/rxtx/rxtxSerial.dll b/lib/logger/rxtx/rxtxSerial.dll similarity index 100% rename from lib/rxtx/rxtxSerial.dll rename to lib/logger/rxtx/rxtxSerial.dll diff --git a/src/enginuity/logger/EcuLogger.java b/src/enginuity/logger/EcuLogger.java index 813879f9..a1d0e023 100644 --- a/src/enginuity/logger/EcuLogger.java +++ b/src/enginuity/logger/EcuLogger.java @@ -5,12 +5,20 @@ import enginuity.logger.definition.EcuParameter; import enginuity.logger.definition.EcuParameterImpl; import enginuity.logger.definition.convertor.AcceleratorOpeningAngleConvertor; import enginuity.logger.definition.convertor.AirFuelRatioLambdaConvertor; -import enginuity.logger.definition.convertor.EcuParameterConvertor; +import enginuity.logger.definition.convertor.EngineSpeedConvertor; import enginuity.logger.definition.convertor.ExhaustGasTemperatureConvertor; import enginuity.logger.definition.convertor.GenericTemperatureConvertor; import enginuity.logger.definition.convertor.ThrottleOpeningAngleConvertor; import enginuity.logger.query.LoggerCallback; -import static enginuity.util.HexUtil.asHex; +import enginuity.logger.ui.LoggerDataRow; +import enginuity.logger.ui.LoggerDataTableModel; +import enginuity.logger.ui.SpringUtilities; +import org.jfree.chart.ChartFactory; +import org.jfree.chart.JFreeChart; +import org.jfree.chart.plot.PlotOrientation; +import org.jfree.data.xy.XYDataset; +import org.jfree.data.xy.XYSeries; +import org.jfree.data.xy.XYSeriesCollection; import javax.swing.*; import static javax.swing.JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED; @@ -29,9 +37,10 @@ import java.util.List; public final class EcuLogger extends JFrame implements WindowListener, PropertyChangeListener { private final Settings settings = new Settings(); private final LoggerController CONTROLLER = new LoggerControllerImpl(settings); - private final JTable dataTable = new JTable(); - private final JTextArea dataTextArea = new JTextArea(); + private final LoggerDataTableModel dataTableModel = new LoggerDataTableModel(); + private final JPanel graphPanel = new JPanel(); private final JComboBox portsComboBox = new JComboBox(); + private int loggerCount = 0; public EcuLogger(String title) { super(title); @@ -49,98 +58,63 @@ public final class EcuLogger extends JFrame implements WindowListener, PropertyC // add test address to log (0x000008 = coolant temp, 8bit) final EcuParameter ecuParam1 = new EcuParameterImpl("Coolant Temperature", "Coolant temperature in degrees C", "0x000008", new GenericTemperatureConvertor()); - CONTROLLER.addLogger(ecuParam1, new LoggerCallback() { - public void callback(byte[] value, EcuParameterConvertor convertor) { - dataTextArea.append(ecuParam1.getName() + " (" + ecuParam1.getAddress() + ") => " + asHex(value) + " => " + convertor.convert(value) - + " " + convertor.getUnits() + "\n"); - } - }); + registerEcuParameterForLogging(ecuParam1); // add test address to log (0x000106 = EGT, 8bit) final EcuParameter ecuParam2 = new EcuParameterImpl("EGT", "Exhaust gas temperature in degrees C", "0x000106", new ExhaustGasTemperatureConvertor()); - CONTROLLER.addLogger(ecuParam2, new LoggerCallback() { - public void callback(byte[] value, EcuParameterConvertor convertor) { - dataTextArea.append(ecuParam2.getName() + " (" + ecuParam2.getAddress() + ") => " + asHex(value) + " => " + convertor.convert(value) - + " " + convertor.getUnits() + "\n"); - } - }); + registerEcuParameterForLogging(ecuParam2); // add test address to log (0x000046 = air/fuel ratio, 8bit) final EcuParameter ecuParam3 = new EcuParameterImpl("AFR", "Air/Fuel Ratio in Lambda", "0x000046", new AirFuelRatioLambdaConvertor()); - CONTROLLER.addLogger(ecuParam3, new LoggerCallback() { - public void callback(byte[] value, EcuParameterConvertor convertor) { - dataTextArea.append(ecuParam3.getName() + " (" + ecuParam3.getAddress() + ") => " + asHex(value) + " => " + convertor.convert(value) - + " " + convertor.getUnits() + "\n"); - } - }); + registerEcuParameterForLogging(ecuParam3); // add test address to log (0x000029 = accelerator opening angle, 8bit) final EcuParameter ecuParam4 = new EcuParameterImpl("Accel Opening Angle", "Accelerator opening angle in %", "0x000029", new AcceleratorOpeningAngleConvertor()); - CONTROLLER.addLogger(ecuParam4, new LoggerCallback() { - public void callback(byte[] value, EcuParameterConvertor convertor) { - dataTextArea.append(ecuParam4.getName() + " (" + ecuParam4.getAddress() + ") => " + asHex(value) + " => " + convertor.convert(value) - + " " + convertor.getUnits() + "\n"); - } - }); + registerEcuParameterForLogging(ecuParam4); // add test address to log (0x000015 = accelerator opening angle, 8bit) final EcuParameter ecuParam5 = new EcuParameterImpl("Throttle Opening Angle", "Throttle opening angle in %", "0x000015", new ThrottleOpeningAngleConvertor()); - CONTROLLER.addLogger(ecuParam5, new LoggerCallback() { - public void callback(byte[] value, EcuParameterConvertor convertor) { - dataTextArea.append(ecuParam5.getName() + " (" + ecuParam5.getAddress() + ") => " + asHex(value) + " => " + convertor.convert(value) - + " " + convertor.getUnits() + "\n"); - } - }); + registerEcuParameterForLogging(ecuParam5); // add test address to log (0x00000E 0x00000F = engine speed, 16bit) -// final EcuParameter ecuParam5 = new EcuParameterImpl("Engine Speed", "Engine speed in rpm", "0x00000E00000F", new EngineSpeedConvertor()); -// CONTROLLER.addLogger(ecuParam5, new LoggerCallback() { -// public void callback(byte[] value, EcuParameterConvertor convertor) { -// dataTextArea.append(ecuParam5.getName() + " (" + ecuParam5.getAddress() + ") => " + asHex(value) + " => " + convertor.convert(value) -// + " " + convertor.getUnits() + "\n"); -// } -// }); + final EcuParameter ecuParam6 = new EcuParameterImpl("Engine Speed", "Engine speed in rpm", "0x00000E00000F", new EngineSpeedConvertor()); + registerEcuParameterForLogging(ecuParam6); + } - public static void main(String... args) { - SwingUtilities.invokeLater(new Runnable() { - public void run() { - createAndShowGUI(); + private void registerEcuParameterForLogging(final EcuParameter ecuParam) { + // add to data table + final LoggerDataRow dataRow = new LoggerDataRow(ecuParam); + dataTableModel.addRow(dataRow); + + // add to charts + final XYSeries series = new XYSeries(ecuParam.getName()); + final XYDataset xyDataset = new XYSeriesCollection(series); + final JFreeChart chart = ChartFactory.createXYLineChart(ecuParam.getName(), "Time (ms)", ecuParam.getName() + " (" + ecuParam.getConvertor().getUnits() + ")", + xyDataset, PlotOrientation.VERTICAL, true, true, false); + final JLabel chartLabel = new JLabel(); + chartLabel.setIcon(new ImageIcon(chart.createBufferedImage(500, 300))); + graphPanel.add(chartLabel); + SpringUtilities.makeCompactGrid(graphPanel, ++loggerCount, 1, 10, 10, 20, 20); + + // add to dashboard + + // add logger and setup callback + CONTROLLER.addLogger(ecuParam, new LoggerCallback() { + public void callback(byte[] value) { + // update data table + dataRow.updateValue(value); + + // update graph + series.add(System.currentTimeMillis(), ecuParam.getConvertor().convert(value)); + chartLabel.setIcon(new ImageIcon(chart.createBufferedImage(500, 300))); + + // update dashboard + } }); } - private static void createAndShowGUI() { - //set look and feel - setLookAndFeel(); - - //make sure we have nice window decorations. - setDefaultLookAndFeelDecorated(true); - JDialog.setDefaultLookAndFeelDecorated(true); - - //instantiate the controlling class. - EcuLogger ecuLogger = new EcuLogger("Enginuity ECU Logger"); - - //set remaining window properties - ecuLogger.setSize(new Dimension(1000, 600)); - ecuLogger.setIconImage(new ImageIcon("./graphics/enginuity-ico.gif").getImage()); - ecuLogger.setDefaultCloseOperation(EXIT_ON_CLOSE); - ecuLogger.addWindowListener(ecuLogger); - - //display the window - ecuLogger.setLocationRelativeTo(null); //center it - ecuLogger.setVisible(true); - } - - private static void setLookAndFeel() { - try { - //use the system look and feel. - UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); - } catch (Exception e) { - e.printStackTrace(); - } - } - private JComponent buildLeftComponent() { JTable parameterList = new JTable(); return new JScrollPane(parameterList, VERTICAL_SCROLLBAR_AS_NEEDED, HORIZONTAL_SCROLLBAR_AS_NEEDED); @@ -217,12 +191,11 @@ public final class EcuLogger extends JFrame implements WindowListener, PropertyC } private JComponent buildDataTab() { - //return new JScrollPane(dataTable, VERTICAL_SCROLLBAR_AS_NEEDED, HORIZONTAL_SCROLLBAR_NEVER); - return new JScrollPane(dataTextArea, VERTICAL_SCROLLBAR_AS_NEEDED, HORIZONTAL_SCROLLBAR_NEVER); + return new JScrollPane(new JTable(dataTableModel), VERTICAL_SCROLLBAR_AS_NEEDED, HORIZONTAL_SCROLLBAR_NEVER); } private JComponent buildGraphTab() { - JPanel graphPanel = new JPanel(); + graphPanel.setLayout(new SpringLayout()); return new JScrollPane(graphPanel, VERTICAL_SCROLLBAR_AS_NEEDED, HORIZONTAL_SCROLLBAR_NEVER); } @@ -256,4 +229,43 @@ public final class EcuLogger extends JFrame implements WindowListener, PropertyC public void propertyChange(PropertyChangeEvent propertyChangeEvent) { } + public static void main(String... args) { + SwingUtilities.invokeLater(new Runnable() { + public void run() { + createAndShowGUI(); + } + }); + } + + private static void createAndShowGUI() { + //set look and feel + setLookAndFeel(); + + //make sure we have nice window decorations. + setDefaultLookAndFeelDecorated(true); + JDialog.setDefaultLookAndFeelDecorated(true); + + //instantiate the controlling class. + EcuLogger ecuLogger = new EcuLogger("Enginuity ECU Logger"); + + //set remaining window properties + ecuLogger.setSize(new Dimension(1000, 600)); + ecuLogger.setIconImage(new ImageIcon("./graphics/enginuity-ico.gif").getImage()); + ecuLogger.setDefaultCloseOperation(EXIT_ON_CLOSE); + ecuLogger.addWindowListener(ecuLogger); + + //display the window + ecuLogger.setLocationRelativeTo(null); //center it + ecuLogger.setVisible(true); + } + + private static void setLookAndFeel() { + try { + //use the system look and feel. + UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); + } catch (Exception e) { + e.printStackTrace(); + } + } + } diff --git a/src/enginuity/logger/comms/SerialConnectionImpl.java b/src/enginuity/logger/comms/SerialConnectionImpl.java index 6450fd96..3fee1275 100644 --- a/src/enginuity/logger/comms/SerialConnectionImpl.java +++ b/src/enginuity/logger/comms/SerialConnectionImpl.java @@ -86,7 +86,7 @@ public final class SerialConnectionImpl implements SerialConnection { serialPort.setRTS(false); os.write(request, 0, request.length); os.flush(); - int timeout = 100; + int timeout = 1000; while (is.available() < response.length) { TimeUnit.MILLISECONDS.sleep(5); timeout -= 5; diff --git a/src/enginuity/logger/definition/EcuParameter.java b/src/enginuity/logger/definition/EcuParameter.java index cb3b00c6..ef19256e 100644 --- a/src/enginuity/logger/definition/EcuParameter.java +++ b/src/enginuity/logger/definition/EcuParameter.java @@ -10,8 +10,6 @@ public interface EcuParameter { String getAddress(); - String getValueLength(); - EcuParameterConvertor getConvertor(); } diff --git a/src/enginuity/logger/definition/EcuParameterImpl.java b/src/enginuity/logger/definition/EcuParameterImpl.java index 45a41e12..504eebf7 100644 --- a/src/enginuity/logger/definition/EcuParameterImpl.java +++ b/src/enginuity/logger/definition/EcuParameterImpl.java @@ -33,11 +33,6 @@ public final class EcuParameterImpl implements EcuParameter { return address; } - //TODO: Is this required??? - public String getValueLength() { - return null; - } - public EcuParameterConvertor getConvertor() { return convertor; } diff --git a/src/enginuity/logger/definition/convertor/AcceleratorOpeningAngleConvertor.java b/src/enginuity/logger/definition/convertor/AcceleratorOpeningAngleConvertor.java index 9fe43347..571ae875 100644 --- a/src/enginuity/logger/definition/convertor/AcceleratorOpeningAngleConvertor.java +++ b/src/enginuity/logger/definition/convertor/AcceleratorOpeningAngleConvertor.java @@ -7,12 +7,15 @@ import java.text.DecimalFormat; public final class AcceleratorOpeningAngleConvertor implements EcuParameterConvertor { private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("0.0"); - public String convert(byte[] bytes) { - double angle = (double) asInt(bytes) / 2.55; - return AcceleratorOpeningAngleConvertor.DECIMAL_FORMAT.format(angle); + public double convert(byte[] bytes) { + return (double) asInt(bytes) / 2.55; } public String getUnits() { return "%"; } + + public String format(double value) { + return DECIMAL_FORMAT.format(value); + } } diff --git a/src/enginuity/logger/definition/convertor/AirFuelRatioLambdaConvertor.java b/src/enginuity/logger/definition/convertor/AirFuelRatioLambdaConvertor.java index 3d37b323..90020f51 100644 --- a/src/enginuity/logger/definition/convertor/AirFuelRatioLambdaConvertor.java +++ b/src/enginuity/logger/definition/convertor/AirFuelRatioLambdaConvertor.java @@ -7,13 +7,16 @@ import java.text.DecimalFormat; public final class AirFuelRatioLambdaConvertor implements EcuParameterConvertor { private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("0.0"); - public String convert(byte[] bytes) { - double afr = (double) asInt(bytes) / 128.0; - return DECIMAL_FORMAT.format(afr); + public double convert(byte[] bytes) { + return (double) asInt(bytes) / 128.0; } public String getUnits() { return "Lambda"; } + public String format(double value) { + return DECIMAL_FORMAT.format(value); + } + } diff --git a/src/enginuity/logger/definition/convertor/EcuParameterConvertor.java b/src/enginuity/logger/definition/convertor/EcuParameterConvertor.java index f6f3c414..a376eff1 100644 --- a/src/enginuity/logger/definition/convertor/EcuParameterConvertor.java +++ b/src/enginuity/logger/definition/convertor/EcuParameterConvertor.java @@ -2,8 +2,10 @@ package enginuity.logger.definition.convertor; public interface EcuParameterConvertor { - String convert(byte[] bytes); + double convert(byte[] bytes); String getUnits(); + String format(double value); + } diff --git a/src/enginuity/logger/definition/convertor/EngineSpeedConvertor.java b/src/enginuity/logger/definition/convertor/EngineSpeedConvertor.java index da9149d5..c9d1d0ad 100644 --- a/src/enginuity/logger/definition/convertor/EngineSpeedConvertor.java +++ b/src/enginuity/logger/definition/convertor/EngineSpeedConvertor.java @@ -2,14 +2,20 @@ package enginuity.logger.definition.convertor; import static enginuity.util.ByteUtil.asInt; -public final class EngineSpeedConvertor implements EcuParameterConvertor { +import java.text.DecimalFormat; - public String convert(byte[] bytes) { - int rpm = asInt(bytes) / 4; - return String.valueOf(rpm); +public final class EngineSpeedConvertor implements EcuParameterConvertor { + private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("0"); + + public double convert(byte[] bytes) { + return asInt(bytes) / 4; } public String getUnits() { return "rpm"; } + + public String format(double value) { + return DECIMAL_FORMAT.format(value); + } } diff --git a/src/enginuity/logger/definition/convertor/ExhaustGasTemperatureConvertor.java b/src/enginuity/logger/definition/convertor/ExhaustGasTemperatureConvertor.java index d0a96442..85daf62e 100644 --- a/src/enginuity/logger/definition/convertor/ExhaustGasTemperatureConvertor.java +++ b/src/enginuity/logger/definition/convertor/ExhaustGasTemperatureConvertor.java @@ -2,14 +2,20 @@ package enginuity.logger.definition.convertor; import static enginuity.util.ByteUtil.asInt; -public final class ExhaustGasTemperatureConvertor implements EcuParameterConvertor { +import java.text.DecimalFormat; - public String convert(byte[] bytes) { - int degreesC = (asInt(bytes) + 40) * 5; - return String.valueOf(degreesC); +public final class ExhaustGasTemperatureConvertor implements EcuParameterConvertor { + private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("0"); + + public double convert(byte[] bytes) { + return (asInt(bytes) + 40) * 5; } public String getUnits() { return "C"; } + + public String format(double value) { + return DECIMAL_FORMAT.format(value); + } } diff --git a/src/enginuity/logger/definition/convertor/GenericTemperatureConvertor.java b/src/enginuity/logger/definition/convertor/GenericTemperatureConvertor.java index ba341bf9..c257dc6a 100644 --- a/src/enginuity/logger/definition/convertor/GenericTemperatureConvertor.java +++ b/src/enginuity/logger/definition/convertor/GenericTemperatureConvertor.java @@ -2,15 +2,21 @@ package enginuity.logger.definition.convertor; import static enginuity.util.ByteUtil.asInt; -public final class GenericTemperatureConvertor implements EcuParameterConvertor { +import java.text.DecimalFormat; - public String convert(byte[] bytes) { - int degreesC = asInt(bytes) - 40; - return String.valueOf(degreesC); +public final class GenericTemperatureConvertor implements EcuParameterConvertor { + private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("0"); + + public double convert(byte[] bytes) { + return asInt(bytes) - 40; } public String getUnits() { return "C"; } + public String format(double value) { + return DECIMAL_FORMAT.format(value); + } + } diff --git a/src/enginuity/logger/definition/convertor/HexConvertor.java b/src/enginuity/logger/definition/convertor/HexConvertor.java deleted file mode 100644 index d9175bf0..00000000 --- a/src/enginuity/logger/definition/convertor/HexConvertor.java +++ /dev/null @@ -1,14 +0,0 @@ -package enginuity.logger.definition.convertor; - -import static enginuity.util.HexUtil.asHex; - -public final class HexConvertor implements EcuParameterConvertor { - - public String convert(byte[] bytes) { - return asHex(bytes); - } - - public String getUnits() { - return "hex"; - } -} diff --git a/src/enginuity/logger/definition/convertor/ThrottleOpeningAngleConvertor.java b/src/enginuity/logger/definition/convertor/ThrottleOpeningAngleConvertor.java index 230e490e..485e5313 100644 --- a/src/enginuity/logger/definition/convertor/ThrottleOpeningAngleConvertor.java +++ b/src/enginuity/logger/definition/convertor/ThrottleOpeningAngleConvertor.java @@ -7,12 +7,15 @@ import java.text.DecimalFormat; public final class ThrottleOpeningAngleConvertor implements EcuParameterConvertor { private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("0.0"); - public String convert(byte[] bytes) { - double angle = (double) asInt(bytes) / 2.55; - return DECIMAL_FORMAT.format(angle); + public double convert(byte[] bytes) { + return (double) asInt(bytes) / 2.55; } public String getUnits() { return "%"; } + + public String format(double value) { + return DECIMAL_FORMAT.format(value); + } } diff --git a/src/enginuity/logger/manager/TransmissionManagerImpl.java b/src/enginuity/logger/manager/TransmissionManagerImpl.java index 5ca748fe..ba58474e 100644 --- a/src/enginuity/logger/manager/TransmissionManagerImpl.java +++ b/src/enginuity/logger/manager/TransmissionManagerImpl.java @@ -3,7 +3,6 @@ package enginuity.logger.manager; import enginuity.Settings; import enginuity.logger.comms.SerialConnection; import enginuity.logger.comms.SerialConnectionImpl; -import enginuity.logger.definition.convertor.EcuParameterConvertor; import enginuity.logger.exception.NotConnectedException; import enginuity.logger.exception.SerialCommunicationException; import enginuity.logger.protocol.Protocol; @@ -39,7 +38,7 @@ public final class TransmissionManagerImpl implements TransmissionManager { public void sendEcuInit(LoggerCallback callback) { if (serialConnection != null) { - callback.callback(serialConnection.sendEcuInit(), null); + callback.callback(serialConnection.sendEcuInit()); } else { throw new NotConnectedException("TransmissionManager must be started before a query can be sent!"); } @@ -66,7 +65,7 @@ public final class TransmissionManagerImpl implements TransmissionManager { try { txManager.start(); txManager.sendEcuInit(new LoggerCallback() { - public void callback(byte[] value, EcuParameterConvertor convertor) { + public void callback(byte[] value) { System.out.println("ECU Init Response = " + HexUtil.asHex(value)); } }); diff --git a/src/enginuity/logger/protocol/SSMProtocol.java b/src/enginuity/logger/protocol/SSMProtocol.java index 18fe9e8f..e3d3893d 100644 --- a/src/enginuity/logger/protocol/SSMProtocol.java +++ b/src/enginuity/logger/protocol/SSMProtocol.java @@ -21,9 +21,10 @@ public final class SSMProtocol implements Protocol { private static final byte READ_ADDRESS_RESPONSE = (byte) 0xE8; private static final byte ECU_INIT_COMMAND = (byte) 0xBF; private static final byte ECU_INIT_RESPONSE = (byte) 0xFF; - private static final int NON_DATA_BYTES = 6; + private static final int RESPONSE_NON_DATA_BYTES = 6; private static final int ADDRESS_SIZE = 3; private static final int DATA_SIZE = 1; + private static final int REQUEST_NON_DATA_BYTES = 7; public byte[] constructReadMemoryRequest(RegisteredQuery query, int numBytes) { checkNotNull(query, "query"); @@ -42,7 +43,11 @@ public final class SSMProtocol implements Protocol { public byte[] constructReadAddressResponse(Collection queries) { checkNotNullOrEmpty(queries, "queries"); // 0x80 0xF0 0x10 data_length 0xE8 value1 value2 ... valueN checksum - return new byte[(DATA_SIZE * queries.size() + NON_DATA_BYTES) + (queries.size() * ADDRESS_SIZE + 7)]; + int numAddresses = 0; + for (RegisteredQuery query : queries) { + numAddresses += (query.getBytes().length / ADDRESS_SIZE); + } + return new byte[(numAddresses * DATA_SIZE + RESPONSE_NON_DATA_BYTES) + (numAddresses * ADDRESS_SIZE + REQUEST_NON_DATA_BYTES)]; } @SuppressWarnings({"PointlessArithmeticExpression"}) @@ -67,10 +72,9 @@ public final class SSMProtocol implements Protocol { public byte[] extractResponseData(byte[] response) { checkNotNullOrEmpty(response, "response"); // 0x80 0xF0 0x10 data_length 0xE8 response_data checksum - //TODO: Take possible echoed request into account when extracting response!! validateResponse(response); - byte[] data = new byte[response.length - NON_DATA_BYTES]; - System.arraycopy(response, (NON_DATA_BYTES - 1), data, 0, data.length); + byte[] data = new byte[response.length - RESPONSE_NON_DATA_BYTES]; + System.arraycopy(response, (RESPONSE_NON_DATA_BYTES - 1), data, 0, data.length); return data; } @@ -111,7 +115,7 @@ public final class SSMProtocol implements Protocol { assertEquals(HEADER, response[i++], "Invalid header"); assertEquals(DIAGNOSTIC_TOOL_ID, response[i++], "Invalid diagnostic tool id"); assertEquals(ECU_ID, response[i++], "Invalid ECU id"); - assertEquals(asByte(response.length - NON_DATA_BYTES + 1), response[i++], "Invalid response data length"); + assertEquals(asByte(response.length - RESPONSE_NON_DATA_BYTES + 1), response[i++], "Invalid response data length"); assertOneOf(new byte[]{READ_ADDRESS_RESPONSE, READ_MEMORY_RESPONSE, ECU_INIT_RESPONSE}, response[i], "Invalid response code"); assertEquals(calculateChecksum(response), response[response.length - 1], "Invalid checksum"); } @@ -147,7 +151,7 @@ public final class SSMProtocol implements Protocol { System.arraycopy(tmp, 0, tmp2, data.length, tmp.length); data = tmp2; } - byte[] request = new byte[data.length + (padContent ? 7 : NON_DATA_BYTES)]; + byte[] request = new byte[data.length + (padContent ? REQUEST_NON_DATA_BYTES : RESPONSE_NON_DATA_BYTES)]; int i = 0; request[i++] = HEADER; request[i++] = ECU_ID; diff --git a/src/enginuity/logger/query/LoggerCallback.java b/src/enginuity/logger/query/LoggerCallback.java index a06525ea..58f0cc78 100644 --- a/src/enginuity/logger/query/LoggerCallback.java +++ b/src/enginuity/logger/query/LoggerCallback.java @@ -1,9 +1,7 @@ package enginuity.logger.query; -import enginuity.logger.definition.convertor.EcuParameterConvertor; - public interface LoggerCallback { - void callback(byte[] value, EcuParameterConvertor convertor); + void callback(byte[] value); } diff --git a/src/enginuity/logger/query/RegisteredQueryImpl.java b/src/enginuity/logger/query/RegisteredQueryImpl.java index 88e9a651..0c0bac6c 100644 --- a/src/enginuity/logger/query/RegisteredQueryImpl.java +++ b/src/enginuity/logger/query/RegisteredQueryImpl.java @@ -4,10 +4,6 @@ import enginuity.logger.definition.EcuParameter; import static enginuity.util.HexUtil.asBytes; import static enginuity.util.ParamChecker.checkNotNull; -//TODO: change address into an EcuParameter object with getAddress() & getLength() methods -//TODO: use the getLength() method to do the response data extraction in SSMProtocol - -@SuppressWarnings({"FieldCanBeLocal"}) public final class RegisteredQueryImpl implements RegisteredQuery { private final EcuParameter ecuParam; private final LoggerCallback callback; @@ -29,6 +25,6 @@ public final class RegisteredQueryImpl implements RegisteredQuery { } public void setResponse(byte[] response) { - callback.callback(response, ecuParam.getConvertor()); + callback.callback(response); } } diff --git a/src/enginuity/logger/ui/LoggerDataRow.java b/src/enginuity/logger/ui/LoggerDataRow.java new file mode 100644 index 00000000..3af99541 --- /dev/null +++ b/src/enginuity/logger/ui/LoggerDataRow.java @@ -0,0 +1,52 @@ +package enginuity.logger.ui; + +import enginuity.logger.definition.EcuParameter; + +import javax.swing.table.AbstractTableModel; + +public final class LoggerDataRow { + private EcuParameter ecuParam; + private AbstractTableModel parentTableModel; + private double minValue; + private double maxValue; + private double currentValue; + + public LoggerDataRow(EcuParameter ecuParam) { + this.ecuParam = ecuParam; + } + + public String getName() { + return ecuParam.getName(); + } + + public String getMinValue() { + return ecuParam.getConvertor().format(minValue); + } + + public String getMaxValue() { + return ecuParam.getConvertor().format(maxValue); + } + + public String getCurrentValue() { + return ecuParam.getConvertor().format(currentValue); + } + + public String getUnits() { + return ecuParam.getConvertor().getUnits(); + } + + public void updateValue(byte[] bytes) { + currentValue = ecuParam.getConvertor().convert(bytes); + if (currentValue < minValue || minValue == 0.0) { + minValue = currentValue; + } + if (currentValue > maxValue || maxValue == 0.0) { + maxValue = currentValue; + } + parentTableModel.fireTableDataChanged(); + } + + public void setParentTableModel(AbstractTableModel parentTableModel) { + this.parentTableModel = parentTableModel; + } +} \ No newline at end of file diff --git a/src/enginuity/logger/ui/LoggerDataTableModel.java b/src/enginuity/logger/ui/LoggerDataTableModel.java new file mode 100644 index 00000000..95265fa1 --- /dev/null +++ b/src/enginuity/logger/ui/LoggerDataTableModel.java @@ -0,0 +1,49 @@ +package enginuity.logger.ui; + +import javax.swing.table.AbstractTableModel; + +public final class LoggerDataTableModel extends AbstractTableModel { + String[] columnNames = {"ECU Parameter", "Min Value", "Current Value", "Max Value", "Units"}; + LoggerDataRow[] data = new LoggerDataRow[0]; + + public int getRowCount() { + return data.length; + } + + public int getColumnCount() { + return columnNames.length; + } + + public String getColumnName(int col) { + return columnNames[col]; + } + + public boolean isCellEditable(int row, int col) { + return false; + } + + public Object getValueAt(int row, int col) { + switch (col) { + case 0: + return data[row].getName(); + case 1: + return data[row].getMinValue(); + case 2: + return data[row].getCurrentValue(); + case 3: + return data[row].getMaxValue(); + case 4: + return data[row].getUnits(); + default: + return "Error!"; + } + } + + public synchronized void addRow(LoggerDataRow newRow) { + newRow.setParentTableModel(this); + LoggerDataRow[] newData = new LoggerDataRow[data.length + 1]; + System.arraycopy(data, 0, newData, 0, data.length); + newData[newData.length - 1] = newRow; + data = newData; + } +} diff --git a/src/enginuity/logger/ui/SpringUtilities.java b/src/enginuity/logger/ui/SpringUtilities.java new file mode 100644 index 00000000..dab891c3 --- /dev/null +++ b/src/enginuity/logger/ui/SpringUtilities.java @@ -0,0 +1,197 @@ +package enginuity.logger.ui; + +import javax.swing.*; +import java.awt.*; + +/** + * A 1.4 file that provides utility methods for + * creating form- or grid-style layouts with SpringLayout. + * These utilities are used by several programs, such as + * SpringBox and SpringCompactGrid. + */ +public class SpringUtilities { + + private SpringUtilities() { + } + + /** + * A debugging utility that prints to stdout the component's + * minimum, preferred, and maximum sizes. + */ + public static void printSizes(Component c) { + System.out.println("minimumSize = " + c.getMinimumSize()); + System.out.println("preferredSize = " + c.getPreferredSize()); + System.out.println("maximumSize = " + c.getMaximumSize()); + } + + /** + * Aligns the first rows * cols + * components of parent in + * a grid. Each component is as big as the maximum + * preferred width and height of the components. + * The parent is made just big enough to fit them all. + * + * @param rows number of rows + * @param cols number of columns + * @param initialX x location to start the grid at + * @param initialY y location to start the grid at + * @param xPad x padding between cells + * @param yPad y padding between cells + */ + public static void makeGrid(Container parent, + int rows, int cols, + int initialX, int initialY, + int xPad, int yPad) { + SpringLayout layout; + try { + layout = (SpringLayout)parent.getLayout(); + } catch (ClassCastException exc) { + System.err.println("The first argument to makeGrid must use SpringLayout."); + return; + } + + Spring xPadSpring = Spring.constant(xPad); + Spring yPadSpring = Spring.constant(yPad); + Spring initialXSpring = Spring.constant(initialX); + Spring initialYSpring = Spring.constant(initialY); + int max = rows * cols; + + //Calculate Springs that are the max of the width/height so that all + //cells have the same size. + Spring maxWidthSpring = layout.getConstraints(parent.getComponent(0)). + getWidth(); + Spring maxHeightSpring = layout.getConstraints(parent.getComponent(0)). + getWidth(); + for (int i = 1; i < max; i++) { + SpringLayout.Constraints cons = layout.getConstraints( + parent.getComponent(i)); + + maxWidthSpring = Spring.max(maxWidthSpring, cons.getWidth()); + maxHeightSpring = Spring.max(maxHeightSpring, cons.getHeight()); + } + + //Apply the new width/height Spring. This forces all the + //components to have the same size. + for (int i = 0; i < max; i++) { + SpringLayout.Constraints cons = layout.getConstraints( + parent.getComponent(i)); + + cons.setWidth(maxWidthSpring); + cons.setHeight(maxHeightSpring); + } + + //Then adjust the x/y constraints of all the cells so that they + //are aligned in a grid. + SpringLayout.Constraints lastCons = null; + SpringLayout.Constraints lastRowCons = null; + for (int i = 0; i < max; i++) { + SpringLayout.Constraints cons = layout.getConstraints( + parent.getComponent(i)); + if (i % cols == 0) { //start of new row + lastRowCons = lastCons; + cons.setX(initialXSpring); + } else { //x position depends on previous component + cons.setX(Spring.sum(lastCons.getConstraint(SpringLayout.EAST), + xPadSpring)); + } + + if (i / cols == 0) { //first row + cons.setY(initialYSpring); + } else { //y position depends on previous row + cons.setY(Spring.sum(lastRowCons.getConstraint(SpringLayout.SOUTH), + yPadSpring)); + } + lastCons = cons; + } + + //Set the parent's size. + SpringLayout.Constraints pCons = layout.getConstraints(parent); + pCons.setConstraint(SpringLayout.SOUTH, + Spring.sum( + Spring.constant(yPad), + lastCons.getConstraint(SpringLayout.SOUTH))); + pCons.setConstraint(SpringLayout.EAST, + Spring.sum( + Spring.constant(xPad), + lastCons.getConstraint(SpringLayout.EAST))); + } + + /* Used by makeCompactGrid. */ + private static SpringLayout.Constraints getConstraintsForCell( + int row, int col, + Container parent, + int cols) { + SpringLayout layout = (SpringLayout) parent.getLayout(); + Component c = parent.getComponent(row * cols + col); + return layout.getConstraints(c); + } + + /** + * Aligns the first rows * cols + * components of parent in + * a grid. Each component in a column is as wide as the maximum + * preferred width of the components in that column; + * height is similarly determined for each row. + * The parent is made just big enough to fit them all. + * + * @param rows number of rows + * @param cols number of columns + * @param initialX x location to start the grid at + * @param initialY y location to start the grid at + * @param xPad x padding between cells + * @param yPad y padding between cells + */ + public static void makeCompactGrid(Container parent, + int rows, int cols, + int initialX, int initialY, + int xPad, int yPad) { + SpringLayout layout; + try { + layout = (SpringLayout)parent.getLayout(); + } catch (ClassCastException exc) { + System.err.println("The first argument to makeCompactGrid must use SpringLayout."); + return; + } + + //Align all cells in each column and make them the same width. + Spring x = Spring.constant(initialX); + for (int c = 0; c < cols; c++) { + Spring width = Spring.constant(0); + for (int r = 0; r < rows; r++) { + width = Spring.max(width, + getConstraintsForCell(r, c, parent, cols). + getWidth()); + } + for (int r = 0; r < rows; r++) { + SpringLayout.Constraints constraints = + getConstraintsForCell(r, c, parent, cols); + constraints.setX(x); + constraints.setWidth(width); + } + x = Spring.sum(x, Spring.sum(width, Spring.constant(xPad))); + } + + //Align all cells in each row and make them the same height. + Spring y = Spring.constant(initialY); + for (int r = 0; r < rows; r++) { + Spring height = Spring.constant(0); + for (int c = 0; c < cols; c++) { + height = Spring.max(height, + getConstraintsForCell(r, c, parent, cols). + getHeight()); + } + for (int c = 0; c < cols; c++) { + SpringLayout.Constraints constraints = + getConstraintsForCell(r, c, parent, cols); + constraints.setY(y); + constraints.setHeight(height); + } + y = Spring.sum(y, Spring.sum(height, Spring.constant(yPad))); + } + + //Set the parent's size. + SpringLayout.Constraints pCons = layout.getConstraints(parent); + pCons.setConstraint(SpringLayout.SOUTH, y); + pCons.setConstraint(SpringLayout.EAST, x); + } +}