Skip to content

feat(android): assemble vehicle VIN from DashKit CAN stream (2/4) - #211

Merged
wpmed92 merged 2 commits into
mainfrom
feat/vin-pipeline
Aug 27, 2026
Merged

feat(android): assemble vehicle VIN from DashKit CAN stream (2/4)#211
wpmed92 merged 2 commits into
mainfrom
feat/vin-pipeline

Conversation

@dkneeland

Copy link
Copy Markdown
Collaborator

Part 2 of 4 of a stacked series that supersedes #201 (closed; work redistributed across this stack). Base is the GATT-subscribe-retry fix (layer 1), which this PR previously contained — extracted so the reliability fix ships independently.

What & why

Reads the vehicle VIN directly from DashKit's existing BLE CAN notification stream so Tesla enrollment can stop asking the user to type it. Purely additive — no existing behavior changes at this layer.

  • VehicleVinAssembler — pure-Kotlin assembler for the muxed VIN frames (bus 1, CAN id 0x405, mux 0x10/0x11/0x12). Accepts segments in any order, tolerates duplicates, rejects short frames / unknown mux / non-ASCII / illegal VIN chars, emits only when all 17 chars validate, resets on teardown. Raw ASCII bytes are joined directly — no 56-bit DBC Double round-trip.
  • CanPacket — raw (bus, address, data) tuple parsing extracted from parseAndEmit() so each frame feeds two consumers (dashboard decoder + assembler); firmware build_ble_packet wire format documented alongside the parser.
  • DashKitDataSource feeds the assembler per frame; exposes vinState.
  • ConnectionViewModel.vehicleVin — dedicated replaying flow; deliberately not added to CarState (stays out of the dash-app data contract); reset during connection teardown.

Inert until layer 4 consumes the flow.

Tests

Assembler unit tests (ordering, duplicates, special mux-A offsets, malformed input) and parser/data-source integration tests (single/multi-notification assembly, batching, truncated packets). Full testDebugUnitTest green at carve time against main @ b506147.

Stack & merge order

Order Layer Base
1 GATT subscribe-retry fix main
2 this PR layer 1
3 Tesla BLE core layer 2
4 VIN-driven enrollment UX layer 3

Merge bottom-up after layer 1; the managed stack handles retarget/rebase automatically.

@dkneeland

Copy link
Copy Markdown
Collaborator Author

Reworked per @wpmed92's review (force-pushed as a single commit; layers 3/4 rebased on top):

  • VIN assembly is now native.
    epo/bridge/car/vin_assembler.h\ (header-only) is driven from \VehicleDecoder::updateFrame(), so it rides the existing decode path — no special-case Kotlin, no extra pass.
  • Raw-byte reads, deliberately: VIN_B405/VIN_C405 are 56-bit, wider than double's 53-bit mantissa; the normal \Signal::getValue()\ route corrupts the top byte(s), so the assembler reads raw frame bytes and validates ASCII there.
  • Next to CarState, not inside it: CarState is a fixed \DoubleArray\ across JNI that flows to dash apps; the plan keeps the VIN out of dash-app data/persistence/logs. It's surfaced via a dedicated
    ativeGetVin() -> String?\ /
    ativeResetVin()\ JNI pair instead of packing ASCII into the numeric array.
  • No downstream churn: \DashKitDataSource.vinState\ + teardown resets unchanged; \VehicleVinState\ stays in Kotlin as the flow type; feat(android): Tesla BLE core - client, status source, VIN-matched scanner (3/4) #212/feat(android): VIN-driven Tesla enrollment UX (4/4) #213 rebased with zero code changes.
  • Coverage moved native too: Kotlin assembler tests deleted; ported into \�ridge/tests/vin_assembler_test.cpp, a host-run CMake/CTest target for non-Android builds (\cmake -B build-host && cmake --build build-host && ctest). Android build path unchanged via an \if(ANDROID)\ guard in bridge/CMakeLists.txt.

Validation: host assembler unit tests pass; decoder-integration check exercised updateFrame→assembler through the real VehicleDecoder; full :app:testDebugUnitTest\ green at every layer of the rebuilt stack.

Base automatically changed from fix/gatt-subscribe-retry to main August 27, 2026 07:51
Move VIN assembly into the C++ layer (repo/bridge/car/vin_assembler.h),
hooked into VehicleDecoder::updateFrame so it rides the existing decode
path with no extra pass. The assembler reads raw frame bytes on purpose:
VIN_B405/VIN_C405 are 56-bit signals, wider than double's 53-bit
mantissa, so the normal Signal::getValue path would silently corrupt the
top byte(s).

VIN is surfaced next to CarState rather than inside it: CarState is a
fixed DoubleArray across JNI that flows to dash apps, and the plan keeps
the VIN out of dash-app data/persistence/logs. New JNI surface:
nativeGetVin(handle) -> String? and nativeResetVin(handle); Kotlin side
exposes them via CanFrameDecoder.getVin()/resetVin(). DashKitDataSource
keeps its vinState StateFlow and teardown resets unchanged, so downstream
layers need no changes.

VehicleVinState stays in Kotlin as the flow's type; the pure-Kotlin
assembler and its tests are deleted, CanPacketVinTest now covers packet
parsing only, and host-run native unit tests cover the assembler
(dashpilot-android/bridge/tests/vin_assembler_test.cpp, wired as a
CMake/CTest target for non-Android builds).
@wpmed92
wpmed92 force-pushed the feat/vin-pipeline branch from e15060c to 87ee249 Compare August 27, 2026 07:51
@wpmed92

wpmed92 commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

@dkneeland I updated with how I suggested, but I think maybe I didn't communicate it clearly.
What I wanted is to have the vin done in car state mapper. Now our dbc parser can return raw u64, and the everything happens in the car_state layer, with vin bytes packed into doubles, then assembly in Kotlin (well, it's not much assembling really, more like just unpacking from the doubles):
This removes all of these: VinAssembler, nativeGetVin/nativeResetVin, VehicleVinState, t hevinState/vehicleVin StateFlows and all reset plumbing.

@wpmed92
wpmed92 merged commit d219ba6 into main Aug 27, 2026
2 checks passed
@wpmed92
wpmed92 deleted the feat/vin-pipeline branch August 27, 2026 09:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants