Document a full sweep validating ISO-open across all 27 firmware discs Follow-up check after shipping direct-from-ISO opening: swept every firmware ISO in this repo (27 distinct discs spanning this project's full range of eras/variants). All resolved correctly in under 0.35s each with zero exceptions, including real cases find_file()'s own docstring calls out but hadn't been exercised end-to-end before -- North-America per-variant NARBY/PROG/ paths and the older FHDD.FLI (no "6") naming. The 2 non-firmware discs in the archive correctly reported "not found" rather than crashing.
Document opening firmware directly from an ISO, no extraction
Document boot-screen cycling in the Simulator tab
Document connecting the Simulator's leaf classes to real decompiled source Real leaf class names that also happen to be one of this firmware's decompilable classes (standalone or streamed) now render as clickable buttons that jump to real decompiled source, instead of staying plain labels for everything. Narrow in practice (most leaf names aren't independently recoverable) but genuinely works on the reference firmware. Also documents a real gap this caught and fixed: a package can have both real sub-packages and real direct classes at the same level, which the drill-down previously only showed one or the other of.
Document drillable menu navigation in the Simulator tab The menu grid now descends through the real vdo/rns/app/* package tree level by level (breadcrumb + Back button) instead of stopping at one flat level, bottoming out at real leaf class names. Added a screenshot showing the drilled-in vdo/rns/app/nav view.
Document the first visual Simulator prototype (boot -> menu -> select) With Java-recovery scaling attempts exhausted for now, pivoted to the original end goal: rns510_firmware_viewer.py now has a Simulator tab assembling real recovered assets (boot screen, button icon) and real structural data (vdo/rns/app/* package names with real class counts) into an actual clickable mockup, with real screenshots as proof. Explicitly not real menu logic -- no recovered navigation bytecode behind it -- and the tab says so on-screen, not just in the wiki.
Document two scaling attempts tried and ruled out Checked all other firmware component images (RADIO.FLI, DAB.FLI, GATEWAY.FLI, SWL.FLI, MPEGAPPS.FLI, etc.) for any embedded Java -- zero in all of them, confirming the Jeode layer lives exclusively in FHDD6.FLI. Also tried tolerating a constant pool that breaks partway through (salvaging entries parsed before the break instead of requiring the whole pool clean). Looked promising at first (produces plausible -looking bytes) but real decompile attempts through CFR reveal why the strict requirement in reconstruct_class_signatures() is correct: once pool consistency breaks, surviving index values can resolve to the wrong entry type elsewhere (ClassCastException in CFR). Confirmed zero net-new real recoveries when actually tested, not just checked for whether bytes came out.
Document recovering real field/method signatures for 29 partial classes Scaled up the cutoff formula into real tooling: truncate each of the 156 distinct streamed-class names (found across all 21 firmware builds) to its intact constant pool, then mine real field/method signatures from Fieldref/Methodref entries that self-reference the class -- a common, naturally-occurring pattern -- and synthesize a minimal decompilable class carrying them (abstract methods need no real bytecode). Recovers real signatures for 29 classes, including genuinely interesting application data: VehicleClampStatusEvent's ignition clamp 15/30/50 states, real RDS radio fields in FMListEntryInfo, real touchscreen calibration data in CalibrationPoint. Clearly labeled as signatures-only (no real method bodies) wherever shown.
Find the formula: streamed-class cutoff scales with constant pool length Scanning all 21 firmware builds in this repo turned up 156 distinct real streamed-class names total (not just the original 7), 30 with enough cross-build samples to measure a reliable cutoff. Correlated each class's cutoff against several structural properties: constant-pool byte length wins clearly (r=0.985) over entry count, UTF8 byte count, or UTF8 entry count. Linear fit: cutoff ~= cp_end + 44 (slope ~1.0, r^2~0.97), with real classes scattered +-25-50 bytes around that line -- strong but not perfect; Mp3ActionEvent specifically sits much closer to cp_end+0 across all 20 of its own builds. Confirms the dominant factor is each class's own constant-pool length, not an unrelated fixed buffer size -- exactly what you'd expect if the real mechanism walks and copies the full constant pool correctly, then reliably captures only a small, roughly -fixed amount beyond it. This is now operationalized in research/firmware_java_reader.py as StreamedClassInfo.trustworthy_prefix_estimate, shown in the viewer's class list.
Settle the corruption question with 21-build cross-comparison: it's a fixed cutoff Tried to act on the LDCG/global-pool hypothesis by hunting for a specific opcode -- but comparing the same classes across all 21 independent FHDD6.FLI builds in this repo (spanning years of revisions) settled the question more directly first. BTPremiumItem.class is byte-for-byte identical across all 21 builds -- its "garbage"-looking header isn't corruption by any reasonable definition, it's perfectly reproducible. Mp3ActionEvent.class and TIPlayer$ActivationMode.class each diverge from the reference at almost the exact same byte in every build, despite wildly different total sizes per build (each class's real implementation evidently changed release to release) -- 20+ independent data points ruling out random damage. Reframes these streamed-ZIP entries from "corrupted complete classes" being chased with decreasing success to "fixed-size, per-class allocations that were only ever designed to capture a bounded prefix," with a concrete next step: look for a formula connecting each class's cutoff-in-bytes to a structural property (field/method count, constant -pool size) visible even within the truncated prefix.
Find the real mechanism: Insignia's own patented "global constant pool" Searched for public documentation of Jeode's romizer/ROM-compaction format. Found real, issued patent US7240341B2 "Global constant pool to allow deletion of constant pool entries" by Insignia Solutions (Jeode's maker, inventors Wayne Plummer and Jerry Kramskoy): common constants are moved out of each class's own pool into one shared global pool, with references rewritten to a new opcode (the patent's own example: LDC 14 -> LDCG 523) and the original local entry deleted. This gives a specific, real, citable explanation for every "out-of-range constant-pool index" anomaly found this session -- our tooling and CFR are correctly reading genuinely Jeode-specific bytecode/fields using standard-JVM-spec assumptions. The patent is architectural, not an implementation spec (no opcode byte value, no index format), so this doesn't hand over a working decoder, but reframes the open question from "mystery" to a concrete, named mechanism with a real next step.
Trace the streamed-class corruption to an upstream reconstruction failure Checked whether corruption position correlates with class size or physical firmware alignment: neither. Real content always survives the first ~100-500 decompressed bytes regardless of total class size, and offset-modulo-blocksize shows no correlation at any plausible flash alignment. The garbage itself contains real, scrambled fragments of each class's own earlier text rather than random noise -- the same repeating-fragment signature flagged before. Since this page's own ZIP/DEFLATE decoding is independently proven lossless three different ways, that artifact must predate our own compression step. Concludes the fault is upstream of the ZIP-level packaging entirely -- likely Jeode's own ROM-compaction format being imperfectly reconstructed -- which is near the practical limit of what's recoverable without its source.
Sharpen the streamed-class corruption diagnosis with a full per-class breakdown Walked the actual class-header fields (not just CFR's one reported error) for all 6 failing classes: corruption position varies per class (clean header + deeper bytecode break; clean pool + garbage header; or broken mid-pool), ruling out any single structural landmark. Also corrects an earlier guess that Mp3ActionEvent's error traced to method bytecode -- it's actually the header fields right after the constant pool. Points more toward a bug in the original per-class extraction tool than the class-file format or a simple shared-table indexing scheme.
Document recovering real UI icons and partial splash screens (8 -> 10 of 11 GIFs) Two more fixes, each targeting a different manifestation of the same localized-corruption pattern seen throughout this firmware: a falsely- claimed local color table on small UI icons (recovered a real "CANCEL" button), and genuine corruption inside the LZW codes themselves for a few full screens (recovered the real, fully-decoded leading 59-60% of rows for a previously-unseen Skoda and VW variant screen, rather than nothing at all). Includes real recovered images as proof.
Document recovering 4 more real splash screens (4/11 -> 8/11 GIFs) Several real GIFs declare a wrong color-table-size bit in their header -- the same general class of localized corruption already documented for the streamed Java classes, here hitting a GIF header field instead of string content. Fixed generically by locating the real image descriptor by content rather than trusting the declared size.
Disprove the premature-BFINAL-bit theory with a from-scratch bit-level decoder Built an instrumented raw-DEFLATE decoder independent of zlib/Inflater to go implement the BFINAL fix -- instead it shows every streamed-ZIP class entry is exactly ONE legitimately-final block, decoding 100% cleanly and in-bounds end to end. The real corruption is already inside the correctly-decompressed bytes (not a decompression bug at all), reproduces byte-for-byte across two unrelated firmware builds (5238 vs 3890 -- not storage bit-rot), and is small/localized rather than systemic. New lead: the out-of-range constant-pool indices look like leftover references into Jeode's shared/global romizer string table.
Rigorously narrow the decompression-corruption diagnosis: preset dictionary and decoder-bug hypotheses both directly ruled out, premature BFINAL bit is the best-supported remaining explanation
Document the streamed-ZIP class recovery path: real OSGi bundle mechanism, 7 validated entries, preset-dictionary hypothesis for the 6 that don't fully decompile
Update: real class/image extraction now works, with reusable tooling in the project's main repo (firmware_java_reader.py, firmware_java_decompile.py, rns510_firmware_viewer.py)
Identify the real embedded JVM: Wind River Jeode EVM (licensed from Insignia Solutions), PersonalJava/EmbeddedJava compatible
Successfully decompile 17 real Java class files from the firmware: confirms Bluetooth MDI integration, MOST FBlock interface, map perspective modes
Discover the embedded Java application layer: 2806 real classes, resolves Bluetooth/climate/parking-sensor mystery, reveals the actual UI/app architecture