live data for wastegate and launch control #3588

PROGRESS!
This commit is contained in:
rusefillc 2021-12-18 11:57:25 -05:00
parent c21b15ccaa
commit 81e0f94dd4
6 changed files with 585 additions and 479 deletions

View File

@ -14,16 +14,19 @@ bool AcController::getAcState() {
engineTooSlow = rpm < 500;
if (engineTooSlow) {
return false;
}
auto maxRpm = engineConfiguration->maxAcRpm;
engineTooFast = maxRpm != 0 && maxRpmDeadband.gt(rpm, maxRpm);
if (engineTooFast) {
invokeMethodRed();
return false;
}
if (engineTooSlow) {
invokeMethod();
return false;
}
auto clt = Sensor::get(SensorType::Clt);
noClt = !clt;

View File

@ -0,0 +1,166 @@
package com.rusefi;
import com.devexperts.logging.Logging;
import com.rusefi.livedata.ParseResult;
import com.rusefi.livedata.generated.CPP14Parser;
import com.rusefi.livedata.generated.CPP14ParserBaseListener;
import com.rusefi.ui.livedata.Range;
import com.rusefi.ui.livedata.SourceCodePainter;
import com.rusefi.ui.livedata.VariableValueSource;
import org.antlr.v4.runtime.ParserRuleContext;
import org.antlr.v4.runtime.Token;
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 java.awt.*;
import java.util.Stack;
import static com.devexperts.logging.Logging.getLogging;
public class CodeWalkthrough {
private static final Logging log = getLogging(CodeWalkthrough.class);
// inactive statements within inactive branch of code - light red
public static final Color INACTIVE_BRANCH = new Color(255, 102, 102);
// active statements - light green
public static final Color ACTIVE_STATEMENT = new Color(102, 255, 102);
// cost past active return statement
public static final Color PASSIVE_CODE = Color.lightGray;
static {
log.configureDebugEnabled(true);
}
private static final String CONFIG_MAGIC_PREFIX = "engineConfiguration";
public static ParseResult applyVariables(VariableValueSource valueSource, String sourceCode, SourceCodePainter painter, ParseTree tree) {
Stack<Boolean> currentState = new Stack<>();
java.util.List<TerminalNode> allTerminals = new java.util.ArrayList<>();
new ParseTreeWalker().walk(new CPP14ParserBaseListener() {
@Override
public void enterFunctionDefinition(CPP14Parser.FunctionDefinitionContext ctx) {
// new method is starting new all over
resetState(currentState);
}
@Override
public void enterDeclarationStatement(CPP14Parser.DeclarationStatementContext ctx) {
super.enterDeclarationStatement(ctx);
colorStatement(ctx, painter);
}
@Override
public void enterJumpStatement(CPP14Parser.JumpStatementContext ctx) {
super.enterJumpStatement(ctx);
colorStatement(ctx, painter);
if ("return".equalsIgnoreCase(ctx.getStart().getText()) &&
!currentState.isEmpty() &&
getOverallState(currentState)) {
// we have experienced 'return' in 'green' active flow looks like end of execution for this method?
currentState.clear();
}
}
@Override
public void enterStatement(CPP14Parser.StatementContext ctx) {
String origin = getOrigin(ctx, sourceCode);
// System.out.println("enter statement [" + origin + "]");
}
@Override
public void visitTerminal(TerminalNode node) {
allTerminals.add(node);
if ("else".equalsIgnoreCase(node.getSymbol().getText())) {
if (log.debugEnabled())
log.debug("CONDITIONAL ELSE terminal, flipping condition");
if (currentState.isEmpty())
return;
Boolean onTop = currentState.pop();
currentState.add(!onTop);
}
}
@Override
public void enterCondition(CPP14Parser.ConditionContext ctx) {
String conditionVariable = ctx.getText();
System.out.println("CONDITIONAL: REQUESTING VALUE " + conditionVariable);
// System.out.println("exp " + getOrigin(ctx.expression(), s));
Boolean state = (Boolean) valueSource.getValue(conditionVariable);
if (state == null) {
// todo: fail on unknown condition variables
return;
}
if (log.debugEnabled())
log.debug("CURRENT STATE ADD " + state);
currentState.add(state);
if (state) {
painter.paintBackground(Color.GREEN, new Range(ctx));
} else {
painter.paintBackground(Color.RED, new Range(ctx));
}
}
@Override
public void exitSelectionStatement(CPP14Parser.SelectionStatementContext ctx) {
super.exitSelectionStatement(ctx);
if (currentState.isEmpty())
return; // we are here if some conditional variables were not resolved
currentState.pop();
if (log.debugEnabled())
log.debug("CONDITIONAL: EXIT");
}
private void colorStatement(ParserRuleContext ctx, SourceCodePainter painter) {
Color color;
if (currentState.isEmpty()) {
color = PASSIVE_CODE; // we are past return or past error
} else {
boolean isAlive = getOverallState(currentState);
color = isAlive ? ACTIVE_STATEMENT : INACTIVE_BRANCH;
}
painter.paintBackground(color, new Range(ctx));
}
}, tree);
java.util.List<Token> configTokens = new java.util.ArrayList<>();
for (int i = 0; i < allTerminals.size() - 3; i++) {
if (allTerminals.get(i).getText().equals(CONFIG_MAGIC_PREFIX) &&
allTerminals.get(i + 1).getText().equals("->")
) {
Token token = allTerminals.get(i + 2).getSymbol();
painter.paintForeground(Color.BLUE, new Range(token, token));
configTokens.add(token);
}
}
return new ParseResult(configTokens);
}
private static void resetState(Stack<Boolean> currentState) {
currentState.clear();
currentState.add(Boolean.TRUE);
}
private static boolean getOverallState(Stack<Boolean> currentState) {
for (boolean value : currentState) {
if (!value)
return false;
}
return true;
}
@NotNull
private static String getOrigin(ParserRuleContext ctx, String s) {
Range range = new Range(ctx);
return s.substring(range.getStart(), range.getStop());
}
}

View File

@ -2,6 +2,7 @@ package com.rusefi.livedata;
import com.devexperts.logging.Logging;
import com.opensr5.ConfigurationImage;
import com.rusefi.CodeWalkthrough;
import com.rusefi.binaryprotocol.BinaryProtocol;
import com.rusefi.binaryprotocol.BinaryProtocolState;
import com.rusefi.config.Field;
@ -9,7 +10,6 @@ import com.rusefi.config.generated.Fields;
import com.rusefi.enums.live_data_e;
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;
@ -19,8 +19,6 @@ import com.rusefi.ui.livedocs.LiveDocsRegistry;
import com.rusefi.ui.livedocs.RefreshActions;
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 javax.swing.*;
@ -28,7 +26,6 @@ import javax.swing.text.*;
import java.awt.*;
import java.io.*;
import java.net.URISyntaxException;
import java.util.Stack;
import java.util.concurrent.atomic.AtomicReference;
import static com.devexperts.logging.Logging.getLogging;
@ -40,7 +37,6 @@ import static javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED;
* @see LiveDataParserPanelSandbox
*/
public class LiveDataParserPanel {
private static final String CONFIG_MAGIC_PREFIX = "engineConfiguration";
private static final Logging log = getLogging(LiveDataParserPanel.class);
{
@ -134,75 +130,6 @@ public class LiveDataParserPanel {
return parser.translationUnit();
}
public static ParseResult applyVariables(VariableValueSource valueSource, String sourceCode, SourceCodePainter painter, ParseTree tree) {
Stack<Boolean> currentState = new Stack<>();
currentState.add(Boolean.TRUE);
java.util.List<TerminalNode> allTerminals = new java.util.ArrayList<>();
new ParseTreeWalker().walk(new CPP14ParserBaseListener() {
@Override
public void enterStatement(CPP14Parser.StatementContext ctx) {
String origin = getOrigin(ctx, sourceCode);
// 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));
Boolean state = (Boolean) valueSource.getValue(conditionVariable);
if (state == null) {
// todo: fail on unknown condition variables
return;
}
if (state) {
painter.paintBackground(Color.GREEN, new Range(ctx));
} else {
painter.paintBackground(Color.RED, new Range(ctx));
}
}
@Override
public void enterSelectionStatement(CPP14Parser.SelectionStatementContext ctx) {
super.enterSelectionStatement(ctx);
// System.out.println("Else terminal " + ctx.Else());
}
@Override
public void enterJumpStatement(CPP14Parser.JumpStatementContext ctx) {
}
}, tree);
java.util.List<Token> configTokens = new java.util.ArrayList<>();
for (int i = 0; i < allTerminals.size() - 3; i++) {
if (allTerminals.get(i).getText().equals(CONFIG_MAGIC_PREFIX) &&
allTerminals.get(i + 1).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
private static String getOrigin(ParserRuleContext ctx, String s) {
Range range = new Range(ctx);
return s.substring(range.getStart(), range.getStop());
}
public JPanel getContent() {
return content;
}
@ -218,7 +145,7 @@ public class LiveDataParserPanel {
// 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() {
parseResult = CodeWalkthrough.applyVariables(valueSource, sourceCode, new SourceCodePainter() {
@Override
public void paintBackground(Color color, Range range) {
AttributeSet s = sc.addAttribute(oldSet, StyleConstants.Background, color);

View File

@ -17,12 +17,7 @@ public class LiveDataParserSandbox {
values.put("engineTooSlow", Boolean.TRUE);
values.put("engineTooFast", Boolean.FALSE);
VariableValueSource valueSource = new VariableValueSource() {
@Override
public Object getValue(String name) {
return values.get(name);
}
};
VariableValueSource valueSource = name -> values.get(name);
new FrameHelper(JDialog.EXIT_ON_CLOSE).showFrame(new LiveDataParserPanel(new UIContext(), valueSource, "ac_control.cpp").getContent());
}

View File

@ -1,5 +1,6 @@
package com.rusefi.ui.livedata;
import com.rusefi.CodeWalkthrough;
import com.rusefi.livedata.LiveDataParserPanel;
import com.rusefi.livedata.LiveDataView;
import com.rusefi.livedata.ParseResult;
@ -31,9 +32,8 @@ public class LiveDataParserTest {
String sourceCode = "bool AcState::getAcState() {\n" +
"\tauto rpm = Sensor::getOrZero(SensorType::Rpm);\n" +
"\n" +
"\tengineTooSlow = rpm < 500;\n" +
"\n" +
"\tif (engineTooSlow) {\n" +
"\t\tinvokeMethod();\n" +
"\t\treturn true;\n" +
"\t} else {\n " +
"auto ff2 = engineConfiguration->Alternatorcontrolpin;\n" +
@ -43,18 +43,30 @@ public class LiveDataParserTest {
"\t\treturn false;\n" +
"\t} \n " +
"return ff;\n" +
"}";
"}\n" +
"bool AcState::getAcState2() {\n" +
"return ff;\n" +
"}\n";
SourceCodePainter painter = mock(SourceCodePainter.class);
ParseTree tree = LiveDataParserPanel.getParseTree(sourceCode);
System.out.println("******************************************* Just print everything for educational purposes");
new ParseTreeWalker().walk(new PrintCPP14ParserListener(), tree);
System.out.println("******************************************* Now running FOR REAL");
LiveDataParserPanel.applyVariables(valueSource, sourceCode, painter, tree);
CodeWalkthrough.applyVariables(valueSource, sourceCode, painter, tree);
verify(painter, times(2)).paintForeground(eq(Color.blue), any());
verify(painter).paintBackground(eq(Color.red), any());
verify(painter).paintBackground(eq(Color.green), any());
verify(painter, times(4)).paintBackground(eq(CodeWalkthrough.ACTIVE_STATEMENT), any());
verify(painter, times(1)).paintBackground(eq(CodeWalkthrough.INACTIVE_BRANCH), any());
verify(painter, times(3)).paintBackground(eq(CodeWalkthrough.PASSIVE_CODE), any());
}
@Test
@ -63,7 +75,7 @@ public class LiveDataParserTest {
assertTrue(sourceCode.length() > 100);
ParseTree tree = LiveDataParserPanel.getParseTree(sourceCode);
ParseResult parseResult = LiveDataParserPanel.applyVariables(VariableValueSource.VOID, sourceCode, SourceCodePainter.VOID, tree);
ParseResult parseResult = CodeWalkthrough.applyVariables(VariableValueSource.VOID, sourceCode, SourceCodePainter.VOID, tree);
assertFalse(parseResult.getConfigTokens().isEmpty());
}
}