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:
parent
e1a78cce41
commit
980a7cc833
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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.
|
@ -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';
|
||||
|
|
|
@ -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 "";
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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 + "];");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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}));
|
||||
|
|
Loading…
Reference in New Issue