Annotations in C++ code to produce formulas in rusEfi console #807 (#848)

This commit is contained in:
rusefi 2019-06-17 19:14:03 -04:00 committed by GitHub
parent a8f456b807
commit 451ace3f5d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
31 changed files with 936 additions and 4 deletions

View File

@ -0,0 +1,9 @@
<component name="libraryTable">
<library name="snakeyaml">
<CLASSES>
<root url="jar://$PROJECT_DIR$/../java_tools/configuration_definition/lib/snakeyaml.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</component>

View File

@ -3,6 +3,8 @@
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/autotest/autotest.iml" filepath="$PROJECT_DIR$/autotest/autotest.iml" />
<module fileurl="file://$PROJECT_DIR$/../java_tools/configuration_definition/configuration_definition.iml" filepath="$PROJECT_DIR$/../java_tools/configuration_definition/configuration_definition.iml" />
<module fileurl="file://$PROJECT_DIR$/../java_tools/enum_to_string/enum_to_string.iml" filepath="$PROJECT_DIR$/../java_tools/enum_to_string/enum_to_string.iml" />
<module fileurl="file://$PROJECT_DIR$/io/io.iml" filepath="$PROJECT_DIR$/io/io.iml" />
<module fileurl="file://$PROJECT_DIR$/logging/logging.iml" filepath="$PROJECT_DIR$/logging/logging.iml" />
<module fileurl="file://$PROJECT_DIR$/models/models.iml" filepath="$PROJECT_DIR$/models/models.iml" />

View File

@ -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 {

View File

@ -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
}

View File

@ -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;

View File

@ -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<RefreshActions> actions;
private final Field[] values;
public LiveDocHolder(int id, List<RefreshActions> 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);
}
}

View File

@ -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<Integer, LiveDocHolder> 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);
}
}
}
}

View File

@ -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);
}

View File

@ -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);

View File

@ -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,
};
}

View File

@ -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;

View File

@ -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,
};
}

View File

@ -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"),
};
}

View File

@ -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

View File

@ -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<RefreshActions> 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<RefreshActions> createComponents(JPanel panel, Request[] content, Field[] values, String instancePrefix) {
List<RefreshActions> 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;
}
}

View File

@ -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;
}
}

View File

@ -0,0 +1,9 @@
package com.rusefi.ui.livedocs.controls;
public class ConfigReference {
final int value;
public ConfigReference(int value) {
this.value = value;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}
}
}

View File

@ -20,5 +20,6 @@
<orderEntry type="module" module-name="autotest" />
<orderEntry type="module" module-name="romraider" />
<orderEntry type="library" name="jlatexmath" level="project" />
<orderEntry type="module" module-name="configuration_definition" />
</component>
</module>

View File

@ -0,0 +1,16 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="LiveDocsMetaParser" type="Application" factoryName="Application" nameIsGenerated="true">
<option name="MAIN_CLASS_NAME" value="com.rusefi.ldmp.LiveDocsMetaParser" />
<module name="configuration_definition" />
<option name="PROGRAM_PARAMETERS" value="&quot;../../firmware/controllers/sensors/thermistors.cpp&quot;" />
<extension name="coverage">
<pattern>
<option name="PATTERN" value="com.rusefi.ldmp.*" />
<option name="ENABLED" value="true" />
</pattern>
</extension>
<method v="2">
<option name="Make" enabled="true" />
</method>
</configuration>
</component>

View File

@ -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 + "\"");
}
}

View File

@ -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 + "\"");
}
}

View File

@ -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<Request> trueBlock = new ArrayList<>();
public List<Request> 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;
}
}

View File

@ -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<String> 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<Request> 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<Request> parse(String string) {
Stack<List<Request>> stack = new Stack<>();
List<Request> 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<Request> 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<Request> 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();
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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 + "\"");
}
}

View File

@ -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<Request> 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<Request> 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<Request> 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<Request> 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<Request> trueBlock = ifRequest.trueBlock;
assertEquals(2, trueBlock.size());
assertEquals(new SensorRequest("RPM"), trueBlock.get(1));
List<Request> falseBlock = ifRequest.falseBlock;
assertEquals(2, falseBlock.size());
assertEquals(new ConfigRequest("tChargeMinRpmMinTps"), falseBlock.get(1));
}
}

View File

@ -8,5 +8,6 @@
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="junit" level="project" />
<orderEntry type="library" name="snakeyaml" level="project" />
</component>
</module>