autoscale fields in generated structs (#3444)

* add to grammar

* parser

* parser

* example consumer

* build config tool

* commit the right jar
This commit is contained in:
Matthew Kennedy 2021-11-02 15:59:19 -07:00 committed by GitHub
parent e1a78cce41
commit 980a7cc833
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 81 additions and 29 deletions

View File

@ -35,7 +35,7 @@ void setTestEngineConfiguration(DECLARE_CONFIG_PARAMETER_SIGNATURE) {
setWholeIatCorrTimingTable(0 PASS_CONFIG_PARAMETER_SUFFIX);
// Many tests were written when the default target AFR was 14.0, so use that for tests by default.
engineConfiguration->stoichRatioPrimary = 140;
engineConfiguration->stoichRatioPrimary = 14.0f;
engineConfiguration->ignitionMode = IM_ONE_COIL;
setConstantDwell(3 PASS_CONFIG_PARAMETER_SUFFIX); // 50% duty cycle @ 5000 rpm

View File

@ -192,10 +192,10 @@ void setDefaultFuel(DECLARE_CONFIG_PARAMETER_SIGNATURE) {
* By the way http://users.erols.com/srweiss/tableifc.htm has a LOT of data
*/
engineConfiguration->injector.flow = 200;
engineConfiguration->stoichRatioPrimary = STOICH_RATIO * PACK_MULT_AFR_CFG;
engineConfiguration->stoichRatioPrimary = STOICH_RATIO;
// 9.0 = E100 pure ethanol
engineConfiguration->stoichRatioSecondary = 9.0f * PACK_MULT_AFR_CFG;
engineConfiguration->stoichRatioSecondary = 9.0f;
// Injector deadtime
setBosch02880155868(PASS_CONFIG_PARAMETER_SIGNATURE);

View File

@ -20,7 +20,7 @@ mass_t FuelComputerBase::getCycleFuel(mass_t airmass, int rpm, float load) const
FuelComputer::FuelComputer(const ValueProvider3D& lambdaTable) : m_lambdaTable(&lambdaTable) {}
float FuelComputer::getStoichiometricRatio() const {
float primary = (float)CONFIG(stoichRatioPrimary) / PACK_MULT_AFR_CFG;
float primary = CONFIG(stoichRatioPrimary);
// Config compatibility: this field may be zero on ECUs with old defaults
if (primary < 5) {
@ -33,7 +33,7 @@ float FuelComputer::getStoichiometricRatio() const {
return primary;
}
float secondary = (float)CONFIG(stoichRatioSecondary) / PACK_MULT_AFR_CFG;
float secondary = CONFIG(stoichRatioSecondary);
// Config compatibility: this field may be zero on ECUs with old defaults
if (secondary < 5) {

View File

@ -1427,11 +1427,11 @@ tChargeMode_e tChargeMode;
int16_t idlerpmpid_iTermMin;iTerm min value;"", 1, 0, -30000, 30000, 0
spi_device_e tle6240spiDevice;
uint8_t stoichRatioPrimary;+Stoichiometric ratio for your primary fuel. When Flex Fuel is enabled, this value is used when the Flex Fuel sensor indicates E0.\nE0 = 14.7\nE10 = 14.1\nE85 = 9.9\nE100 = 9.0;":1", {1/@@PACK_MULT_AFR_CFG@@}, 0, 5, 25, 1
uint8_t autoscale<PACK_MULT_AFR_CFG> stoichRatioPrimary;+Stoichiometric ratio for your primary fuel. When Flex Fuel is enabled, this value is used when the Flex Fuel sensor indicates E0.\nE0 = 14.7\nE10 = 14.1\nE85 = 9.9\nE100 = 9.0;":1", {1/@@PACK_MULT_AFR_CFG@@}, 0, 5, 25, 1
int16_t idlerpmpid_iTermMax;iTerm max value;"", 1, 0, -30000, 30000, 0
spi_device_e mc33972spiDevice;
uint8_t stoichRatioSecondary;+Stoichiometric ratio for your secondary fuel. This value is used when the Flex Fuel sensor indicates E100, typically 9.0;":1", {1/@@PACK_MULT_AFR_CFG@@}, 0, 5, 25, 1
uint8_t autoscale<PACK_MULT_AFR_CFG> stoichRatioSecondary;+Stoichiometric ratio for your secondary fuel. This value is used when the Flex Fuel sensor indicates E100, typically 9.0;":1", {1/@@PACK_MULT_AFR_CFG@@}, 0, 5, 25, 1
uint8_t[2] unusedSpiPadding8;;"units", 1, 0, -20, 100, 0

Binary file not shown.

View File

@ -24,6 +24,7 @@ Bit: 'bit';
Array: 'array';
Scalar: 'scalar';
FsioVisible: 'fsio_visible';
Autoscale: 'autoscale';
ArrayDimensionSeparator: 'x';
@ -93,8 +94,10 @@ fieldOptionsList
arrayLengthSpec: numexpr (ArrayDimensionSeparator numexpr)?;
scalarField: identifier FsioVisible? identifier (fieldOptionsList)?;
arrayField: identifier '[' arrayLengthSpec Iterate? ']' identifier SemicolonedString? (fieldOptionsList)?;
autoscale: Autoscale '<' numexpr '>';
scalarField: identifier autoscale? FsioVisible? identifier (fieldOptionsList)?;
arrayField: identifier '[' arrayLengthSpec Iterate? ']' autoscale? identifier SemicolonedString? (fieldOptionsList)?;
bitField: Bit identifier (',' QuotedString ',' QuotedString)? ('(' 'comment' ':' QuotedString ')')? SemicolonedSuffix?;
unionField: 'union' ENDL+ fields 'end_union';

View File

@ -3,6 +3,7 @@ package com.rusefi;
import com.rusefi.util.SystemOut;
import com.rusefi.test.ConfigFieldParserTest;
import java.util.Arrays;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@ -13,10 +14,10 @@ import java.util.regex.Pattern;
* 1/15/15
*/
public class ConfigField {
public static final ConfigField VOID = new ConfigField(null, "", null, null, null, 1, null, false, false, null, -1, null, null);
public static final ConfigField VOID = new ConfigField(null, "", null, null, null, 1, null, false, false, null,null, -1, null, null);
private static final String typePattern = "([\\w\\d_]+)(\\[([\\w\\d]+)(\\s([\\w\\d]+))?\\])?";
private static final String namePattern = "[[\\w\\d\\s_]]+";
private static final String namePattern = "[[\\w\\d\\s<>_]]+";
private static final String commentPattern = ";([^;]*)";
private static final Pattern FIELD = Pattern.compile(typePattern + "\\s(" + namePattern + ")(" + commentPattern + ")?(;(.*))?");
@ -40,6 +41,7 @@ public class ConfigField {
private final boolean isIterate;
private final ReaderState state;
private boolean fsioVisible;
private final String autoscaleSpec;
private final String individualName;
private final int indexWithinArray;
private final String trueName;
@ -57,9 +59,11 @@ public class ConfigField {
String tsInfo,
boolean isIterate,
boolean fsioVisible,
String autoscaleSpec,
String individualName,
int indexWithinArray, String trueName, String falseName) {
this.fsioVisible = fsioVisible;
this.autoscaleSpec = autoscaleSpec;
this.individualName = individualName;
this.indexWithinArray = indexWithinArray;
this.trueName = trueName == null ? "true" : trueName;
@ -136,8 +140,17 @@ public class ConfigField {
String[] nameTokens = nameString.split("\\s");
String name = nameTokens[nameTokens.length - 1];
boolean isFsioVisible = nameTokens[0].equalsIgnoreCase("fsio_visible");
boolean isFsioVisible = Arrays.stream(nameTokens).anyMatch(s -> s.equalsIgnoreCase("fsio_visible"));
String autoscaleSpec = null;
for (String autoscaler : nameTokens) {
if (!autoscaler.startsWith("autoscale")) {
continue;
}
autoscaleSpec = autoscaler.split("[<>]")[1];
break;
}
String comment = matcher.group(8);
String type = matcher.group(1);
@ -156,7 +169,7 @@ public class ConfigField {
ConfigField field = new ConfigField(state, name, comment, arraySizeAsText, type, arraySize,
tsInfo, isIterate, isFsioVisible, null, -1, null, null);
tsInfo, isIterate, isFsioVisible, autoscaleSpec, null, -1, null, null);
SystemOut.println("type " + type);
SystemOut.println("name " + name);
SystemOut.println("comment " + comment);
@ -237,6 +250,8 @@ public class ConfigField {
return fsioVisible;
}
public String autoscaleSpec() { return this.autoscaleSpec; }
public String getUnits() {
if (tsInfo == null)
return "";

View File

@ -75,7 +75,7 @@ public class ConfigStructure {
if (fillSize != 0) {
ConfigField fill = new ConfigField(state, ALIGNMENT_FILL_AT + totalSize, "need 4 byte alignment",
"" + fillSize,
TypesHelper.UINT8_T, fillSize, "\"units\", 1, 0, -20, 100, 0", false, false, null, -1, null, null);
TypesHelper.UINT8_T, fillSize, "\"units\", 1, 0, -20, 100, 0", false, false, null, null, -1, null, null);
addBoth(fill);
}
totalSize += fillSize;
@ -109,7 +109,7 @@ public class ConfigStructure {
return;
int sizeAtStartOfPadding = cFields.size();
while (readingBitState.get() < 32) {
ConfigField bitField = new ConfigField(readerState, "unusedBit_" + sizeAtStartOfPadding + "_" + readingBitState.get(), "", null, BOOLEAN_T, 0, null, false, false, null, -1, null, null);
ConfigField bitField = new ConfigField(readerState, "unusedBit_" + sizeAtStartOfPadding + "_" + readingBitState.get(), "", null, BOOLEAN_T, 0, null, false, false, null, null, -1, null, null);
addBitField(bitField);
}
readingBitState.reset();

View File

@ -52,7 +52,7 @@ public class ReaderState {
String trueName = bitNameParts.length > 1 ? bitNameParts[1].replaceAll("\"", "") : null;
String falseName = bitNameParts.length > 2 ? bitNameParts[2].replaceAll("\"", "") : null;
ConfigField bitField = new ConfigField(state, bitNameParts[0], comment, null, BOOLEAN_T, 0, null, false, false, null, -1, trueName, falseName);
ConfigField bitField = new ConfigField(state, bitNameParts[0], comment, null, BOOLEAN_T, 0, null, false, false, null, null, -1, trueName, falseName);
if (state.stack.isEmpty())
throw new IllegalStateException("Parent structure expected");
ConfigStructure structure = state.stack.peek();
@ -246,7 +246,7 @@ public class ReaderState {
if (cf == null) {
if (ConfigField.isPreprocessorDirective(state, line)) {
cf = new ConfigField(state, "", line, null,
ConfigField.DIRECTIVE_T, 0, null, false, false, null, 0, null, null);
ConfigField.DIRECTIVE_T, 0, null, false, false, null, null, 0, null, null);
} else {
throw new IllegalStateException("Cannot parse line [" + line + "]");
}
@ -269,7 +269,7 @@ public class ReaderState {
structure.addC(cf);
for (int i = 1; i <= cf.getArraySize(); i++) {
ConfigField element = new ConfigField(state, cf.getName() + i, cf.getComment(), null,
cf.getType(), 1, cf.getTsInfo(), false, false, cf.getName(), i, null, null);
cf.getType(), 1, cf.getTsInfo(), false, false, null, cf.getName(), i, null, null);
structure.addTs(element);
}
} else if (cf.isDirective()) {

View File

@ -325,6 +325,11 @@ public class ParseState {
public void exitScalarField(RusefiConfigGrammarParser.ScalarFieldContext ctx) {
String type = ctx.identifier(0).getText();
String name = ctx.identifier(1).getText();
boolean autoscale = ctx.autoscale() != null;
if (autoscale) {
evalResults.remove();
}
// First check if this is an instance of a struct
if (structs.containsKey(type)) {
@ -351,7 +356,7 @@ public class ParseState {
// Merge the read-in options list with the default from the typedef (if exists)
handleFieldOptionsList(options, ctx.fieldOptionsList());
ScalarField prototype = new ScalarField(arTypedef.type, name, options);
ScalarField prototype = new ScalarField(arTypedef.type, name, options, autoscale);
scope.structFields.add(new ArrayField<>(prototype, arTypedef.length, false));
return;
} else if (typedef instanceof EnumTypedef) {
@ -384,7 +389,7 @@ public class ParseState {
// Merge the read-in options list with the default from the typedef (if exists)
handleFieldOptionsList(options, ctx.fieldOptionsList());
scope.structFields.add(new ScalarField(Type.findByCtype(type).get(), name, options));
scope.structFields.add(new ScalarField(Type.findByCtype(type).get(), name, options, autoscale));
}
@Override
@ -427,6 +432,11 @@ public class ParseState {
int[] length = this.arrayDim;
// check if the iterate token is present
boolean iterate = ctx.Iterate() != null;
boolean autoscale = ctx.autoscale() != null;
if (autoscale) {
evalResults.remove();
}
// First check if this is an array of structs
if (structs.containsKey(type)) {
@ -483,7 +493,7 @@ public class ParseState {
// Merge the read-in options list with the default from the typedef (if exists)
handleFieldOptionsList(options, ctx.fieldOptionsList());
ScalarField prototype = new ScalarField(Type.findByCtype(type).get(), name, options);
ScalarField prototype = new ScalarField(Type.findByCtype(type).get(), name, options, autoscale);
scope.structFields.add(new ArrayField<>(prototype, length, iterate));
}

View File

@ -12,11 +12,13 @@ public class ScalarLayout extends Layout {
private String name;
private Type type;
private FieldOptions options;
private boolean autoscale;
public ScalarLayout(ScalarField field) {
this.name = field.name;
this.options = field.options;
this.type = field.type;
this.autoscale = field.autoscale;
}
@Override
@ -86,7 +88,14 @@ public class ScalarLayout extends Layout {
@Override
public void writeCLayout(PrintStream ps) {
this.writeCOffsetHeader(ps, this.options.comment, this.options.units);
ps.print("\t" + this.type.cType.replaceAll("^int32_t$", "int") + " " + this.name);
String cTypeName = this.type.cType.replaceAll("^int32_t$", "int");
if (this.autoscale) {
cTypeName = "scaled_channel<" + cTypeName + ", " + Math.round(1 / this.options.scale) + ">";
}
ps.print("\t" + cTypeName + " " + this.name);
if (ConfigDefinition.needZeroInit) {
ps.print(" = (" + this.type.cType.replaceAll("^int32_t$", "int") + ")0");
@ -108,6 +117,12 @@ public class ScalarLayout extends Layout {
al.append(arrayLength[i]);
}
ps.println("\t" + this.type.cType.replaceAll("^int32_t$", "int") + " " + this.name + "[" + al + "];");
String cTypeName = this.type.cType.replaceAll("^int32_t$", "int");
if (this.autoscale) {
cTypeName = "scaled_channel<" + cTypeName + ", " + Math.round(1 / this.options.scale) + ">";
}
ps.println("\t" + cTypeName + " " + this.name + "[" + al + "];");
}
}

View File

@ -3,12 +3,14 @@ package com.rusefi.newparse.parsing;
public class ScalarField extends PrototypeField {
public final Type type;
public final FieldOptions options;
public final Boolean autoscale;
public ScalarField(Type type, String name, FieldOptions options) {
public ScalarField(Type type, String name, FieldOptions options, boolean autoscale) {
super(name);
this.type = type;
this.options = options;
this.autoscale = autoscale;
}
@Override

View File

@ -16,16 +16,23 @@ public abstract class BaseCHeaderConsumer implements ConfigurationConsumer {
String cEntry = ConfigDefinition.getComment(configField.getCommentContent(), currentOffset, configField.getUnits());
String typeName = configField.getType();
String autoscaleSpec = configField.autoscaleSpec();
if (autoscaleSpec != null) {
typeName = "scaled_channel<" + typeName + ", " + autoscaleSpec + ">";
}
if (!configField.isArray()) {
// not an array
cEntry += "\t" + configField.getType() + " " + configField.getName();
cEntry += "\t" + typeName + " " + configField.getName();
if (ConfigDefinition.needZeroInit && TypesHelper.isPrimitive(configField.getType())) {
// we need this cast in case of enums
cEntry += " = (" + configField.getType() + ")0";
}
cEntry += ";" + EOL;
} else {
cEntry += "\t" + configField.getType() + " " + configField.getName() + "[" + configField.arraySizeVariableName + "];" + EOL;
cEntry += "\t" + typeName + " " + configField.getName() + "[" + configField.arraySizeVariableName + "];" + EOL;
}
return cEntry;
}

View File

@ -48,8 +48,8 @@ TEST(FuelComputer, FlexFuel) {
INJECT_ENGINE_REFERENCE(&dut);
// easier values for testing
engineConfiguration->stoichRatioPrimary = 150;
engineConfiguration->stoichRatioSecondary = 100;
engineConfiguration->stoichRatioPrimary = 15;
engineConfiguration->stoichRatioSecondary = 10;
// No sensor -> returns primary
Sensor::resetMockValue(SensorType::FuelEthanolPercent);

View File

@ -298,7 +298,7 @@ TEST(misc, testRpmCalculator) {
ENGINE(tdcMarkEnabled) = false;
// These tests were written when the default target AFR was 14.0, so replicate that
engineConfiguration->stoichRatioPrimary = 140;
engineConfiguration->stoichRatioPrimary = 14;
EXPECT_CALL(eth.mockAirmass, getAirmass(_))
.WillRepeatedly(Return(AirmassResult{0.1008f, 50.0f}));