2023-06-18 16:35:46 -07:00
|
|
|
package com.rusefi.tools.tune;
|
|
|
|
|
2023-11-25 14:24:23 -08:00
|
|
|
import com.devexperts.logging.Logging;
|
2023-06-18 16:35:46 -07:00
|
|
|
import com.opensr5.ini.DialogModel;
|
|
|
|
import com.opensr5.ini.IniFileModel;
|
|
|
|
import com.rusefi.*;
|
2023-11-25 21:07:20 -08:00
|
|
|
import com.rusefi.config.generated.Fields;
|
2023-06-18 16:35:46 -07:00
|
|
|
import com.rusefi.core.preferences.storage.Node;
|
|
|
|
import com.rusefi.output.ConfigStructure;
|
|
|
|
import com.rusefi.tune.xml.Constant;
|
|
|
|
import com.rusefi.tune.xml.Msq;
|
|
|
|
import org.jetbrains.annotations.NotNull;
|
2023-11-25 21:07:20 -08:00
|
|
|
import org.jetbrains.annotations.Nullable;
|
2023-06-18 16:35:46 -07:00
|
|
|
|
2023-06-19 07:47:48 -07:00
|
|
|
import javax.xml.bind.JAXBException;
|
2023-06-18 16:35:46 -07:00
|
|
|
import java.io.File;
|
2023-06-19 07:47:48 -07:00
|
|
|
import java.io.FileWriter;
|
2023-06-18 16:35:46 -07:00
|
|
|
import java.io.IOException;
|
2023-07-03 11:44:18 -07:00
|
|
|
import java.io.InputStream;
|
|
|
|
import java.net.URL;
|
2023-06-18 16:35:46 -07:00
|
|
|
import java.nio.file.Files;
|
|
|
|
import java.nio.file.Paths;
|
2023-07-03 11:44:18 -07:00
|
|
|
import java.nio.file.StandardCopyOption;
|
2023-06-18 16:35:46 -07:00
|
|
|
import java.util.List;
|
2023-06-18 17:01:56 -07:00
|
|
|
import java.util.Objects;
|
2023-06-18 16:35:46 -07:00
|
|
|
|
2023-11-25 14:24:23 -08:00
|
|
|
import static com.devexperts.logging.Logging.getLogging;
|
2023-06-18 16:35:46 -07:00
|
|
|
import static com.rusefi.ConfigFieldImpl.unquote;
|
2023-06-20 06:02:49 -07:00
|
|
|
import static com.rusefi.config.Field.niceToString;
|
2023-06-18 16:35:46 -07:00
|
|
|
import static com.rusefi.tools.tune.WriteSimulatorConfiguration.INI_FILE_FOR_SIMULATOR;
|
|
|
|
|
|
|
|
public class TuneCanTool {
|
2023-11-25 14:24:23 -08:00
|
|
|
private static final Logging log = getLogging(TuneCanTool.class);
|
|
|
|
|
2023-06-18 16:35:46 -07:00
|
|
|
public static final String SRC_TEST_RESOURCES = "src/test/resources/";
|
|
|
|
private static final String FOLDER = "generated";
|
2023-11-25 16:02:56 -08:00
|
|
|
public static final String SIMULATED_PREFIX = FOLDER + File.separator + "simulator_tune";
|
|
|
|
public static final String SIMULATED_SUFFIX = ".xml";
|
|
|
|
public static final String DEFAULT_TUNE = SIMULATED_PREFIX + SIMULATED_SUFFIX;
|
2023-07-03 11:44:18 -07:00
|
|
|
private static final String workingFolder = "downloaded_tunes";
|
2023-06-18 16:35:46 -07:00
|
|
|
|
2023-06-19 07:47:48 -07:00
|
|
|
private static IniFileModel ini;
|
|
|
|
|
|
|
|
|
2023-06-18 16:35:46 -07:00
|
|
|
public static void main(String[] args) throws Exception {
|
2023-06-19 07:47:48 -07:00
|
|
|
ini = new IniFileModel().readIniFile(INI_FILE_FOR_SIMULATOR);
|
2023-06-18 16:35:46 -07:00
|
|
|
if (ini == null)
|
|
|
|
throw new IllegalStateException("Not found " + INI_FILE_FOR_SIMULATOR);
|
|
|
|
|
|
|
|
RootHolder.ROOT = "../firmware/";
|
|
|
|
|
2023-12-27 21:17:01 -08:00
|
|
|
writeDiffBetweenLocalTuneFileAndDefaultTune("x", TuneCanTool.DEFAULT_TUNE,
|
|
|
|
"C:\\stuff\\i\\canam-2022-short\\canam-progress-nov-26.msq", "x");
|
|
|
|
|
|
|
|
|
|
|
|
// processREOtune(1507, Fields.engine_type_e_HELLEN_154_HYUNDAI_COUPE_BK2, "BK2");
|
2023-12-24 23:33:27 -08:00
|
|
|
// processREOtune(1502, Fields.engine_type_e_HYUNDAI_PB, "PB");
|
|
|
|
// processREOtune(1490, Fields.engine_type_e_MRE_M111, "m111-alex");
|
2023-11-25 14:24:23 -08:00
|
|
|
// handle("Mitsubicha", 1258);
|
|
|
|
// handle("Scion-1NZ-FE", 1448);
|
|
|
|
// handle("4g93", 1425);
|
|
|
|
// handle("BMW-mtmotorsport", 1479);
|
2023-06-19 07:47:48 -07:00
|
|
|
}
|
2023-06-18 16:35:46 -07:00
|
|
|
|
2023-12-24 23:33:27 -08:00
|
|
|
/**
|
|
|
|
* @see WriteSimulatorConfiguration
|
|
|
|
*/
|
|
|
|
private static void processREOtune(int tuneId, int engineType, String key) throws JAXBException, IOException {
|
|
|
|
// compare specific internet tune to total global default
|
2023-11-25 21:07:20 -08:00
|
|
|
handle(key, tuneId, TuneCanTool.DEFAULT_TUNE);
|
2023-12-24 23:33:27 -08:00
|
|
|
// compare same internet tune to default tune of specified engine type
|
2023-11-25 21:07:20 -08:00
|
|
|
handle(key + "-diff", tuneId, SIMULATED_PREFIX + "_" + engineType + SIMULATED_SUFFIX);
|
|
|
|
}
|
|
|
|
|
|
|
|
private static void handle(String vehicleName, int tuneId, String currentTuneFileName) throws JAXBException, IOException {
|
2023-07-03 11:44:18 -07:00
|
|
|
String localFileName = workingFolder + File.separator + tuneId + ".msq";
|
2023-06-19 07:47:48 -07:00
|
|
|
String url = "https://rusefi.com/online/view.php?msq=" + tuneId;
|
2023-06-18 20:02:38 -07:00
|
|
|
|
2023-07-03 11:44:18 -07:00
|
|
|
downloadTune(tuneId, localFileName);
|
2023-06-18 16:35:46 -07:00
|
|
|
|
2023-12-24 23:33:27 -08:00
|
|
|
writeDiffBetweenLocalTuneFileAndDefaultTune(vehicleName, currentTuneFileName, localFileName, url);
|
|
|
|
}
|
2023-12-27 21:17:01 -08:00
|
|
|
private static void writeDiffBetweenLocalTuneFileAndDefaultTune(String vehicleName, String defaultTuneFileName, String localFileName, String cannedComment) throws JAXBException, IOException {
|
2023-07-03 11:44:18 -07:00
|
|
|
String reportsOutputFolder = "tune_reports";
|
|
|
|
new File(reportsOutputFolder).mkdir();
|
|
|
|
|
|
|
|
Msq custom = Msq.readTune(localFileName);
|
2023-11-25 21:07:20 -08:00
|
|
|
|
|
|
|
StringBuilder methods = new StringBuilder();
|
|
|
|
|
2023-12-27 21:17:01 -08:00
|
|
|
Msq defaultTune = Msq.readTune(defaultTuneFileName);
|
|
|
|
StringBuilder sb = TuneCanTool.getTunePatch(defaultTune, custom, ini, defaultTuneFileName, methods);
|
2023-11-25 21:07:20 -08:00
|
|
|
|
|
|
|
String fileNameMethods = reportsOutputFolder + "/" + vehicleName + "_methods.md";
|
|
|
|
try (FileWriter methodsWriter = new FileWriter(fileNameMethods)) {
|
|
|
|
methodsWriter.append(methods);
|
|
|
|
}
|
2023-06-18 16:35:46 -07:00
|
|
|
|
2023-11-25 19:55:20 -08:00
|
|
|
String fileName = reportsOutputFolder + "/" + vehicleName + ".md";
|
|
|
|
log.info("Writing to " + fileName);
|
|
|
|
|
2023-11-25 21:07:20 -08:00
|
|
|
try (FileWriter w = new FileWriter(fileName)) {
|
|
|
|
w.append("# " + vehicleName + "\n\n");
|
2023-12-24 23:33:27 -08:00
|
|
|
w.append("// canned tune " + cannedComment + "\n\n");
|
2023-06-18 16:35:46 -07:00
|
|
|
|
2023-11-25 21:07:20 -08:00
|
|
|
w.append("```\n");
|
|
|
|
w.append(sb);
|
|
|
|
w.append("```\n");
|
|
|
|
}
|
2023-06-18 16:35:46 -07:00
|
|
|
}
|
|
|
|
|
2023-12-24 23:33:27 -08:00
|
|
|
private static void downloadTune(int tuneId, String localFileName) throws IOException {
|
2023-07-03 11:44:18 -07:00
|
|
|
new File(workingFolder).mkdirs();
|
|
|
|
String downloadUrl = "https://rusefi.com/online/download.php?msq=" + tuneId;
|
|
|
|
InputStream in = new URL(downloadUrl).openStream();
|
|
|
|
Files.copy(in, Paths.get(localFileName), StandardCopyOption.REPLACE_EXISTING);
|
|
|
|
}
|
|
|
|
|
2023-06-18 16:35:46 -07:00
|
|
|
private static boolean isHardwareEnum(String type) {
|
|
|
|
switch (type) {
|
|
|
|
case "output_pin_e":
|
|
|
|
case "brain_input_pin_e":
|
|
|
|
case "adc_channel_e":
|
|
|
|
case "Gpio":
|
2023-06-19 07:18:40 -07:00
|
|
|
case "spi_device_e":
|
|
|
|
case "pin_input_mode_e":
|
2023-06-19 07:47:48 -07:00
|
|
|
case "pin_output_mode_e":
|
2023-06-18 16:35:46 -07:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
private static Object simplerSpaces(String value) {
|
|
|
|
if (value == null)
|
|
|
|
return value;
|
|
|
|
return value.replaceAll("\\s+", " ").trim();
|
|
|
|
}
|
|
|
|
|
|
|
|
@NotNull
|
2023-11-25 21:07:20 -08:00
|
|
|
public static StringBuilder getTunePatch(Msq defaultTune, Msq customTune, IniFileModel ini, String currentTuneFileName, StringBuilder methods) throws IOException {
|
2023-06-18 16:35:46 -07:00
|
|
|
List<String> options = Files.readAllLines(Paths.get(RootHolder.ROOT + "../" + ConfigDefinition.CONFIG_PATH));
|
|
|
|
String[] totalArgs = options.toArray(new String[0]);
|
|
|
|
|
2023-11-25 21:07:20 -08:00
|
|
|
StringBuilder invokeMethods = new StringBuilder();
|
|
|
|
|
2023-06-18 16:35:46 -07:00
|
|
|
ReaderStateImpl state = new ReaderStateImpl();
|
|
|
|
ConfigDefinition.doJob(totalArgs, state);
|
|
|
|
|
|
|
|
StringBuilder sb = new StringBuilder();
|
2023-06-19 07:18:40 -07:00
|
|
|
for (DialogModel.Field f : ini.fieldsInUiOrder.values()) {
|
2023-06-18 16:35:46 -07:00
|
|
|
String name = f.getKey();
|
2023-06-18 17:01:56 -07:00
|
|
|
Constant customValue = customTune.getConstantsAsMap().get(name);
|
|
|
|
Constant defaultValue = defaultTune.getConstantsAsMap().get(name);
|
2023-06-18 16:35:46 -07:00
|
|
|
if (defaultValue == null) {
|
|
|
|
// no longer present
|
|
|
|
continue;
|
|
|
|
}
|
2023-06-18 17:01:56 -07:00
|
|
|
Objects.requireNonNull(defaultValue.getValue(), "d value");
|
|
|
|
if (customValue == null) {
|
2023-11-25 21:07:20 -08:00
|
|
|
log.info("Skipping " + name + " not present in tune");
|
2023-06-18 17:01:56 -07:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
Objects.requireNonNull(customValue.getValue(), "c value");
|
2023-06-18 16:35:46 -07:00
|
|
|
|
|
|
|
boolean isSameValue = simplerSpaces(defaultValue.getValue()).equals(simplerSpaces(customValue.getValue()));
|
|
|
|
if (!isSameValue) {
|
2023-11-25 14:24:23 -08:00
|
|
|
// todo: what about stuff outside of engine_configuration_s?
|
2023-11-25 19:55:20 -08:00
|
|
|
StringBuffer context = new StringBuffer();
|
|
|
|
|
|
|
|
ConfigField cf = findField(state, name, context);
|
2023-06-18 16:35:46 -07:00
|
|
|
if (cf == null) {
|
2023-11-25 14:24:23 -08:00
|
|
|
log.info("Not found " + name);
|
2023-06-18 16:35:46 -07:00
|
|
|
continue;
|
|
|
|
}
|
2023-11-25 19:55:20 -08:00
|
|
|
String cName = context + cf.getOriginalArrayName();
|
2023-06-18 16:35:46 -07:00
|
|
|
|
|
|
|
if (cf.getType().equals("boolean")) {
|
2023-11-25 21:07:20 -08:00
|
|
|
sb.append(TuneTools.getAssignmentCode(defaultValue, cName, unquote(customValue.getValue())));
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cf.isArray()) {
|
2023-12-25 17:13:08 -08:00
|
|
|
if (cf.getArraySizes().length == 2) {
|
2023-12-27 21:17:01 -08:00
|
|
|
float[][] tableData = TableData.readTable(currentTuneFileName, name, ini);
|
|
|
|
System.out.printf(" " + name);
|
2023-12-25 17:13:08 -08:00
|
|
|
continue;
|
|
|
|
}
|
2023-11-25 21:07:20 -08:00
|
|
|
|
|
|
|
CurveData data = CurveData.valueOf(currentTuneFileName, name, ini);
|
|
|
|
if (data == null)
|
|
|
|
continue;
|
|
|
|
|
2023-11-27 11:45:48 -08:00
|
|
|
String parentReference;
|
|
|
|
if (cf.getParent().getName().equals("engine_configuration_s")) {
|
|
|
|
parentReference = "engineConfiguration->";
|
|
|
|
} else if (cf.getParent().getName().equals("persistent_config_s")) {
|
|
|
|
parentReference = "config->";
|
|
|
|
} else {
|
|
|
|
// todo: for instance map.samplingAngle
|
|
|
|
//throw new IllegalStateException("Unexpected " + cf.getParent());
|
|
|
|
System.out.println(" " + cf);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
methods.append(data.getCsourceMethod(parentReference));
|
2023-11-25 21:07:20 -08:00
|
|
|
invokeMethods.append(data.getCinvokeMethod());
|
|
|
|
|
2023-06-18 16:35:46 -07:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!Node.isNumeric(customValue.getValue())) {
|
|
|
|
// todo: smarter logic for enums
|
|
|
|
|
|
|
|
String type = cf.getType();
|
|
|
|
if (isHardwareEnum(type)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
EnumsReader.EnumState sourceCodeEnum = state.getEnumsReader().getEnums().get(type);
|
|
|
|
if (sourceCodeEnum == null) {
|
2023-11-25 14:24:23 -08:00
|
|
|
log.info("No info for " + type);
|
2023-06-18 16:35:46 -07:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
String customEnum = state.getTsCustomLine().get(type);
|
|
|
|
|
|
|
|
int ordinal;
|
|
|
|
try {
|
|
|
|
ordinal = TuneTools.resolveEnumByName(customEnum, unquote(customValue.getValue()));
|
|
|
|
} catch (IllegalStateException e) {
|
2023-11-25 14:24:23 -08:00
|
|
|
log.info("Looks like things were renamed: " + customValue.getValue() + " not found in " + customEnum);
|
2023-06-18 16:35:46 -07:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2023-11-25 14:24:23 -08:00
|
|
|
log.info(cf + " " + sourceCodeEnum + " " + customEnum + " " + ordinal);
|
2023-06-18 16:35:46 -07:00
|
|
|
|
|
|
|
String sourceCodeValue = sourceCodeEnum.findByValue(ordinal);
|
2023-11-25 19:55:20 -08:00
|
|
|
sb.append(TuneTools.getAssignmentCode(defaultValue, cName, sourceCodeValue));
|
2023-06-18 16:35:46 -07:00
|
|
|
|
|
|
|
continue;
|
|
|
|
}
|
2023-07-09 18:54:54 -07:00
|
|
|
double doubleValue = Double.valueOf(customValue.getValue());
|
|
|
|
int intValue = (int) doubleValue;
|
|
|
|
boolean isInteger = intValue == doubleValue;
|
2023-06-20 06:02:49 -07:00
|
|
|
if (isInteger) {
|
2023-07-09 18:54:54 -07:00
|
|
|
sb.append(TuneTools.getAssignmentCode(defaultValue, cName, Integer.toString(intValue)));
|
2023-06-20 06:02:49 -07:00
|
|
|
} else {
|
2023-07-09 18:54:54 -07:00
|
|
|
sb.append(TuneTools.getAssignmentCode(defaultValue, cName, niceToString(doubleValue)));
|
2023-06-20 06:02:49 -07:00
|
|
|
}
|
2023-06-18 16:35:46 -07:00
|
|
|
}
|
|
|
|
}
|
2023-11-25 21:07:20 -08:00
|
|
|
sb.append("\n\n").append(invokeMethods);
|
|
|
|
|
2023-06-18 16:35:46 -07:00
|
|
|
return sb;
|
|
|
|
}
|
2023-11-25 19:55:20 -08:00
|
|
|
|
|
|
|
private static ConfigField findField(ReaderStateImpl state, String name, StringBuffer context) {
|
2023-11-27 11:45:48 -08:00
|
|
|
ConfigField field = doLook(state, name, context, "engine_configuration_s");
|
|
|
|
if (field != null)
|
|
|
|
return field;
|
|
|
|
return doLook(state, name, context, "persistent_config_s");
|
2023-11-25 21:07:20 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
@Nullable
|
2023-11-27 11:45:48 -08:00
|
|
|
private static ConfigField doLook(ReaderStateImpl state, String name, StringBuffer context, String parentStructName) {
|
|
|
|
ConfigStructure s = state.getStructures().get(parentStructName);
|
2023-11-25 19:55:20 -08:00
|
|
|
// log.info("We have a custom value " + name);
|
|
|
|
ConfigField cf = s.getTsFieldByName(name);
|
|
|
|
if (cf != null) {
|
2023-11-25 21:07:20 -08:00
|
|
|
return cf;
|
2023-11-25 19:55:20 -08:00
|
|
|
}
|
|
|
|
int fromIndex = 0;
|
|
|
|
while (true) {
|
|
|
|
fromIndex = name.indexOf('_', fromIndex);
|
|
|
|
if (fromIndex == -1) {
|
|
|
|
// no struct names
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
String parentName = name.substring(0, fromIndex);
|
|
|
|
cf = s.getTsFieldByName(parentName);
|
2023-11-25 21:07:20 -08:00
|
|
|
fromIndex++; // skip underscore
|
|
|
|
if (cf == null)
|
|
|
|
continue;
|
2023-11-25 19:55:20 -08:00
|
|
|
String type = cf.getType();
|
|
|
|
s = state.getStructures().get(type);
|
|
|
|
|
|
|
|
if (s != null) {
|
2023-11-25 21:07:20 -08:00
|
|
|
String substring = name.substring(fromIndex);
|
2023-11-25 19:55:20 -08:00
|
|
|
ConfigField tsFieldByName = s.getTsFieldByName(substring);
|
|
|
|
if (tsFieldByName == null) {
|
|
|
|
log.info("Not located " + substring + " in " + s);
|
|
|
|
} else {
|
|
|
|
context.append(cf.getOriginalArrayName()).append(".");
|
|
|
|
log.info("Located " + tsFieldByName + " in " + s);
|
|
|
|
}
|
|
|
|
return tsFieldByName;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-06-18 16:35:46 -07:00
|
|
|
}
|