diff --git a/java_console/inifile/src/main/java/com/rusefi/config/Field.java b/java_console/inifile/src/main/java/com/rusefi/config/Field.java index 0e08fe8fde..463836bee5 100644 --- a/java_console/inifile/src/main/java/com/rusefi/config/Field.java +++ b/java_console/inifile/src/main/java/com/rusefi/config/Field.java @@ -49,10 +49,17 @@ public class Field { this.options = options; } + public static Field findField(Field[] values, String instancePrefix, String fieldName) { + Field field = findFieldOrNull(values, instancePrefix, fieldName); + if (field == null) + throw new IllegalStateException("No field: " + fieldName); + return field; + } + /** * Finds field by name, ignoring case */ - public static Field findField(Field[] values, String instancePrefix, String fieldName) { + public static Field findFieldOrNull(Field[] values, String instancePrefix, String fieldName) { Objects.requireNonNull(fieldName); for (Field f : values) { if (fieldName.equalsIgnoreCase(f.getName())) @@ -66,7 +73,7 @@ public class Field { return f; } } - throw new IllegalStateException("No field: " + fieldName); + return null; } public static int getStructureSize(Field[] values) { @@ -159,7 +166,7 @@ public class Field { // todo: rename to getNumberValue? @NotNull public Double getValue(ConfigurationImage ci, double multiplier) { - Objects.requireNonNull(ci); + Objects.requireNonNull(ci, "ConfigurationImage"); Number value; ByteBuffer wrapped = ci.getByteBuffer(getOffset(), type.getStorageSize()); if (bitOffset != NO_BIT_OFFSET) { diff --git a/java_console/io/src/main/java/com/rusefi/io/LinkManager.java b/java_console/io/src/main/java/com/rusefi/io/LinkManager.java index a3173211d7..ce5d0b2bd2 100644 --- a/java_console/io/src/main/java/com/rusefi/io/LinkManager.java +++ b/java_console/io/src/main/java/com/rusefi/io/LinkManager.java @@ -43,7 +43,7 @@ public class LinkManager implements Closeable { public static final String LOG_VIEWER = "log viewer"; private final CommandQueue commandQueue; - private LinkConnector connector; + private LinkConnector connector = LinkConnector.VOID; private boolean isStarted; private boolean compositeLogicEnabled = true; private boolean needPullData = true; @@ -205,6 +205,7 @@ public class LinkManager implements Closeable { connector.connectAndReadConfiguration(stateListener); } + @NotNull public LinkConnector getConnector() { return connector; } diff --git a/java_console/ui/src/main/java/com/rusefi/livedata/LiveDataParserPanel.java b/java_console/ui/src/main/java/com/rusefi/livedata/LiveDataParserPanel.java index 5c8035f130..886004c55f 100644 --- a/java_console/ui/src/main/java/com/rusefi/livedata/LiveDataParserPanel.java +++ b/java_console/ui/src/main/java/com/rusefi/livedata/LiveDataParserPanel.java @@ -1,30 +1,39 @@ package com.rusefi.livedata; import com.devexperts.logging.Logging; +import com.opensr5.ConfigurationImage; +import com.rusefi.binaryprotocol.BinaryProtocol; +import com.rusefi.binaryprotocol.BinaryProtocolState; +import com.rusefi.config.Field; +import com.rusefi.config.generated.Fields; +import com.rusefi.enums.live_data_e; +import com.rusefi.io.LinkConnector; import com.rusefi.livedata.generated.CPP14Lexer; import com.rusefi.livedata.generated.CPP14Parser; import com.rusefi.livedata.generated.CPP14ParserBaseListener; +import com.rusefi.ui.UIContext; import com.rusefi.ui.livedata.Range; import com.rusefi.ui.livedata.SourceCodePainter; import com.rusefi.ui.livedata.VariableValueSource; -import org.antlr.v4.runtime.ANTLRInputStream; -import org.antlr.v4.runtime.CharStream; -import org.antlr.v4.runtime.CommonTokenStream; -import org.antlr.v4.runtime.ParserRuleContext; +import com.rusefi.ui.livedocs.LiveDocHolder; +import com.rusefi.ui.livedocs.LiveDocsRegistry; +import com.rusefi.ui.livedocs.RefreshActions; +import com.rusefi.ui.livedocs.RefreshActionsMap; +import org.antlr.v4.runtime.*; import org.antlr.v4.runtime.tree.ParseTree; import org.antlr.v4.runtime.tree.ParseTreeWalker; +import org.antlr.v4.runtime.tree.TerminalNode; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import javax.swing.*; -import javax.swing.text.AttributeSet; -import javax.swing.text.StyleConstants; -import javax.swing.text.StyleContext; -import javax.swing.text.StyledDocument; +import javax.swing.text.*; import java.awt.*; import java.io.*; import java.net.URISyntaxException; import java.net.URL; import java.util.Stack; +import java.util.concurrent.atomic.AtomicReference; import static com.devexperts.logging.Logging.getLogging; import static javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED; @@ -37,11 +46,48 @@ public class LiveDataParserPanel { private static final Logging log = getLogging(LiveDataParserPanel.class); private final JPanel content = new JPanel(new BorderLayout()); - private final JTextPane text = new JTextPane(); + private ParseResult parseResult = ParseResult.VOID; + private final UIContext uiContext; + private final JTextPane text = new JTextPane() { + @Override + public void paint(Graphics g) { + super.paint(g); + BinaryProtocol binaryProtocol = uiContext.getLinkManager().getConnector().getBinaryProtocol(); + if (binaryProtocol == null) + return; + BinaryProtocolState bps = binaryProtocol.getBinaryProtocolState(); + if (bps == null) + return; + ConfigurationImage ci = bps.getControllerConfiguration(); + if (ci == null) + return; + + g.setColor(Color.red); + + for (Token setting : parseResult.getConfigTokens()) { + Field field = Field.findFieldOrNull(Fields.VALUES, "", setting.getText()); + if (field == null) + continue; + Number value = field.getValue(ci); + Rectangle r; + try { + r = getUI().modelToView(text, setting.getStopIndex()); + } catch (BadLocationException e) { + throw new IllegalStateException(e); + } + g.drawString(value.toString(), r.x, r.y); + + + } + + + } + }; private final VariableValueSource valueSource; private String sourceCode; - public LiveDataParserPanel(VariableValueSource valueSource) { + public LiveDataParserPanel(UIContext uiContext, VariableValueSource valueSource, String fileName) { + this.uiContext = uiContext; this.valueSource = valueSource; JScrollPane rightScrollPane = new JScrollPane(text, @@ -50,7 +96,7 @@ public class LiveDataParserPanel { content.add(rightScrollPane); try { - sourceCode = getContent(getClass(), "ac_control.cpp"); + sourceCode = getContent(getClass(), fileName); text.setText(sourceCode); refresh(); @@ -84,22 +130,29 @@ public class LiveDataParserPanel { return parser.translationUnit(); } - public static void applyVariables(VariableValueSource valueSource, String s, SourceCodePainter painter, ParseTree tree) { + public static ParseResult applyVariables(VariableValueSource valueSource, String s, SourceCodePainter painter, ParseTree tree) { Stack currentState = new Stack<>(); currentState.add(Boolean.TRUE); + java.util.List allTerminals = new java.util.ArrayList<>(); + new ParseTreeWalker().walk(new CPP14ParserBaseListener() { @Override public void enterStatement(CPP14Parser.StatementContext ctx) { String origin = getOrigin(ctx, s); - System.out.println("enter statement [" + origin + "]"); +// System.out.println("enter statement [" + origin + "]"); + } + + @Override + public void visitTerminal(TerminalNode node) { + allTerminals.add(node); } @Override public void enterCondition(CPP14Parser.ConditionContext ctx) { String conditionVariable = ctx.getText(); - System.out.println("REQUESTING VALUE " + conditionVariable); - System.out.println("exp " + getOrigin(ctx.expression(), s)); +// System.out.println("REQUESTING VALUE " + conditionVariable); +// System.out.println("exp " + getOrigin(ctx.expression(), s)); Boolean state = (Boolean) valueSource.getValue(conditionVariable); if (state == null) { @@ -107,17 +160,16 @@ public class LiveDataParserPanel { return; } if (state) { - painter.paint(Color.GREEN, new Range(ctx)); + painter.paintBackground(Color.GREEN, new Range(ctx)); } else { - painter.paint(Color.RED, new Range(ctx)); + painter.paintBackground(Color.RED, new Range(ctx)); } } @Override public void enterSelectionStatement(CPP14Parser.SelectionStatementContext ctx) { super.enterSelectionStatement(ctx); - - System.out.println("Else terminal " + ctx.Else()); +// System.out.println("Else terminal " + ctx.Else()); } @Override @@ -125,6 +177,21 @@ public class LiveDataParserPanel { } }, tree); + + java.util.List configTokens = new java.util.ArrayList<>(); + + for (int i = 0; i < allTerminals.size() - 3; i++) { + + if (allTerminals.get(i).getText().equals("CONFIG") && + allTerminals.get(i + 1).getText().equals("(") && + allTerminals.get(i + 3).getText().equals(")") + ) { + Token token = allTerminals.get(i + 2).getSymbol(); + painter.paintForeground(Color.BLUE, new Range(token, token)); + configTokens.add(token); + } + } + return new ParseResult(configTokens); } @NotNull @@ -146,12 +213,62 @@ public class LiveDataParserPanel { AttributeSet oldSet = styledDocument.getCharacterElement(0).getAttributes(); styledDocument.setCharacterAttributes(0, sourceCode.length(), sc.getEmptySet(), true); - applyVariables(valueSource, sourceCode, new SourceCodePainter() { + // todo: technically we do not need to do the complete re-compile on fresh data arrival just repaint! + // todo: split compilation and painting/repainting + parseResult = applyVariables(valueSource, sourceCode, new SourceCodePainter() { @Override - public void paint(Color color, Range range) { + public void paintBackground(Color color, Range range) { AttributeSet s = sc.addAttribute(oldSet, StyleConstants.Background, color); styledDocument.setCharacterAttributes(range.getStart(), range.getLength(), s, true); } + + @Override + public void paintForeground(Color color, Range range) { + AttributeSet s = sc.addAttribute(oldSet, StyleConstants.Foreground, color); + styledDocument.setCharacterAttributes(range.getStart(), range.getLength(), s, true); + } }, tree); } + + @Nullable + public static LiveDataParserPanel getLiveDataParserPanel(UIContext uiContext, final live_data_e live_data_e, final Field[] values, String fileName) { + AtomicReference reference = new AtomicReference<>(); + + LiveDataParserPanel livePanel = new LiveDataParserPanel(uiContext, new VariableValueSource() { + @Override + public Object getValue(String name) { + byte[] bytes = reference.get(); + if (bytes == null) + return null; + Field f = Field.findField(values, "", name); + int number = f.getValue(new ConfigurationImage(bytes)).intValue(); +// System.out.println("getValue " + f); + // convert Number to Boolean + return number != 0; + } + }, fileName); + RefreshActionsMap refreshActionsMap = new RefreshActionsMap(); + refreshActionsMap.put(live_data_e, new RefreshActions() { + @Override + public void refresh(BinaryProtocol bp, byte[] response) { + reference.set(response); + livePanel.refresh(); + } + }); + + LiveDocsRegistry.INSTANCE.register(new LiveDocHolder(live_data_e, refreshActionsMap) { + @Override + public boolean isVisible() { + JPanel panel = livePanel.getContent(); + boolean isVisible = !panel.getVisibleRect().isEmpty(); + return isVisible && isRecursivelyVisible(panel); + } + }); + return livePanel; + } + + private static boolean isRecursivelyVisible(Container c) { + Container parent = c.getParent(); + return c.isVisible() && (parent == null || isRecursivelyVisible(parent)); + } } diff --git a/java_console/ui/src/main/java/com/rusefi/livedata/ParseResult.java b/java_console/ui/src/main/java/com/rusefi/livedata/ParseResult.java new file mode 100644 index 0000000000..0ed0fbe635 --- /dev/null +++ b/java_console/ui/src/main/java/com/rusefi/livedata/ParseResult.java @@ -0,0 +1,20 @@ +package com.rusefi.livedata; + +import org.antlr.v4.runtime.Token; + +import java.util.Collections; +import java.util.List; + +public class ParseResult { + static ParseResult VOID = new ParseResult(Collections.emptyList()); + + private List configTokens; + + public ParseResult(List configTokens) { + this.configTokens = configTokens; + } + + public List getConfigTokens() { + return configTokens; + } +} diff --git a/java_console/ui/src/main/java/com/rusefi/ui/FormulasPane.java b/java_console/ui/src/main/java/com/rusefi/ui/FormulasPane.java index 2662a3e3a1..4b2dc3c570 100644 --- a/java_console/ui/src/main/java/com/rusefi/ui/FormulasPane.java +++ b/java_console/ui/src/main/java/com/rusefi/ui/FormulasPane.java @@ -4,7 +4,6 @@ import com.opensr5.ConfigurationImage; import com.opensr5.Logger; import com.rusefi.FileLog; import com.rusefi.binaryprotocol.BinaryProtocol; -import com.rusefi.config.Field; import com.rusefi.config.generated.AcControl; import com.rusefi.config.generated.Fields; import com.rusefi.core.Sensor; @@ -12,11 +11,6 @@ import com.rusefi.core.SensorCentral; import com.rusefi.enums.live_data_e; import com.rusefi.livedata.LiveDataParserPanel; import com.rusefi.ui.config.ConfigField; -import com.rusefi.ui.livedata.VariableValueSource; -import com.rusefi.ui.livedocs.LiveDocHolder; -import com.rusefi.ui.livedocs.LiveDocsRegistry; -import com.rusefi.ui.livedocs.RefreshActions; -import com.rusefi.ui.livedocs.RefreshActionsMap; import com.rusefi.ui.util.UiUtils; import com.rusefi.ui.widgets.IntGaugeLabel; import org.jetbrains.annotations.NotNull; @@ -30,10 +24,12 @@ import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.image.BufferedImage; -import java.util.concurrent.atomic.AtomicReference; /** + * todo: it was a nice prototype of jlatexmath usage but it's time to remove it soon! + * Lua nad live_data_e seems much more promising at the moment + * * Andrey Belomutskiy, (c) 2013-2020 */ public class FormulasPane { @@ -52,40 +48,9 @@ public class FormulasPane { public FormulasPane(UIContext uiContext) { this.uiContext = uiContext; - - AtomicReference reference = new AtomicReference<>(); + LiveDataParserPanel livePanel = LiveDataParserPanel.getLiveDataParserPanel(uiContext, live_data_e.LDS_AC_CONTROL, AcControl.VALUES, "ac_control.cpp"); JPanel vertical = new JPanel(new VerticalFlowLayout()); - LiveDataParserPanel livePanel = new LiveDataParserPanel(new VariableValueSource() { - @Override - public Object getValue(String name) { - byte[] bytes = reference.get(); - if (bytes == null) - return null; - Field f = Field.findField(AcControl.VALUES, "", name); - int number = f.getValue(new ConfigurationImage(bytes)).intValue(); - System.out.println("getValue"); - return number != 0; - } - }); - RefreshActionsMap refreshActionsMap = new RefreshActionsMap(); - refreshActionsMap.put(live_data_e.LDS_AC_CONTROL, new RefreshActions() { - @Override - public void refresh(BinaryProtocol bp, byte[] response) { - reference.set(response); - livePanel.refresh(); - } - }); - - LiveDocsRegistry.INSTANCE.register(new LiveDocHolder(live_data_e.LDS_AC_CONTROL, refreshActionsMap) { - @Override - public boolean isVisible() { - JPanel panel = livePanel.getContent(); - boolean isVisible = !panel.getVisibleRect().isEmpty(); - return isVisible && isRecursivelyVisible(panel); - } - }); - vertical.add(livePanel.getContent()); vertical.add(formulaProxy); @@ -318,9 +283,4 @@ public class FormulasPane { public JPanel getContent() { return content; } - - static boolean isRecursivelyVisible(Container c) { - Container parent = c.getParent(); - return c.isVisible() && (parent == null || isRecursivelyVisible(parent)); - } } \ No newline at end of file diff --git a/java_console/ui/src/main/java/com/rusefi/ui/UIContext.java b/java_console/ui/src/main/java/com/rusefi/ui/UIContext.java index fd0ea6aca2..bcfd4b8627 100644 --- a/java_console/ui/src/main/java/com/rusefi/ui/UIContext.java +++ b/java_console/ui/src/main/java/com/rusefi/ui/UIContext.java @@ -4,6 +4,7 @@ import com.rusefi.SensorSnifferCentral; import com.rusefi.io.CommandQueue; import com.rusefi.io.LinkManager; import com.rusefi.sensor_logs.SensorLogger; +import org.jetbrains.annotations.NotNull; public class UIContext { private final LinkManager linkManager = new LinkManager(); @@ -13,6 +14,7 @@ public class UIContext { public SensorSnifferCentral sensorSnifferCentral = new SensorSnifferCentral(linkManager); + @NotNull public LinkManager getLinkManager() { return linkManager; } diff --git a/java_console/ui/src/main/java/com/rusefi/ui/livedata/Range.java b/java_console/ui/src/main/java/com/rusefi/ui/livedata/Range.java index 7e15a840d2..b39221bce1 100644 --- a/java_console/ui/src/main/java/com/rusefi/ui/livedata/Range.java +++ b/java_console/ui/src/main/java/com/rusefi/ui/livedata/Range.java @@ -1,6 +1,7 @@ package com.rusefi.ui.livedata; import org.antlr.v4.runtime.ParserRuleContext; +import org.antlr.v4.runtime.Token; public class Range { private final int start; @@ -11,8 +12,13 @@ public class Range { this.stop = stop; } + public Range(Token start, Token stop) { + this(start.getStartIndex(), stop.getStopIndex() + 1); + } + + public Range(ParserRuleContext context) { - this(context.start.getStartIndex(), context.stop.getStopIndex() + 1); + this(context.start, context.stop); } public int getStart() { diff --git a/java_console/ui/src/main/java/com/rusefi/ui/livedata/SourceCodePainter.java b/java_console/ui/src/main/java/com/rusefi/ui/livedata/SourceCodePainter.java index e06b626915..c6e1d3b42a 100644 --- a/java_console/ui/src/main/java/com/rusefi/ui/livedata/SourceCodePainter.java +++ b/java_console/ui/src/main/java/com/rusefi/ui/livedata/SourceCodePainter.java @@ -3,5 +3,7 @@ package com.rusefi.ui.livedata; import java.awt.*; public interface SourceCodePainter { - void paint(Color color, Range range); + void paintBackground(Color color, Range range); + + void paintForeground(Color color, Range range); } diff --git a/java_console/ui/src/test/java/com/rusefi/livedata/LiveDataParserSandbox.java b/java_console/ui/src/test/java/com/rusefi/livedata/LiveDataParserSandbox.java index b20e9dd379..a95827b3da 100644 --- a/java_console/ui/src/test/java/com/rusefi/livedata/LiveDataParserSandbox.java +++ b/java_console/ui/src/test/java/com/rusefi/livedata/LiveDataParserSandbox.java @@ -1,5 +1,6 @@ package com.rusefi.livedata; +import com.rusefi.ui.UIContext; import com.rusefi.ui.livedata.VariableValueSource; import com.rusefi.ui.util.FrameHelper; @@ -19,6 +20,6 @@ public class LiveDataParserSandbox { } }; - new FrameHelper().showFrame(new LiveDataParserPanel(valueSource).getContent()); + new FrameHelper().showFrame(new LiveDataParserPanel(new UIContext(), valueSource, "ac_control.cpp").getContent()); } } diff --git a/java_console/ui/src/test/java/com/rusefi/ui/livedata/LiveDataParserTest.java b/java_console/ui/src/test/java/com/rusefi/ui/livedata/LiveDataParserTest.java index 9ce0f7e7e1..96520527bf 100644 --- a/java_console/ui/src/test/java/com/rusefi/ui/livedata/LiveDataParserTest.java +++ b/java_console/ui/src/test/java/com/rusefi/ui/livedata/LiveDataParserTest.java @@ -26,7 +26,7 @@ public class LiveDataParserTest { } }; - String s = "bool AcState::getAcState(DECLARE_ENGINE_PARAMETER_SIGNATURE) {\n" + + String sourceCode = "bool AcState::getAcState(DECLARE_ENGINE_PARAMETER_SIGNATURE) {\n" + "\tauto rpm = Sensor::getOrZero(SensorType::Rpm);\n" + "\n" + "\tengineTooSlow = rpm < 500;\n" + @@ -34,9 +34,9 @@ public class LiveDataParserTest { "\tif (engineTooSlow) {\n" + "\t\treturn true;\n" + "\t} else {\n " + - "auto ff2 = 1;\n" + + "auto ff2 = CONFIG(Alternatorcontrolpin);\n" + "\t}\n " + - "auto ff = 1;\n" + + "auto ff = CONFIG(tpsMax);\n" + "\tif (engineTooFast) {\n" + "\t\treturn false;\n" + "\t} \n " + @@ -45,15 +45,21 @@ public class LiveDataParserTest { SourceCodePainter painter = new SourceCodePainter() { @Override - public void paint(Color color, Range range) { + public void paintBackground(Color color, Range range) { System.out.println("paint " + color + " " + range); } + + @Override + public void paintForeground(Color color, Range range) { + System.out.println("paintForeground"); + + } }; - ParseTree tree = LiveDataParserPanel.getParseTree(s); + ParseTree tree = LiveDataParserPanel.getParseTree(sourceCode); new ParseTreeWalker().walk(new PrintCPP14ParserListener(), tree); - LiveDataParserPanel.applyVariables(valueSource, s, painter, tree); + LiveDataParserPanel.applyVariables(valueSource, sourceCode, painter, tree); } diff --git a/java_console/ui/src/test/java/com/rusefi/ui/livedata/PrintCPP14ParserListener.java b/java_console/ui/src/test/java/com/rusefi/ui/livedata/PrintCPP14ParserListener.java index 7504c376fa..b9bf296551 100644 --- a/java_console/ui/src/test/java/com/rusefi/ui/livedata/PrintCPP14ParserListener.java +++ b/java_console/ui/src/test/java/com/rusefi/ui/livedata/PrintCPP14ParserListener.java @@ -33,7 +33,7 @@ public class PrintCPP14ParserListener implements CPP14ParserListener { @Override public void enterPrimaryExpression(CPP14Parser.PrimaryExpressionContext ctx) { - System.out.println("enterPrimaryExpression"); + System.out.println("enterPrimaryExpression " + ctx.getText()); }