diff --git a/java_console/inifile/src/com/rusefi/config/Field.java b/java_console/inifile/src/com/rusefi/config/Field.java index 71aced1d0f..881d5d229a 100644 --- a/java_console/inifile/src/com/rusefi/config/Field.java +++ b/java_console/inifile/src/com/rusefi/config/Field.java @@ -146,13 +146,13 @@ public class Field { */ @NotNull @Deprecated - public Number getValue(ConfigurationImage ci) { + public Double getValue(ConfigurationImage ci) { return getValue(ci, 1); } // todo: rename to getNumberValue? @NotNull - public Number getValue(ConfigurationImage ci, double multiplier) { + public Double getValue(ConfigurationImage ci, double multiplier) { Objects.requireNonNull(ci); Number value; ByteBuffer wrapped = ci.getByteBuffer(getOffset(), type.getStorageSize()); diff --git a/java_console/models/src/com/rusefi/core/Sensor.java b/java_console/models/src/com/rusefi/core/Sensor.java index d6183ad306..926e91f42a 100644 --- a/java_console/models/src/com/rusefi/core/Sensor.java +++ b/java_console/models/src/com/rusefi/core/Sensor.java @@ -239,6 +239,10 @@ public enum Sensor { public void writeToLog(DataOutputStream dos, double value) throws IOException { switch (type) { + case INT8: + case UINT8: + dos.write((int) value); + return; case FLOAT: dos.writeFloat((float) value); return; diff --git a/java_console/ui/src/main/java/com/rusefi/ConsoleUI.java b/java_console/ui/src/main/java/com/rusefi/ConsoleUI.java index bb320edc8d..43cf3ce46e 100644 --- a/java_console/ui/src/main/java/com/rusefi/ConsoleUI.java +++ b/java_console/ui/src/main/java/com/rusefi/ConsoleUI.java @@ -10,6 +10,7 @@ import com.rusefi.io.LinkManager; import com.rusefi.io.serial.BaudRateHolder; import com.rusefi.maintenance.FirmwareFlasher; import com.rusefi.maintenance.VersionChecker; +import com.rusefi.sensor_logs.SensorLogger; import com.rusefi.ui.*; import com.rusefi.ui.console.MainFrame; import com.rusefi.ui.console.TabbedPanel; @@ -135,6 +136,7 @@ public class ConsoleUI { tabbedPane.addTab("rusEFI Online", new OnlineTab().getContent()); + SensorLogger.init(); if (!LinkManager.isLogViewerMode(port)) { int selectedIndex = getConfig().getRoot().getIntProperty(TAB_INDEX, DEFAULT_TAB_INDEX); 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 30c45f6fdb..7ff7821272 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,34 +1,46 @@ package com.rusefi.sensor_logs; import com.rusefi.FileLog; +import com.rusefi.config.FieldType; 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.*; import java.util.function.Function; +import java.util.function.Predicate; +import java.util.stream.Collectors; +/** + * MLV .mlq binary log file + *

+ * Andrey Belomutskiy, (c) 2013-2020 + */ public class BinarySensorLog extends SensorLog { private final Function valueProvider; - private final Sensor[] sensors; + private final Collection sensors; private DataOutputStream stream; private int counter; public BinarySensorLog() { - this(new Function() { - @Override - public Double apply(Sensor sensor) { - return SensorCentral.getInstance().getValue(sensor); - } - }, SensorLogger.SENSORS); + this(sensor -> SensorCentral.getInstance().getValue(sensor), SensorLogger.SENSORS); } public BinarySensorLog(Function valueProvider, Sensor... sensors) { this.valueProvider = valueProvider; - this.sensors = sensors; + this.sensors = filterOutSensorsWithoutType(Objects.requireNonNull(sensors, "sensors")); + } + + private Collection filterOutSensorsWithoutType(Sensor[] sensors) { + return Arrays.stream(sensors).filter(new Predicate() { + @Override + public boolean test(Sensor sensor) { + return sensor.getType() != null; + } + }).collect(Collectors.toCollection(ArrayList::new)); } @Override @@ -44,11 +56,11 @@ public class BinarySensorLog extends SensorLog { try { stream = new DataOutputStream(new FileOutputStream(fileName)); - } catch (IOException e) { + writeHeader(); + } catch (Throwable e) { e.printStackTrace(); stream = null; } - writeHeader(); } if (stream != null) { @@ -73,69 +85,76 @@ public class BinarySensorLog extends SensorLog { stream.write(byteArray); stream.write(checkSum); + if (counter % 20 == 0) { + // for not flush on each block of data but still flush + stream.flush(); + } + } catch (IOException e) { e.printStackTrace(); } } } - private void writeHeader() { - try { + private void writeHeader() throws IOException { + String headerText = "\"rusEFI " + rusEFIVersion.CONSOLE_VERSION + "\"\n" + + "\"Capture Date: " + new Date() + "\"\n"; - 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(); + for (char c : "MLVLG\0".toCharArray()) { + stream.write(c); } + + int fieldsDataSize = 0; + for (Sensor sensor : sensors) { + FieldType type = sensor.getType(); + if (type == null) + throw new NullPointerException("No type for " + sensor); + fieldsDataSize += type.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.size(); + 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.size()); + + 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); + } private int getSensorTypeValue(Sensor sensor) { switch (sensor.getType()) { + case UINT8: + return 0; + case INT8: + return 1; case UINT16: return 2; case INT16: @@ -149,8 +168,10 @@ public class BinarySensorLog extends SensorLog { } } + @Override public void close() { close(stream); + stream = null; } public static void close(Closeable closeable) { 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 index a27b3633f4..5510c28e65 100644 --- 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 @@ -20,11 +20,13 @@ public class BinarySensorLogSandbox { BinarySensorLog l = new BinarySensorLog(valueProvider, Sensor.TIME_SECONDS, Sensor.RPM, + Sensor.VSS, Sensor.FIRMWARE_VERSION, Sensor.CLT); values.put(Sensor.TIME_SECONDS, 1.0); values.put(Sensor.RPM, 0.0); + values.put(Sensor.VSS, 60.0); values.put(Sensor.FIRMWARE_VERSION, 20200101.0); values.put(Sensor.CLT, 29.0); @@ -39,6 +41,5 @@ public class BinarySensorLogSandbox { } l.close(); - } } diff --git a/java_console/ui/src/main/java/com/rusefi/sensor_logs/PlainTextSensorLog.java b/java_console/ui/src/main/java/com/rusefi/sensor_logs/PlainTextSensorLog.java index 7c287bc1d2..090d6596fe 100644 --- a/java_console/ui/src/main/java/com/rusefi/sensor_logs/PlainTextSensorLog.java +++ b/java_console/ui/src/main/java/com/rusefi/sensor_logs/PlainTextSensorLog.java @@ -14,13 +14,17 @@ import java.io.FileWriter; import java.io.IOException; import java.io.Writer; +/** + * Legacy human readable CSV log file + *

+ * Andrey Belomutskiy, (c) 2013-2020 + */ public class PlainTextSensorLog extends SensorLog { private Writer logFile; private long fileStartTime; - - public void startIfNeeded() { + private void startIfNeeded() { if (logFile == null) { /* * we only start file header once we have first bunch of data @@ -75,7 +79,6 @@ public class PlainTextSensorLog extends SensorLog { return msSinceFileStart / 1000.0; } - @Override void writeSensorLogLine() { startIfNeeded(); @@ -94,5 +97,11 @@ public class PlainTextSensorLog extends SensorLog { logFile = null; } } + + @Override + public void close() { + BinarySensorLog.close(logFile); + logFile = null; + } } diff --git a/java_console/ui/src/main/java/com/rusefi/sensor_logs/SensorLog.java b/java_console/ui/src/main/java/com/rusefi/sensor_logs/SensorLog.java index 836d96b565..9650cdaff1 100644 --- a/java_console/ui/src/main/java/com/rusefi/sensor_logs/SensorLog.java +++ b/java_console/ui/src/main/java/com/rusefi/sensor_logs/SensorLog.java @@ -4,4 +4,6 @@ public abstract class SensorLog { public abstract double getSecondsSinceFileStart(); abstract void writeSensorLogLine(); + + public abstract void close(); } diff --git a/java_console/ui/src/main/java/com/rusefi/sensor_logs/SensorLogger.java b/java_console/ui/src/main/java/com/rusefi/sensor_logs/SensorLogger.java index a1eadb6af5..cb9d72c5eb 100644 --- a/java_console/ui/src/main/java/com/rusefi/sensor_logs/SensorLogger.java +++ b/java_console/ui/src/main/java/com/rusefi/sensor_logs/SensorLogger.java @@ -5,13 +5,14 @@ import com.rusefi.core.SensorCentral; import com.rusefi.io.ConnectionStatusLogic; import com.rusefi.io.ConnectionStatusValue; +import java.util.Arrays; +import java.util.List; + /** * Andrey Belomutskiy, (c) 2013-2020 * 4/15/2016. */ public class SensorLogger { - private static SensorLog sensorLog = new PlainTextSensorLog(); - protected static Sensor[] SENSORS = {Sensor.RPM, Sensor.INT_TEMP, @@ -79,6 +80,10 @@ public class SensorLogger { Sensor.tuneCrc16, }; + private static List sensorLogs = Arrays.asList(new PlainTextSensorLog(), new BinarySensorLog()); + + private static boolean isInitialized; + private SensorLogger() { } @@ -86,19 +91,24 @@ public class SensorLogger { init(); } - private static void init() { + public synchronized static void init() { + if (isInitialized) { + return; + } + isInitialized = true; SensorCentral.getInstance().addListener(Sensor.TIME_SECONDS, new SensorCentral.SensorListener() { @Override public void onSensorUpdate(double value) { if (ConnectionStatusLogic.INSTANCE.getValue() != ConnectionStatusValue.CONNECTED) return; - sensorLog.writeSensorLogLine(); + for (SensorLog sensorLog : sensorLogs) + sensorLog.writeSensorLogLine(); } }); } public static double getSecondsSinceFileStart() { - return sensorLog.getSecondsSinceFileStart(); + return sensorLogs.get(0).getSecondsSinceFileStart(); } static String getSensorName(Sensor sensor, int debugMode) { diff --git a/java_console/ui/src/main/java/com/rusefi/ui/FormulasPane.java b/java_console/ui/src/main/java/com/rusefi/ui/FormulasPane.java index 1f1e28d672..cfbf7b74e4 100644 --- a/java_console/ui/src/main/java/com/rusefi/ui/FormulasPane.java +++ b/java_console/ui/src/main/java/com/rusefi/ui/FormulasPane.java @@ -210,7 +210,7 @@ public class FormulasPane { double displacement = ConfigField.getFloatValue(ci, Fields.DISPLACEMENT); int cylinderCount = ConfigField.getIntValue(ci, Fields.CYLINDERSCOUNT); String cylinderDisplacement = oneDecimal(displacement / cylinderCount); - String injectorFlow = oneDecimal((float) Fields.INJECTOR_FLOW.getValue(ci)); + String injectorFlow = oneDecimal((float) Fields.INJECTOR_FLOW.getValue(ci).doubleValue()); String tCharge = "$Tcharge=f(CLT=" + oneDecimal(Sensor.CLT) + "C,IAT=" + IAT + "C,TPS=" + tpsStr + "\\%, RPM = " + RPM + ")=" + T_CHARGE + "C$"; diff --git a/java_console/ui/src/main/java/com/rusefi/ui/light/LightweightGUI.java b/java_console/ui/src/main/java/com/rusefi/ui/light/LightweightGUI.java index b8a055b881..739ad2d7bb 100644 --- a/java_console/ui/src/main/java/com/rusefi/ui/light/LightweightGUI.java +++ b/java_console/ui/src/main/java/com/rusefi/ui/light/LightweightGUI.java @@ -6,6 +6,7 @@ import com.rusefi.io.ConnectionStateListener; import com.rusefi.io.ConnectionStatusLogic; import com.rusefi.io.ConnectionWatchdog; import com.rusefi.io.LinkManager; +import com.rusefi.sensor_logs.SensorLogger; import com.rusefi.ui.util.FrameHelper; import javax.swing.*; @@ -54,6 +55,7 @@ public class LightweightGUI { ConnectionStatusLogic.INSTANCE.addListener(new ConnectionStatusLogic.Listener() { @Override public void onConnectionStatus(boolean isConnected) { + SensorLogger.init(); SwingUtilities.invokeLater(new Runnable() { @Override public void run() { diff --git a/java_console/ui/src/main/java/com/rusefi/ui/livedocs/LiveDocPanel.java b/java_console/ui/src/main/java/com/rusefi/ui/livedocs/LiveDocPanel.java index ac8dcd2572..4900880231 100644 --- a/java_console/ui/src/main/java/com/rusefi/ui/livedocs/LiveDocPanel.java +++ b/java_console/ui/src/main/java/com/rusefi/ui/livedocs/LiveDocPanel.java @@ -193,7 +193,7 @@ public class LiveDocPanel { combined.put(context, new RefreshActions() { @Override public void refresh(BinaryProtocol bp, byte[] response) { - int value = (int) conditionField.getValue(new ConfigurationImage(response)); + int value = (int) conditionField.getValue(new ConfigurationImage(response)).intValue(); conditionLabel.setText(request.getField() + " is " + (value == 1 ? "TRUE" : "FALSE")); JPanel active; JPanel passive;