Skip to content

fix(can): auto-recover wedged mcp2515 RX path via hardware-confirmed stall watchdog#1459

Closed
slothish wants to merge 133 commits into
openvehicles:masterfrom
slothish:fix/mcp2515-rx-stall
Closed

fix(can): auto-recover wedged mcp2515 RX path via hardware-confirmed stall watchdog#1459
slothish wants to merge 133 commits into
openvehicles:masterfrom
slothish:fix/mcp2515-rx-stall

Conversation

@slothish

Copy link
Copy Markdown

Caught this live on my e-Golf: can3 (mcp2515) RX froze mid-drive — Rx pkt and interrupt counters stuck, CANINTF "RX buffer 0 full" latched, Rx err/ovrflw all zero. The existing inactivity watchdog never fires in this state since it only runs while the vehicle is on, so the bus needed a manual can can3 stop/start to come back. Happened twice in one day under normal KCAN load (~1.3k fps).

This adds a hardware-confirmed RX-stall watchdog to BusTicker10:

  • fires only when the bus is started (Active/Listen), packets_rx has been frozen for CAN_RXSTALL_THRESHOLD (20s), AND the driver confirms unserviced RX pending via a new virtual CheckRxStalled() — mcp2515 implements it as a live CANINTF read (RX0IF|RX1IF). Base class returns false so esp32can is untouched.
  • pure RX silence never triggers it — a sleeping bus (car off, DC charging) has no CANINTF RX bits set, so no false resets. The SPI readback only happens in the slow path after 20s of frozen counter, nothing added to the hot path.
  • recovery is Reset(), counted in a new rxstall_resets status field ("Wedge Rsts" in can status), one ESP_LOGE per event.

On-car validation: with this firmware the watchdog caught and auto-recovered 2 wedges in one drive session (Wedge Rsts: 2), which also pinned the root cause — RX pending in CANINTF with zero ISR entries, i.e. the INT edge got lost. I'm submitting the root-cause fix (level-triggered INT) as a separate PR on top of this one; this watchdog stays useful as the regression detector for it.

Heads up per my usual disclosure: developed with AI assistance, validated against the real car (counters and logs above).

Andreas and others added 30 commits May 11, 2026 21:20
- CLAUDE.md: build system, architecture, framework patterns, maintainer
  code review rules, BAP protocol note, e-Golf KCAN capabilities
- vw-bap-protocol.md: full BAP frame encoding reference derived from
  norly/revag-bap reverse engineering work
- Include upstream developer guide markdown for offline reference

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Documents the build-flash-verify loop, CAN log capture/replay for
desk testing without the car, verbose logging, single-frame injection,
metric verification, canbitset usage, and branch strategy.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- tests/mock/mock_ovms.hpp: stubs for all OVMS/ESP32/FreeRTOS types
  needed to compile vehicle_vwegolf.cpp with g++ on a Linux/Mac laptop
- tests/mock/mock_ovms.cpp: global singleton definitions
- tests/mock/*.h: stub headers that shadow the real OVMS headers
- tests/test_can_decode.cpp: tests for SoC, speed, gear, VIN decoding
- tests/Makefile: 'make test' builds and runs everything natively

Running 'make test' in the tests/ directory compiles and runs the actual
vehicle module C++ code without any ESP32 hardware or OVMS framework.
New decode paths should have a test here before being flashed to the car.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Module is tucked under the dash so SD card is inaccessible.
OVMS runs its own AP at 192.168.4.1 — laptop connects directly,
no iOS hotspot client isolation issues. CAN frames stream via
'can log start tcpserver' to nc on the laptop. Flash via Python
HTTP server + 'ota flash http'.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds test_crtd_replay.cpp which parses a CRTD log file, replays all
frames through IncomingFrameCan3, and asserts that speed, SoC, and gear
metrics contain plausible values.  Confirms the full pipeline works
end-to-end with 44k+ real frames from the car.

Adds candumps/ directory with .gitignore (captures excluded — they
contain VINs) and a README documenting how to create a capture and
run the test.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
scripts/setup-toolchain.sh: one-time setup of the Xtensa toolchain
binary, OVMS ESP-IDF fork (v3.3), and a Python venv. Prints env
exports to activate for the current session or shell profile.

scripts/build.sh: wraps the firmware make, initialises sdkconfig from
the hw31 default if missing, and optionally serves the binary via HTTP
for OTA flashing over the OVMS hotspot.

Updates CLAUDE.md Build System section with the full workflow using
these scripts instead of manual environment setup.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
scripts/hooks/pre-push: blocks pushes on fix/* and feat/* branches
unless the native test suite passes. investigation and master push
freely. Bypassed with git push --no-verify if genuinely needed.

scripts/install-hooks.sh: copies hooks from scripts/hooks/ into
.git/hooks/ — run once after cloning.

scripts/build.sh: now runs the test suite before compiling firmware.
Build is aborted if any test fails.

CLAUDE.md: rewrites the Iterative Development Workflow section to
document the full pipeline — toolchain setup, hook install, build,
OTA deploy — in the order a new developer would follow it.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
0x66E broadcasts 0xFE as a no-data sentinel before valid data is
available, which decodes to 77°C and persists across reboots.
Skip the metric update on sentinel, and clear the metric in the
constructor to evict any persisted wrong value.

Investigation showed 0x66E does not broadcast on KCAN while the
car is off or during standstill clima — cabin temp appears to be
available only via BAP, not as a plain CAN frame.

Also fix CRTD replay test to route frames by bus number (1/2/3)
rather than hardcoding bus 3, and dispatch bus-2 frames to both
IncomingFrameCan2 and IncomingFrameCan3 to model J533 gateway
bridging of KCAN onto Powertrain CAN.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add *.crtd to .gitignore — CAN log captures are large (8 MB+) and
  belong on the local machine, not in the repo
- Add TODO-clima-capture.md with planned capture sequence and BAP port
  analysis notes for the climate control RE effort
- Update scripts/build.sh with a post-flash credential reminder
- Commit rebuilt tests/test binary

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
From kcan-can3-clima_range.crtd (full LO→HI dial sweep):
- Confirmed temperature setpoint encoding on 0x17330110 BAP node 0x01 port 0x1B/0x21
- Formula: raw = (temp_C - 10) * 10  (tenths-of-°C above 10°C base)
- LO = 0x3C (16.0°C), HI = 0xFF sentinel, 20°C = 0x64
- Sweep confirmed step-by-step at 0.5°C increments, zero gaps

From kcan-can3-clima_schedule.crtd (e-Manager departure schedule 17:00/16:50):
- Confirmed node 0x25 port 0x16 format: FF FF FF [temp_C] [duration_min] FE 02 00
- Identified command channel: 0x17332501 (SetGet to node 0x25)
- Schedule timer data lives in node 0x25 port 0x12
- No write commands to clima ECU visible in passive capture → Capture 4 needed

Updated TODO with full findings and a concrete plan for Capture 4 (active injection test).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ence

Cross-referenced thomasakarlsen's e-golf-comfort-can captures against our
own KCAN traces. Documents:
- Correct CAN ID (0x17332501), BAP node 0x25, port map
- 3-frame start sequence: port 0x19 params + continuation + port 0x18 trigger
- Why injection attempt 1 failed (node 0x26→0x25, wrong port, missing continuation)
- Schedule slot temperature encoding confirmed: byte = celsius + 35
- Port 0x19 Ack structure confirmed from schedule capture
- Outstanding unknowns: port 0x19 payload temp/duration encoding (using thomasakarlsen
  defaults 06 00 01 06 00 20 00 until confirmed with second capture)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
.md files in candumps/ are capture context notes (no raw bus data,
no VINs) — safe to commit. Widen the gitignore whitelist from
README.md to *.md so all note files are tracked.

Adds clima inject analysis and clima-start-test2 field reference.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Documents which OVMS standard metrics are currently implemented,
partially working, buggy, or missing for the e-Golf integration.
Grounded in the metrics-master-parked.txt real-car snapshot.
Overall: 47/85 (55%) implemented.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
From kcan-can3-clima_start2.crtd analysis:
- Confirmed multi-frame start TX_Fails when car is sleeping (no ACK)
- Dominant bits from the failed TX wake the bus in ~4 ms
- Continuation and trigger frames succeed ~110 ms / ~500 ms later
- ECU discards the orphan continuation → no HVAC activation
- NM base ID on KCAN is 0x1B000000; each node uses base | node_id
- Clima ECU NM ID would be 0x1B000025

Documents correct wake-then-send sequence and adds wake ping guidance.
Adds test2.md (CAN status before/after) and kcan-can3-clima_start2.md
(capture procedure) to the candumps notes.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
kcan-can3-clima_on_off.crtd confirmed CommandClimateControl working from
both OVMS shell and iOS app (TurboServ). Analysis of the capture produced:

- ECU sends immediate ACK on 0x17332510 (counter echoed with bit 7 set)
- 5s status bursts on 0x17332501 begin ~16s after command, last ~4 cycles
- Keepalive poll pair (19 42 / 19 41) precedes each status cycle
- Port 0x1a full-state dump length and header byte differ between idle
  (90 22, c0) and running (90 19, c2) — candidate clima-active flag
- Note: port 0x19 params frame alone may be sufficient to trigger start;
  Frame 3 (port 0x18 trigger) appears secondary based on one anomalous TX

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…tion

- TODO-clima-capture.md: mark Capture 4 done (confirmed CommandClimateControl
  works from shell and iOS app); add Captures 5-7 TODOs (cabin temp in remote
  mode, natural timer expiry, port 0x19 temperature encoding)
- TODO-metrics.md: update v.e.cabintemp/temp (sentinel suppressed, real value
  still needed), v.e.hvac now ~ (implemented in climate-control branch, not yet
  confirmed in parked-remote capture); update high-value gaps list
- CLAUDE.md: add reference to clima-control-bap.md alongside vw-bap-protocol.md

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds remote climate start/stop using the 3-frame BAP sequence on KCAN
(node 0x25, ports 0x18/0x19). Includes OSEK NM wake-from-sleep, 5 Hz
OCU heartbeat driven from IncomingFrameCan3, bus-idle timeout, and
bus-off guard. Config keys use dashes per maintainer convention
(cc-temp, cc-onbat). Heartbeat comments translated to English, log
level demoted to VERBOSE at the higher call rate.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The bus idle threshold for triggering NM wake before BAP clima was
VWEGOLF_BUS_TIMEOUT_SECS (10s), but KCAN goes silent ~2s after
ignition off. Commands issued 3–9s after shutdown skipped the wake
entirely — no NM join, no dominant-bit wake frame — causing the ECU
to briefly acknowledge then drop back to sleep.

Extract WakeKcanBus() from CommandWakeup and use a shorter 3-second
threshold (VWEGOLF_CLIMA_WAKE_SECS) in CommandClimateControl, gated
on both bus silence AND absence of non-zero OEM 0x5A7 frames to
avoid the documented arbitration-loss conflict window.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Ticker10 updates m_climate_temp every 10s. If config is changed and
climatecontrol issued within that window, the stale cached value is
sent. Confirmed on car: Capture 7 showed 18°C sent despite cc-temp
set to 22 four seconds earlier. Now reads config directly in
CommandClimateControl.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…_mode

0x5EA remote_mode is unreliable when ignition is off: field reads 0
(idle) even with clima actively running, and the frame barely
broadcasts in remote mode (2 frames in 304s, both sentinels).

BAP port 0x12 on 0x17332510 is the authoritative HVAC state:
payload[0]=0x05 means active, 0x00 means idle. Confirmed working
for both OVMS-triggered (Capture 6) and schedule-triggered (Capture
12) clima sessions. Decodes both single-frame and multi-frame BAP
variants.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- CLAUDE.md: build system, architecture, framework patterns, maintainer
  code review rules, BAP protocol note, e-Golf KCAN capabilities
- vw-bap-protocol.md: full BAP frame encoding reference derived from
  norly/revag-bap reverse engineering work
- Include upstream developer guide markdown for offline reference

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Documents the build-flash-verify loop, CAN log capture/replay for
desk testing without the car, verbose logging, single-frame injection,
metric verification, canbitset usage, and branch strategy.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- tests/mock/mock_ovms.hpp: stubs for all OVMS/ESP32/FreeRTOS types
  needed to compile vehicle_vwegolf.cpp with g++ on a Linux/Mac laptop
- tests/mock/mock_ovms.cpp: global singleton definitions
- tests/mock/*.h: stub headers that shadow the real OVMS headers
- tests/test_can_decode.cpp: tests for SoC, speed, gear, VIN decoding
- tests/Makefile: 'make test' builds and runs everything natively

Running 'make test' in the tests/ directory compiles and runs the actual
vehicle module C++ code without any ESP32 hardware or OVMS framework.
New decode paths should have a test here before being flashed to the car.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Module is tucked under the dash so SD card is inaccessible.
OVMS runs its own AP at 192.168.4.1 — laptop connects directly,
no iOS hotspot client isolation issues. CAN frames stream via
'can log start tcpserver' to nc on the laptop. Flash via Python
HTTP server + 'ota flash http'.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds test_crtd_replay.cpp which parses a CRTD log file, replays all
frames through IncomingFrameCan3, and asserts that speed, SoC, and gear
metrics contain plausible values.  Confirms the full pipeline works
end-to-end with 44k+ real frames from the car.

Adds candumps/ directory with .gitignore (captures excluded — they
contain VINs) and a README documenting how to create a capture and
run the test.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
scripts/setup-toolchain.sh: one-time setup of the Xtensa toolchain
binary, OVMS ESP-IDF fork (v3.3), and a Python venv. Prints env
exports to activate for the current session or shell profile.

scripts/build.sh: wraps the firmware make, initialises sdkconfig from
the hw31 default if missing, and optionally serves the binary via HTTP
for OTA flashing over the OVMS hotspot.

Updates CLAUDE.md Build System section with the full workflow using
these scripts instead of manual environment setup.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
scripts/hooks/pre-push: blocks pushes on fix/* and feat/* branches
unless the native test suite passes. investigation and master push
freely. Bypassed with git push --no-verify if genuinely needed.

scripts/install-hooks.sh: copies hooks from scripts/hooks/ into
.git/hooks/ — run once after cloning.

scripts/build.sh: now runs the test suite before compiling firmware.
Build is aborted if any test fails.

CLAUDE.md: rewrites the Iterative Development Workflow section to
document the full pipeline — toolchain setup, hook install, build,
OTA deploy — in the order a new developer would follow it.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
0x66E broadcasts 0xFE as a no-data sentinel before valid data is
available, which decodes to 77°C and persists across reboots.
Skip the metric update on sentinel, and clear the metric in the
constructor to evict any persisted wrong value.

Investigation showed 0x66E does not broadcast on KCAN while the
car is off or during standstill clima — cabin temp appears to be
available only via BAP, not as a plain CAN frame.

Also fix CRTD replay test to route frames by bus number (1/2/3)
rather than hardcoding bus 3, and dispatch bus-2 frames to both
IncomingFrameCan2 and IncomingFrameCan3 to model J533 gateway
bridging of KCAN onto Powertrain CAN.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Andreas and others added 27 commits May 13, 2026 01:20
Run tests/analysis/test_dbc_decode.py in CI alongside the C++ native
tests so silent DBC drift (signal scaling, bit position, units) fails
the build instead of slipping through. Installs cantools+pytest into
a clean Python 3.12 env — no toolchain needed. Job runs in parallel
with the C++ test job; firmware build still gated only on the C++ job.

setup-python pinned to v5 tag with TODO to SHA-pin to match the rest
of the workflow.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Remote pre-conditioning (start/stop) via KCAN/BAP, with wake-on-sleeping-bus:
- CommandClimateControl wakes a quiet bus, defers the 3-frame BAP burst to
  Ticker1 once the NM-join flood settles, and bounds the OCU/NM session so we
  don't talk alone on a sleeping ring (ACK grace + hard session cap).
- ms_v_env_hvac driven by 0x3B5 ClimaRunning (trigger-agnostic) with a run-hold
  to bridge thermostat cycling and a stop-suppress window for blower spin-down;
  commands update the metric instantly for a responsive stop. See capture notes
  all-168388a82-…-224827 (definitive hvac-source resolution).

Charging: AC line voltage/current/power from 0x569 (gated on charge_inprogress),
charge state/type/timer/duration/cabin setpoint from 0x594.

Review fixes:
- cc-temp clamped to 16–28 C at the BAP burst site, not just the web form — the
  CLI (config set) bypasses web validation and would otherwise truncate an
  out-of-range value into a garbage temperature byte. Web + burst now share
  VWEGOLF_CLIMA_TEMP_MIN_C/MAX_C so the ranges can't drift.
- Deferred-burst race: a clima command arriving while a deferred burst is pending
  now re-targets it instead of taking the warm-bus path and firing a second,
  interleaving BAP sequence; Ticker1 holds m_clima_pending across the send.

Tests: native clima suite + cc-temp clamp regression (158/158). Mock OvmsConfig
gained a real backing store so config-driven paths are testable.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Hardware filter passes only the 5 decoded FCAN IDs, which blinds
full-bus discovery captures. New cfg "xvg fcan-filter" (default on)
plus "xvg fcanfilter on|off|status" apply to the MCP2515 live and
persist across reboot. Unfiltered FCAN at ~1700 fps stresses the
poller but survives short supervised captures — keep enabled during
normal operation (charging OBC flood → TWDT, see filter rationale).

Mock OvmsConfig/OvmsWriter gain SetParamValueBool/puts/printf to
match the real API.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Broadcast frames carry no measured pack current while charging:
0x191 is silent during CCS DC and reads 0 A during AC, so ABRP
shows 0 kW for every session. Poll the BMS (ECU 8C, 0x7E5/0x7ED,
DIDs 0x1E3B/0x1E3D) on can1 = J533 diag CAN instead — addresses,
DIDs and scaling adopted from vehicle_vweup (same platform family),
to be validated on car before the metrics can be trusted.

Poll state machine: CHARGING via the 0x594 gate feeds bat_* metrics;
ON (FCAN alive) logs only, since 0x191 owns the metrics when driving;
OFF/AWAKE do not poll (diag CAN sleeps with the car).

Requires the OBD CAN+ wire landed on DB9 pin 7 (can1-H); inert
without it. Mock gains the OvmsPoller subset used here.

Refs garmzon/ovms3-VWeGolf#3

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
eb54d7a accidentally shipped a stale copy of j533_to_ovms.svg,
reverting the 56b51b3 typo fix: DB9 pin 7 is OBD CAN+ (can1-H),
not nc. All three buses are wired in the harness; the published
docs (PR 1) were already correct. Restored from master.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Harness has all three buses wired (diagram restored in cd03632);
can1 UDS polling is live, not pending a crimp.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Cap 25: events-only file (FCAN asleep during charge at the tap).
Cap 26: first unfiltered FCAN capture — CCS rejection at 100% SoC;
handshake-window IDs, 0x131 sentinel observed live, filter-off
storm headroom measured.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Add `xvg camping on|off|status`: an OVMS-side thermostat that holds cabin
temperature within [cc-camp-tmin, cc-camp-tmax] overnight by tripping the
existing BAP clima start/stop, so the AC runs only when needed off-battery.

The factory clima is car-capped (~15-30 min per command) and can't run all
night from one request, so Ticker1 re-evaluates each second and trips
start/stop against the band. Reacting to actual cabin temp (not a fixed
timer) means it also absorbs the car's own mid-window stops and adapts if
the per-command duration is raised via OBDeleven adaptation.

Guards for unattended overnight use:
- SoC floor (cc-camp-socfloor) stops camping; skipped while charging or when
  ms_v_bat_soc is stale/unset (avoids false-stop on a just-woken bus)
- max-hours backstop (cc-camp-maxhours)
- auto-exit when the vehicle is switched on (normal clima resumes)
- fail-safe: thermostat pauses when cabin temp is stale/out-of-range or the
  band is misconfigured (tmin>tmax) — never runs the climate blind
- anti-short-cycle dwell (VWEGOLF_CAMPING_MIN_CYCLE_SECS)

All state in class members (no statics); no metric defaults in the ctor;
config defaults live only at the read sites. Native tests cover start/stop
on band edges, dwell, stale-sensor pause, SoC floor (and charging skip),
max-hours (immediate and boundary counting), and drive-exit. Mock gains
IsStale() support. 195/195 tests pass.

Deferred: docs/index.rst user-guide entry and auto-stop notifications
(follow-up before upstream PR).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ice)

Port DID 0x74CB from vehicle_vweup: SoH (raw/50 %) and CAC (raw/100 Ah)
from the same uint16 at offset 0, older-platform constants (e-Golf has
no modelyear branch). Slow 600 s poll in AWAKE/CHARGING/ON. Scaling
adopted verbatim from vweup, pending on-car validation.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
PR openvehicles#1430 review follow-up: encoding confirmed on 0x17330110 setpoint
broadcast (dash-knob sweep); explicit temp in command byte unverified —
Cap H added to CAPTURES_TODO (HIGH). 0x20 in external trace likely
stored-setting sentinel.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Neither ms_v_env_awake nor ms_v_env_on was ever set, so the app always
showed the car as asleep and parked.

Decode two frames already documented on the bus:
- 0x3C0 (clamp status) d[2] bit 1 = KL_15 (terminal 15, ignition), i.e.
  the car is awake / switched on by the user -> ms_v_env_awake.
- 0x391 (OBD_01) d[7] bit 5 = OBD_Driving_Cycle, the drivetrain READY
  flag: set only when the car is drivable, clear during charging, remote
  climate and while the ignition is merely on but not yet READY.

Drivable (ms_v_env_on) requires both KL_15 && READY. The READY bit is not
cleared promptly at ignition-off - the frame keeps broadcasting with the
bit latched high for several seconds into power-down - so gating it with
KL_15 is what makes v.e.on track the drivable state. As a backstop, when
the bus goes silent both metrics are forced off.

Validated against captures: awake tracks the ignition periods; on is true
only during the drivable windows and stays off across the charge, lock,
remote-climate, precondition and wakeup captures.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add DBC entries for the two frames the ignition/awake/on decode reads:
- 0x3C0 ClampStatus: KL_S (accessory) and KL_15 (ignition) terminal bits.
- 0x391 OBD_01: OBD_Driving_Cycle (drive-READY, d[7] bit 5) and
  OBD_Abs_Pedal_Pos (accelerator pedal, d[5], 0.392 %/bit).

Also declare the Powertrain transmitter node used by 0x391. Both frames'
signals are verified against captures; the pedal scaling was additionally
cross-checked against BMS pack current (0x191) and the motor raw-pedal
signal MO_Fahrpedalrohwert_01 (0x121).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… port)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The 3-frame climate start was misdecoded: frames 1+2 are a SetGet on
ProfilesArray (LSG 0x25 func 0x19) doing a RecordAddr-6 compact update
of battery control profile 0, not a parameter block. The byte we
encoded cc-temp into is the profile's maxCurrent field (21 °C sent
110 A); the "duration" byte is the array-header RecordAddr; the
"rolling counter" is the array-header ASG-ID/Transaction-ID.

Per smartkar-cano-new BAP docs (thomasakarlsen) and MIB2 firmware RE
(SCjona), PR openvehicles#1430 review. The car climatizes to the setpoint stored
in its global profile; an OVMS-side temperature had no wire effect.

- send constant maxCurrent 0x20 (32 A), matching the proven trace
- drop cc-temp config, web settings page, and clamp defines
- rewrite clima-control-bap.md and vw-bap-protocol.md in standard BAP
  terminology (FSG/ASG/LSG, OpCode, Function ID, RecordAddr); fix the
  opcode table (0x02 SetGet, 0x04 Status)
- replace clamp test with test_clima_burst_bytes pinning all 3 frames

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… poll

Capture review disproved the AC-inlet decode of 0x569: d[4] is a
constant 0xF8 in every state (idle, clima, AC, CCS DC) and d[5] is a
DC-DC/aux current (~13 A through a 33 kW CCS session) — d[4]*d[5] was
a flat ~3.2 kW that never tracked the charge rate.

- 0x569 demoted to a diagnostic log; drives no metric
- charge voltage/current/power now derived from the BMS pack UDS poll
  (positive-magnitude convention; zeroed on charge stop since the
  poll leaves CHARGING state and would freeze the last sample)
- 0x191 current sign flipped to OVMS discharge-positive convention,
  matching the UDS DID_I path (raw field is charge-positive)
- vwegolf.dbc: frame renamed OBC_AuxStatus, signal comments rewritten
  with capture evidence; tests updated to pin the new behavior

Caps: all-dc583be4a-20260503-132333 (CCS DC), all-168388a82 (idle),
kcan-can3-clima_control (parked clima).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
H1 confirmed: MIB nav guidance readable on KCAN (BAP node 0x32,
cleartext destination). Next: drive capture, then firmware handler.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Cross-referenced commaai opendbc vw_mqb.dbc against our captures:

- 0x086 -> LWI_01: steering angle signals added (stationary-plausible in
  20260412-175611 static 5.1 deg and 20260611-195720 live jitter);
  dynamic scale/sign pending cap 27
- 0x0A7/0x0A8 -> Motor_11/Motor_12 (torque/rpm; SNA sentinel + zeros
  stationary, signals withheld until drive validation)
- 0x107/0x120/0x121 -> Motor_04/TSK_06/Motor_20 (names only)
- 0x187 gear enum independently corroborated (identical VAL_ table);
  EV_Rekuperationsstufe + HVEM_MaxLeistung noted as candidates
- 0x569 HVEM_04 naming supports energy-management (not AC inlet) reading

New pytest pins LWI_01 static decode; captures.tsv item 27 = unfiltered
D-mode drive to validate the withheld signals.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
On-car MQTT snapshot 2026-07-10 showed v.b.soh=863.54%, v.b.cac=431.77Ah,
v.b.capacity=5kWh. UDS 0x74CB raw is 10x the pre-2020 vweup scale ->
SoH=raw/500 (86.35%, provisional); CAC scaling unknown, no longer written.
0x05CA carries REMAINING energy (tracks SoC), not pack capacity: log-only,
DBC signal renamed BatEnergyRemaining. Upstream fix rides the charging PR.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Log firmware metric values from the MQTT broker to <BASE>.metrics.tsv
during a capture so analysis can correlate frames vs firmware belief.
Best-effort: no config/password/broker -> capture proceeds without it.
Server facts live in gitignored mqtt_log.json (copy the .example);
password via OVMS_MQTT_PW env or pluggable password_cmd. GPS metrics
dropped (candumps/ is committed, no-PII rule); retained rows flagged.
Verified live against broker.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Stable unique SIM identifier — same no-PII class as VIN/GPS. Unlike
GPS there is no keep flag; it has no analysis value.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Flash-regression hunt capture 20260712-124542 (clima -> drive -> CCS
0.5 kWh) did not reproduce the awake/on/charging metric flaps: all
flips match frame content. Bonus second sighting of ChargeType=2
during CCS DC confirms the June provisional finding.

- vwegolf.dbc: fix BO_ 1428 comment (CCS DC now observed; KCAN wakes
  only at plug-in/charge-stop). Note cantools cannot decode 0x594 due
  to intentional ChargeType/ChargePort bit overlap - use raw bytes.
- test_dbc_decode.py: pin ChargeType=2 window + charging-bit
  transitions from cap 28 (raw-byte extraction).
- captures.tsv: row 28.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…stall watchdog

On-car failure (VW e-Golf, can3/KCAN, 2026-07-12): mcp2515 RX delivery
stopped with interrupt and RX counters frozen and CANINTF RX-full
latched; the existing inactivity watchdog never fired because it only
runs while the vehicle is on, and the bus needed a manual stop/start.

BusTicker10 now declares an RX stall only when the bus is started
(Active/Listen), packets_rx has been frozen for CAN_RXSTALL_THRESHOLD
seconds, AND the driver hardware-confirms unserviced RX pending
(CheckRxStalled(): mcp2515 live CANINTF read, RX0IF|RX1IF). Pure RX
silence (bus legitimately asleep) never triggers. Recovery is Reset(),
counted as a new rxstall_resets status field.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@slothish

Copy link
Copy Markdown
Author

closing — accidentally based on my integration branch, will refile clean off master

@slothish slothish closed this Jul 12, 2026
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.

3 participants