diff --git a/java_tools/ConfigDefinition.jar b/java_tools/ConfigDefinition.jar index 8da9edad14..16241aad60 100644 Binary files a/java_tools/ConfigDefinition.jar and b/java_tools/ConfigDefinition.jar differ diff --git a/java_tools/configuration_definition/src/main/java/com/rusefi/ConfigDefinition.java b/java_tools/configuration_definition/src/main/java/com/rusefi/ConfigDefinition.java index 0d8e86eb14..002b9132f6 100644 --- a/java_tools/configuration_definition/src/main/java/com/rusefi/ConfigDefinition.java +++ b/java_tools/configuration_definition/src/main/java/com/rusefi/ConfigDefinition.java @@ -1,24 +1,14 @@ package com.rusefi; -import com.rusefi.enum_reader.Value; -import com.rusefi.generated.RusefiConfigGrammarLexer; -import com.rusefi.generated.RusefiConfigGrammarParser; import com.rusefi.newparse.ParseState; import com.rusefi.newparse.parsing.Definition; import com.rusefi.output.*; import com.rusefi.util.IoUtils; import com.rusefi.util.LazyFile; import com.rusefi.util.SystemOut; -import org.antlr.v4.runtime.*; -import org.antlr.v4.runtime.tree.ParseTree; -import org.antlr.v4.runtime.tree.ParseTreeListener; -import org.antlr.v4.runtime.tree.ParseTreeWalker; -import org.yaml.snakeyaml.Yaml; import java.io.*; -import java.nio.file.Files; import java.util.*; -import java.util.zip.CRC32; /** * Andrey Belomutskiy, (c) 2013-2020 @@ -28,7 +18,7 @@ import java.util.zip.CRC32; */ @SuppressWarnings("StringConcatenationInsideStringBufferAppend") public class ConfigDefinition { - private static final String SIGNATURE_HASH = "SIGNATURE_HASH"; + static final String SIGNATURE_HASH = "SIGNATURE_HASH"; private static String TS_OUTPUTS_DESTINATION = null; public static String MESSAGE; @@ -96,7 +86,7 @@ public class ConfigDefinition { String signaturePrependFile = null; List enumInputFiles = new ArrayList<>(); CHeaderConsumer.withC_Defines = true; - File[] yamlFiles = null; + File[] boardYamlFiles = null; // used to update other files List inputFiles = new ArrayList<>(); @@ -147,7 +137,7 @@ public class ConfigDefinition { String keyName = args[i + 1]; // yes, we take three parameters here thus pre-increment! String fileName = args[++i + 1]; - state.variableRegistry.register(keyName, readFile(fileName)); + state.variableRegistry.register(keyName, IoUtil.readFile(fileName)); inputFiles.add(fileName); case KEY_FIRING: firingEnumFileName = args[i + 1]; @@ -184,9 +174,9 @@ public class ConfigDefinition { String dirPath = "./config/boards/" + boardName + "/connectors"; File dirName = new File(dirPath); FilenameFilter filter = (f, name) -> name.endsWith(".yaml"); - yamlFiles = dirName.listFiles(filter); - if (yamlFiles != null) { - for (File yamlFile : yamlFiles) { + boardYamlFiles = dirName.listFiles(filter); + if (boardYamlFiles != null) { + for (File yamlFile : boardYamlFiles) { inputFiles.add("config/boards/" + boardName + "/connectors/" + yamlFile.getName()); } } @@ -209,7 +199,7 @@ public class ConfigDefinition { ParseState parseState = new ParseState(state.enumsReader); // Add the variable for the config signature - long crc32 = signatureHash(state, parseState, tsInputFileFolder, inputFiles); + long crc32 = IoUtil.signatureHash(state, parseState, tsInputFileFolder, inputFiles); handleFiringOrder(firingEnumFileName, state.variableRegistry, parseState); @@ -220,8 +210,8 @@ public class ConfigDefinition { for (String prependFile : prependFiles) state.variableRegistry.readPrependValues(prependFile); - if (yamlFiles != null) { - processYamls(state.variableRegistry, yamlFiles, state); + if (boardYamlFiles != null) { + PinoutLogic.processYamls(state.variableRegistry, boardYamlFiles, state); } // Parse the input files @@ -235,7 +225,7 @@ public class ConfigDefinition { parseState.setDefinitionPolicy(Definition.OverwritePolicy.IgnoreNew); for (String prependFile : prependFiles) { - parseFile(parseState.getListener(), prependFile); + RusefiParseErrorStrategy.parseDefinitionFile(parseState.getListener(), prependFile); } } @@ -243,7 +233,7 @@ public class ConfigDefinition { { // don't allow duplicates in the main file parseState.setDefinitionPolicy(Definition.OverwritePolicy.NotAllowed); - parseFile(parseState.getListener(), definitionInputFile); + RusefiParseErrorStrategy.parseDefinitionFile(parseState.getListener(), definitionInputFile); } // Write C structs @@ -297,26 +287,6 @@ public class ConfigDefinition { } } - private static String readFile(String fileName) { - String line; - StringBuilder stringBuilder = new StringBuilder(); - String ls = System.getProperty("line.separator"); - try { - - try (BufferedReader reader = new BufferedReader(new FileReader(fileName))) { - while (true) { - if (!((line = reader.readLine()) != null)) break; - stringBuilder.append(line); - stringBuilder.append(ls); - } - - return stringBuilder.toString(); - } - } catch (IOException e) { - return ""; - } - } - private static void handleFiringOrder(String firingEnumFileName, VariableRegistry variableRegistry, ParseState parseState) throws IOException { if (firingEnumFileName != null) { SystemOut.println("Reading firing from " + firingEnumFileName); @@ -326,158 +296,6 @@ public class ConfigDefinition { } } - private static long signatureHash(ReaderState state, ParseState parseState, String tsPath, List inputAllFiles) throws IOException { - // get CRC32 of given input files - long crc32 = 0; - for (String iFile : inputAllFiles) { - long c = getCrc32(iFile) & 0xffffffffL; - SystemOut.println("CRC32 from " + iFile + " = " + c); - crc32 ^= c; - } - SystemOut.println("CRC32 from all input files = " + crc32); - // store the CRC32 as a built-in variable - - // nasty trick - do not insert signature into live data files - if (tsPath != null) { - state.variableRegistry.register(SIGNATURE_HASH, "" + crc32); - parseState.addDefinition(SIGNATURE_HASH, Long.toString(crc32), Definition.OverwritePolicy.NotAllowed); - } - - return crc32; - } - - public static void processYamls(VariableRegistry registry, File[] yamlFiles, ReaderState state) throws IOException { - ArrayList> listPins = new ArrayList<>(); - for (File yamlFile : yamlFiles) { - processYamlFile(yamlFile, listPins); - } - registerPins(listPins, registry, state); - } - - @SuppressWarnings("unchecked") - private static void processYamlFile(File yamlFile, - ArrayList> listPins) throws IOException { - Yaml yaml = new Yaml(); - Map yamlData = yaml.load(new FileReader(yamlFile)); - if (yamlData == null) { - SystemOut.println("Null yaml for " + yamlFile); - return; - } - List> data = (List>) yamlData.get("pins"); - if (data == null) { - SystemOut.println("Null yaml for " + yamlFile); - return; - } - SystemOut.println(data); - Objects.requireNonNull(data, "data"); - for (Map pin : data) { - ArrayList> thisPinList = new ArrayList<>(); - Object pinId = pin.get("id"); - Object pinClass = pin.get("class"); - Object pinName = pin.get("ts_name"); - if (pinId == null || pinClass == null || pinName == null) { - continue; - } - if (pinId instanceof ArrayList) { - ArrayList pinIds = (ArrayList) pinId; - if (!(pinClass instanceof ArrayList)) - throw new IllegalStateException("Expected multiple classes for " + pinIds); - for (int i = 0; i < pinIds.size(); i++) { - String id = pinIds.get(i); - addPinToList(listPins, thisPinList, id, pinName, ((ArrayList) pinClass).get(i)); - } - } else if (pinId instanceof String) { - if (((String) pinId).length() == 0) { - throw new IllegalStateException("Unexpected empty ID field"); - } - addPinToList(listPins, thisPinList, pinId, pinName, pinClass); - } else { - throw new IllegalStateException("Unexpected type of ID field: " + pinId.getClass().getSimpleName()); - } - listPins.addAll(thisPinList); - } - } - - private static void addPinToList(ArrayList> listPins, ArrayList> thisPinList, Object id, Object pinName, Object pinClass) { -/* - This doesn't work as expected because it's possible that a board has multiple connector pins connected to the same MCU pin. - https://github.com/rusefi/rusefi/issues/2897 - https://github.com/rusefi/rusefi/issues/2925 - for (int i = 0; i < listPins.size(); i++) { - if (id.equals(listPins.get(i).get("id"))) { - throw new IllegalStateException("ID used multiple times: " + id); - } - } -*/ - Map thisPin = new HashMap<>(); - thisPin.put("id", id); - thisPin.put("ts_name", pinName); - thisPin.put("class", pinClass); - thisPinList.add(thisPin); - } - - private static void registerPins(ArrayList> listPins, VariableRegistry registry, ReaderState state) { - if (listPins == null || listPins.isEmpty()) { - return; - } - Map> names = new HashMap<>(); - names.put("outputs", new ArrayList<>()); - names.put("analog_inputs", new ArrayList<>()); - names.put("event_inputs", new ArrayList<>()); - names.put("switch_inputs", new ArrayList<>()); - for (int i = 0; i < listPins.size(); i++) { - String id = (String) listPins.get(i).get("id"); - String className = (String) listPins.get(i).get("class"); - ArrayList classList = names.get(className); - if (classList == null) { - throw new IllegalStateException("Class not found: " + className); - } - PinType listPinType = PinType.find((String) listPins.get(i).get("class")); - String pinType = listPinType.getPinType(); - EnumsReader.EnumState enumList = state.enumsReader.getEnums().get(pinType); - for (Map.Entry kv : enumList.entrySet()) { - if (kv.getKey().equals(id)) { - int index = kv.getValue().getIntValue(); - classList.ensureCapacity(index + 1); - for (int ii = classList.size(); ii <= index; ii++) { - classList.add(null); - } - classList.set(index, (String) listPins.get(i).get("ts_name")); - break; - } - } - } - for (Map.Entry> kv : names.entrySet()) { - PinType namePinType = PinType.find(kv.getKey()); - String outputEnumName = namePinType.getOutputEnumName(); - String pinType = namePinType.getPinType(); - String nothingName = namePinType.getNothingName(); - EnumsReader.EnumState enumList = state.enumsReader.getEnums().get(pinType); - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < kv.getValue().size(); i++) { - if (sb.length() > 0) - sb.append(","); - String key = ""; - for (Map.Entry entry : enumList.entrySet()) { - if (entry.getValue().getIntValue() == i) { - key = entry.getKey(); - break; - } - } - if (key.equals(nothingName)) { - sb.append("\"NONE\""); - } else if (kv.getValue().get(i) == null) { - sb.append("\"INVALID\""); - } else { - sb.append("\"" + kv.getValue().get(i) + "\""); - } - } - if (sb.length() > 0) { - registry.register(outputEnumName, sb.toString()); - } - } - } - private static void processTextTemplate(ReaderState state, String inputFileName, String outputFileName) throws IOException { SystemOut.println("Reading from " + inputFileName); SystemOut.println("Writing to " + outputFileName); @@ -526,19 +344,6 @@ public class ConfigDefinition { return Integer.parseInt(s); } - private static long getCrc32(String fileName) throws IOException { - File file = new File(fileName); - byte[] fileContent = Files.readAllBytes(file.toPath()); - for (int i = 0; i < fileContent.length; i++) { - byte aByte = fileContent[i]; - if (aByte == '\r') - throw new IllegalStateException("CR \\r 0x0D byte not allowed in cacheable content " + fileName + " at index=" + i); - } - CRC32 c = new CRC32(); - c.update(fileContent, 0, fileContent.length); - return c.getValue(); - } - public static void writeDefinesToFile(VariableRegistry variableRegistry, String fileName) throws IOException { SystemOut.println("Writing to " + fileName); @@ -549,48 +354,4 @@ public class ConfigDefinition { cHeader.close(); } - public static class RusefiParseErrorStrategy extends DefaultErrorStrategy { - private boolean hadError = false; - - public boolean hadError() { - return this.hadError; - } - - @Override - public void recover(Parser recognizer, RecognitionException e) { - this.hadError = true; - - super.recover(recognizer, e); - } - - @Override - public Token recoverInline(Parser recognizer) throws RecognitionException { - this.hadError = true; - - return super.recoverInline(recognizer); - } - } - - private static void parseFile(ParseTreeListener listener, String filePath) throws IOException { - SystemOut.println("Parsing file (Antlr) " + filePath); - - CharStream in = new ANTLRInputStream(new FileInputStream(filePath)); - - long start = System.nanoTime(); - - RusefiConfigGrammarParser parser = new RusefiConfigGrammarParser(new CommonTokenStream(new RusefiConfigGrammarLexer(in))); - - RusefiParseErrorStrategy errorStrategy = new RusefiParseErrorStrategy(); - parser.setErrorHandler(errorStrategy); - - ParseTree tree = parser.content(); - new ParseTreeWalker().walk(listener, tree); - double durationMs = (System.nanoTime() - start) / 1e6; - - if (errorStrategy.hadError()) { - throw new RuntimeException("Parse failed, see error output above!"); - } - - SystemOut.println("Successfully parsed " + filePath + " in " + durationMs + "ms"); - } } diff --git a/java_tools/configuration_definition/src/main/java/com/rusefi/IoUtil.java b/java_tools/configuration_definition/src/main/java/com/rusefi/IoUtil.java new file mode 100644 index 0000000000..45ae57f45a --- /dev/null +++ b/java_tools/configuration_definition/src/main/java/com/rusefi/IoUtil.java @@ -0,0 +1,68 @@ +package com.rusefi; + +import com.rusefi.newparse.ParseState; +import com.rusefi.newparse.parsing.Definition; +import com.rusefi.util.SystemOut; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.nio.file.Files; +import java.util.List; +import java.util.zip.CRC32; + +public class IoUtil { + static String readFile(String fileName) { + String line; + StringBuilder stringBuilder = new StringBuilder(); + String ls = System.getProperty("line.separator"); + try { + + try (BufferedReader reader = new BufferedReader(new FileReader(fileName))) { + while (true) { + if (!((line = reader.readLine()) != null)) break; + stringBuilder.append(line); + stringBuilder.append(ls); + } + + return stringBuilder.toString(); + } + } catch (IOException e) { + return ""; + } + } + + static long getCrc32(String fileName) throws IOException { + File file = new File(fileName); + byte[] fileContent = Files.readAllBytes(file.toPath()); + for (int i = 0; i < fileContent.length; i++) { + byte aByte = fileContent[i]; + if (aByte == '\r') + throw new IllegalStateException("CR \\r 0x0D byte not allowed in cacheable content " + fileName + " at index=" + i); + } + CRC32 c = new CRC32(); + c.update(fileContent, 0, fileContent.length); + return c.getValue(); + } + + static long signatureHash(ReaderState state, ParseState parseState, String tsPath, List inputAllFiles) throws IOException { + // get CRC32 of given input files + long crc32 = 0; + for (String iFile : inputAllFiles) { + long c = getCrc32(iFile) & 0xffffffffL; + SystemOut.println("CRC32 from " + iFile + " = " + c); + crc32 ^= c; + } + SystemOut.println("CRC32 from all input files = " + crc32); + // store the CRC32 as a built-in variable + + // nasty trick - do not insert signature into live data files + if (tsPath != null) { + state.variableRegistry.register(ConfigDefinition.SIGNATURE_HASH, "" + crc32); + parseState.addDefinition(ConfigDefinition.SIGNATURE_HASH, Long.toString(crc32), Definition.OverwritePolicy.NotAllowed); + } + + return crc32; + } +} diff --git a/java_tools/configuration_definition/src/main/java/com/rusefi/PinoutLogic.java b/java_tools/configuration_definition/src/main/java/com/rusefi/PinoutLogic.java new file mode 100644 index 0000000000..3c511e22e4 --- /dev/null +++ b/java_tools/configuration_definition/src/main/java/com/rusefi/PinoutLogic.java @@ -0,0 +1,144 @@ +package com.rusefi; + +import com.rusefi.enum_reader.Value; +import com.rusefi.util.SystemOut; +import org.yaml.snakeyaml.Yaml; + +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.util.*; + +public class PinoutLogic { + public static void processYamls(VariableRegistry registry, File[] yamlFiles, ReaderState state) throws IOException { + ArrayList> listPins = new ArrayList<>(); + for (File yamlFile : yamlFiles) { + processYamlFile(yamlFile, listPins); + } + registerPins(listPins, registry, state); + } + + private static void registerPins(ArrayList> listPins, VariableRegistry registry, ReaderState state) { + if (listPins == null || listPins.isEmpty()) { + return; + } + Map> names = new HashMap<>(); + names.put("outputs", new ArrayList<>()); + names.put("analog_inputs", new ArrayList<>()); + names.put("event_inputs", new ArrayList<>()); + names.put("switch_inputs", new ArrayList<>()); + for (int i = 0; i < listPins.size(); i++) { + String id = (String) listPins.get(i).get("id"); + String className = (String) listPins.get(i).get("class"); + ArrayList classList = names.get(className); + if (classList == null) { + throw new IllegalStateException("Class not found: " + className); + } + PinType listPinType = PinType.find((String) listPins.get(i).get("class")); + String pinType = listPinType.getPinType(); + EnumsReader.EnumState enumList = state.enumsReader.getEnums().get(pinType); + for (Map.Entry kv : enumList.entrySet()) { + if (kv.getKey().equals(id)) { + int index = kv.getValue().getIntValue(); + classList.ensureCapacity(index + 1); + for (int ii = classList.size(); ii <= index; ii++) { + classList.add(null); + } + classList.set(index, (String) listPins.get(i).get("ts_name")); + break; + } + } + } + for (Map.Entry> kv : names.entrySet()) { + PinType namePinType = PinType.find(kv.getKey()); + String outputEnumName = namePinType.getOutputEnumName(); + String pinType = namePinType.getPinType(); + String nothingName = namePinType.getNothingName(); + EnumsReader.EnumState enumList = state.enumsReader.getEnums().get(pinType); + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < kv.getValue().size(); i++) { + if (sb.length() > 0) + sb.append(","); + String key = ""; + for (Map.Entry entry : enumList.entrySet()) { + if (entry.getValue().getIntValue() == i) { + key = entry.getKey(); + break; + } + } + if (key.equals(nothingName)) { + sb.append("\"NONE\""); + } else if (kv.getValue().get(i) == null) { + sb.append("\"INVALID\""); + } else { + sb.append("\"" + kv.getValue().get(i) + "\""); + } + } + if (sb.length() > 0) { + registry.register(outputEnumName, sb.toString()); + } + } + } + + @SuppressWarnings("unchecked") + private static void processYamlFile(File yamlFile, + ArrayList> listPins) throws IOException { + Yaml yaml = new Yaml(); + Map yamlData = yaml.load(new FileReader(yamlFile)); + if (yamlData == null) { + SystemOut.println("Null yaml for " + yamlFile); + return; + } + List> data = (List>) yamlData.get("pins"); + if (data == null) { + SystemOut.println("Null yaml for " + yamlFile); + return; + } + SystemOut.println(data); + Objects.requireNonNull(data, "data"); + for (Map pin : data) { + ArrayList> thisPinList = new ArrayList<>(); + Object pinId = pin.get("id"); + Object pinClass = pin.get("class"); + Object pinName = pin.get("ts_name"); + if (pinId == null || pinClass == null || pinName == null) { + continue; + } + if (pinId instanceof ArrayList) { + ArrayList pinIds = (ArrayList) pinId; + if (!(pinClass instanceof ArrayList)) + throw new IllegalStateException("Expected multiple classes for " + pinIds); + for (int i = 0; i < pinIds.size(); i++) { + String id = pinIds.get(i); + addPinToList(listPins, thisPinList, id, pinName, ((ArrayList) pinClass).get(i)); + } + } else if (pinId instanceof String) { + if (((String) pinId).length() == 0) { + throw new IllegalStateException("Unexpected empty ID field"); + } + addPinToList(listPins, thisPinList, pinId, pinName, pinClass); + } else { + throw new IllegalStateException("Unexpected type of ID field: " + pinId.getClass().getSimpleName()); + } + listPins.addAll(thisPinList); + } + } + + private static void addPinToList(ArrayList> listPins, ArrayList> thisPinList, Object id, Object pinName, Object pinClass) { +/* + This doesn't work as expected because it's possible that a board has multiple connector pins connected to the same MCU pin. + https://github.com/rusefi/rusefi/issues/2897 + https://github.com/rusefi/rusefi/issues/2925 + for (int i = 0; i < listPins.size(); i++) { + if (id.equals(listPins.get(i).get("id"))) { + throw new IllegalStateException("ID used multiple times: " + id); + } + } +*/ + Map thisPin = new HashMap<>(); + thisPin.put("id", id); + thisPin.put("ts_name", pinName); + thisPin.put("class", pinClass); + thisPinList.add(thisPin); + } +} diff --git a/java_tools/configuration_definition/src/main/java/com/rusefi/RusefiParseErrorStrategy.java b/java_tools/configuration_definition/src/main/java/com/rusefi/RusefiParseErrorStrategy.java new file mode 100644 index 0000000000..eafd3c4f53 --- /dev/null +++ b/java_tools/configuration_definition/src/main/java/com/rusefi/RusefiParseErrorStrategy.java @@ -0,0 +1,57 @@ +package com.rusefi; + +import com.rusefi.generated.RusefiConfigGrammarLexer; +import com.rusefi.generated.RusefiConfigGrammarParser; +import com.rusefi.util.SystemOut; +import org.antlr.v4.runtime.*; +import org.antlr.v4.runtime.tree.ParseTree; +import org.antlr.v4.runtime.tree.ParseTreeListener; +import org.antlr.v4.runtime.tree.ParseTreeWalker; + +import java.io.FileInputStream; +import java.io.IOException; + +public class RusefiParseErrorStrategy extends DefaultErrorStrategy { + private boolean hadError = false; + + static void parseDefinitionFile(ParseTreeListener listener, String filePath) throws IOException { + SystemOut.println("Parsing file (Antlr) " + filePath); + + CharStream in = new ANTLRInputStream(new FileInputStream(filePath)); + + long start = System.nanoTime(); + + RusefiConfigGrammarParser parser = new RusefiConfigGrammarParser(new CommonTokenStream(new RusefiConfigGrammarLexer(in))); + + RusefiParseErrorStrategy errorStrategy = new RusefiParseErrorStrategy(); + parser.setErrorHandler(errorStrategy); + + ParseTree tree = parser.content(); + new ParseTreeWalker().walk(listener, tree); + double durationMs = (System.nanoTime() - start) / 1e6; + + if (errorStrategy.hadError()) { + throw new RuntimeException("Parse failed, see error output above!"); + } + + SystemOut.println("Successfully parsed " + filePath + " in " + durationMs + "ms"); + } + + public boolean hadError() { + return this.hadError; + } + + @Override + public void recover(Parser recognizer, RecognitionException e) { + this.hadError = true; + + super.recover(recognizer, e); + } + + @Override + public Token recoverInline(Parser recognizer) throws RecognitionException { + this.hadError = true; + + return super.recoverInline(recognizer); + } +}