feat: publish NIRO Gen5W research overview and reviewed source examples
This commit is contained in:
commit
ccad0ed9f3
23 files changed
+1279
No files matched your search
@@ -0,0 +1,96 @@
|
||||
package com.chaegeon.niro;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public final class HscanRpmDecoderTest {
|
||||
private static int assertions;
|
||||
private static final class Sink implements HscanRpmDecoder.Listener {
|
||||
final List<Integer> values = new ArrayList<Integer>();
|
||||
public void onRpm(int rpm) { values.add(rpm); }
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
Sink sink = new Sink();
|
||||
HscanRpmDecoder decoder = new HscanRpmDecoder(sink);
|
||||
byte[] zero = packet(0), rev = packet(8403);
|
||||
decoder.accept(zero, 0, zero.length);
|
||||
check(sink.values.equals(Arrays.asList(0)), "valid stopped engine");
|
||||
for (byte b : rev) decoder.accept(new byte[] {b}, 0, 1);
|
||||
check(sink.values.equals(Arrays.asList(0, 2100)), "single-byte fragmentation + stock truncation");
|
||||
byte[] burst = new byte[528];
|
||||
System.arraycopy(packet(9200), 0, burst, 0, 264);
|
||||
System.arraycopy(packet(6400), 0, burst, 264, 264);
|
||||
decoder.accept(burst, 0, burst.length);
|
||||
check(sink.values.equals(Arrays.asList(0, 2100, 2300, 1600)), "coalesced changes emitted before accept returns");
|
||||
int before = sink.values.size();
|
||||
byte[] bad = packet(4000); bad[30] ^= 1;
|
||||
decoder.accept(bad, 0, bad.length);
|
||||
check(sink.values.size() == before, "bad XOR never emitted");
|
||||
bad = packet(4000); bad[9] = 2; bad[22] = 9; checksum(bad);
|
||||
decoder.accept(bad, 0, bad.length);
|
||||
check(sink.values.size() == before, "validate entire frame before any callback");
|
||||
bad = packet(4000); bad[12] = 7; checksum(bad);
|
||||
decoder.accept(bad, 0, bad.length);
|
||||
check(sink.values.size() == before, "wrong EMS1 length");
|
||||
bad = packet(4000); bad[200] = 1; checksum(bad);
|
||||
decoder.accept(bad, 0, bad.length);
|
||||
check(sink.values.size() == before, "nonzero tail rejected");
|
||||
bad = packet(4000); bad[9] = (byte) 255; checksum(bad);
|
||||
decoder.accept(bad, 0, bad.length);
|
||||
check(sink.values.size() == before, "excess count bounded");
|
||||
bad = packet(4000); bad[11] = 0x17; checksum(bad);
|
||||
decoder.accept(bad, 0, bad.length);
|
||||
check(sink.values.size() == before, "unrelated CAN not RPM");
|
||||
bad = packet(4000); bad[2] = 0; checksum(bad);
|
||||
decoder.accept(bad, 0, bad.length);
|
||||
check(sink.values.size() == before, "other envelope not accepted");
|
||||
for (int sentinel : new int[] {65534, 65535}) {
|
||||
byte[] bytes = packet(sentinel); decoder.accept(bytes, 0, bytes.length);
|
||||
}
|
||||
check(sink.values.size() == before, "reserved raw values ignored");
|
||||
decoder.accept(new byte[] {1, 2, (byte) 255, 4, 5}, 0, 5);
|
||||
decoder.accept(rev, 0, rev.length);
|
||||
check(sink.values.size() == before + 1, "recovery after corrupt frames and garbage");
|
||||
for (int split = 1; split < 264; split++) {
|
||||
Sink s = new Sink(); HscanRpmDecoder d = new HscanRpmDecoder(s);
|
||||
d.accept(rev, 0, split);
|
||||
check(s.values.isEmpty(), "partial frame held");
|
||||
d.accept(rev, split, rev.length - split);
|
||||
check(s.values.equals(Arrays.asList(2100)), "every split decodes once");
|
||||
}
|
||||
if (args.length > 0) {
|
||||
Sink live = new Sink(); HscanRpmDecoder d = new HscanRpmDecoder(live);
|
||||
long bytes = 0;
|
||||
for (String file : args) {
|
||||
FileInputStream in = new FileInputStream(file);
|
||||
try {
|
||||
byte[] buffer = new byte[137]; int n;
|
||||
while ((n = in.read(buffer)) >= 0) { d.accept(buffer, 0, n); bytes += n; }
|
||||
} finally { in.close(); }
|
||||
}
|
||||
check(d.validFrames * 264 == bytes, "all private capture frames validated");
|
||||
check(d.rejectedFrames == 0 && d.samples > 500, "real EMS1 samples recovered");
|
||||
System.out.println("private_fixture_frames=" + d.validFrames + " rpm_samples=" + d.samples);
|
||||
}
|
||||
System.out.println("HscanRpmDecoderTest OK assertions=" + assertions);
|
||||
}
|
||||
|
||||
private static byte[] packet(int raw) {
|
||||
byte[] b = new byte[264];
|
||||
int[] header = {255, 11, 142, 1, 139, 199, 1, 0, 199, 1, 0, 22, 8};
|
||||
for (int i = 0; i < header.length; i++) b[i] = (byte) header[i];
|
||||
b[15] = (byte) raw; b[16] = (byte) (raw >> 8);
|
||||
checksum(b); return b;
|
||||
}
|
||||
|
||||
private static void checksum(byte[] b) {
|
||||
b[263] = 0;
|
||||
for (int i = 0; i < 263; i++) b[263] ^= b[i];
|
||||
}
|
||||
private static void check(boolean good, String message) {
|
||||
assertions++; if (!good) throw new AssertionError(message);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user