diff --git a/firmware/console/binary_log/binary_logging.cpp b/firmware/console/binary_log/binary_logging.cpp index 1ee38c3623..d0e6a29520 100644 --- a/firmware/console/binary_log/binary_logging.cpp +++ b/firmware/console/binary_log/binary_logging.cpp @@ -11,14 +11,14 @@ #include "crc.h" static const LogField fields[] = { - {tsOutputChannels.rpm, "RPM", "rpm", 0}, + {tsOutputChannels.rpm, GAUGE_NAME_RPM, "rpm", 0}, {tsOutputChannels.vehicleSpeedKph, GAUGE_NAME_VVS, "kph", 0}, {tsOutputChannels.internalMcuTemperature, GAUGE_NAME_CPU_TEMP, "C", 0}, - {tsOutputChannels.coolantTemperature, "CLT", "C", 1}, - {tsOutputChannels.intakeAirTemperature, "IAT", "C", 1}, - {tsOutputChannels.throttlePosition, "TPS", "%", 2}, + {tsOutputChannels.coolantTemperature, GAUGE_NAME_CLT, "C", 1}, + {tsOutputChannels.intakeAirTemperature, GAUGE_NAME_IAT, "C", 1}, + {tsOutputChannels.throttlePosition, GAUGE_NAME_TPS, "%", 2}, {tsOutputChannels.pedalPosition, GAUGE_NAME_THROTTLE_PEDAL, "%", 2}, - {tsOutputChannels.manifoldAirPressure, "MAP", "kPa", 1}, + {tsOutputChannels.manifoldAirPressure, GAUGE_NAME_MAP, "kPa", 1}, {tsOutputChannels.airFuelRatio, GAUGE_NAME_AFR, "afr", 2}, {tsOutputChannels.vBatt, GAUGE_NAME_VBAT, "v", 2}, {tsOutputChannels.oilPressure, "Oil Press", "kPa", 0}, diff --git a/firmware/tunerstudio/rusefi.input b/firmware/tunerstudio/rusefi.input index e938819725..ff61149b8a 100644 --- a/firmware/tunerstudio/rusefi.input +++ b/firmware/tunerstudio/rusefi.input @@ -1106,16 +1106,16 @@ gaugeCategory = Sensors - Raw [Datalog] ; Channel Label Type Format - entry = time, "Time", float, "%.3f" - entry = RPMValue, "RPM", int, "%d" + entry = time, @@GAUGE_NAME_TIME@@, float, "%.3f" + entry = RPMValue, @@GAUGE_NAME_RPM@@, int, "%d" entry = firmwareVersion, @@GAUGE_NAME_VERSION@@, int, "%d" - entry = coolant, "CLT", float, "%.2f" - entry = intake, "IAT", float, "%.2f" + entry = coolant, @@GAUGE_NAME_CLT@@, float, "%.2f" + entry = intake, @@GAUGE_NAME_IAT@@, float, "%.2f" entry = oilPressure, "Oil Press", float, "%.1f" - entry = TPSValue, "TPS", float, "%.2f" - entry = MAFValue, "MAF", float, "%.2f" - entry = MAPValue, "MAP", float, "%.1f" - entry = AFRValue, @@GAUGE_NAME_AFR@@, float, "%.2f" + entry = TPSValue, @@GAUGE_NAME_TPS@@, float, "%.2f" + entry = MAFValue, @@GAUGE_NAME_MAF@@, float, "%.2f" + entry = MAPValue, @@GAUGE_NAME_MAP@@, float, "%.1f" + entry = AFRValue, @@GAUGE_NAME_AFR@@, float, "%.2f" entry = VBatt, @@GAUGE_NAME_VBAT@@, float, "%.2f" entry = engineLoad, @@GAUGE_NAME_ENGINE_LOAD@@, float, "%.1f" entry = ignitionAdvance, @@GAUGE_NAME_TIMING_ADVANCE@@, float, "%.2f" diff --git a/java_console/models/src/com/rusefi/core/Sensor.java b/java_console/models/src/com/rusefi/core/Sensor.java index 07f0e55310..d6183ad306 100644 --- a/java_console/models/src/com/rusefi/core/Sensor.java +++ b/java_console/models/src/com/rusefi/core/Sensor.java @@ -4,6 +4,8 @@ import com.rusefi.config.FieldType; import com.rusefi.config.generated.Fields; import org.jetbrains.annotations.Nullable; +import java.io.DataOutputStream; +import java.io.IOException; import java.util.Collection; import java.util.Comparator; import java.util.Set; @@ -28,17 +30,17 @@ public enum Sensor { // Temperatures INT_TEMP(GAUGE_NAME_CPU_TEMP, SensorCategory.OPERATIONS, FieldType.INT8, 10, 1, 0, 5, "C"), CLT(GAUGE_NAME_CLT, SensorCategory.SENSOR_INPUTS, FieldType.INT16, 12, 1.0 / PACK_MULT_TEMPERATURE, -40, 150, "deg C"), - IAT("IAT", SensorCategory.SENSOR_INPUTS, FieldType.INT16, 14, 1.0 / PACK_MULT_TEMPERATURE, -40, 150, "deg C"), + IAT(GAUGE_NAME_IAT, SensorCategory.SENSOR_INPUTS, FieldType.INT16, 14, 1.0 / PACK_MULT_TEMPERATURE, -40, 150, "deg C"), // throttle, pedal - TPS("TPS", SensorCategory.SENSOR_INPUTS, FieldType.INT16, 20, 1.0 / PACK_MULT_PERCENT, 0, 100, "%"), // throttle position sensor + TPS(GAUGE_NAME_TPS, SensorCategory.SENSOR_INPUTS, FieldType.INT16, 20, 1.0 / PACK_MULT_PERCENT, 0, 100, "%"), // throttle position sensor PPS(GAUGE_NAME_THROTTLE_PEDAL, SensorCategory.SENSOR_INPUTS, FieldType.INT16, 22, 1.0 / PACK_MULT_PERCENT, 0, 100, "%"), // pedal position sensor // air flow/mass measurement - MAF("MAF", SensorCategory.SENSOR_INPUTS, FieldType.UINT16, 26, 1.0 / PACK_MULT_VOLTAGE, 0, 5, "Volts"), - MAP("MAP", SensorCategory.SENSOR_INPUTS, FieldType.UINT16, 30, 1.0 / PACK_MULT_PRESSURE, 20, 300, "kPa"), + MAF(GAUGE_NAME_MAF, SensorCategory.SENSOR_INPUTS, FieldType.UINT16, 26, 1.0 / PACK_MULT_VOLTAGE, 0, 5, "Volts"), + MAP(GAUGE_NAME_MAP, SensorCategory.SENSOR_INPUTS, FieldType.UINT16, 30, 1.0 / PACK_MULT_PRESSURE, 20, 300, "kPa"), - AFR("A/F ratio", SensorCategory.SENSOR_INPUTS, FieldType.UINT16, 34, 1.0 / PACK_MULT_AFR, 10, 20, "afr"), + AFR(GAUGE_NAME_AFR, SensorCategory.SENSOR_INPUTS, FieldType.UINT16, 34, 1.0 / PACK_MULT_AFR, 10, 20, "afr"), VBATT(GAUGE_NAME_VBAT, SensorCategory.SENSOR_INPUTS, FieldType.UINT16, 38, 1.0 / PACK_MULT_VOLTAGE, 4, 18, "Volts"), oilPressure("Oil Pressure", SensorCategory.SENSOR_INPUTS, FieldType.INT16, 40, 1.0 / PACK_MULT_PRESSURE, 0, 5, "X"), @@ -47,7 +49,7 @@ public enum Sensor { // fuel math CHARGE_AIR_MASS("airmass", SensorCategory.OPERATIONS, FieldType.UINT16, 44, 0.001, 0, 3, "g/cyl"), crankingFuel(GAUGE_NAME_FUEL_CRANKING, SensorCategory.FUEL, FieldType.UINT16, 46, 1.0 / PACK_MULT_MS, 0, 30, "ms"), - TARGET_AFR("A/F target", SensorCategory.OPERATIONS, FieldType.INT16, 48, 1.0 / PACK_MULT_AFR, 10, 20, "afr"), + TARGET_AFR(GAUGE_NAME_TARGET_AFR, SensorCategory.OPERATIONS, FieldType.INT16, 48, 1.0 / PACK_MULT_AFR, 10, 20, "afr"), baseFuel(Fields.GAUGE_NAME_FUEL_BASE, SensorCategory.FUEL, FieldType.UINT16, 50, 1.0 / PACK_MULT_MS, 0, 30, "ms"), runningFuel(GAUGE_NAME_FUEL_RUNNING, SensorCategory.FUEL, FieldType.UINT16, 52, 1.0 / PACK_MULT_MS, 0, 15, "ms"), actualLastInjection(GAUGE_NAME_FUEL_LAST_INJECTION, SensorCategory.FUEL, FieldType.UINT16, 54, 1.0 / PACK_MULT_MS, 0, 30, "ms"), @@ -59,7 +61,7 @@ public enum Sensor { injectorLagMs(GAUGE_NAME_INJECTOR_LAG, SensorCategory.FUEL, FieldType.UINT16, 62, 1.0 / PACK_MULT_MS, 0, 15, "ms"), iatCorrection(GAUGE_NAME_FUEL_IAT_CORR, SensorCategory.FUEL, FieldType.INT16, 64, 1.0 / PACK_MULT_PERCENT, 0, 5, "ratio"), cltCorrection(GAUGE_NAME_FUEL_CLT_CORR, SensorCategory.FUEL, FieldType.INT16, 66, 1.0 / PACK_MULT_PERCENT, 0, 5, "ratio"), - fuelPidCorrection("Fuel PID", SensorCategory.FUEL, FieldType.INT16, 70, 1.0 / PACK_MULT_MS, -2, 2, "ms"), + fuelPidCorrection("Fuel PID", SensorCategory.FUEL, FieldType.INT16, 70, 1.0 / PACK_MULT_MS, -2, 2, "ms"), // Wall model AE wallFuelAmount(GAUGE_NAME_FUEL_WALL_AMOUNT, SensorCategory.FUEL, FieldType.UINT16, 72, 1.0 / PACK_MULT_MS, 0, 20, "ms"), @@ -234,4 +236,21 @@ public enum Sensor { public double translateValue(double value) { return value; } + + public void writeToLog(DataOutputStream dos, double value) throws IOException { + switch (type) { + case FLOAT: + dos.writeFloat((float) value); + return; + case UINT16: + case INT16: + dos.writeShort((int) value); + return; + case INT: + dos.writeInt((int) value); + return; + default: + throw new UnsupportedOperationException("Type " + type); + } + } } diff --git a/java_console/ui/src/main/java/com/rusefi/sensor_logs/BinarySensorLog.java b/java_console/ui/src/main/java/com/rusefi/sensor_logs/BinarySensorLog.java index 93db134426..30c45f6fdb 100644 --- a/java_console/ui/src/main/java/com/rusefi/sensor_logs/BinarySensorLog.java +++ b/java_console/ui/src/main/java/com/rusefi/sensor_logs/BinarySensorLog.java @@ -1,16 +1,34 @@ package com.rusefi.sensor_logs; import com.rusefi.FileLog; +import com.rusefi.config.generated.Fields; import com.rusefi.core.Sensor; +import com.rusefi.core.SensorCentral; +import com.rusefi.rusEFIVersion; import java.io.*; +import java.util.Date; +import java.util.function.Function; public class BinarySensorLog extends SensorLog { - private BufferedWriter stream; + private final Function valueProvider; + private final Sensor[] sensors; + private DataOutputStream stream; - public static void main(String[] args) { - BinarySensorLog l = new BinarySensorLog(); - l.writeSensorLogLine(); + private int counter; + + public BinarySensorLog() { + this(new Function() { + @Override + public Double apply(Sensor sensor) { + return SensorCentral.getInstance().getValue(sensor); + } + }, SensorLogger.SENSORS); + } + + public BinarySensorLog(Function valueProvider, Sensor... sensors) { + this.valueProvider = valueProvider; + this.sensors = sensors; } @Override @@ -25,36 +43,35 @@ public class BinarySensorLog extends SensorLog { String fileName = FileLog.DIR + "rusEFI_gauges_" + FileLog.getDate() + ".mlg"; try { - stream = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(fileName))); + stream = new DataOutputStream(new FileOutputStream(fileName)); } catch (IOException e) { e.printStackTrace(); stream = null; } + writeHeader(); + } + if (stream != null) { try { - for (char c : "MLVLG\0".toCharArray()) { - stream.write(c); - } stream.write(0); - stream.write(1); - - - for (Sensor sensor : SensorLogger.SENSORS) { - String name = SensorLogger.getSensorName(sensor, 0); - String unit = sensor.getUnits(); - - writeLine(stream, name, 34); - writeLine(stream, unit, 11); - - stream.write(0); - stream.write(0); - stream.write(0); - stream.write(0); + stream.write(counter++); + stream.writeShort((int) (System.currentTimeMillis() * 100)); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + DataOutputStream dos = new DataOutputStream(baos); + for (Sensor sensor : sensors) { + double value = valueProvider.apply(sensor); + sensor.writeToLog(dos, value); } - stream.close(); + byte[] byteArray = baos.toByteArray(); + byte checkSum = 0; + for (int i = 0; i < byteArray.length; i++) { + checkSum += byteArray[i]; + } + stream.write(byteArray); + stream.write(checkSum); } catch (IOException e) { e.printStackTrace(); @@ -62,7 +79,89 @@ public class BinarySensorLog extends SensorLog { } } - private void writeLine(BufferedWriter stream, String name, int length) throws IOException { + private void writeHeader() { + try { + + String headerText = "\"rusEFI " + rusEFIVersion.CONSOLE_VERSION + "\"\n" + + "\"Capture Date: " + new Date() + "\"\n"; + + for (char c : "MLVLG\0".toCharArray()) { + stream.write(c); + } + + int fieldsDataSize = 0; + for (Sensor sensor : sensors) { + fieldsDataSize += sensor.getType().getStorageSize(); + } + + // 0006h Format version = 01 + stream.write(0); + stream.write(1); + // 0008h Timestamp + stream.writeInt(0); + // 000ch + int offsetToText = Fields.MLQ_HEADER_SIZE + Fields.MLQ_FIELD_HEADER_SIZE * sensors.length; + stream.writeShort(offsetToText); + stream.writeShort(0); // reserved? + // 0010h = offset_to_data + stream.writeShort(offsetToText + headerText.length()); + // 0012h + stream.writeShort(fieldsDataSize); + // 0014h number of fields + stream.writeShort(sensors.length); + + for (Sensor sensor : sensors) { + String name = SensorLogger.getSensorName(sensor, 0); + String unit = sensor.getUnits(); + + // 0000h + stream.write(getSensorTypeValue(sensor)); + // 0001h + writeLine(stream, name, 34); + // 0023h + writeLine(stream, unit, 11); + // 002Eh scale + stream.writeFloat(1); // todo: multiplier? + // 0032h zeroes + stream.writeInt(0); + // 0036h precision + stream.write(2); + } + writeLine(stream, headerText, 0); + + } catch (IOException e) { + e.printStackTrace(); + } + } + + private int getSensorTypeValue(Sensor sensor) { + switch (sensor.getType()) { + case UINT16: + return 2; + case INT16: + return 3; + case INT: + return 4; + case FLOAT: + return 7; + default: + throw new UnsupportedOperationException("" + sensor.getType()); + } + } + + public void close() { + close(stream); + } + + public static void close(Closeable closeable) { + try { + closeable.close(); + } catch (IOException e) { + // ignoring + } + } + + private void writeLine(DataOutputStream stream, String name, int length) throws IOException { for (int i = 0; i < name.length(); i++) { stream.write(name.charAt(i)); } diff --git a/java_console/ui/src/main/java/com/rusefi/sensor_logs/BinarySensorLogSandbox.java b/java_console/ui/src/main/java/com/rusefi/sensor_logs/BinarySensorLogSandbox.java new file mode 100644 index 0000000000..a27b3633f4 --- /dev/null +++ b/java_console/ui/src/main/java/com/rusefi/sensor_logs/BinarySensorLogSandbox.java @@ -0,0 +1,44 @@ +package com.rusefi.sensor_logs; + +import com.rusefi.core.Sensor; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.function.Function; + +public class BinarySensorLogSandbox { + public static void main(String[] args) { + Map values = new HashMap<>(); + + Function valueProvider = sensor -> { + Double result = values.get(sensor); + Objects.requireNonNull(result, "value for sensor"); + return result; + }; + + BinarySensorLog l = new BinarySensorLog(valueProvider, + Sensor.TIME_SECONDS, + Sensor.RPM, + Sensor.FIRMWARE_VERSION, + Sensor.CLT); + + values.put(Sensor.TIME_SECONDS, 1.0); + values.put(Sensor.RPM, 0.0); + values.put(Sensor.FIRMWARE_VERSION, 20200101.0); + values.put(Sensor.CLT, 29.0); + + l.writeSensorLogLine(); + + for (int i = 2; i < 10; i++) { + values.put(Sensor.TIME_SECONDS, (double) i); + values.put(Sensor.RPM, 180.0 + i); + values.put(Sensor.FIRMWARE_VERSION, 20200101.0); + values.put(Sensor.CLT, 39.0); + l.writeSensorLogLine(); + } + + l.close(); + + } +} diff --git a/java_console/ui/src/main/java/com/rusefi/sensor_logs/mlq_file_format.txt b/java_console/ui/src/main/java/com/rusefi/sensor_logs/mlq_file_format.txt index 2fab56fd8c..30b94d51e6 100644 --- a/java_console/ui/src/main/java/com/rusefi/sensor_logs/mlq_file_format.txt +++ b/java_console/ui/src/main/java/com/rusefi/sensor_logs/mlq_file_format.txt @@ -28,7 +28,7 @@ Field format: 0001h = name (34 bytes) 0023h = units (11 bytes) 002Eh = scale (4 bytes) = float - 0032h = zeroes (4 bytes) + 0032h = shift (4 bytes) = float, usually zero for rusEFI 0036h = precision (1 byte) 1="%.1f", 2="%.2f",... } fields[num_fields] @@ -41,5 +41,5 @@ Data format: { 0000h = "counter-ish" (4 bytes) 0004h = packed fields data (see type_and_size) - ..... = crc (1 byte) + ..... = checksum just the sum of all packed fields bytes (1 byte) } records[]