configuration generator refactoring

This commit is contained in:
rusefi 2019-05-18 17:10:28 -04:00
parent 3c4119c5c3
commit 2c758692ef
14 changed files with 402 additions and 340 deletions

Binary file not shown.

View File

@ -8,12 +8,12 @@ public class BitState {
private int bitIndex;
public void incrementBitIndex(ConfigField cf, ConfigField next) {
if (!cf.isBit) {
if (!cf.isBit()) {
bitIndex = 0;
return;
}
if (bitIndex == 32)
throw new IllegalStateException("Too many bits: " + cf.name);
throw new IllegalStateException("Too many bits: " + cf.getName());
bitIndex++;
}

View File

@ -1,38 +0,0 @@
package com.rusefi;
import java.io.BufferedWriter;
import java.io.IOException;
import static com.rusefi.ConfigDefinition.EOL;
/**
* Configuration consumer which writes C header file
*/
public class CHeaderConsumer implements ConfigurationConsumer {
private final BufferedWriter cHeader;
public CHeaderConsumer(BufferedWriter cHeader) {
this.cHeader = cHeader;
}
@Override
public void startFile() throws IOException {
cHeader.write("// this section " + ConfigDefinition.MESSAGE + EOL);
cHeader.write("// begin" + EOL);
cHeader.write("#ifndef ENGINE_CONFIGURATION_GENERATED_H_" + EOL);
cHeader.write("#define ENGINE_CONFIGURATION_GENERATED_H_" + EOL);
cHeader.write("#include \"rusefi_types.h\"" + EOL);
}
@Override
public void endFile() throws IOException {
cHeader.write("#endif" + EOL);
cHeader.write("// end" + EOL);
cHeader.write("// this section " + ConfigDefinition.MESSAGE + EOL);
}
@Override
public void handleEndStruct(ConfigStructure structure) throws IOException {
ConfigStructure.headerWrite(structure, cHeader);
}
}

View File

@ -1,5 +1,10 @@
package com.rusefi;
import com.rusefi.output.CHeaderConsumer;
import com.rusefi.output.ConfigurationConsumer;
import com.rusefi.output.JavaFieldsConsumer;
import com.rusefi.output.TSProjectConsumer;
import java.io.*;
import java.util.Arrays;
import java.util.Date;
@ -12,8 +17,7 @@ import java.util.Date;
public class ConfigDefinition {
public static final String EOL = "\n";
private static final String INPUT_FILE_NAME = "rusefi_config.txt";
static final String MESSAGE = "was generated automatically by ConfigDefinition.jar based on " + INPUT_FILE_NAME + " " + new Date();
static final String TS_FILE_INPUT_NAME = "rusefi.input";
public static final String MESSAGE = "was generated automatically by ConfigDefinition.jar based on " + INPUT_FILE_NAME + " " + new Date();
private static final String ROM_RAIDER_XML_TEMPLATE = "rusefi_template.xml";
private static final String ROM_RAIDER_XML_OUTPUT = "rusefi.xml";
private static final String ENGINE_CONFIGURATION_GENERATED_STRUCTURES_H = "engine_configuration_generated_structures.h";
@ -22,7 +26,7 @@ public class ConfigDefinition {
public static void main(String[] args) throws IOException {
if (args.length != 4 && args.length != 5) {
System.out.println("Please specify path to '" + INPUT_FILE_NAME + "' file, path to " + TS_FILE_INPUT_NAME +
System.out.println("Please specify path to '" + INPUT_FILE_NAME + "' file, path to " + TSProjectConsumer.TS_FILE_INPUT_NAME +
", destination folder and [optional] file name of custom prepend file");
return;
}

View File

@ -4,8 +4,7 @@ import com.rusefi.test.ConfigFieldParserTest;
import java.io.IOException;
import java.io.Writer;
import java.util.HashSet;
import java.util.Set;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@ -17,56 +16,66 @@ import static com.rusefi.ConfigDefinition.EOL;
* 1/15/15
*/
public class ConfigField {
public static final ConfigField VOID = new ConfigField(null, "", null, false, null, null, 1, null, false);
public static final ConfigField VOID = new ConfigField(null, "", null, null, null, 1, null, false);
private static final String typePattern = "([\\w\\d_]+)(\\[([\\w\\d]+)(\\s([\\w\\d]+))?\\])?";
private static final String namePattern = "[[\\w\\d\\s_]]+";
private static final String commentPattern = ";([^;]*)";
private static final Pattern FIELD = Pattern.compile(typePattern + "\\s(" + namePattern + ")(" + commentPattern + ")?(;(.*))?");
private static final Set<String> javaEnums = new HashSet<>();
private static final String BOOLEAN_TYPE = "bool";
public static final int LENGTH = 24;
private static final char TS_COMMENT_TAG = '+';
public static final char TS_COMMENT_TAG = '+';
public static final String ENUM_SUFFIX = "_enum";
public static final String VOID_NAME = "";
public static final String BOOLEAN_T = "boolean";
/**
* field name without structure name
* @see #writeJavaFields prefix parameter for structure name
*/
public final String name;
public final String comment;
final boolean isBit;
private final String arraySizeAsText;
public final String type;
public final int arraySize;
private final String name;
private final String comment;
public final String arraySizeAsText;
private final String type;
private final int arraySize;
public final String tsInfo;
private final int elementSize;
/**
* this property of array expands field into a bunch of variables like field1 field2 field3 etc
*/
public final boolean isIterate;
private final ReaderState state;
public final ReaderState state;
public ConfigField(ReaderState state, String name, String comment, boolean isBit, String arraySizeAsText, String type,
int arraySize, String tsInfo, boolean isIterate) {
this.state = state;
if (name == null)
throw new NullPointerException(comment + " " + isBit + " " + type);
public ConfigField(ReaderState state,
String name,
String comment,
String arraySizeAsText,
String type,
int arraySize,
String tsInfo,
boolean isIterate) {
Objects.requireNonNull(name, comment + " " + type);
assertNoWhitespaces(name);
this.name = name;
if (!isVoid())
Objects.requireNonNull(state);
this.state = state;
this.comment = comment;
this.isBit = isBit;
this.arraySizeAsText = arraySizeAsText;
if (!isVoid())
Objects.requireNonNull(type);
this.type = type;
elementSize = TypesHelper.getElementSize(state, type);
this.arraySizeAsText = arraySizeAsText;
this.arraySize = arraySize;
this.tsInfo = tsInfo;
this.isIterate = isIterate;
}
public boolean isBit() {
return BOOLEAN_T.equalsIgnoreCase(type);
}
private boolean isVoid() {
return name.equals(VOID_NAME);
}
public static void assertNoWhitespaces(String name) {
if (name.contains(" ") || name.contains("\t"))
throw new IllegalArgumentException("Invalid name: " + name);
@ -95,7 +104,7 @@ public class ConfigField {
String tsInfo = matcher.group(10);
boolean isIterate = "iterate".equalsIgnoreCase(matcher.group(5));
ConfigField field = new ConfigField(state, name, comment, false, arraySizeAsText, type, arraySize,
ConfigField field = new ConfigField(state, name, comment, arraySizeAsText, type, arraySize,
tsInfo, isIterate);
System.out.println("type " + type);
System.out.println("name " + name);
@ -105,28 +114,11 @@ public class ConfigField {
}
public int getSize(ConfigField next) {
if (isBit && next.isBit)
if (isBit() && next.isBit())
return 0;
if (isBit)
if (isBit())
return 4;
return elementSize * arraySize;
}
String getHeaderText(int currentOffset, int bitIndex) {
if (isBit) {
String comment = "\t/**" + EOL + ConfigDefinition.packComment(getCommentContent(), "\t") + "\toffset " + currentOffset + " bit " + bitIndex + " */" + EOL;
return comment + "\t" + BOOLEAN_TYPE + " " + name + " : 1;" + EOL;
}
String cEntry = ConfigDefinition.getComment(getCommentContent(), currentOffset);
if (arraySize == 1) {
// not an array
cEntry += "\t" + type + " " + name + ";" + EOL;
} else {
cEntry += "\t" + type + " " + name + "[" + arraySizeAsText + "];" + EOL;
}
return cEntry;
return getElementSize() * arraySize;
}
@Override
@ -135,129 +127,11 @@ public class ConfigField {
"name='" + name + '\'' +
", type='" + type + '\'' +
", arraySize=" + arraySize +
", elementSize=" + elementSize +
'}';
}
public int writeTunerStudio(String prefix, Writer tsHeader, int tsPosition, ConfigField next, int bitIndex) throws IOException {
String nameWithPrefix = prefix + name;
VariableRegistry.INSTANCE.register(nameWithPrefix + "_offset", tsPosition);
ConfigStructure cs = state.structures.get(type);
if (cs != null) {
String extraPrefix = cs.withPrefix ? name + "_" : "";
return cs.writeTunerStudio(prefix + extraPrefix, tsHeader, tsPosition);
}
if (isBit) {
tsHeader.write("\t" + addTabsUpTo(nameWithPrefix, LENGTH));
tsHeader.write("= bits, U32, ");
tsHeader.write("\t" + tsPosition + ", [");
tsHeader.write(bitIndex + ":" + bitIndex);
tsHeader.write("], \"false\", \"true\"");
tsHeader.write(EOL);
tsPosition += getSize(next);
return tsPosition;
}
if (state.tsCustomLine.containsKey(type)) {
String bits = state.tsCustomLine.get(type);
tsHeader.write("\t" + addTabsUpTo(nameWithPrefix, LENGTH));
int size = state.tsCustomSize.get(type);
// tsHeader.headerWrite("\t" + size + ",");
// tsHeader.headerWrite("\t" + tsPosition + ",");
bits = bits.replaceAll("@OFFSET@", "" + tsPosition);
tsHeader.write("\t = " + bits);
tsPosition += size;
} else if (tsInfo == null) {
tsHeader.write(";no TS info - skipping " + prefix + name + " offset " + tsPosition);
tsPosition += arraySize * elementSize;
} else if (arraySize != 1) {
tsHeader.write("\t" + addTabsUpTo(nameWithPrefix, LENGTH) + "\t\t= array, ");
tsHeader.write(TypesHelper.convertToTs(type) + ",");
tsHeader.write("\t" + tsPosition + ",");
tsHeader.write("\t[" + arraySize + "],");
tsHeader.write("\t" + tsInfo);
tsPosition += arraySize * elementSize;
} else {
tsHeader.write("\t" + addTabsUpTo(nameWithPrefix, LENGTH) + "\t\t= scalar, ");
tsHeader.write(TypesHelper.convertToTs(type) + ",");
tsHeader.write("\t" + tsPosition + ",");
tsHeader.write("\t" + tsInfo);
tsPosition += arraySize * elementSize;
}
tsHeader.write(EOL);
return tsPosition;
}
private String addTabsUpTo(String name, int length) {
StringBuilder result = new StringBuilder(name);
int currentLength = name.length();
while (currentLength < length) {
result.append("\t");
currentLength += 4;
}
return result.toString();
}
public int writeJavaFields(String prefix, Writer javaFieldsWriter, int tsPosition, ConfigField next, int bitIndex) throws IOException {
ConfigStructure cs = state.structures.get(type);
if (cs != null) {
String extraPrefix = cs.withPrefix ? name + "_" : "";
return cs.writeJavaFields(state, prefix + extraPrefix, javaFieldsWriter, tsPosition);
}
String nameWithPrefix = prefix + name;
if (comment != null && comment.startsWith(TS_COMMENT_TAG + "")) {
ConfigDefinition.settingContextHelp.append("\t" + nameWithPrefix + " = \"" + getCommentContent() + "\"" + EOL);
}
if (isBit) {
writeJavaFieldName(javaFieldsWriter, nameWithPrefix, tsPosition);
javaFieldsWriter.append("FieldType.BIT, " + bitIndex + ");" + EOL);
tsPosition += getSize(next);
return tsPosition;
}
if (arraySize != 1) {
// todo: array support
} else if (TypesHelper.isFloat(type)) {
writeJavaFieldName(javaFieldsWriter, nameWithPrefix, tsPosition);
javaFieldsWriter.write("FieldType.FLOAT);" + EOL);
} else {
String enumOptions = VariableRegistry.INSTANCE.get(type + ENUM_SUFFIX);
if (enumOptions != null && !javaEnums.contains(type)) {
javaEnums.add(type);
javaFieldsWriter.write("\tpublic static final String[] " + type + " = {" + enumOptions + "};" + EOL);
}
writeJavaFieldName(javaFieldsWriter, nameWithPrefix, tsPosition);
if (elementSize == 1) {
javaFieldsWriter.write("FieldType.INT8");
} else if (elementSize == 2) {
javaFieldsWriter.write("FieldType.INT16");
} else {
javaFieldsWriter.write("FieldType.INT");
}
if (enumOptions != null) {
javaFieldsWriter.write(", " + type);
}
javaFieldsWriter.write(");" + EOL);
}
tsPosition += arraySize * elementSize;
return tsPosition;
}
private void writeJavaFieldName(Writer javaFieldsWriter, String nameWithPrefix, int tsPosition) throws IOException {
public void writeJavaFieldName(Writer javaFieldsWriter, String nameWithPrefix, int tsPosition) throws IOException {
javaFieldsWriter.write("\tpublic static final Field ");
javaFieldsWriter.write(nameWithPrefix.toUpperCase());
javaFieldsWriter.write(" = Field.create(\"" + nameWithPrefix.toUpperCase() + "\", "
@ -269,4 +143,30 @@ public class ConfigField {
return comment;
return comment.charAt(0) == TS_COMMENT_TAG ? comment.substring(1) : comment;
}
public int getArraySize() {
return arraySize;
}
public String getComment() {
return comment;
}
/**
* field name without structure name
*
* @see JavaFieldsConsumer#writeJavaFields prefix parameter for structure name
*/
public String getName() {
return name;
}
public String getType() {
return type;
}
public int getElementSize() {
return isVoid() ? 0 : TypesHelper.getElementSize(state, type);
}
}

View File

@ -1,31 +1,33 @@
package com.rusefi;
import com.rusefi.output.TSProjectConsumer;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.List;
/**
* Mutable representation of a list of related {@link ConfigField}
*
* (c) Andrey Belomutskiy
* 1/15/15
*/
public class ConfigStructure {
public static final String UINT8_T = "uint8_t";
public static final String UINT_16_T = "uint16_t";
public static final String INT_16_T = "int16_t";
private final String name;
private final String comment;
public final String name;
public final String comment;
public final boolean withPrefix;
/**
* We have two different collections because if 'array iterate' feature which is handled differently
* in C and TS
*/
private final List<ConfigField> cFields = new ArrayList<>();
private final List<ConfigField> tsFields = new ArrayList<>();
private int currentOffset;
public final List<ConfigField> cFields = new ArrayList<>();
public final List<ConfigField> tsFields = new ArrayList<>();
public int currentOffset;
public int totalSize;
BitState bitState = new BitState();
public BitState bitState = new BitState();
public ConfigStructure(String name, String comment, boolean withPrefix) {
this.name = name;
@ -53,57 +55,20 @@ public class ConfigStructure {
int fillSize = totalSize % 4 == 0 ? 0 : 4 - (totalSize % 4);
if (fillSize != 0) {
ConfigField fill = new ConfigField(state, "alignmentFill", "need 4 byte alignment", false,
ConfigField fill = new ConfigField(state, "alignmentFill", "need 4 byte alignment",
"" + fillSize,
UINT8_T, fillSize, null, false);
TypesHelper.UINT8_T, fillSize, null, false);
addBoth(fill);
}
totalSize += fillSize;
}
/**
* This method writes a C header version of a data structure
*/
public static void headerWrite(ConfigStructure configStructure, Writer cHeader) throws IOException {
if (configStructure.comment != null) {
cHeader.write("/**" + ConfigDefinition.EOL + ConfigDefinition.packComment(configStructure.comment, "") + ConfigDefinition.EOL + "*/" + ConfigDefinition.EOL);
}
cHeader.write("// start of " + configStructure.name + ConfigDefinition.EOL);
cHeader.write("typedef struct {" + ConfigDefinition.EOL);
configStructure.bitState.reset();
for (int i = 0; i < configStructure.cFields.size(); i++) {
ConfigField cf = configStructure.cFields.get(i);
cHeader.write(cf.getHeaderText(configStructure.currentOffset, configStructure.bitState.get()));
ConfigField next = i == configStructure.cFields.size() - 1 ? ConfigField.VOID : configStructure.cFields.get(i + 1);
configStructure.bitState.incrementBitIndex(cf, next);
configStructure.currentOffset += cf.getSize(next);
}
cHeader.write("\t/** total size " + configStructure.currentOffset + "*/" + ConfigDefinition.EOL);
cHeader.write("} " + configStructure.name + ";" + ConfigDefinition.EOL + ConfigDefinition.EOL);
}
public int writeTunerStudio(String prefix, Writer tsHeader, int tsPosition) throws IOException {
FieldIterator fieldIterator = new FieldIterator();
for (int i = 0; i < tsFields.size(); i++) {
ConfigField next = i == tsFields.size() - 1 ? ConfigField.VOID : tsFields.get(i + 1);
ConfigField cf = tsFields.get(i);
tsPosition = cf.writeTunerStudio(prefix, tsHeader, tsPosition, next, fieldIterator.bitState.get());
fieldIterator.bitState.incrementBitIndex(cf, next);
}
return tsPosition;
}
public int writeJavaFields(ReaderState state, String prefix, Writer javaFieldsWriter, int tsPosition) throws IOException {
FieldIterator fieldIterator = new FieldIterator();
for (int i = 0; i < tsFields.size(); i++) {
ConfigField next = i == tsFields.size() - 1 ? ConfigField.VOID : tsFields.get(i + 1);
ConfigField cf = tsFields.get(i);
tsPosition = cf.writeJavaFields(prefix, javaFieldsWriter, tsPosition, next, fieldIterator.bitState.get());
tsPosition = TSProjectConsumer.writeTunerStudio(cf, prefix, tsHeader, tsPosition, next, fieldIterator.bitState.get());
fieldIterator.bitState.incrementBitIndex(cf, next);
}

View File

@ -1,45 +0,0 @@
package com.rusefi;
import java.io.*;
public class JavaFieldsConsumer implements ConfigurationConsumer {
private static final String FIELDS_JAVA = "models/src/com/rusefi/config/Fields.java";
private final CharArrayWriter javaFieldsWriter;
private final ReaderState state;
private final String javaConsolePath;
public JavaFieldsConsumer(CharArrayWriter javaFieldsWriter, ReaderState state, String javaConsolePath) {
this.javaFieldsWriter = javaFieldsWriter;
this.state = state;
this.javaConsolePath = javaConsolePath;
}
private static void writeFields(String javaConsolePath, CharArrayWriter javaFieldsWriter) throws IOException {
BufferedWriter javaFields = new BufferedWriter(new FileWriter(javaConsolePath + File.separator + FIELDS_JAVA));
javaFields.write("package com.rusefi.config;" + ConfigDefinition.EOL + ConfigDefinition.EOL);
javaFields.write("// this file " + ConfigDefinition.MESSAGE + ConfigDefinition.EOL);
javaFields.write("public class Fields {" + ConfigDefinition.EOL);
javaFields.write(VariableRegistry.INSTANCE.getJavaConstants());
javaFields.write(javaFieldsWriter.toString());
javaFields.write("}" + ConfigDefinition.EOL);
javaFields.close();
}
@Override
public void startFile() throws IOException {
}
@Override
public void endFile() throws IOException {
JavaFieldsConsumer.writeFields(javaConsolePath, javaFieldsWriter);
}
@Override
public void handleEndStruct(ConfigStructure structure) throws IOException {
if (state.stack.isEmpty()) {
structure.writeJavaFields(state,"", javaFieldsWriter, 0);
}
}
}

View File

@ -1,5 +1,8 @@
package com.rusefi;
import com.rusefi.output.CHeaderConsumer;
import com.rusefi.output.ConfigurationConsumer;
import java.io.BufferedReader;
import java.io.IOException;
import java.util.HashMap;
@ -7,6 +10,8 @@ import java.util.List;
import java.util.Map;
import java.util.Stack;
import static com.rusefi.ConfigField.BOOLEAN_T;
/**
* We keep state here as we read configuration definition
*
@ -20,7 +25,7 @@ public class ReaderState {
private static final String END_STRUCT = "end_struct";
private static final String STRUCT_NO_PREFIX = "struct_no_prefix ";
private static final String STRUCT = "struct ";
Stack<ConfigStructure> stack = new Stack<>();
public Stack<ConfigStructure> stack = new Stack<>();
public Map<String, Integer> tsCustomSize = new HashMap<>();
public Map<String, String> tsCustomLine = new HashMap<>();
public Map<String, ConfigStructure> structures = new HashMap<>();
@ -39,7 +44,7 @@ public class ReaderState {
comment = line.substring(index + 1);
}
ConfigField bitField = new ConfigField(state, bitName, comment, true, null, null, 0, null, false);
ConfigField bitField = new ConfigField(state, bitName, comment, null, BOOLEAN_T, 0, null, false);
state.stack.peek().addBoth(bitField);
}
@ -147,14 +152,14 @@ public class ReaderState {
throw new IllegalStateException("Cannot parse line [" + line + "]");
if (state.stack.isEmpty())
throw new IllegalStateException(cf.name + ": Not enclosed in a struct");
throw new IllegalStateException(cf.getName() + ": Not enclosed in a struct");
ConfigStructure structure = state.stack.peek();
if (cf.isIterate) {
structure.addC(cf);
for (int i = 1; i <= cf.arraySize; i++) {
ConfigField element = new ConfigField(state, cf.name + i, cf.comment, false, null,
cf.type, 1, cf.tsInfo, false);
for (int i = 1; i <= cf.getArraySize(); i++) {
ConfigField element = new ConfigField(state, cf.getName() + i, cf.getComment(), null,
cf.getType(), 1, cf.tsInfo, false);
structure.addTs(element);
}
} else {

View File

@ -1,15 +1,17 @@
package com.rusefi;
import static com.rusefi.ConfigStructure.INT_16_T;
import static com.rusefi.ConfigStructure.UINT8_T;
import static com.rusefi.ConfigStructure.UINT_16_T;
import java.util.Objects;
/**
* 1/22/15
*/
public class TypesHelper {
public static final String UINT8_T = "uint8_t";
public static final String UINT_16_T = "uint16_t";
public static final String INT_16_T = "int16_t";
public static int getElementSize(ReaderState state, String type) {
Objects.requireNonNull(state);
if (type == null)
return 0;
if (state != null && state.structures.containsKey(type))
@ -24,7 +26,7 @@ public class TypesHelper {
return 4;
}
static String convertToTs(String type) {
public static String convertToTs(String type) {
if (isFloat(type))
return "F32";
if ("uint32_t".equals(type))

View File

@ -0,0 +1,78 @@
package com.rusefi.output;
import com.rusefi.ConfigDefinition;
import com.rusefi.ConfigField;
import com.rusefi.ConfigStructure;
import java.io.BufferedWriter;
import java.io.IOException;
import static com.rusefi.ConfigDefinition.EOL;
/**
* Configuration consumer which writes C header file
*/
public class CHeaderConsumer implements ConfigurationConsumer {
public static final String BOOLEAN_TYPE = "bool";
private final BufferedWriter cHeader;
public CHeaderConsumer(BufferedWriter cHeader) throws IOException {
this.cHeader = cHeader;
cHeader.write("// this section " + ConfigDefinition.MESSAGE + EOL);
cHeader.write("// begin" + EOL);
cHeader.write("#ifndef ENGINE_CONFIGURATION_GENERATED_H_" + EOL);
cHeader.write("#define ENGINE_CONFIGURATION_GENERATED_H_" + EOL);
cHeader.write("#include \"rusefi_types.h\"" + EOL);
}
public static String getHeaderText(ConfigField configField, int currentOffset, int bitIndex) {
if (configField.isBit()) {
String comment = "\t/**" + EOL + ConfigDefinition.packComment(configField.getCommentContent(), "\t") + "\toffset " + currentOffset + " bit " + bitIndex + " */" + EOL;
return comment + "\t" + BOOLEAN_TYPE + " " + configField.getName() + " : 1;" + EOL;
}
String cEntry = ConfigDefinition.getComment(configField.getCommentContent(), currentOffset);
if (configField.getArraySize() == 1) {
// not an array
cEntry += "\t" + configField.getType() + " " + configField.getName() + ";" + EOL;
} else {
cEntry += "\t" + configField.getType() + " " + configField.getName() + "[" + configField.arraySizeAsText + "];" + EOL;
}
return cEntry;
}
@Override
public void startFile() throws IOException {
}
@Override
public void handleEndStruct(ConfigStructure structure) throws IOException {
if (structure.comment != null) {
cHeader.write("/**" + EOL + ConfigDefinition.packComment(structure.comment, "") + EOL + "*/" + EOL);
}
cHeader.write("// start of " + structure.name + EOL);
cHeader.write("typedef struct {" + EOL);
structure.bitState.reset();
for (int i = 0; i < structure.cFields.size(); i++) {
ConfigField cf = structure.cFields.get(i);
cHeader.write(getHeaderText(cf, structure.currentOffset, structure.bitState.get()));
ConfigField next = i == structure.cFields.size() - 1 ? ConfigField.VOID : structure.cFields.get(i + 1);
structure.bitState.incrementBitIndex(cf, next);
structure.currentOffset += cf.getSize(next);
}
cHeader.write("\t/** total size " + structure.currentOffset + "*/" + EOL);
cHeader.write("} " + structure.name + ";" + EOL + EOL);
}
@Override
public void endFile() throws IOException {
cHeader.write("#endif" + EOL);
cHeader.write("// end" + EOL);
cHeader.write("// this section " + ConfigDefinition.MESSAGE + EOL);
}
}

View File

@ -1,4 +1,6 @@
package com.rusefi;
package com.rusefi.output;
import com.rusefi.ConfigStructure;
import java.io.IOException;

View File

@ -0,0 +1,120 @@
package com.rusefi.output;
import com.rusefi.*;
import java.io.*;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import static com.rusefi.ConfigDefinition.EOL;
/**
* This class generates java representation of rusEfi data structures used by rusEfi console
*/
public class JavaFieldsConsumer implements ConfigurationConsumer {
private static final Set<String> javaEnums = new HashSet<>();
private static final String JAVA_SOURCE_CODE_FILE_NAME = "models/src/com/rusefi/config/Fields.java";
public static final String JAVA_PACKAGE = "com.rusefi.config";
private final CharArrayWriter javaFieldsWriter;
private final ReaderState state;
private final String javaConsolePath;
private final BufferedWriter javaFields;
public JavaFieldsConsumer(CharArrayWriter javaFieldsWriter, ReaderState state, String javaConsolePath) throws IOException {
this.javaFieldsWriter = javaFieldsWriter;
this.state = state;
this.javaConsolePath = javaConsolePath;
javaFields = new BufferedWriter(new FileWriter(javaConsolePath + File.separator + JAVA_SOURCE_CODE_FILE_NAME));
}
public static int writeJavaFields(List<ConfigField> tsFields, ReaderState state, String prefix, Writer javaFieldsWriter, int tsPosition) throws IOException {
FieldIterator fieldIterator = new FieldIterator();
for (int i = 0; i < tsFields.size(); i++) {
ConfigField next = i == tsFields.size() - 1 ? ConfigField.VOID : tsFields.get(i + 1);
ConfigField cf = tsFields.get(i);
tsPosition = writeJavaFields(cf, prefix, javaFieldsWriter, tsPosition, next, fieldIterator.bitState.get());
fieldIterator.bitState.incrementBitIndex(cf, next);
}
return tsPosition;
}
public static int writeJavaFields(ConfigField configField, String prefix, Writer javaFieldsWriter, int tsPosition, ConfigField next, int bitIndex) throws IOException {
ConfigStructure cs = configField.state.structures.get(configField.getType());
if (cs != null) {
String extraPrefix = cs.withPrefix ? configField.getName() + "_" : "";
return writeJavaFields(cs.tsFields, configField.state, prefix + extraPrefix, javaFieldsWriter, tsPosition);
}
String nameWithPrefix = prefix + configField.getName();
if (configField.getComment() != null && configField.getComment().startsWith(ConfigField.TS_COMMENT_TAG + "")) {
ConfigDefinition.settingContextHelp.append("\t" + nameWithPrefix + " = \"" + configField.getCommentContent() + "\"" + EOL);
}
if (configField.isBit()) {
configField.writeJavaFieldName(javaFieldsWriter, nameWithPrefix, tsPosition);
javaFieldsWriter.append("FieldType.BIT, " + bitIndex + ");" + EOL);
tsPosition += configField.getSize(next);
return tsPosition;
}
if (configField.getArraySize() != 1) {
// todo: array support
} else if (TypesHelper.isFloat(configField.getType())) {
configField.writeJavaFieldName(javaFieldsWriter, nameWithPrefix, tsPosition);
javaFieldsWriter.write("FieldType.FLOAT);" + EOL);
} else {
String enumOptions = VariableRegistry.INSTANCE.get(configField.getType() + ConfigField.ENUM_SUFFIX);
if (enumOptions != null && !javaEnums.contains(configField.getType())) {
javaEnums.add(configField.getType());
javaFieldsWriter.write("\tpublic static final String[] " + configField.getType() + " = {" + enumOptions + "};" + EOL);
}
configField.writeJavaFieldName(javaFieldsWriter, nameWithPrefix, tsPosition);
if (configField.getElementSize() == 1) {
javaFieldsWriter.write("FieldType.INT8");
} else if (configField.getElementSize() == 2) {
javaFieldsWriter.write("FieldType.INT16");
} else {
javaFieldsWriter.write("FieldType.INT");
}
if (enumOptions != null) {
javaFieldsWriter.write(", " + configField.getType());
}
javaFieldsWriter.write(");" + EOL);
}
tsPosition += configField.getArraySize() * configField.getElementSize();
return tsPosition;
}
@Override
public void startFile() throws IOException {
javaFields.write("package " + JAVA_PACKAGE + ";" + ConfigDefinition.EOL + ConfigDefinition.EOL);
javaFields.write("// this file " + ConfigDefinition.MESSAGE + ConfigDefinition.EOL);
javaFields.write("public class Fields {" + ConfigDefinition.EOL);
}
@Override
public void handleEndStruct(ConfigStructure structure) throws IOException {
if (state.stack.isEmpty()) {
writeJavaFields(structure.tsFields, state, "", javaFieldsWriter, 0);
}
}
@Override
public void endFile() throws IOException {
javaFields.write(VariableRegistry.INSTANCE.getJavaConstants());
javaFields.write(javaFieldsWriter.toString());
javaFields.write("}" + ConfigDefinition.EOL);
javaFields.close();
}
}

View File

@ -1,10 +1,14 @@
package com.rusefi;
package com.rusefi.output;
import com.rusefi.*;
import java.io.*;
import static com.rusefi.ConfigDefinition.EOL;
public class TSProjectConsumer implements ConfigurationConsumer {
public static final String TS_FILE_INPUT_NAME = "rusefi.input";
private static final int LENGTH = 24;
private static final String CONFIG_DEFINITION_START = "CONFIG_DEFINITION_START";
private static final String CONFIG_DEFINITION_END = "CONFIG_DEFINITION_END";
private static final String TS_FILE_OUTPUT_NAME = "rusefi.ini";
@ -20,9 +24,64 @@ public class TSProjectConsumer implements ConfigurationConsumer {
this.state = state;
}
public static int writeTunerStudio(ConfigField configField, String prefix, Writer tsHeader, int tsPosition, ConfigField next, int bitIndex) throws IOException {
String nameWithPrefix = prefix + configField.getName();
VariableRegistry.INSTANCE.register(nameWithPrefix + "_offset", tsPosition);
ConfigStructure cs = configField.state.structures.get(configField.getType());
if (cs != null) {
String extraPrefix = cs.withPrefix ? configField.getName() + "_" : "";
return cs.writeTunerStudio(prefix + extraPrefix, tsHeader, tsPosition);
}
if (configField.isBit()) {
tsHeader.write("\t" + addTabsUpTo(nameWithPrefix, LENGTH));
tsHeader.write("= bits, U32, ");
tsHeader.write("\t" + tsPosition + ", [");
tsHeader.write(bitIndex + ":" + bitIndex);
tsHeader.write("], \"false\", \"true\"");
tsHeader.write(EOL);
tsPosition += configField.getSize(next);
return tsPosition;
}
if (configField.state.tsCustomLine.containsKey(configField.getType())) {
String bits = configField.state.tsCustomLine.get(configField.getType());
tsHeader.write("\t" + addTabsUpTo(nameWithPrefix, LENGTH));
int size = configField.state.tsCustomSize.get(configField.getType());
// tsHeader.headerWrite("\t" + size + ",");
// tsHeader.headerWrite("\t" + tsPosition + ",");
bits = bits.replaceAll("@OFFSET@", "" + tsPosition);
tsHeader.write("\t = " + bits);
tsPosition += size;
} else if (configField.tsInfo == null) {
tsHeader.write(";no TS info - skipping " + prefix + configField.getName() + " offset " + tsPosition);
tsPosition += configField.getArraySize() * configField.getElementSize();
} else if (configField.getArraySize() != 1) {
tsHeader.write("\t" + addTabsUpTo(nameWithPrefix, LENGTH) + "\t\t= array, ");
tsHeader.write(TypesHelper.convertToTs(configField.getType()) + ",");
tsHeader.write("\t" + tsPosition + ",");
tsHeader.write("\t[" + configField.getArraySize() + "],");
tsHeader.write("\t" + configField.tsInfo);
tsPosition += configField.getArraySize() * configField.getElementSize();
} else {
tsHeader.write("\t" + addTabsUpTo(nameWithPrefix, LENGTH) + "\t\t= scalar, ");
tsHeader.write(TypesHelper.convertToTs(configField.getType()) + ",");
tsHeader.write("\t" + tsPosition + ",");
tsHeader.write("\t" + configField.tsInfo);
tsPosition += configField.getArraySize() * configField.getElementSize();
}
tsHeader.write(EOL);
return tsPosition;
}
private void writeTunerStudioFile(String tsPath, String fieldsSection) throws IOException {
TsFileContent tsContent = readTsFile(tsPath);
System.out.println("Got " + tsContent.getPrefix().length() + "/" + tsContent.getPostfix().length() + " of " + ConfigDefinition.TS_FILE_INPUT_NAME);
System.out.println("Got " + tsContent.getPrefix().length() + "/" + tsContent.getPostfix().length() + " of " + TS_FILE_INPUT_NAME);
BufferedWriter tsHeader = new BufferedWriter(new FileWriter(tsPath + File.separator + TS_FILE_OUTPUT_NAME));
tsHeader.write(tsContent.getPrefix());
@ -42,7 +101,7 @@ public class TSProjectConsumer implements ConfigurationConsumer {
}
private static TsFileContent readTsFile(String tsPath) throws IOException {
BufferedReader r = new BufferedReader(new FileReader(tsPath + File.separator + ConfigDefinition.TS_FILE_INPUT_NAME));
BufferedReader r = new BufferedReader(new FileReader(tsPath + File.separator + TS_FILE_INPUT_NAME));
StringBuilder prefix = new StringBuilder();
StringBuilder postfix = new StringBuilder();
@ -88,4 +147,15 @@ public class TSProjectConsumer implements ConfigurationConsumer {
VariableRegistry.INSTANCE.register("TOTAL_CONFIG_SIZE", totalTsSize);
}
}
private static String addTabsUpTo(String name, int length) {
StringBuilder result = new StringBuilder(name);
int currentLength = name.length();
while (currentLength < length) {
result.append("\t");
currentLength += 4;
}
return result.toString();
}
}

View File

@ -1,6 +1,5 @@
package com.rusefi.test;
import com.rusefi.ConfigDefinition;
import com.rusefi.ConfigField;
import com.rusefi.ReaderState;
import org.junit.Test;
@ -18,8 +17,8 @@ public class ConfigFieldParserTest {
ReaderState state = new ReaderState();
{
ConfigField cf = ConfigField.parse(state, "uint8_t[8] field");
assertEquals(cf.type, "uint8_t");
assertEquals(cf.arraySize, 8);
assertEquals(cf.getType(), "uint8_t");
assertEquals(cf.getArraySize(), 8);
assertEquals(cf.getSize(null), 8);
assertFalse("isIterate", cf.isIterate);
}
@ -31,45 +30,45 @@ public class ConfigFieldParserTest {
assertNull(ConfigField.parse(state, "int"));
{
ConfigField cf = ConfigField.parse(state, "int field");
assertEquals(cf.type, "int");
assertEquals("Name", cf.name, "field");
assertEquals(cf.getType(), "int");
assertEquals("Name", cf.getName(), "field");
}
{
ConfigField cf = ConfigField.parse(state, "int_4 fie4_ld");
assertEquals(cf.type, "int_4");
assertEquals(cf.name, "fie4_ld");
assertEquals(cf.getType(), "int_4");
assertEquals(cf.getName(), "fie4_ld");
}
{
ConfigField cf = ConfigField.parse(state, "int_8 fi_eld;comm_;ts");
assertEquals(cf.type, "int_8");
assertEquals(cf.name, "fi_eld");
assertEquals("Comment", cf.comment, "comm_");
assertEquals(cf.getType(), "int_8");
assertEquals(cf.getName(), "fi_eld");
assertEquals("Comment", cf.getComment(), "comm_");
assertEquals(cf.tsInfo, "ts");
}
{
ConfigField cf = ConfigField.parse(state, "int[3 iterate] field");
assertEquals(cf.type, "int");
assertEquals(cf.arraySize, 3);
assertEquals(cf.getType(), "int");
assertEquals(cf.getArraySize(), 3);
assertTrue("isIterate", cf.isIterate);
}
{
ConfigField cf = ConfigField.parse(state, "int16_t crankingRpm;This,. value controls what RPM values we consider 'cranking' (any RPM below 'crankingRpm')\\nAnything above 'crankingRpm' would be 'running'");
assertEquals(cf.name, "crankingRpm");
assertEquals(cf.arraySize, 1);
assertEquals(cf.type, "int16_t");
assertEquals(cf.getName(), "crankingRpm");
assertEquals(cf.getArraySize(), 1);
assertEquals(cf.getType(), "int16_t");
}
{
ConfigField cf = ConfigField.parse(state, "MAP_sensor_config_s map");
assertEquals(cf.name, "map");
assertEquals(cf.arraySize, 1);
assertEquals(cf.type, "MAP_sensor_config_s");
assertEquals(cf.getName(), "map");
assertEquals(cf.getArraySize(), 1);
assertEquals(cf.getType(), "MAP_sensor_config_s");
}
{
ConfigField cf = ConfigField.parse(state, "MAP_sensor_config_s map;@see hasMapSensor\\n@see isMapAveragingEnabled");
assertEquals(cf.name, "map");
assertEquals(cf.arraySize, 1);
assertEquals(cf.type, "MAP_sensor_config_s");
assertEquals(cf.comment, "@see hasMapSensor\\n@see isMapAveragingEnabled");
assertEquals(cf.getName(), "map");
assertEquals(cf.getArraySize(), 1);
assertEquals(cf.getType(), "MAP_sensor_config_s");
assertEquals(cf.getComment(), "@see hasMapSensor\\n@see isMapAveragingEnabled");
}
}
}