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