Repository navigation
Conversation
Member
|
Heya! Was following along; did you need some help getting this one over the finish line? |
Author
|
Ha! Figured I was making a lot of noise, but I'll reopen for you to follow along! I am pretty excited by how much I've uncovered so far--big trip coming up and excited to use it! |
Cadence per tier, and the caveat that matters: every 'never moved' reading came from a parked truck, and 3B00/3B01/3B08 were read at one ride height where they could not have moved regardless. Records the 197C and D11C reversal rather than quietly undoing it. Also the suspension decode audit - pressures, signed height offset and module voltage all check out against every logged sample; 3B4D has returned zero on all 171 samples, and only 36 minutes in fourteen months have all four corners at once.
CLAUDE.md is what someone needs before touching this repo: layout, the F4xx convention and why it exists, that freq is an interval and the budget has 0.01 req/s of slack, runnable validation, and five traps that all bit during this work. The load-bearing one is that a command's presence in the signalset does not mean it is being collected. TESTING.md tracks what can only be answered in the truck - eight open tasks, and a per-DID table of what each debug param is believed to be and what would count as a result. Deciding a DID is dead requires a drive with a ride-height change and a terrain-mode switch, because everything in the 600s tier was classified from a parked vehicle.
The ATSH/ATCRA pair is the part that is not obvious: one sets who you are addressing, the other filters what comes back, and the block repeats because each pair retargets the same three questions at the next module. ATAR at the end matters more than it looks - leave a filter set and the next healthy request reads as dead. Worked examples are real frames from this truck's logs rather than invented ones, so they can be checked: 7E80462F40582 decodes to 90 C coolant, and 726's multi-frame F18C reply spells serial 5224293808. Command meanings are taken from the Elm Electronics AT command list.
…answer Trade the SAE duplicates for three PIDs that answer, name two modules
All 109 commands were polled. F40C answered 172 of 172 and engine speed reached the signal database for the first time in fourteen months, with nothing in this file having changed to cause it - the app had been holding an older copy. The budget and freq theories were both wrong, and they were worth ruling out only because doing so left no other explanation. Thirty-six debug params came straight back out. The 7E0 11xx family and the 7E1 03xx/101A/21xx/2B1x block answer only inside an extended diagnostic session; they answered in December 2025 because that session sent 10 03 first, and nobody had noticed. They are not dead probes, they are unreachable by polling, and they now live in TESTING.md with the 10 03 recipe and its warning. F408 and F409 answered, so there is bank-2 data at last, and it says the banks agree: long term +9.31 and +7.32 percent. Both lean together, which is a shared cause rather than the asymmetry we thought we had. The ride-height change moved 3B01, 3B3C, both height sensors, all four corner pressures and the compressor. Access height did register, in the pressures rather than the state fields, which were sampled too slowly to catch it - 3B01 goes to freq 10. 3B4D read zero throughout and is no longer called Drive Mode. 73 commands at 10.55 req/s.
F423 and F45C came out of the signalset when their proprietary equivalents won on sample count, but the signal tables kept listing them. Note the reason on the surviving rows so nobody re-adds them.
First drive on the debug batch: the stale signalset explained, 36 params are session-gated
Decoding the ECM's own 0100/0120/0140/0160 bitmasks says it supports 54 mode-01 PIDs; 25 had no entry here. Dropping the metadata ones and the two SAE aliases that already lost to their proprietary twins leaves sixteen. Three of them exist to prosecute the lean finding rather than to collect data: F403 says whether the engine was even in closed loop when those trims were measured, F42E tests the stuck-purge-valve hypothesis that would explain both banks drifting together, and F438 is the bank 2 oxygen sensor sitting behind the bank 2 trim we only just started reading. Eight go in as single raw bytes because we do not know what they are. len 8 is deliberate - reading the first byte is safe whatever the real width turns out to be, and they get widened once something replies. 89 commands at 10.93 req/s.
Probe the sixteen PIDs the ECM says it supports and we never read
F466, F467, F468 and F470 went in at len 8 because nobody knew how wide they were. The first byte of each turns out to be a sensor-support mask, so all four have been faithfully recording the constant 3. The real payloads are two mass airflow sensors, two coolant sensors, two intake air sensors and ten bytes of boost control, and every number we have from them was read out of raw frames by hand rather than by the signalset. The dual MAF is the reason to care: 2.09 g/s against 1.78, a 17.5% split between intake tracts, summing to roughly what F410 reports on its own. MAF calibration was one of three explanations for both banks trimming lean together and this is the first evidence touching it, so F466 goes to freq 5. F416, F419 and F41A answer FFFF, not available, every time and are gone. F413 said 0x77 once - both banks have sensors 1 through 3 - which can never change, so it is written down rather than polled. Re-tiered for a two-hour drive with off-roading: the diff-lock pair to 30, boost control to 15, purge to 10. Barometric pressure pays for it at freq 5 instead of 1, which frees 0.9 req/s and loses nothing. 85 commands at 10.53 req/s.
…-long-drive Widen the four PIDs whose first byte was a support bitmask, and set up for a long off-road drive
Read against the SAE J1979 definition of PID 70, the ten bytes we were storing as three anonymous words are commanded and measured boost for two channels at 1/32 kPa. The support byte says channel A exists and it reads 24.72 kPa at idle. First direct boost measurement on this truck - the boost ratio synthetic has only ever inferred it from MAP over barometric - and it costs nothing, because the reply was already arriving. Checked every other command the same way against the canonical SAE signalset. Nothing else is being left behind: the unread fields are sensor-present bits and channels a V6 does not have. Also recorded what Jaguar does for tire pressures, since it fills eight metric slots we leave empty. Its 751 is silent here across 1386 attempts, but its temperature DIDs 2A0A-2A0D have never been sent to a module that answers, which is a parked sweep rather than a drive.
Twenty-nine signals are raw probes or byte splits that nobody can read yet. They belong in the log, not on the screen, so they get hidden: true. SAE J1979 hides 76 of its 294 the same way; we were hiding none of 98. Twenty-three get a description, aimed at the ones that would mislead a reader who trusted the name: the height sensors are inverted, bank 2 lambda rails at FFFF about half the time and those samples are invalid rather than lean, altitude is a barometric lookup and not GPS, and 3B4D is emphatically not the drive mode its old name claimed. Also recorded why sixteen metric slots is the ceiling rather than an oversight. Of the twenty unfilled, ten are electric-vehicle only, eight are tires we cannot read yet, and the last two need data this ECM does not produce. fuelRate cannot be faked with a synthetic either - the only supported formula op is a plain ratio with no constant, so the number would be wrong by a factor of fourteen. An empty slot beats a wrong gauge.
F470 is boost pressure, and what the other OBDb repos suggest
Hide the raw probes, describe the misleading ones, and record why 16 metric slots is the ceiling
The app never gives signalset traffic more than about 4.2 req/s. Measured over seven sessions: 108 distinct DIDs got 4.19 req/s, 23 DIDs got 4.22. The adapter's 13.4 req/s is real but the app spends 3.3 on AT commands and 5.9 on its own mode-01 polling. We had been asking for 10.53 against a ceiling of 11 that was never ours to spend. Overdrawing it has a cost that isn't slower polling. The app retires ECUs and never retries them: 726 and 761 went at 10:59, 732 and 792 at 12:40, 7D3 at 14:07, all while answering correctly. On the 137-minute drive that followed, 61 of 84 commands were never sent once. The off-road tests were all aimed at 7D3 and collected nothing. Cut to 66 commands at 3.922 req/s. Nineteen deleted as dead across all logged history, not one drive, including 3B4D, which was the Terrain Response candidate and is constant zero across 236 samples spanning several modes. Engine speed is back on a real cadence. Three duplicates proven by correlation and resolved: PID 67 sensor 1 is the coolant PID to 0.0 C over 135 pairs; PID 70 channel A is manifold pressure to 1.3 kPa over 525 pairs, not a separate boost sensor; the proprietary oil temp DID is standard PID 5C to 0.7 C over 1,135 pairs. PID 67 sensor 2 turns out to be the supercharger intercooler's low temperature circuit, which is new. Ride height Access never registered because 3B3C is a bitfield, not an ordinal. 0x04 is Access and was not in the map; the 0 we had labelled Access never occurs. Pinned against the inverted front height sensor. Fuel rate is computed. The ECM's bitmask says PID 5E is unsupported, so it is derived from MAF and commanded lambda with the constant folded into a hidden operand, since synthetics only allow a bare ratio. Integrates to 11.21 L against 9.48 L from the tank gauge over 91.5 km. Corrects two claims made earlier today: F470 is manifold pressure at finer resolution rather than boost, and the two MAF channels do not sum to the single MAF PID. That rested on one idle sample; 1,474 samples give a least-squares slope of 0.88 with scatter too wide to trust the split. Also documents that the app only ever stores signals carrying a suggestedMetric. Fifteen distinct signals in fifteen months. Everything else is polled and thrown away.
The suspension section, the off-road no-data section and the new charge cooler signal all needed the same caveat spelled out locally: resetting the app's vehicle profile brings those modules back to life, but none of their signals carry a suggestedMetric, so none of them will ever be recorded as history either way. Live readouts and scan logs only. Claude-Session: https://claude.ai/code/session_01Kzsf15spEW5oNrt7zCt8Z7
I read one day of sessions and called it a one-way ratchet in which the app permanently retires ECUs, then told the owner to delete and re-add the vehicle. He pushed back and asked whether this was new. It wasn't. Taking the longest session of each day since 09-05, coverage has been 12 to 23 distinct DIDs every time. The 137-minute off-road drive polled 23 -- the widest of any long session in the period. The drive was not degraded, it was the best long session on record, and 61-of-84 is simply what this app has always done. The stable core explains itself. Thirteen commands appear in every long session since 09-05 and they are exactly thirteen of the sixteen carrying a suggestedMetric at the time. The app converges on polling what it will store. Modules with no metric-bearing command drift out of the rotation, which covers 7D3, 792, 732, 726 and 761 without needing a ratchet. Coverage recovers on its own every time the signalset changes. Nothing is stuck and nothing needs resetting from inside the app. The retraction is recorded in place rather than deleted, because the wrong version was convincing. The signalset itself is untouched: the budget cut, the nineteen deletions, the duplicate decodes, the ride height bitfield and the fuel rate all rest on direct measurement, not on this explanation. Claude-Session: https://claude.ai/code/session_01Kzsf15spEW5oNrt7zCt8Z7
The cull was wrong. I deleted nineteen commands for reading constant, but most had between 6 and 30 samples and none of those samples covered the event the command would report. 1E88's six readings were all taken with the differential unlocked, which says nothing about a diff lock DID. A signal that only moves during a rare event looks dead until the event happens, and deleting it guarantees it never gets caught. F458 was not weak evidence, it was a misread. 62F458 7F is a positive reply carrying data byte 0x7F, not a 7F negative response. PID 58 is long term secondary O2 trim bank 2, the counterpart to PID 56 already in the file, and 0x7F is -0.78%. Now mapped as LR4_SEC_O2_TRIM_B2. All nineteen are back at exploratory cadences: the event-driven ones (1E88, 1E89, 3B4D) at 60s, 3B00 and 3B08 at 120s, the rest at 600s. The whole set costs 0.03 req/s against a 4.2 ceiling, so the budget was never the real argument for removing them. 3B4D stays despite being the one genuinely conclusive case, because at 600s it is free. Also adds six probes the ECM's own supported-PID bitmask says exist and that this file has never requested: PID 23 fuel rail gauge pressure (158 logged samples, 35 to 197 bar, the right shape for this DI rail and worth comparing against 033E), PID 01 and PID 41 monitor status, PID 13 O2 sensors present, PID 51 fuel type, PID 1C OBD standard. 91 commands at 4.043 req/s, still under the ceiling, with twenty-five more things to look at than before the cut. Claude-Session: https://claude.ai/code/session_01Kzsf15spEW5oNrt7zCt8Z7
…-gives Fit the budget the adapter actually gives us
The restored probes paid off within hours, and the merge did what it was supposed to: coverage went from 23 distinct DIDs across 10 modules to 70 across 13, with 87 of 90 commands polled. Every module that had drifted out came back on its own. No app reset, and deleting the vehicle would have been wrong. 3B4D is alive. It was the one deletion I called conclusive -- flat 0x00 across 236 samples -- and it returned 0x04, 0x01 and 0x00 within eight minutes of the off-road features being used. It does not track the ride height mode PID, so Terrain Response is back to being the leading candidate. Now at 30s. Six of the eleven 792 counters advance: 2A32 through 2A37 gained 14000, 480, 960, 2170, 88 and 1 over 111 km and nine hours. They are counters, not constants. What they count is still unknown because that window mixed driving with parked time, so they now poll at 120s to make one drive enough to regress against distance and running time. 3B01's last bit is pinned. 0x400 was Off-Road by elimination; it was caught twice at a front reading of 85 to 89 with the mode PID reading Off-Road. 3B01 is a mapped signal now: 0x100 Normal, 0x400 Off-Road, 0x800 Access. The ride height map checks out against a screenshot showing Access, which had never displayed before the map was fixed. All six new probes answered. MIL off with zero stored DTCs, six oxygen sensors, gasoline, OBD-II, and a rail gauge pressure that ranges 29 to 197 bar against 033E's 41 to 46 over the same evening. Also corrects two documented claims. hidden: true does not hide anything -- fifteen hidden signals are on screen in the screenshots. And non-metric signals do display live, which resolves the open question: the bandwidth buys a readout, just never history. Claude-Session: https://claude.ai/code/session_01Kzsf15spEW5oNrt7zCt8Z7
Holding the lower button puts the truck into a held-Access mode that stays down instead of self-levelling. It appears in none of the 484 3B3C or 142 3B01 samples, and both words have exactly one unfilled slot: 3B01 bit 9 (0x200), between Normal at 0x100, Off-Road at 0x400 and Access at 0x800; and 3B3C bit 3 (0x08), seen only inside 0x0D with the truck in motion. The problem with catching it is that a mapped signal renders nothing for a value it has not been taught, so a new state would show as a blank in the app and survive only in the scan logs. That is exactly how 3B4D went unnoticed. Both DIDs now carry an untranslated twin, Ride Height State Raw and Ride Height Mode Raw, deliberately not hidden. They cost no extra request and turn an unknown state into a number. Two more suspension DIDs are not flat either. 3B00 reads 0x03 in 111 of 113 samples with one 0x103 taken at Access, and 3B02 carries a bit-8 flag that toggles the same way; 3B08 reads 0x00 in 130 of 131 with one 0x01 taken with Off-Road engaged. One sample each is not a decode, but none is dead. Claude-Session: https://claude.ai/code/session_01Kzsf15spEW5oNrt7zCt8Z7
Decoding every signal in the file against the evening log turned up more than the three headline movers. The second word of F434 and F438 was being read as a voltage. SAE J1979 PIDs 34 to 3B carry equivalence ratio plus sensor current; the voltage variants are 24 to 2B, which this ECM does not support. Read as voltage it produced a flat 4.0 across 28,432 samples, which should have been the giveaway. Read as current it spans -0.95 to +1.36 mA around +0.16, which is what a wideband pump cell does. Both become O2 Pump Current in milliamps. D11A was called Suspension Module Voltage. It is not battery voltage: over 221 paired samples its raw value swings 57 to 105 while control module voltage moves 12.51 to 14.75, and the implied scale scatters 9%. The old scaling put it at 16.8 V. Best correlation is 0.58 against compressor activity, not enough to name it, so it goes back to an undecoded raw byte. The two fuel rail pressures are different quantities, not one scaled two ways. Over 157 pairs the ratio drifts 0.41 to 0.56, and in one stretch PID 23 sat pinned near 197 bar while 033E climbed 79 to 110. A scaling error would hold a fixed ratio. Warm-ups since codes cleared is saturated at 255 and says only that they were cleared more than 255 cycles ago. Claude-Session: https://claude.ai/code/session_01Kzsf15spEW5oNrt7zCt8Z7
…oved Three things I called dead moved as soon as a feature was used
Fuel Rate now divides MAF by a lambda operand prescaled to US gallons per hour and declares gallonsPerHour, one of the schema's own units, rather than hoping the app converts. Four more fuel synthetics come from the same three polled DIDs at no extra bandwidth: gal/min, mpg, gal/100 mi, and a lambda-corrected mpg that only works if a synthetic may read another synthetic. That one is an experiment; TESTING.md says which of the two mpg signals to keep once a drive has answered it. The mpg and gal/100 mi signals assume lambda 1 because a ratio has room for two operands and an exact mpg needs three. It cost 3% over the 2026-09-23 drive. Decimal places are not fixable here. The schema's fmt has no precision field, so the float on the fuel rate and the one decimal on Fahrenheit temperatures are the app's formatting. Recorded as trap 9. Also fixes CLAUDE.md's command count and demand, stale since PR #8.
MAF goes 5s to 2s and commanded lambda 5s to 3s, which is what the fuel synthetics update from. The 0.43 req/s comes from throttle position and the gear selector (10s), lambda B1S1 (15s), rail pressure, timing advance, absolute load and both pedals (30s) and MAF A/B (60s). Demand lands at 4.083 req/s. The 2026-09-23 drive shows why it felt slow: 5s commands were answered every 5.7s, 2s commands every 3.05s, and the app chose 21 commands worth 1.8 req/s, so the budget was never the constraint. Also recorded: no probe on 7D3, 732, 792, 761 or 726 has been sent since 2026-09-21, so the open suspension and Terrain Response items got nothing from these drives.
…d-it Fuel rate in gallons, plus mpg and the two things the schema won't do
jverkoey
added a commit
that referenced
this pull request
Oct 11, 2026
…ates (#11) The LR4 repo was empty, so its cars fell back to the Land Rover make repo, which has few reads for this generation. This seeds it with 100 commands and 108 signals, most of them debug commands for the cars to try. **What the 2016 captures answered** (90 captures, all one model year): - Gear selector `732 22 D928`: `00`, `01`, `02` and `03` decode as Park, Reverse, Neutral and Drive. - Engine `7E0`, replying from `7E8`: - fuel rail pressure `033E`: 3,102-19,989 kPa; - charge air temperature `0520`: 33-88 °C; - engine speed `F40C`: 0-3,128 rpm; - module voltage `F442`: 10.8-14.7 V. The engine refused `00E6`, `00F2`, `00F3`, `5200`, the `D9xx` block and `F18D`-`F300`. Those are left out. **Candidates:** - Most reads come from #5 by @mwvolo, written on a 2016 LR4: - air suspension pressures, heights and ride mode on `7D3`; - engine oil temperature, oil level and Service 22 copies of the Service 01 engine data on `7E0`; - transmission reads on `7E1`; - the `792`, `761` and `795` reads. Its fuel-rate and fuel-economy synthetics are left out, along with the helper signals that only fed them. - Transmission, wheel speed and brake reads from the Defender repo on `7E1`, `7E6` and `726`, as candidates. **Changes to the community PR's reads:** - The gear selector keeps the Park/Reverse/Neutral/Drive map. The make repo's parked bit read `00` (Park) as "no". - Duplicate raw signals that decoded the same bits as a named signal are removed. - Names are in sentence case. - The odometer id is `LR4_ODO`. `generations.yaml` covers 2010-2016. Response tests pass (6), and schema validation and lint are clean. 6 fixtures are added and none deleted. The 2016 support file no longer lists twelve Service 01 PIDs as supported: the capture refused them, and the regenerated support data agrees. Co-authored-by: Jeff Verkoeyen <jeff@featherless.design>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Partially working on 2016 LR4
Adds (additional to core - confirmed working):
LANDROVER_PARKED(yes/no, reversed on main LR repo)LANDROVER_ENGINE_LOAD(0-100%)LANDROVER_IAT- Intake Air Temp (ºC)LANDROVER_MAF- Mass Air Flow (g/Sec)LANDROVER_ENGINE_OIL_TEMP(ªC)LANDROVER_BOOST(1-5)Other commands are [WIP]