feat: publish NIRO Gen5W research overview and reviewed source examples

This commit is contained in:
seo committed 2026-11-02 09:59:38 +09:00
commit ccad0ed9f3
23 files changed
+1279

No files matched your search

+96
View File
@@ -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);
}
}