From 451ace3f5da173d56f0df3bdc77e7d3cf2c4dbaf Mon Sep 17 00:00:00 2001 From: rusefi Date: Mon, 17 Jun 2019 19:14:03 -0400 Subject: [PATCH] Annotations in C++ code to produce formulas in rusEfi console #807 (#848) --- java_console/.idea/libraries/snakeyaml.xml | 9 ++ java_console/.idea/modules.xml | 2 + .../rusefi/binaryprotocol/BinaryProtocol.java | 4 +- .../BinaryProtocolCommands.java | 1 + .../com/rusefi/binaryprotocol/IoHelper.java | 4 +- .../com/rusefi/ui/livedocs/LiveDocHolder.java | 33 +++++ .../rusefi/ui/livedocs/LiveDocsRegistry.java | 51 +++++++ .../rusefi/ui/livedocs/RefreshActions.java | 7 + .../models/src/com/rusefi/config/Field.java | 41 ++++++ .../rusefi/config/generated/EngineState.java | 22 +++ .../com/rusefi/config/generated/Fields.java | 6 +- .../config/generated/ThermistorState.java | 16 ++ .../rusefi/ldmp/generated/ThermistorMeta.java | 20 +++ .../ui/src/com/rusefi/ui/FormulasPane.java | 17 +++ .../com/rusefi/ui/livedocs/LiveDocPanel.java | 87 +++++++++++ .../rusefi/ui/livedocs/LiveDocsSandbox.java | 74 ++++++++++ .../ui/livedocs/controls/ConfigReference.java | 9 ++ .../ui/livedocs/controls/ConfigView.java | 35 +++++ .../ui/livedocs/controls/LogicReference.java | 35 +++++ .../rusefi/ui/livedocs/controls/Toolbox.java | 26 ++++ java_console/ui/ui.iml | 1 + .../runConfigurations/LiveDocsMetaParser.xml | 16 ++ .../src/com/rusefi/ldmp/ConfigRequest.java | 45 ++++++ .../src/com/rusefi/ldmp/FieldRequest.java | 40 +++++ .../src/com/rusefi/ldmp/IfRequest.java | 27 ++++ .../com/rusefi/ldmp/LiveDocsMetaParser.java | 139 ++++++++++++++++++ .../src/com/rusefi/ldmp/Request.java | 13 ++ .../src/com/rusefi/ldmp/SensorRequest.java | 38 +++++ .../src/com/rusefi/ldmp/TextRequest.java | 46 ++++++ .../ldmp/test/LiveDocsMetaParserTest.java | 75 ++++++++++ java_tools/enum_to_string/enum_to_string.iml | 1 + 31 files changed, 936 insertions(+), 4 deletions(-) create mode 100644 java_console/.idea/libraries/snakeyaml.xml create mode 100644 java_console/io/src/com/rusefi/ui/livedocs/LiveDocHolder.java create mode 100644 java_console/io/src/com/rusefi/ui/livedocs/LiveDocsRegistry.java create mode 100644 java_console/io/src/com/rusefi/ui/livedocs/RefreshActions.java create mode 100644 java_console/models/src/com/rusefi/config/generated/EngineState.java create mode 100644 java_console/models/src/com/rusefi/config/generated/ThermistorState.java create mode 100644 java_console/ui/src/com/rusefi/ldmp/generated/ThermistorMeta.java create mode 100644 java_console/ui/src/com/rusefi/ui/livedocs/LiveDocPanel.java create mode 100644 java_console/ui/src/com/rusefi/ui/livedocs/LiveDocsSandbox.java create mode 100644 java_console/ui/src/com/rusefi/ui/livedocs/controls/ConfigReference.java create mode 100644 java_console/ui/src/com/rusefi/ui/livedocs/controls/ConfigView.java create mode 100644 java_console/ui/src/com/rusefi/ui/livedocs/controls/LogicReference.java create mode 100644 java_console/ui/src/com/rusefi/ui/livedocs/controls/Toolbox.java create mode 100644 java_tools/configuration_definition/.idea/runConfigurations/LiveDocsMetaParser.xml create mode 100644 java_tools/configuration_definition/src/com/rusefi/ldmp/ConfigRequest.java create mode 100644 java_tools/configuration_definition/src/com/rusefi/ldmp/FieldRequest.java create mode 100644 java_tools/configuration_definition/src/com/rusefi/ldmp/IfRequest.java create mode 100644 java_tools/configuration_definition/src/com/rusefi/ldmp/LiveDocsMetaParser.java create mode 100644 java_tools/configuration_definition/src/com/rusefi/ldmp/Request.java create mode 100644 java_tools/configuration_definition/src/com/rusefi/ldmp/SensorRequest.java create mode 100644 java_tools/configuration_definition/src/com/rusefi/ldmp/TextRequest.java create mode 100644 java_tools/configuration_definition/src/com/rusefi/ldmp/test/LiveDocsMetaParserTest.java diff --git a/java_console/.idea/libraries/snakeyaml.xml b/java_console/.idea/libraries/snakeyaml.xml new file mode 100644 index 0000000000..2ca18f77b8 --- /dev/null +++ b/java_console/.idea/libraries/snakeyaml.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/java_console/.idea/modules.xml b/java_console/.idea/modules.xml index 706059be07..0ee521d085 100644 --- a/java_console/.idea/modules.xml +++ b/java_console/.idea/modules.xml @@ -3,6 +3,8 @@ + + diff --git a/java_console/io/src/com/rusefi/binaryprotocol/BinaryProtocol.java b/java_console/io/src/com/rusefi/binaryprotocol/BinaryProtocol.java index caf39a0c27..74930242b6 100644 --- a/java_console/io/src/com/rusefi/binaryprotocol/BinaryProtocol.java +++ b/java_console/io/src/com/rusefi/binaryprotocol/BinaryProtocol.java @@ -12,6 +12,7 @@ import com.rusefi.core.Pair; import com.rusefi.core.Sensor; import com.rusefi.core.SensorCentral; import com.rusefi.io.*; +import com.rusefi.ui.livedocs.LiveDocsRegistry; import jssc.SerialPortException; import java.io.EOFException; @@ -141,6 +142,7 @@ public class BinaryProtocol implements BinaryProtocolCommands { String text = requestPendingMessages(); if (text != null) listener.onDataArrived((text + "\r\n").getBytes()); + LiveDocsRegistry.INSTANCE.refresh(BinaryProtocol.this); } }); } @@ -271,7 +273,7 @@ public class BinaryProtocol implements BinaryProtocolCommands { * * @return null in case of IO issues */ - private byte[] executeCommand(byte[] packet, String msg, boolean allowLongResponse) { + public byte[] executeCommand(byte[] packet, String msg, boolean allowLongResponse) { if (isClosed) return null; try { diff --git a/java_console/io/src/com/rusefi/binaryprotocol/BinaryProtocolCommands.java b/java_console/io/src/com/rusefi/binaryprotocol/BinaryProtocolCommands.java index 2691af6650..e18d0e364c 100644 --- a/java_console/io/src/com/rusefi/binaryprotocol/BinaryProtocolCommands.java +++ b/java_console/io/src/com/rusefi/binaryprotocol/BinaryProtocolCommands.java @@ -20,4 +20,5 @@ public interface BinaryProtocolCommands { char COMMAND_READ = 'R'; // 082 decimal char COMMAND_CHUNK_WRITE = 'C'; // pageChunkWrite char COMMAND_BURN = 'B'; // burnCommand + char COMMAND_GET_STRUCT = '9'; // TS_GET_STRUCT } diff --git a/java_console/io/src/com/rusefi/binaryprotocol/IoHelper.java b/java_console/io/src/com/rusefi/binaryprotocol/IoHelper.java index e6e6c8f859..29231d37d3 100644 --- a/java_console/io/src/com/rusefi/binaryprotocol/IoHelper.java +++ b/java_console/io/src/com/rusefi/binaryprotocol/IoHelper.java @@ -35,7 +35,7 @@ public class IoHelper { return packet; } - static int swap16(int x) { + public static int swap16(int x) { return (((x & 0xFF) << 8) | ((x) >> 8)); } @@ -51,7 +51,7 @@ public class IoHelper { } } - static void putShort(byte[] packet, int offset, int value) { + public static void putShort(byte[] packet, int offset, int value) { int index = offset + 1; for (int i = 0; i < 2; i++) { packet[index--] = (byte) value; diff --git a/java_console/io/src/com/rusefi/ui/livedocs/LiveDocHolder.java b/java_console/io/src/com/rusefi/ui/livedocs/LiveDocHolder.java new file mode 100644 index 0000000000..7d4a3127c4 --- /dev/null +++ b/java_console/io/src/com/rusefi/ui/livedocs/LiveDocHolder.java @@ -0,0 +1,33 @@ +package com.rusefi.ui.livedocs; + +import com.rusefi.binaryprotocol.BinaryProtocol; +import com.rusefi.config.Field; + +import java.util.List; + +public abstract class LiveDocHolder { + private final int id; + private final List actions; + private final Field[] values; + + public LiveDocHolder(int id, List actions, Field[] values) { + this.id = id; + this.actions = actions; + this.values = values; + } + + public void update(BinaryProtocol binaryProtocol, byte[] response) { + for (RefreshActions action : actions) + action.refresh(binaryProtocol, response); + } + + public abstract boolean isVisible(); + + public Integer getId() { + return id; + } + + public int getStructSize() { + return Field.getStructureSize(values); + } +} diff --git a/java_console/io/src/com/rusefi/ui/livedocs/LiveDocsRegistry.java b/java_console/io/src/com/rusefi/ui/livedocs/LiveDocsRegistry.java new file mode 100644 index 0000000000..47f4ac5007 --- /dev/null +++ b/java_console/io/src/com/rusefi/ui/livedocs/LiveDocsRegistry.java @@ -0,0 +1,51 @@ +package com.rusefi.ui.livedocs; + +import com.rusefi.binaryprotocol.BinaryProtocol; +import com.rusefi.config.generated.Fields; + +import java.util.HashMap; +import java.util.Map; + +import static com.rusefi.binaryprotocol.BinaryProtocolCommands.COMMAND_GET_STRUCT; +import static com.rusefi.binaryprotocol.BinaryProtocolCommands.RESPONSE_OK; +import static com.rusefi.binaryprotocol.IoHelper.putShort; +import static com.rusefi.binaryprotocol.IoHelper.swap16; + +/** + * Singleton map of all live documentation entities. Using this registry we know all the entities to update periodically. + */ +public enum LiveDocsRegistry { + INSTANCE; + + private final Map liveDocs = new HashMap<>(); + + public void register(LiveDocHolder holder) { + liveDocs.put(holder.getId(), holder); + } + + public void refresh(BinaryProtocol binaryProtocol) { + for (LiveDocHolder h : liveDocs.values()) { + boolean visible = h.isVisible(); + System.out.println(h + ": " + visible); + if (visible) { + int liveDocRequestId = h.getId(); + int size = h.getStructSize(); + + byte packet[] = new byte[5]; + packet[0] = COMMAND_GET_STRUCT; + putShort(packet, 1, swap16(liveDocRequestId)); // offset + putShort(packet, 3, swap16(size)); + + byte[] responseWithCode = binaryProtocol.executeCommand(packet, "get LiveDoc", false); + if (responseWithCode == null || responseWithCode.length != (size + 1) || responseWithCode[0] != RESPONSE_OK) + continue; + + byte [] response = new byte[size]; + + System.arraycopy(responseWithCode, 1, response, 0, size); + + h.update(binaryProtocol, response); + } + } + } +} diff --git a/java_console/io/src/com/rusefi/ui/livedocs/RefreshActions.java b/java_console/io/src/com/rusefi/ui/livedocs/RefreshActions.java new file mode 100644 index 0000000000..836c0b5fab --- /dev/null +++ b/java_console/io/src/com/rusefi/ui/livedocs/RefreshActions.java @@ -0,0 +1,7 @@ +package com.rusefi.ui.livedocs; + +import com.rusefi.binaryprotocol.BinaryProtocol; + +public abstract class RefreshActions { + public abstract void refresh(BinaryProtocol bp, byte[] response); +} diff --git a/java_console/models/src/com/rusefi/config/Field.java b/java_console/models/src/com/rusefi/config/Field.java index 3681a2da98..3670e53b83 100644 --- a/java_console/models/src/com/rusefi/config/Field.java +++ b/java_console/models/src/com/rusefi/config/Field.java @@ -8,6 +8,8 @@ import org.jetbrains.annotations.NotNull; import java.nio.ByteBuffer; import java.util.Objects; +import java.util.Objects; + import static com.rusefi.config.FieldType.*; /** @@ -46,6 +48,33 @@ public class Field { this.options = options; } + /** + * Finds field by name, ignoring case + */ + public static Field findField(Field[] values, String instancePrefix, String fieldName) { + Objects.requireNonNull(fieldName); + for (Field f : values) { + if (fieldName.equalsIgnoreCase(f.getName())) + return f; + } + // 2nd pass - let's try to find field with prefix if it was not found without prefix + if (!instancePrefix.isEmpty()) { + fieldName = instancePrefix + "_" + fieldName; + for (Field f : values) { + if (fieldName.equalsIgnoreCase(f.getName())) + return f; + } + } + throw new IllegalStateException("No field " + fieldName); + } + + public static int getStructureSize(Field[] values) { + Field last = values[values.length - 1]; + // todo: at the moment we do not support arrays and + // todo: a lot of information is missing for example for Bit type, but this implementation is good enough for now + return last.offset + 4; + } + public String getName() { return name; } @@ -130,6 +159,18 @@ public class Field { '}'; } + public Object getAnyValue(ConfigurationImage ci) { + if (options == null) { + // not enum field + return getValue(ci); + } + if (type != INT8) + throw new IllegalStateException("Unsupported enum " + type); + int ordinal = ci.getByteBuffer(offset, type.getStorageSize()).get(); + return options[ordinal]; + } + + // todo: rename to getNumberValue? @NotNull public Number getValue(ConfigurationImage ci) { Objects.requireNonNull(ci); diff --git a/java_console/models/src/com/rusefi/config/generated/EngineState.java b/java_console/models/src/com/rusefi/config/generated/EngineState.java new file mode 100644 index 0000000000..8d65f6874c --- /dev/null +++ b/java_console/models/src/com/rusefi/config/generated/EngineState.java @@ -0,0 +1,22 @@ +package com.rusefi.config.generated; + +// this file was generated automatically by ConfigDefinition.jar based on integration/engine_state.txt Sun Jun 16 22:18:54 EDT 2019 + +import com.rusefi.config.*; + +public class EngineState { + public static final Field ISTCHARGEAIRMODEL = Field.create("ISTCHARGEAIRMODEL", 0, FieldType.BIT, 0); + public static final Field AIRMASS = Field.create("AIRMASS", 4, FieldType.FLOAT); + public static final Field ENGINECYCLEDURATIONMS = Field.create("ENGINECYCLEDURATIONMS", 8, FieldType.FLOAT); + public static final Field TCHARGE_COFF = Field.create("TCHARGE_COFF", 12, FieldType.FLOAT); + public static final Field AIRFLOW = Field.create("AIRFLOW", 16, FieldType.FLOAT); + public static final Field MINRPMKCURRENTTPS = Field.create("MINRPMKCURRENTTPS", 20, FieldType.FLOAT); + public static final Field[] VALUES = { + ISTCHARGEAIRMODEL, + AIRMASS, + ENGINECYCLEDURATIONMS, + TCHARGE_COFF, + AIRFLOW, + MINRPMKCURRENTTPS, + }; +} diff --git a/java_console/models/src/com/rusefi/config/generated/Fields.java b/java_console/models/src/com/rusefi/config/generated/Fields.java index 4a5e6f3c7e..7b8c788ba8 100644 --- a/java_console/models/src/com/rusefi/config/generated/Fields.java +++ b/java_console/models/src/com/rusefi/config/generated/Fields.java @@ -1,8 +1,9 @@ package com.rusefi.config.generated; +// this file was generated automatically by ConfigDefinition.jar based on integration\rusefi_config.txt Sun Jun 16 22:17:51 EDT 2019 + import com.rusefi.config.*; -// this file was generated automatically by ConfigDefinition.jar based on integration\rusefi_config.txt Sun Jun 16 22:00:08 EDT 2019 public class Fields { public static final int accelerometerSpiDevice_offset = 2736; public static final int acCutoffHighRpm_offset = 1498; @@ -857,6 +858,9 @@ public class Fields { public static final int knockNoiseRpmBins_offset_hex = 750; public static final int knockVThreshold_offset = 1520; public static final int lcdThreadPeriodMs_offset = 720; + public static final int LDS_CLT_INDEX = 0; + public static final int LDS_IAT_INDEX = 1; + public static final int LDS_SPEED_DENSITY_INDEX = 2; public static final int LE_COMMAND_LENGTH = 200; public static final int LIS302DLCsPin_offset = 2063; public static final int logFormat_offset = 496; diff --git a/java_console/models/src/com/rusefi/config/generated/ThermistorState.java b/java_console/models/src/com/rusefi/config/generated/ThermistorState.java new file mode 100644 index 0000000000..c4b8a769b2 --- /dev/null +++ b/java_console/models/src/com/rusefi/config/generated/ThermistorState.java @@ -0,0 +1,16 @@ +package com.rusefi.config.generated; + +// this file was generated automatically by ConfigDefinition.jar based on integration/thermistor.txt Sun Jun 16 22:18:54 EDT 2019 + +import com.rusefi.config.*; + +public class ThermistorState { + public static final Field RESISTANCE = Field.create("RESISTANCE", 0, FieldType.FLOAT); + public static final Field VOLTAGEMCU = Field.create("VOLTAGEMCU", 4, FieldType.FLOAT); + public static final Field VOLTAGEBOARD = Field.create("VOLTAGEBOARD", 8, FieldType.FLOAT); + public static final Field[] VALUES = { + RESISTANCE, + VOLTAGEMCU, + VOLTAGEBOARD, + }; +} diff --git a/java_console/ui/src/com/rusefi/ldmp/generated/ThermistorMeta.java b/java_console/ui/src/com/rusefi/ldmp/generated/ThermistorMeta.java new file mode 100644 index 0000000000..c6de6efa1b --- /dev/null +++ b/java_console/ui/src/com/rusefi/ldmp/generated/ThermistorMeta.java @@ -0,0 +1,20 @@ +package com.rusefi.ldmp.generated; + +import com.rusefi.ldmp.*; + +public class ThermistorMeta { + public static final Request[] CONTENT = new Request[]{ + new TextRequest("Analog_MCU_reads"), + new FieldRequest("voltageMCU"), + new TextRequest("from_pin"), + new ConfigRequest("adcChannel"), + new TextRequest("EOL"), + new TextRequest("Analog_ECU_read"), + new FieldRequest("voltageBoard"), + new TextRequest("Rdivider"), + new ConfigRequest("analogInputDividerCoefficient"), + new TextRequest("EOL"), + new TextRequest("Measured_resistance"), + new FieldRequest("resistance"), + }; +} \ No newline at end of file diff --git a/java_console/ui/src/com/rusefi/ui/FormulasPane.java b/java_console/ui/src/com/rusefi/ui/FormulasPane.java index 10a8fc9b72..4f93bfc4a3 100644 --- a/java_console/ui/src/com/rusefi/ui/FormulasPane.java +++ b/java_console/ui/src/com/rusefi/ui/FormulasPane.java @@ -5,12 +5,15 @@ import com.rusefi.FileLog; import com.rusefi.binaryprotocol.BinaryProtocol; import com.rusefi.binaryprotocol.BinaryProtocolHolder; import com.rusefi.config.generated.Fields; +import com.rusefi.config.generated.ThermistorState; import com.rusefi.core.Sensor; import com.rusefi.core.SensorCentral; import com.rusefi.ui.config.ConfigField; +import com.rusefi.ui.livedocs.LiveDocPanel; import com.rusefi.ui.util.UiUtils; import com.rusefi.ui.widgets.IntGaugeLabel; import org.jetbrains.annotations.NotNull; +import org.putgemin.VerticalFlowLayout; import org.scilab.forge.jlatexmath.TeXConstants; import org.scilab.forge.jlatexmath.TeXFormula; import org.scilab.forge.jlatexmath.TeXIcon; @@ -21,6 +24,10 @@ import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.image.BufferedImage; +import static com.rusefi.config.generated.Fields.LDS_CLT_INDEX; +import static com.rusefi.config.generated.Fields.LDS_IAT_INDEX; + + /** * (c) Andrey Belomutskiy 2013-2018 */ @@ -29,13 +36,21 @@ public class FormulasPane { private static final String NL2 = NL + "\\ " + NL; // two new lines private static final String NL3 = NL2 + "\\ " + NL; // two new lines + /** + * this is the panel we expose to the outside world + */ private final JPanel content = new JPanel(new BorderLayout()); private final JPanel centerProxy = new JPanel(new BorderLayout()); private boolean isPaused; + private JPanel liveDocs = new JPanel(new VerticalFlowLayout()); + public FormulasPane() { content.add(centerProxy, BorderLayout.CENTER); + liveDocs.add(LiveDocPanel.getThermistorPanel("Coolant Sensor", "CLT", LDS_CLT_INDEX, ThermistorState.VALUES)); + liveDocs.add(LiveDocPanel.getThermistorPanel("Intake Air Sensor", "IAT", LDS_IAT_INDEX, ThermistorState.VALUES)); + centerProxy.add(new JLabel("Waiting for data..."), BorderLayout.CENTER); JButton saveImage = UiUtils.createSaveImageButton(); @@ -147,6 +162,8 @@ public class FormulasPane { warning.setForeground(Color.red); centerProxy.add(warning, BorderLayout.NORTH); centerProxy.add(formulaLabel, BorderLayout.CENTER); + + centerProxy.add(liveDocs, BorderLayout.SOUTH); } @NotNull diff --git a/java_console/ui/src/com/rusefi/ui/livedocs/LiveDocPanel.java b/java_console/ui/src/com/rusefi/ui/livedocs/LiveDocPanel.java new file mode 100644 index 0000000000..947261b9c3 --- /dev/null +++ b/java_console/ui/src/com/rusefi/ui/livedocs/LiveDocPanel.java @@ -0,0 +1,87 @@ +package com.rusefi.ui.livedocs; + +import com.opensr5.ConfigurationImage; +import com.rusefi.binaryprotocol.BinaryProtocol; +import com.rusefi.config.Field; +import com.rusefi.config.generated.Fields; +import com.rusefi.ldmp.ConfigRequest; +import com.rusefi.ldmp.FieldRequest; +import com.rusefi.ldmp.Request; +import com.rusefi.ldmp.TextRequest; +import com.rusefi.ldmp.generated.ThermistorMeta; +import net.miginfocom.swing.MigLayout; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; +import java.awt.*; +import java.util.*; +import java.util.List; + +public class LiveDocPanel { + @NotNull + public static JPanel getThermistorPanel(String title, String instancePrefix, final int id, Field[] values) { + JPanel panel = new JPanel(new MigLayout()); + panel.setBorder(BorderFactory.createTitledBorder(title)); + + List actions = createComponents(panel, ThermistorMeta.CONTENT, values, instancePrefix); + + LiveDocHolder holder = new LiveDocHolder(id, actions, values) { + @Override + public boolean isVisible() { + boolean isVisible = !panel.getVisibleRect().isEmpty(); + return isVisible && isRecursivelyVisible(panel); + } + }; + + LiveDocsRegistry.INSTANCE.register(holder); + return panel; + } + + static boolean isRecursivelyVisible(Container c) { + Container parent = c.getParent(); + return c.isVisible() && (parent == null || isRecursivelyVisible(parent)); + } + + private static List createComponents(JPanel panel, Request[] content, Field[] values, String instancePrefix) { + List actionsList = new ArrayList<>(); + for (Request r : content) { + if (r instanceof TextRequest) { + TextRequest request = (TextRequest) r; + if (request.isEol()) { + panel.add(new JLabel(), "wrap"); + } else { + panel.add(new JLabel(request.getValue().replaceAll("_", " "))); + } + } else if (r instanceof FieldRequest) { + FieldRequest request = (FieldRequest) r; + Field field = Field.findField(values, "", request.getField()); + JLabel label = new JLabel(field.getName()); + panel.add(label); + actionsList.add(new RefreshActions() { + @Override + public void refresh(BinaryProtocol bp, byte[] response) { + String value = field.getValue(new ConfigurationImage(response)).toString(); + label.setText(value); + } + }); + } else if (r instanceof ConfigRequest) { + ConfigRequest request = (ConfigRequest) r; + Field field = Field.findField(Fields.VALUES, instancePrefix, request.getField()); + + JLabel label = new JLabel(field.getName()); + actionsList.add(new RefreshActions() { + @Override + public void refresh(BinaryProtocol bp, byte[] response) { + String value = field.getAnyValue(bp.getController()).toString(); + label.setText(value); + } + }); + panel.add(label); + + } else { + throw new UnsupportedOperationException(r.toString()); + } + } + return actionsList; + } +} diff --git a/java_console/ui/src/com/rusefi/ui/livedocs/LiveDocsSandbox.java b/java_console/ui/src/com/rusefi/ui/livedocs/LiveDocsSandbox.java new file mode 100644 index 0000000000..cbaecbaa4d --- /dev/null +++ b/java_console/ui/src/com/rusefi/ui/livedocs/LiveDocsSandbox.java @@ -0,0 +1,74 @@ +package com.rusefi.ui.livedocs; + +import com.rusefi.config.generated.ThermistorState; +import com.rusefi.ui.livedocs.controls.Toolbox; +import com.rusefi.ui.util.FrameHelper; +import net.miginfocom.swing.MigLayout; +import org.jetbrains.annotations.NotNull; + +import javax.swing.*; +import java.awt.*; + +import static com.rusefi.config.generated.Fields.LDS_CLT_INDEX; +import static com.rusefi.ui.livedocs.controls.Toolbox.setTransparentLineBorder; + +public class LiveDocsSandbox { + public static JLabel comment = new JLabel("Prototype Comments appear here"); + + public static void main(String[] args) { + comment.setForeground(Color.blue); + + JPanel panels = new JPanel(new MigLayout("gap 0, insets 0")); + panels.add(LiveDocPanel.getThermistorPanel("Coolant Sensor", "CLT", LDS_CLT_INDEX, ThermistorState.VALUES), "wrap"); + panels.add(LiveDocPanel.getThermistorPanel("Intake Air Sensor", "CLT", LDS_CLT_INDEX, ThermistorState.VALUES), "wrap"); + + panels.add(getTChargePanel(), "wrap"); + + panels.add(comment); + + new FrameHelper().showFrame(panels); + } + + private static Component getTChargePanel() { + JPanel panel = new JPanel(new MigLayout("gap 0, insets 0")); + panel.setBorder(BorderFactory.createTitledBorder("Air Charge Temperature")); + panel.setBorder(BorderFactory.createLineBorder(Color.CYAN)); + + JPanel topPanel = new JPanel(new MigLayout()); + setTransparentLineBorder(topPanel); + topPanel.add(new JLabel("top")); + + JPanel bottomPanel = new JPanel(new MigLayout()); + setTransparentLineBorder(bottomPanel); + bottomPanel.add(new JLabel("bottom")); + + addBranch(panel, true, topPanel, bottomPanel); + + return panel; + } + + private static void addBranch(JPanel panel, boolean b, JPanel topPanel, JPanel bottomPanel) { + //IfBranch branch; + JPanel topWrapped = wrapWithOffset(topPanel); + JPanel bottomWrapped = wrapWithOffset(bottomPanel); + + topPanel.setBorder(BorderFactory.createLineBorder(Color.green)); + bottomPanel.setBorder(BorderFactory.createLineBorder(Color.red)); + Toolbox.setEnabledRecursive(bottomPanel, false); + + + panel.add(new JLabel("If xa"), "wrap"); + panel.add(topWrapped, "wrap"); + panel.add(new JLabel("else"), "wrap"); + panel.add(bottomWrapped, "wrap"); + + } + + @NotNull + private static JPanel wrapWithOffset(JPanel panel) { + JPanel topWrapped = new JPanel(new FlowLayout()); + topWrapped.add(new JLabel("x")); + topWrapped.add(panel); + return topWrapped; + } +} diff --git a/java_console/ui/src/com/rusefi/ui/livedocs/controls/ConfigReference.java b/java_console/ui/src/com/rusefi/ui/livedocs/controls/ConfigReference.java new file mode 100644 index 0000000000..fd2e5b7c05 --- /dev/null +++ b/java_console/ui/src/com/rusefi/ui/livedocs/controls/ConfigReference.java @@ -0,0 +1,9 @@ +package com.rusefi.ui.livedocs.controls; + +public class ConfigReference { + final int value; + + public ConfigReference(int value) { + this.value = value; + } +} diff --git a/java_console/ui/src/com/rusefi/ui/livedocs/controls/ConfigView.java b/java_console/ui/src/com/rusefi/ui/livedocs/controls/ConfigView.java new file mode 100644 index 0000000000..c1bf736008 --- /dev/null +++ b/java_console/ui/src/com/rusefi/ui/livedocs/controls/ConfigView.java @@ -0,0 +1,35 @@ +package com.rusefi.ui.livedocs.controls; + +import com.rusefi.ui.livedocs.LiveDocsSandbox; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +public class ConfigView { + private final JLabel content; + + public ConfigView(ConfigReference e) { + content = new JLabel(Integer.toString(e.value)); + markLiveElement(content); + content.setToolTipText("Configuration XXX"); + + content.addMouseListener(new MouseAdapter() { + @Override + public void mouseEntered(MouseEvent e) { + LiveDocsSandbox.comment.setText("Mouse action shows tooltip"); + } + }); + + } + + public static void markLiveElement(JComponent content) { + content.setBackground(Color.lightGray); + content.setOpaque(true); + } + + public JLabel getContent() { + return content; + } +} diff --git a/java_console/ui/src/com/rusefi/ui/livedocs/controls/LogicReference.java b/java_console/ui/src/com/rusefi/ui/livedocs/controls/LogicReference.java new file mode 100644 index 0000000000..0220c80bd4 --- /dev/null +++ b/java_console/ui/src/com/rusefi/ui/livedocs/controls/LogicReference.java @@ -0,0 +1,35 @@ +package com.rusefi.ui.livedocs.controls; + +import com.rusefi.ui.livedocs.LiveDocsSandbox; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +import static com.rusefi.ui.livedocs.controls.ConfigView.markLiveElement; + +public class LogicReference { + private final JLabel content = new JLabel(); + + public LogicReference(double value, JComponent reference) { + content.setText(Double.toString(value)); + markLiveElement(content); + content.addMouseListener(new MouseAdapter() { + @Override + public void mouseEntered(MouseEvent e) { + reference.setBorder(BorderFactory.createLineBorder(Color.red)); + LiveDocsSandbox.comment.setText("Mouse action highlights referenced element"); + } + + @Override + public void mouseExited(MouseEvent e) { + Toolbox.setTransparentLineBorder(reference); + } + }); + } + + public JLabel getContent() { + return content; + } +} diff --git a/java_console/ui/src/com/rusefi/ui/livedocs/controls/Toolbox.java b/java_console/ui/src/com/rusefi/ui/livedocs/controls/Toolbox.java new file mode 100644 index 0000000000..b19f432719 --- /dev/null +++ b/java_console/ui/src/com/rusefi/ui/livedocs/controls/Toolbox.java @@ -0,0 +1,26 @@ +package com.rusefi.ui.livedocs.controls; + +import javax.swing.*; +import java.awt.*; + +/** + * Swing UI utilities + */ +public class Toolbox { + public static void setTransparentLineBorder(JComponent reference) { + reference.setBorder(BorderFactory.createEmptyBorder(1, 1, 1, 1)); + } + + public static void setEnabledRecursive(Container panel, boolean value) { + panel.setEnabled(value); + Component[] com = panel.getComponents(); + for (int a = 0; a < com.length; a++) { + Component element = com[a]; + if (element instanceof Container) { + setEnabledRecursive((Container) element, value); + } else { + element.setEnabled(value); + } + } + } +} diff --git a/java_console/ui/ui.iml b/java_console/ui/ui.iml index 7967ad3d1b..91616b7195 100644 --- a/java_console/ui/ui.iml +++ b/java_console/ui/ui.iml @@ -20,5 +20,6 @@ + \ No newline at end of file diff --git a/java_tools/configuration_definition/.idea/runConfigurations/LiveDocsMetaParser.xml b/java_tools/configuration_definition/.idea/runConfigurations/LiveDocsMetaParser.xml new file mode 100644 index 0000000000..fb20ad5272 --- /dev/null +++ b/java_tools/configuration_definition/.idea/runConfigurations/LiveDocsMetaParser.xml @@ -0,0 +1,16 @@ + + + + \ No newline at end of file diff --git a/java_tools/configuration_definition/src/com/rusefi/ldmp/ConfigRequest.java b/java_tools/configuration_definition/src/com/rusefi/ldmp/ConfigRequest.java new file mode 100644 index 0000000000..20c6f2844e --- /dev/null +++ b/java_tools/configuration_definition/src/com/rusefi/ldmp/ConfigRequest.java @@ -0,0 +1,45 @@ +package com.rusefi.ldmp; + + +import java.util.Objects; + +import static com.rusefi.ConfigDefinition.EOL; + +public class ConfigRequest extends Request { + //@NotNull + private final String field; + + public ConfigRequest(String field) { + Objects.requireNonNull(field); + this.field = field; + } + + public String getField() { + return field; + } + + @Override + public String toString() { + return "ConfigRequest{" + + "field='" + field + '\'' + + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ConfigRequest that = (ConfigRequest) o; + return field.equals(that.field); + } + + @Override + public int hashCode() { + return Objects.hash(field); + } + + @Override + public String getJavaCode() { + return withSimpleParameter("\"" + field + "\""); + } +} diff --git a/java_tools/configuration_definition/src/com/rusefi/ldmp/FieldRequest.java b/java_tools/configuration_definition/src/com/rusefi/ldmp/FieldRequest.java new file mode 100644 index 0000000000..bb03d2963e --- /dev/null +++ b/java_tools/configuration_definition/src/com/rusefi/ldmp/FieldRequest.java @@ -0,0 +1,40 @@ +package com.rusefi.ldmp; + +import java.util.Objects; + +public class FieldRequest extends Request { + private final String field; + + public FieldRequest(String field) { + this.field = field; + } + + public String getField() { + return field; + } + + @Override + public String toString() { + return "FieldRequest{" + + "field='" + field + '\'' + + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + FieldRequest that = (FieldRequest) o; + return field.equals(that.field); + } + + @Override + public int hashCode() { + return Objects.hash(field); + } + + @Override + public String getJavaCode() { + return withSimpleParameter("\"" + field + "\""); + } +} diff --git a/java_tools/configuration_definition/src/com/rusefi/ldmp/IfRequest.java b/java_tools/configuration_definition/src/com/rusefi/ldmp/IfRequest.java new file mode 100644 index 0000000000..5851fbc2c3 --- /dev/null +++ b/java_tools/configuration_definition/src/com/rusefi/ldmp/IfRequest.java @@ -0,0 +1,27 @@ +package com.rusefi.ldmp; + +import java.util.ArrayList; +import java.util.List; + +public class IfRequest extends Request { + private final String variable; + public List trueBlock = new ArrayList<>(); + public List falseBlock = new ArrayList<>(); + + public IfRequest(String variable) { + this.variable = variable; + } + + @Override + public String toString() { + return "IfRequest{" + + "variable='" + variable + '\'' + + ", trueBlock=" + trueBlock + + ", falseBlock=" + falseBlock + + '}'; + } + + public String getVariable() { + return variable; + } +} diff --git a/java_tools/configuration_definition/src/com/rusefi/ldmp/LiveDocsMetaParser.java b/java_tools/configuration_definition/src/com/rusefi/ldmp/LiveDocsMetaParser.java new file mode 100644 index 0000000000..99f0a04dc0 --- /dev/null +++ b/java_tools/configuration_definition/src/com/rusefi/ldmp/LiveDocsMetaParser.java @@ -0,0 +1,139 @@ +package com.rusefi.ldmp; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; +import java.util.Scanner; +import java.util.Stack; +import java.util.stream.Stream; + +import static com.rusefi.ConfigDefinition.EOL; + +public class LiveDocsMetaParser { + private static final String DISPLAY_CONFIG = "DISPLAY_CONFIG"; + private static final String DISPLAY_FIELD = "DISPLAY_FIELD"; + private static final String DISPLAY_TEXT = "DISPLAY_TEXT"; + private static final String DISPLAY_SENSOR = "DISPLAY_SENSOR"; + private static final String DISPLAY_IF = "DISPLAY_IF"; + private static final String DISPLAY_ELSE = "DISPLAY_ELSE"; + private static final String DISPLAY_ENDIF = "DISPLAY_ENDIF"; + + private static String readLineByLine(String filePath) throws IOException { + StringBuilder contentBuilder = new StringBuilder(); + Stream stream = Files.lines(Paths.get(filePath), StandardCharsets.UTF_8); + stream.forEach(s -> contentBuilder.append(s).append("\n")); + return contentBuilder.toString(); + } + + public static void main(String[] args) throws IOException { + String fileName = args[0]; + String destinationPath = args[1]; + System.out.println(fileName); + if (!new File(fileName).exists()) + throw new IllegalStateException("Not found " + fileName); + String content = readLineByLine(fileName); + List r = parse(content); + System.out.println(r); + + + String className = "ThermistorMeta"; + String javaCode = generateJavaCode(r, className); + FileWriter fw = new FileWriter(destinationPath + "java_console/ui/src/com/rusefi/ldmp/generated/" + className + ".java"); + fw.write(javaCode); + fw.close(); + } + + public static List parse(String string) { + Stack> stack = new Stack<>(); + + List result = new ArrayList<>(); + string = string.replaceAll("[()>]", " "); + System.out.println(string); + Scanner s = new Scanner(string); + while (s.hasNext()) { + String token = s.next(); + //System.out.println(token); + if (DISPLAY_CONFIG.equals(token)) { + if (s.hasNext()) { + String config = s.next(); + System.out.println("REQ CONF " + config); + result.add(new ConfigRequest(config)); + } + } else if (DISPLAY_TEXT.equals(token)) { + if (s.hasNext()) { + String config = s.next(); + System.out.println("REQ TEXT " + config); + result.add(new TextRequest(config)); + } + } else if (DISPLAY_FIELD.equals(token)) { + if (s.hasNext()) { + String config = s.next(); + System.out.println("REQ FIELD " + config); + result.add(new FieldRequest(config)); + } + } else if (DISPLAY_IF.equals(token)) { + if (s.hasNext()) { + stack.push(result); + + String variable = s.next(); + + + String config = s.next(); + System.out.println("REQ TEXT " + config); + IfRequest ifRequest = new IfRequest(variable); + result.add(ifRequest); + + result = ifRequest.trueBlock; + } + } else if (DISPLAY_ELSE.equals(token)) { + if (stack.isEmpty()) + throw new IllegalStateException("No IF statement on stack"); + List onStack = stack.peek(); + if (onStack.isEmpty()) + throw new IllegalStateException("Empty on stack"); + Request request = onStack.get(onStack.size() - 1); + if (!(request instanceof IfRequest)) + throw new IllegalStateException("Something not right " + request); + IfRequest ifRequest = (IfRequest) request; + + result = ifRequest.falseBlock; + } else if (DISPLAY_ENDIF.equals(token)) { + if (stack.isEmpty()) + throw new IllegalStateException("No IF statement on stack"); + result = stack.pop(); + + } else if (DISPLAY_SENSOR.equals(token)) { + if (s.hasNext()) { + String config = s.next(); + System.out.println("REQ SENSOR " + config); + result.add(new SensorRequest(config)); + } + } + } + + if (!stack.isEmpty()) + throw new IllegalStateException("Unfinished"); + return result; + } + + public static String generateJavaCode(List r, String className) { + StringBuilder java = new StringBuilder("package com.rusefi.ldmp.generated;" + EOL + EOL + + "import com.rusefi.ldmp.*;" + EOL + EOL + + "public class " + className + " {" + EOL + + "\tpublic static final Request[] CONTENT = new Request[]{" + EOL); + + for (Request request : r) { + java.append(request.getJavaCode()); + } + + java.append("\t};" + EOL + + "}"); + + return java.toString(); + } +} diff --git a/java_tools/configuration_definition/src/com/rusefi/ldmp/Request.java b/java_tools/configuration_definition/src/com/rusefi/ldmp/Request.java new file mode 100644 index 0000000000..7d04b1b187 --- /dev/null +++ b/java_tools/configuration_definition/src/com/rusefi/ldmp/Request.java @@ -0,0 +1,13 @@ +package com.rusefi.ldmp; + +import static com.rusefi.ConfigDefinition.EOL; + +public class Request { + public String getJavaCode() { + return withSimpleParameter(""); + } + + protected String withSimpleParameter(String parameter) { + return "\t\t\tnew " + getClass().getSimpleName() + "(" + parameter + ")," + EOL; + } +} diff --git a/java_tools/configuration_definition/src/com/rusefi/ldmp/SensorRequest.java b/java_tools/configuration_definition/src/com/rusefi/ldmp/SensorRequest.java new file mode 100644 index 0000000000..e68d527339 --- /dev/null +++ b/java_tools/configuration_definition/src/com/rusefi/ldmp/SensorRequest.java @@ -0,0 +1,38 @@ +package com.rusefi.ldmp; + +import java.util.Objects; + +import static com.rusefi.ConfigDefinition.EOL; + +public class SensorRequest extends Request { + private final String value; + + public SensorRequest(String value) { + this.value = value; + } + + @Override + public String toString() { + return "SensorRequest{" + + "value='" + value + '\'' + + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + SensorRequest that = (SensorRequest) o; + return value.equals(that.value); + } + + @Override + public int hashCode() { + return Objects.hash(value); + } + + @Override + public String getJavaCode() { + return "/*sens*/" + EOL; + } +} diff --git a/java_tools/configuration_definition/src/com/rusefi/ldmp/TextRequest.java b/java_tools/configuration_definition/src/com/rusefi/ldmp/TextRequest.java new file mode 100644 index 0000000000..418b633d88 --- /dev/null +++ b/java_tools/configuration_definition/src/com/rusefi/ldmp/TextRequest.java @@ -0,0 +1,46 @@ +package com.rusefi.ldmp; + +import java.util.Objects; + +import static com.rusefi.ConfigDefinition.EOL; + +public class TextRequest extends Request { + private final String value; + + public TextRequest(String value) { + this.value = value; + } + + public String getValue() { + return value; + } + + public boolean isEol() { + return "EOL".equalsIgnoreCase(value); + } + + @Override + public String toString() { + return "TextRequest{" + + "value='" + value + '\'' + + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + TextRequest that = (TextRequest) o; + return value.equals(that.value); + } + + @Override + public int hashCode() { + return Objects.hash(value); + } + + @Override + public String getJavaCode() { + return withSimpleParameter("\"" + value + "\""); + } +} diff --git a/java_tools/configuration_definition/src/com/rusefi/ldmp/test/LiveDocsMetaParserTest.java b/java_tools/configuration_definition/src/com/rusefi/ldmp/test/LiveDocsMetaParserTest.java new file mode 100644 index 0000000000..9e1f24b4f5 --- /dev/null +++ b/java_tools/configuration_definition/src/com/rusefi/ldmp/test/LiveDocsMetaParserTest.java @@ -0,0 +1,75 @@ +package com.rusefi.ldmp.test; + +import com.rusefi.ldmp.*; +import org.junit.Test; + +import java.util.List; + +import static org.junit.Assert.assertEquals; + +public class LiveDocsMetaParserTest { + @Test + public void parseConfigElements() { + List r = LiveDocsMetaParser.parse("\t\t// TCHARGE_MODE_RPM_TPS\n" + + "\t\tfloat minRpmKcurrentTPS = interpolateMsg(\"minRpm\", tpMin, DISPLAY_CONFIG(tChargeMinRpmMinTps), tpMax,\n" + + "\t\t\t\t/***display*/CONFIG(tChargeMinRpmMaxTps), tps);\n" + + "\t\tfloat maxRpmKcurrentTPS = interpolateMsg(\"maxRpm\", tpMin, DISPLAY_CONFIG(tChargeMaxRpmMinTps), tpMax,\n" + + "\t\t\t\tDISPLAY_CONFIG(tChargeMaxRpmMaxTps), tps);\n" + + "\n" + + "\t\tengine->engineState.Tcharge_coff = interpolateMsg(\"Kcurr\", rpmMin, minRpmKcurrentTPS, rpmMax, maxRpmKcurrentTPS, rpm);\n"); + assertEquals(3, r.size()); + assertEquals(new ConfigRequest("tChargeMinRpmMinTps"), r.get(0)); + } + + @Test + public void parseDisplayConfig() { + List r = LiveDocsMetaParser.parse("\t\t// DISPLAY_TEXT(interpolate(\")\n" + + "+\t\tDISPLAY_SENSOR(RPM) DISPLAY_TEXT(TCHARGE_MODE_RPM_TPS)\n" + + "\t\tfloat minRpmKcurrentTPS = interpolateMsg(\"minRpm\", tpMin, DISPLAY_CONFIG(tChargeMinRpmMinTps), tpMax,\n"); + assertEquals(4, r.size()); + // implementation has eaten the bracket :( + assertEquals(new TextRequest("interpolate"), r.get(0)); + assertEquals(new SensorRequest("RPM"), r.get(1)); + + String javaCode = LiveDocsMetaParser.generateJavaCode(r, "xx"); + assertEquals("package com.rusefi.ldmp.generated;\n" + + "\n" + + "import com.rusefi.ldmp.*;\n" + + "\n" + + "public class xx {\n" + + "\tpublic static final Request[] CONTENT = new Request[]{\n" + + "\t\t\tnew TextRequest(\"interpolate\"),\n" + + "/*sens*/\n" + + "\t\t\tnew TextRequest(\"TCHARGE_MODE_RPM_TPS\"),\n" + + "\t\t\tnew ConfigRequest(\"tChargeMinRpmMinTps\"),\n" + + "\t};\n" + + "}", javaCode); + + } + + @Test + public void testField() { + List r = LiveDocsMetaParser.parse("tm->DISPLAY_FIELD(voltageMCU) = getVoltage(\"term\", config->adcChannel);"); + assertEquals(1, r.size()); + assertEquals(new FieldRequest("voltageMCU"), r.get(0)); + } + + @Test + public void parseIf() { + List r = LiveDocsMetaParser.parse("\tDISPLAY_IF(cond)\t// DISPLAY_TEXT(\"interpolate(\")\n" + + "+\t\tDISPLAY_SENSOR(RPM)" + + "/* DISPLAY_ELSE */ DISPLAY_TEXT(\"TCHARGE_MODE_RPM_TPS\")\n" + + "\t\tfloat minRpmKcurrentTPS = interpolateMsg(\"minRpm\", tpMin, DISPLAY_CONFIG(tChargeMinRpmMinTps), tpMax,\n" + + "/* DISPLAY_ENDIF */"); + + assertEquals(1, r.size()); + IfRequest ifRequest = (IfRequest) r.get(0); + List trueBlock = ifRequest.trueBlock; + assertEquals(2, trueBlock.size()); + assertEquals(new SensorRequest("RPM"), trueBlock.get(1)); + + List falseBlock = ifRequest.falseBlock; + assertEquals(2, falseBlock.size()); + assertEquals(new ConfigRequest("tChargeMinRpmMinTps"), falseBlock.get(1)); + } +} diff --git a/java_tools/enum_to_string/enum_to_string.iml b/java_tools/enum_to_string/enum_to_string.iml index 8e1b626b59..56884b34f4 100644 --- a/java_tools/enum_to_string/enum_to_string.iml +++ b/java_tools/enum_to_string/enum_to_string.iml @@ -8,5 +8,6 @@ + \ No newline at end of file