2022-11-12 09:29:20 -08:00
|
|
|
package com.rusefi.can.analysis;
|
2022-11-10 15:12:02 -08:00
|
|
|
|
2022-11-12 09:29:20 -08:00
|
|
|
import com.rusefi.can.CANPacket;
|
2022-11-10 15:12:02 -08:00
|
|
|
|
2022-11-12 20:00:51 -08:00
|
|
|
import java.io.*;
|
2022-11-10 15:12:02 -08:00
|
|
|
import java.util.*;
|
|
|
|
|
|
|
|
public class ByteRateOfChange {
|
|
|
|
|
2022-11-12 18:12:54 -08:00
|
|
|
static class TraceFileMetaIndex {
|
2023-07-30 16:52:39 -07:00
|
|
|
final HashMap<ByteId, ByteStatistics> statistics = new HashMap<>();
|
2022-11-10 15:12:02 -08:00
|
|
|
|
2023-07-30 16:52:39 -07:00
|
|
|
final Set<Integer> SIDs = new HashSet<>();
|
2022-11-12 18:12:54 -08:00
|
|
|
}
|
2022-11-12 10:07:13 -08:00
|
|
|
|
2022-11-12 18:12:54 -08:00
|
|
|
public static TraceReport process(String reportDestinationFolder, String simpleFileName, List<CANPacket> packets) throws IOException {
|
|
|
|
TraceFileMetaIndex traceFileMetaIndex = calculateByteStatistics(packets);
|
|
|
|
|
2022-11-12 20:00:51 -08:00
|
|
|
writeByteReport(reportDestinationFolder, simpleFileName, traceFileMetaIndex);
|
|
|
|
|
2023-07-30 21:01:10 -07:00
|
|
|
return new TraceReport(packets, simpleFileName, traceFileMetaIndex.statistics);
|
2022-11-12 20:00:51 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
private static void writeByteReport(String reportDestinationFolder, String simpleFileName, TraceFileMetaIndex traceFileMetaIndex) throws FileNotFoundException {
|
2023-10-06 18:17:18 -07:00
|
|
|
String byteChangesFolder = reportDestinationFolder + File.separator + "byte_changes";
|
|
|
|
new File(byteChangesFolder).mkdirs();
|
|
|
|
|
2022-11-12 18:12:54 -08:00
|
|
|
List<ByteStatistics> allStats = new ArrayList<>(traceFileMetaIndex.statistics.values());
|
2023-10-06 18:17:18 -07:00
|
|
|
allStats.sort((o1, o2) -> o2.getUniqueValuesCount() - o1.getUniqueValuesCount());
|
2022-11-10 15:12:02 -08:00
|
|
|
|
2023-10-06 18:17:18 -07:00
|
|
|
writeByteReport(allStats, byteChangesFolder + File.separator + simpleFileName + "byte_rate_of_changes_sorted_counter.txt");
|
2022-11-10 15:12:02 -08:00
|
|
|
|
2023-10-06 18:17:18 -07:00
|
|
|
allStats.sort(new Comparator<ByteStatistics>() {
|
|
|
|
@Override
|
|
|
|
public int compare(ByteStatistics o1, ByteStatistics o2) {
|
|
|
|
return o1.key.compareTo(o2.key);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
writeByteReport(allStats, byteChangesFolder + File.separator + simpleFileName + "byte_rate_of_changes_sorted_index.txt");
|
2022-11-12 20:00:51 -08:00
|
|
|
}
|
|
|
|
|
2023-10-06 18:17:18 -07:00
|
|
|
private static void writeByteReport(List<ByteStatistics> allStats, String fileName) throws FileNotFoundException {
|
|
|
|
System.out.println("Writing byte report to " + fileName);
|
|
|
|
PrintStream ps = new PrintStream(new FileOutputStream(fileName, false));
|
2022-11-10 15:12:02 -08:00
|
|
|
|
|
|
|
for (ByteStatistics byteStatistics : allStats) {
|
|
|
|
ByteId key = byteStatistics.key;
|
2023-10-22 20:13:55 -07:00
|
|
|
ps.println(dualSid(key.sid) + " byte " + key.getByteIndex() + " has " + byteStatistics.getUniqueValuesCount() + " unique value(s)");
|
2022-11-10 15:12:02 -08:00
|
|
|
}
|
|
|
|
|
2022-11-10 16:23:51 -08:00
|
|
|
ps.close();
|
2022-11-10 15:12:02 -08:00
|
|
|
}
|
|
|
|
|
2022-11-12 18:12:54 -08:00
|
|
|
private static TraceFileMetaIndex calculateByteStatistics(List<CANPacket> packets) {
|
|
|
|
TraceFileMetaIndex traceFileMetaIndex = new TraceFileMetaIndex();
|
|
|
|
|
|
|
|
for (CANPacket packet : packets) {
|
|
|
|
traceFileMetaIndex.SIDs.add(packet.getId());
|
2022-11-12 20:00:51 -08:00
|
|
|
for (int byteIndex = 0; byteIndex < packet.getData().length; byteIndex++) {
|
|
|
|
ByteId key = new ByteId(packet.getId(), byteIndex);
|
2022-11-12 18:12:54 -08:00
|
|
|
ByteStatistics stats = traceFileMetaIndex.statistics.computeIfAbsent(key, byteId -> new ByteStatistics(key));
|
2023-10-22 20:37:22 -07:00
|
|
|
stats.registerValue(packet.getData()[byteIndex]);
|
2022-11-12 18:12:54 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return traceFileMetaIndex;
|
|
|
|
}
|
|
|
|
|
|
|
|
private static double getDurationMs(List<CANPacket> packets) {
|
|
|
|
return packets.isEmpty() ? 0 : packets.get(packets.size() - 1).getTimeStamp() - packets.get(0).getTimeStamp();
|
|
|
|
}
|
|
|
|
|
2022-11-10 15:12:02 -08:00
|
|
|
public static String dualSid(int sid) {
|
2022-11-12 10:39:32 -08:00
|
|
|
return dualSid(sid, "/");
|
|
|
|
}
|
|
|
|
|
|
|
|
public static String dualSid(int sid, String separator) {
|
|
|
|
return String.format("%d%s0x%x", sid, separator, sid);
|
2022-11-10 15:12:02 -08:00
|
|
|
}
|
|
|
|
|
2022-11-12 09:29:20 -08:00
|
|
|
public static class ByteStatistics {
|
2023-10-22 20:37:22 -07:00
|
|
|
private final HashSet<Integer> uniqueValues = new HashSet<>();
|
|
|
|
int totalTransitions;
|
2022-11-10 15:12:02 -08:00
|
|
|
private final ByteId key;
|
|
|
|
|
2023-10-22 20:37:22 -07:00
|
|
|
private int previousValue;
|
|
|
|
|
2022-11-10 15:12:02 -08:00
|
|
|
public ByteStatistics(ByteId key) {
|
|
|
|
this.key = key;
|
|
|
|
}
|
|
|
|
|
2023-10-06 18:17:18 -07:00
|
|
|
public int getUniqueValuesCount() {
|
2022-11-10 15:12:02 -08:00
|
|
|
return uniqueValues.size();
|
|
|
|
}
|
|
|
|
|
2023-10-06 18:17:18 -07:00
|
|
|
public ByteId getKey() {
|
|
|
|
return key;
|
|
|
|
}
|
|
|
|
|
2022-11-10 15:12:02 -08:00
|
|
|
@Override
|
|
|
|
public String toString() {
|
|
|
|
return "ByteStatistics{" +
|
|
|
|
"counter=" + uniqueValues.size() +
|
|
|
|
", key=" + key +
|
|
|
|
'}';
|
|
|
|
}
|
2023-10-22 20:37:22 -07:00
|
|
|
|
|
|
|
public void registerValue(int value) {
|
|
|
|
if (!uniqueValues.isEmpty()) {
|
|
|
|
if (previousValue != value)
|
|
|
|
totalTransitions++;
|
|
|
|
}
|
|
|
|
|
|
|
|
previousValue = value;
|
|
|
|
uniqueValues.add(value);
|
|
|
|
}
|
2022-11-10 15:12:02 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-07-30 21:01:10 -07:00
|
|
|
public static class ByteId implements Comparable<ByteId> {
|
2022-11-10 15:12:02 -08:00
|
|
|
final int sid;
|
2023-10-22 20:13:55 -07:00
|
|
|
final int byteIndex;
|
2022-11-10 15:12:02 -08:00
|
|
|
|
2023-10-22 20:13:55 -07:00
|
|
|
public ByteId(int sid, int byteIndex) {
|
2022-11-10 15:12:02 -08:00
|
|
|
this.sid = sid;
|
2023-10-22 20:13:55 -07:00
|
|
|
this.byteIndex = byteIndex;
|
2022-11-10 15:12:02 -08:00
|
|
|
}
|
|
|
|
|
2023-01-11 13:20:44 -08:00
|
|
|
public String getLogKey() {
|
2023-10-22 20:13:55 -07:00
|
|
|
return dualSid(sid) + "_byte_" + byteIndex + "_bit_" + (byteIndex * 8);
|
2022-11-11 22:53:31 -08:00
|
|
|
}
|
|
|
|
|
2022-11-10 15:12:02 -08:00
|
|
|
@Override
|
|
|
|
public boolean equals(Object o) {
|
|
|
|
if (this == o) return true;
|
|
|
|
if (o == null || getClass() != o.getClass()) return false;
|
|
|
|
ByteId byteId = (ByteId) o;
|
2023-10-22 20:13:55 -07:00
|
|
|
return sid == byteId.sid && byteIndex == byteId.byteIndex;
|
|
|
|
}
|
|
|
|
|
|
|
|
public int getByteIndex() {
|
|
|
|
return byteIndex;
|
2022-11-10 15:12:02 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public int hashCode() {
|
2023-10-22 20:13:55 -07:00
|
|
|
return Objects.hash(sid, byteIndex);
|
2022-11-10 15:12:02 -08:00
|
|
|
}
|
|
|
|
|
2023-01-01 23:08:45 -08:00
|
|
|
@Override
|
2023-07-30 21:01:10 -07:00
|
|
|
public int compareTo(ByteId o) {
|
2023-10-21 20:07:51 -07:00
|
|
|
ByteId other = o;
|
2023-01-01 23:08:45 -08:00
|
|
|
if (other.sid != sid)
|
|
|
|
return sid - other.sid;
|
2023-10-22 20:13:55 -07:00
|
|
|
return byteIndex - other.byteIndex;
|
2023-01-01 23:08:45 -08:00
|
|
|
}
|
|
|
|
|
2022-11-10 15:12:02 -08:00
|
|
|
@Override
|
|
|
|
public String toString() {
|
2022-11-11 23:12:28 -08:00
|
|
|
return getLogKey();
|
2022-11-10 15:12:02 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-11-10 16:23:51 -08:00
|
|
|
public static class TraceReport extends HashMap<ByteId, ByteStatistics> {
|
2022-11-12 18:12:54 -08:00
|
|
|
private final List<CANPacket> packets;
|
2022-11-10 16:23:51 -08:00
|
|
|
private final String simpleFileName;
|
|
|
|
private final HashMap<ByteId, ByteStatistics> statistics;
|
2022-11-12 10:07:13 -08:00
|
|
|
private final double durationMs;
|
2022-11-10 16:23:51 -08:00
|
|
|
|
2022-11-12 18:12:54 -08:00
|
|
|
public TraceReport(List<CANPacket> packets, String simpleFileName, HashMap<ByteId, ByteStatistics> statistics) {
|
|
|
|
this.packets = packets;
|
2022-11-10 16:23:51 -08:00
|
|
|
this.simpleFileName = simpleFileName;
|
|
|
|
this.statistics = statistics;
|
2022-11-12 18:12:54 -08:00
|
|
|
this.durationMs = getDurationMs(packets);
|
2022-11-12 09:29:20 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
String getSummary() {
|
2022-11-12 20:00:51 -08:00
|
|
|
return getSimpleFileName() + " (duration=" + (int) (durationMs / 1000) + "secs)";
|
2022-11-10 16:23:51 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
public String getSimpleFileName() {
|
|
|
|
return simpleFileName;
|
|
|
|
}
|
|
|
|
|
|
|
|
public HashMap<ByteId, ByteStatistics> getStatistics() {
|
|
|
|
return statistics;
|
|
|
|
}
|
2022-11-10 20:38:46 -08:00
|
|
|
|
2023-01-01 23:08:45 -08:00
|
|
|
}
|
|
|
|
}
|