rusefi/java_console/ui/src/main/java/com/rusefi/sensor_logs/BinarySensorLog.java

175 lines
5.3 KiB
Java
Raw Normal View History

2020-06-13 22:15:54 -07:00
package com.rusefi.sensor_logs;
2020-07-02 17:39:10 -07:00
import com.opensr5.Logger;
2020-06-13 22:15:54 -07:00
import com.rusefi.FileLog;
2020-06-14 12:43:54 -07:00
import com.rusefi.config.generated.Fields;
import com.rusefi.core.rusEFIVersion;
2020-06-13 22:15:54 -07:00
import java.io.*;
2020-06-14 13:19:33 -07:00
import java.util.*;
2020-06-14 12:43:54 -07:00
import java.util.function.Function;
2020-06-14 13:19:33 -07:00
/**
* MLV .mlq binary log file
* </p>
* Andrey Belomutskiy, (c) 2013-2020
*/
public class BinarySensorLog<T extends BinaryLogEntry> implements SensorLog {
private final Function<T, Double> valueProvider;
private final Collection<T> entries;
private final TimeProvider timeProvider;
2020-06-14 12:43:54 -07:00
private DataOutputStream stream;
2020-06-13 22:15:54 -07:00
2020-06-14 15:47:58 -07:00
private String fileName;
2020-06-14 12:43:54 -07:00
private int counter;
public BinarySensorLog(Function<T, Double> valueProvider, Collection<T> sensors) {
this(valueProvider, sensors, System::currentTimeMillis);
}
public BinarySensorLog(Function<T, Double> valueProvider, Collection<T> sensors, TimeProvider timeProvider) {
this.valueProvider = Objects.requireNonNull(valueProvider, "valueProvider");
this.entries = Objects.requireNonNull(sensors, "entries");
this.timeProvider = timeProvider;
}
interface TimeProvider {
long currentTimestamp();
2020-06-13 22:15:54 -07:00
}
@Override
public double getSecondsSinceFileStart() {
throw new UnsupportedOperationException();
}
@Override
2020-06-14 15:47:58 -07:00
public void writeSensorLogLine() {
2020-06-13 22:15:54 -07:00
if (stream == null) {
FileLog.createFolderIfNeeded();
2022-02-12 13:16:11 -08:00
fileName = Logger.DIR + "rusEFI_gauges_" + FileLog.getDate() + ".mlg";
2020-06-13 22:15:54 -07:00
try {
2020-06-14 12:43:54 -07:00
stream = new DataOutputStream(new FileOutputStream(fileName));
2020-06-14 13:19:33 -07:00
writeHeader();
} catch (Throwable e) {
2020-06-13 22:15:54 -07:00
e.printStackTrace();
stream = null;
}
2020-06-14 12:43:54 -07:00
}
2020-06-13 22:15:54 -07:00
2020-06-14 12:43:54 -07:00
if (stream != null) {
2020-06-13 22:15:54 -07:00
try {
stream.write(0);
2020-06-14 12:43:54 -07:00
stream.write(counter++);
stream.writeShort((int) (timeProvider.currentTimestamp() * 100));
2020-06-13 22:15:54 -07:00
2020-06-14 12:43:54 -07:00
ByteArrayOutputStream baos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(baos);
2020-06-13 22:15:54 -07:00
for (T sensor : entries) {
Double value = valueProvider.apply(sensor);
if (value == null)
throw new NullPointerException("No value for " + sensor);
2020-06-14 12:43:54 -07:00
sensor.writeToLog(dos, value);
}
2020-06-13 22:15:54 -07:00
2020-06-14 12:43:54 -07:00
byte[] byteArray = baos.toByteArray();
byte checkSum = 0;
2022-02-09 22:51:48 -08:00
for (byte b : byteArray) {
checkSum += b;
2020-06-14 12:43:54 -07:00
}
stream.write(byteArray);
stream.write(checkSum);
2020-06-13 22:15:54 -07:00
2020-06-14 13:19:33 -07:00
if (counter % 20 == 0) {
// for not flush on each block of data but still flush
stream.flush();
}
2020-06-14 12:43:54 -07:00
} catch (IOException e) {
e.printStackTrace();
}
}
}
2020-06-13 22:15:54 -07:00
2020-06-14 13:19:33 -07:00
private void writeHeader() throws IOException {
String headerText = "\"rusEFI " + rusEFIVersion.CONSOLE_VERSION + "\"\n" +
"\"Capture Date: " + new Date() + "\"\n";
2020-06-13 22:15:54 -07:00
2020-06-14 13:19:33 -07:00
for (char c : "MLVLG\0".toCharArray()) {
stream.write(c);
}
2020-06-13 22:15:54 -07:00
2020-06-14 13:19:33 -07:00
int fieldsDataSize = 0;
for (BinaryLogEntry entry : entries) {
fieldsDataSize += entry.getByteSize();
2020-06-14 13:19:33 -07:00
}
2020-06-14 12:43:54 -07:00
2020-06-14 13:19:33 -07:00
// 0006h Format version = 01
stream.write(0);
stream.write(1);
// 0008h Timestamp
stream.writeInt((int) (System.currentTimeMillis() / 1000));
2020-06-14 13:19:33 -07:00
// 000ch
int offsetToText = Fields.MLQ_HEADER_SIZE + Fields.MLQ_FIELD_HEADER_SIZE * entries.size();
2020-06-14 13:19:33 -07:00
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(entries.size());
2020-06-14 13:19:33 -07:00
for (BinaryLogEntry sensor : entries) {
String name = sensor.getName();
String unit = sensor.getUnit();
2020-06-14 13:19:33 -07:00
// 0000h
stream.write(sensor.getByteSize());
2020-06-14 13:19:33 -07:00
// 0001h
writeLine(stream, name, 34);
// 0023h
writeLine(stream, unit, 11);
// 002Eh scale
stream.writeFloat(1); // todo: multiplier?
// 0032h zeroes
2020-06-14 12:43:54 -07:00
stream.writeInt(0);
2020-06-14 13:19:33 -07:00
// 0036h precision
stream.write(2);
2020-06-14 12:43:54 -07:00
}
if (stream.size() != offsetToText)
throw new IllegalStateException("We are doing something wrong :( stream.size=" + stream.size());
writeLine(stream, headerText, headerText.length());
2020-06-14 12:43:54 -07:00
}
2020-06-14 13:19:33 -07:00
@Override
2020-06-14 12:43:54 -07:00
public void close() {
close(stream);
2020-06-14 13:19:33 -07:00
stream = null;
2020-06-14 12:43:54 -07:00
}
public static void close(Closeable closeable) {
try {
if (closeable != null) {
closeable.close();
}
2020-06-14 12:43:54 -07:00
} catch (IOException e) {
// ignoring
2020-06-13 22:15:54 -07:00
}
}
2020-06-14 15:47:58 -07:00
public String getFileName() {
return fileName;
}
2020-06-14 12:43:54 -07:00
private void writeLine(DataOutputStream stream, String name, int length) throws IOException {
for (int i = 0; i < Math.min(name.length(), length); i++) {
2020-06-13 22:15:54 -07:00
stream.write(name.charAt(i));
}
for (int i = name.length(); i < length; i++)
stream.write(0);
}
}