Add --watch/--ford/--pid/--scan modes + 2026-06-29 session diagnostics
obd_reader.py: - Mode 22 plumbing: ELM.mode22() sends a 16-bit PID request, parses both positive (62 ..) and negative (7F 22 NRC) responses. - --ford runs a small TENTATIVE table of community-sourced Ford 6.0 PIDs (ICP/IPR/FICM/EBP/EOT). All printed with raw bytes for verification. - --pid XXXX probes a single PID and prints multiple candidate decodings (u8, u16, mV, temp, duty) so we can eyeball the right scaling. - --watch [N] streams ATRV + module voltage (PID 0142) for N seconds. Designed for capturing voltage sag during cranking. - --scan AAAA-BBBB brute-force scans Mode-22 PIDs with --scan-log PATH for output. Uses fast ELM timing (ATAT2, ATST19) for ~3.5 PIDs/sec. diagnostics/2026-06-29-no-start/: - Captured cranking voltage trace, full Mode-22 scan (1000-14FF -> 46 hits), and a session writeup. Working hypothesis: not batteries, not fuel -- ICP / FICM / CMP. FICM meter test still owed. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,115 @@
|
|||||||
|
# 2026-06-29 — 6.0 Power Stroke no-start session
|
||||||
|
|
||||||
|
In-cab diagnostic session using the `ford-obd` tool on the truck.
|
||||||
|
Charger on "12V Hi" was attached for most of the session.
|
||||||
|
|
||||||
|
## Symptoms
|
||||||
|
|
||||||
|
- Cranks **fast** (starter spins the engine normally)
|
||||||
|
- **Zero combustion event** — no sputter, no cough, no kickback
|
||||||
|
- HFCM lift pump heard priming on key-RUN and shutting off normally
|
||||||
|
- Battery at OBD port: 11.2 – 12.7V key-RUN (varied with charger state)
|
||||||
|
|
||||||
|
## Codes pulled (multiple reads, slight variation between reads)
|
||||||
|
|
||||||
|
| Mode | Code | Description |
|
||||||
|
|---|---|---|
|
||||||
|
| Stored (03) | `C0300` | (chassis — not engine, not in our DB) |
|
||||||
|
| Pending (07) | `C0700` / `C0701` | (chassis — alternated between reads) |
|
||||||
|
| Pending (07) | `P0113` | IAT circuit HIGH — sensor wiring, not a no-start |
|
||||||
|
| Permanent (0A) | `C3F0A` | (chassis — not engine) |
|
||||||
|
|
||||||
|
No engine P-codes, no FICM codes, no injector codes, no CMP/CKP codes.
|
||||||
|
|
||||||
|
## What we ruled out
|
||||||
|
|
||||||
|
- **Batteries as primary cause** — cranks fast and voltage held adequately
|
||||||
|
(see `watch-cranking.log`). Bus sagged to 10.8–11.2V during ~11s crank,
|
||||||
|
borderline-low but not catastrophic. Healthy starter spin means batteries
|
||||||
|
have current to give.
|
||||||
|
- **Fuel supply** — HFCM lift pump audibly primes and shuts off correctly
|
||||||
|
on key-RUN.
|
||||||
|
- **Compression / mechanical** — fast even cranking, would feel different
|
||||||
|
with a low-compression cylinder.
|
||||||
|
|
||||||
|
## Working hypothesis (in order of suspicion)
|
||||||
|
|
||||||
|
1. **ICP / high-pressure oil leak** — STC fitting is the classic 6.0 culprit
|
||||||
|
for "cranks great, won't fire, no codes". Need ≥500 psi ICP to fire even
|
||||||
|
one injector.
|
||||||
|
2. **FICM weakness** — should boost to ~48V. Sometimes doesn't throw a code
|
||||||
|
even when failing. **Not yet measured** — see open items.
|
||||||
|
3. **CMP sensor** — would usually throw P0340/P0341 but not always.
|
||||||
|
|
||||||
|
## What we did with the tool this session
|
||||||
|
|
||||||
|
- Pulled DTCs across all 3 modes (multiple times).
|
||||||
|
- Captured cranking voltage with `--watch 30` (see `watch-cranking.log`):
|
||||||
|
- Pre-crank: bus 11.7→12.1V, VPCM 12.39→12.71V
|
||||||
|
- Cranking (~11s): bus 10.8–11.2V, VPCM 11.32–11.70V
|
||||||
|
- Recovery: bus 11.8–12.2V, VPCM stopped responding (`?`) — possible
|
||||||
|
PCM brief recovery state after the dip.
|
||||||
|
- Ran first attempt at Mode-22 probes (`--ford`) with community-sourced
|
||||||
|
PIDs (ICP=1209, FICM=1228/1229/122A, IPR=120B, etc.). **All returned
|
||||||
|
"no response."** Either the PCM uses different PID numbers, or these
|
||||||
|
values live on Ford's SCP bus and aren't gatewayed to OBD-CAN.
|
||||||
|
- Brute-force scanned PIDs `0x1000-0x14FF` (1280 PIDs, ~6 min, 46 hits).
|
||||||
|
See `mode22-scan-hits.txt`. Data is noisy because **multiple modules on
|
||||||
|
the bus answer the same query** — positive responses from PCM mixed
|
||||||
|
with negative-response bytes (`7F 22 12`, `7F 22 31`) from other modules.
|
||||||
|
|
||||||
|
## Interesting PIDs from the scan to verify next session
|
||||||
|
|
||||||
|
Cleanest-looking PCM-side responses worth re-probing individually
|
||||||
|
(with normal timing, `python obd_reader.py --pid XXXX`):
|
||||||
|
|
||||||
|
```
|
||||||
|
1310 2 1C 92 (was 1C 69 earlier — value changes; maybe a counter?)
|
||||||
|
1440 2 01 89 = 393
|
||||||
|
1442 2 01 88 = 392 ← three closely-spaced ~390 values
|
||||||
|
1445 2 01 8F = 399 suggests a related sensor cluster
|
||||||
|
1446 2 00 16 = 22
|
||||||
|
1447 2 00 34 = 52
|
||||||
|
1448 2 00 11 = 17
|
||||||
|
11B3 1 02
|
||||||
|
11B4 2 00 00
|
||||||
|
11BA 2 FF 5C
|
||||||
|
```
|
||||||
|
|
||||||
|
Likely scaling guesses:
|
||||||
|
- raw / 100 → fits if these are voltage-tenths or pressure-tenths
|
||||||
|
- raw / 1000 → if mV (0.393V plausible for sensor outputs)
|
||||||
|
- raw - some offset → temperature
|
||||||
|
|
||||||
|
To know what each one *is*, compare against a known measurement:
|
||||||
|
- Run `--pid 1440` with engine off, write down value.
|
||||||
|
- Get engine running (eventually), write down value.
|
||||||
|
- Change condition, watch which PIDs move.
|
||||||
|
|
||||||
|
## Open items / what's next
|
||||||
|
|
||||||
|
1. **FICM meter test was started but no readings reported back yet.**
|
||||||
|
Measure M / S / L on the FICM body, key-ON and during a (short) crank:
|
||||||
|
- M (Main) target ~48V cranking, <45V suspect, <40V dead
|
||||||
|
- S (Sync) target ~48V cranking
|
||||||
|
- L (Logic) target ~12V (mirrors battery)
|
||||||
|
2. **Visual under-engine check** for STC-fitting oil leak (wet/oily mess
|
||||||
|
at the rear of the engine, around the turbo / bell housing).
|
||||||
|
3. **Verify scan-hit PIDs.** Re-probe the clean ones above with
|
||||||
|
`--pid XXXX` to get uncontaminated readings, log them against known
|
||||||
|
conditions.
|
||||||
|
4. **Try addressing other modules with `ATSH`** — particularly the FICM
|
||||||
|
on its CAN address if it has one (uncertain on 6.0 — likely on SCP).
|
||||||
|
5. Try **FORScan** when forscan.org / CyanLabs mirror is back, on the
|
||||||
|
same CH340 adapter, to capture FORScan's actual PID requests for
|
||||||
|
ICP/FICM/IPR. That gives us the ground truth.
|
||||||
|
|
||||||
|
## Tool state at end of session
|
||||||
|
|
||||||
|
`obd_reader.py` now has:
|
||||||
|
- `--ford` — try the (tentative) Ford 6.0 Mode-22 PID table
|
||||||
|
- `--pid XXXX` — one-shot probe of any 16-bit Mode-22 PID
|
||||||
|
- `--watch [N]` — stream ATRV + VPCM for N seconds (default 20)
|
||||||
|
- `--scan AAAA-BBBB` + `--scan-log PATH` — brute-force scan a PID range
|
||||||
|
|
||||||
|
All work on the CH340 ELM327 v1.5 clone at 38400 baud, HS-CAN switch.
|
||||||
@@ -0,0 +1,121 @@
|
|||||||
|
================================================================
|
||||||
|
OBD-II Code Reader - ELM327 / 6.0 Power Stroke triage
|
||||||
|
================================================================
|
||||||
|
|
||||||
|
Auto-selected port: COM5 (USB-SERIAL CH340 (COM5))
|
||||||
|
(other ports seen: COM4, COM3 -- pass one as an argument if wrong)
|
||||||
|
Opening COM5 @ 38400 baud ...
|
||||||
|
Adapter : ELM327 v1.5
|
||||||
|
Battery : 12.5V (key ON; healthy 6.0 KOEO ~12.4-12.7V)
|
||||||
|
|
||||||
|
Connecting to vehicle (turn key to ON / RUN, engine off is fine)...
|
||||||
|
Protocol: A6 (CAN=True)
|
||||||
|
|
||||||
|
----------------------------------------------------------------
|
||||||
|
TROUBLE CODES
|
||||||
|
----------------------------------------------------------------
|
||||||
|
|
||||||
|
STORED (mode 03):
|
||||||
|
C0300 - (look up this code)
|
||||||
|
|
||||||
|
PENDING (mode 07):
|
||||||
|
P0113 - Intake air temp (IAT) circuit HIGH
|
||||||
|
C0700 - (look up this code)
|
||||||
|
|
||||||
|
PERMANENT (mode 0A):
|
||||||
|
C3F0A - (look up this code)
|
||||||
|
|
||||||
|
----------------------------------------------------------------
|
||||||
|
KEY LIVE VALUES (key ON)
|
||||||
|
----------------------------------------------------------------
|
||||||
|
Engine RPM 0 rpm
|
||||||
|
Coolant temp 33 C
|
||||||
|
Intake air temp 35 C
|
||||||
|
Intake MAP 98 kPa
|
||||||
|
Engine load 0 %
|
||||||
|
Accel/throttle pos n/a
|
||||||
|
Module voltage 13.1 V
|
||||||
|
|
||||||
|
================================================================
|
||||||
|
SCAN Mode-22 PIDs 1000 - 14FF (1280 PIDs)
|
||||||
|
================================================================
|
||||||
|
Logging hits to: C:\Users\justin\AppData\Local\Temp\ford-scan-hits.txt
|
||||||
|
Safe: Mode 22 is read-only. Will print every PID that answers.
|
||||||
|
|
||||||
|
... 100/1280 scanned in 28s (3.6/s), ~330s remaining, 0 hits so far
|
||||||
|
... 200/1280 scanned in 55s (3.6/s), ~298s remaining, 0 hits so far
|
||||||
|
HIT 1100 len= 7 raw=[01 00 40 05 7F 22 12]
|
||||||
|
HIT 1101 len= 5 raw=[00 62 11 01 00]
|
||||||
|
HIT 1102 len= 1 raw=[00]
|
||||||
|
HIT 1103 len= 5 raw=[00 62 11 03 00]
|
||||||
|
HIT 1104 len= 5 raw=[00 62 11 04 00]
|
||||||
|
HIT 1105 len= 1 raw=[00]
|
||||||
|
HIT 1106 len= 5 raw=[00 62 11 06 04]
|
||||||
|
HIT 1107 len= 5 raw=[00 62 11 07 00]
|
||||||
|
HIT 110C len= 4 raw=[00 7F 22 12]
|
||||||
|
HIT 1123 len= 5 raw=[1E 62 11 23 30]
|
||||||
|
HIT 1125 len= 1 raw=[FF]
|
||||||
|
HIT 1126 len= 5 raw=[00 62 11 26 00]
|
||||||
|
HIT 1127 len= 1 raw=[E7]
|
||||||
|
... 300/1280 scanned in 82s (3.6/s), ~269s remaining, 13 hits so far
|
||||||
|
HIT 1135 len= 2 raw=[FF FF]
|
||||||
|
HIT 1139 len= 5 raw=[2E 62 11 39 2E]
|
||||||
|
HIT 114A len= 5 raw=[7E 00 7F 22 12]
|
||||||
|
HIT 114B len= 5 raw=[A6 56 7F 22 12]
|
||||||
|
HIT 114D len= 2 raw=[81 40]
|
||||||
|
HIT 1155 len= 2 raw=[FF FF]
|
||||||
|
HIT 1165 len= 7 raw=[00 00 62 11 65 00 00]
|
||||||
|
HIT 1169 len= 2 raw=[00 00]
|
||||||
|
HIT 1172 len= 5 raw=[D1 62 11 72 D3]
|
||||||
|
HIT 1177 len= 5 raw=[00 C8 7F 22 12]
|
||||||
|
... 400/1280 scanned in 110s (3.6/s), ~241s remaining, 23 hits so far
|
||||||
|
HIT 11B3 len= 1 raw=[02]
|
||||||
|
HIT 11B4 len= 2 raw=[00 00]
|
||||||
|
HIT 11B5 len= 5 raw=[00 00 7F 22 31]
|
||||||
|
HIT 11B6 len= 4 raw=[8C 7F 22 31]
|
||||||
|
HIT 11B7 len= 5 raw=[00 00 7F 22 31]
|
||||||
|
HIT 11B8 len= 5 raw=[00 00 7F 22 31]
|
||||||
|
HIT 11BA len= 2 raw=[FF 5C]
|
||||||
|
HIT 11BD len= 5 raw=[87 1E 7F 22 31]
|
||||||
|
HIT 11C1 len= 7 raw=[00 00 62 11 C1 00 00]
|
||||||
|
... 500/1280 scanned in 138s (3.6/s), ~215s remaining, 32 hits so far
|
||||||
|
... 600/1280 scanned in 165s (3.6/s), ~187s remaining, 32 hits so far
|
||||||
|
... 700/1280 scanned in 192s (3.6/s), ~159s remaining, 32 hits so far
|
||||||
|
HIT 1310 len= 2 raw=[1C 92]
|
||||||
|
... 800/1280 scanned in 220s (3.6/s), ~132s remaining, 33 hits so far
|
||||||
|
... 900/1280 scanned in 247s (3.6/s), ~104s remaining, 33 hits so far
|
||||||
|
... 1000/1280 scanned in 274s (3.6/s), ~77s remaining, 33 hits so far
|
||||||
|
HIT 1410 len= 2 raw=[00 00]
|
||||||
|
HIT 1411 len= 5 raw=[00 00 7F 22 12]
|
||||||
|
HIT 1412 len= 2 raw=[00 00]
|
||||||
|
HIT 1434 len= 1 raw=[26]
|
||||||
|
HIT 1440 len= 2 raw=[01 89]
|
||||||
|
HIT 1441 len= 5 raw=[00 00 7F 22 12]
|
||||||
|
HIT 1442 len= 2 raw=[01 88]
|
||||||
|
HIT 1445 len= 2 raw=[01 8F]
|
||||||
|
HIT 1446 len= 2 raw=[00 16]
|
||||||
|
HIT 1447 len= 2 raw=[00 34]
|
||||||
|
HIT 1448 len= 2 raw=[00 11]
|
||||||
|
... 1100/1280 scanned in 303s (3.6/s), ~50s remaining, 44 hits so far
|
||||||
|
HIT 1450 len= 2 raw=[00 00]
|
||||||
|
HIT 1451 len= 2 raw=[00 00]
|
||||||
|
... 1200/1280 scanned in 331s (3.6/s), ~22s remaining, 46 hits so far
|
||||||
|
|
||||||
|
Done. 46 responding PIDs in 353s.
|
||||||
|
|
||||||
|
================================================================
|
||||||
|
6.0 POWER STROKE -- NO-START QUICK TRIAGE
|
||||||
|
================================================================
|
||||||
|
|
||||||
|
NO-CODE no-start basics to check by hand on a 6.0:
|
||||||
|
1. BATTERIES: both must be strong. Low voltage -> FICM won't boost ->
|
||||||
|
no injector fire. Load-test both; ~12.5V+ at rest, hold while cranking.
|
||||||
|
2. FICM voltage while cranking (~48V). The #1 6.0 cold no-start cause.
|
||||||
|
3. ICP (Injection Control Pressure): needs ~500 psi to fire. Big leaks =
|
||||||
|
STC fitting, oil rail O-rings, high-pressure oil hoses.
|
||||||
|
4. FUEL: lift pump (HFCM) priming, fuel filters, water-in-fuel.
|
||||||
|
5. CMP/CKP sensors (see codes above).
|
||||||
|
6. Glow plugs/relay if it's cold out (won't stop start, but hard start).
|
||||||
|
|
||||||
|
|
||||||
|
Done. (Re-run any time; codes persist until cleared.)
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
# Mode-22 scan 1000-14FF
|
||||||
|
# pid_hex len raw_bytes
|
||||||
|
1100 7 01 00 40 05 7F 22 12
|
||||||
|
1101 5 00 62 11 01 00
|
||||||
|
1102 1 00
|
||||||
|
1103 5 00 62 11 03 00
|
||||||
|
1104 5 00 62 11 04 00
|
||||||
|
1105 1 00
|
||||||
|
1106 5 00 62 11 06 04
|
||||||
|
1107 5 00 62 11 07 00
|
||||||
|
110C 4 00 7F 22 12
|
||||||
|
1123 5 1E 62 11 23 30
|
||||||
|
1125 1 FF
|
||||||
|
1126 5 00 62 11 26 00
|
||||||
|
1127 1 E7
|
||||||
|
1135 2 FF FF
|
||||||
|
1139 5 2E 62 11 39 2E
|
||||||
|
114A 5 7E 00 7F 22 12
|
||||||
|
114B 5 A6 56 7F 22 12
|
||||||
|
114D 2 81 40
|
||||||
|
1155 2 FF FF
|
||||||
|
1165 7 00 00 62 11 65 00 00
|
||||||
|
1169 2 00 00
|
||||||
|
1172 5 D1 62 11 72 D3
|
||||||
|
1177 5 00 C8 7F 22 12
|
||||||
|
11B3 1 02
|
||||||
|
11B4 2 00 00
|
||||||
|
11B5 5 00 00 7F 22 31
|
||||||
|
11B6 4 8C 7F 22 31
|
||||||
|
11B7 5 00 00 7F 22 31
|
||||||
|
11B8 5 00 00 7F 22 31
|
||||||
|
11BA 2 FF 5C
|
||||||
|
11BD 5 87 1E 7F 22 31
|
||||||
|
11C1 7 00 00 62 11 C1 00 00
|
||||||
|
1310 2 1C 92
|
||||||
|
1410 2 00 00
|
||||||
|
1411 5 00 00 7F 22 12
|
||||||
|
1412 2 00 00
|
||||||
|
1434 1 26
|
||||||
|
1440 2 01 89
|
||||||
|
1441 5 00 00 7F 22 12
|
||||||
|
1442 2 01 88
|
||||||
|
1445 2 01 8F
|
||||||
|
1446 2 00 16
|
||||||
|
1447 2 00 34
|
||||||
|
1448 2 00 11
|
||||||
|
1450 2 00 00
|
||||||
|
1451 2 00 00
|
||||||
@@ -0,0 +1,117 @@
|
|||||||
|
================================================================
|
||||||
|
OBD-II Code Reader - ELM327 / 6.0 Power Stroke triage
|
||||||
|
================================================================
|
||||||
|
|
||||||
|
Auto-selected port: COM5 (USB-SERIAL CH340 (COM5))
|
||||||
|
(other ports seen: COM4, COM3 -- pass one as an argument if wrong)
|
||||||
|
Opening COM5 @ 38400 baud ...
|
||||||
|
Adapter : ELM327 v1.5
|
||||||
|
Battery : 11.7V (key ON; healthy 6.0 KOEO ~12.4-12.7V)
|
||||||
|
|
||||||
|
Connecting to vehicle (turn key to ON / RUN, engine off is fine)...
|
||||||
|
Protocol: A6 (CAN=True)
|
||||||
|
|
||||||
|
----------------------------------------------------------------
|
||||||
|
TROUBLE CODES
|
||||||
|
----------------------------------------------------------------
|
||||||
|
|
||||||
|
STORED (mode 03):
|
||||||
|
C0300 - (look up this code)
|
||||||
|
|
||||||
|
PENDING (mode 07):
|
||||||
|
C0701 - (look up this code)
|
||||||
|
P0113 - Intake air temp (IAT) circuit HIGH
|
||||||
|
|
||||||
|
PERMANENT (mode 0A):
|
||||||
|
C3F0A - (look up this code)
|
||||||
|
|
||||||
|
----------------------------------------------------------------
|
||||||
|
KEY LIVE VALUES (key ON)
|
||||||
|
----------------------------------------------------------------
|
||||||
|
Engine RPM 0 rpm
|
||||||
|
Coolant temp 33 C
|
||||||
|
Intake air temp 35 C
|
||||||
|
Intake MAP 98 kPa
|
||||||
|
Engine load 0 %
|
||||||
|
Accel/throttle pos n/a
|
||||||
|
Module voltage 12.39 V
|
||||||
|
|
||||||
|
================================================================
|
||||||
|
WATCH MODE (30s) -- Ctrl-C to stop early
|
||||||
|
================================================================
|
||||||
|
ATRV = battery V at OBD port, VPCM = PCM/module V (PID 0142).
|
||||||
|
TURN KEY TO START NOW (or whenever you're ready).
|
||||||
|
|
||||||
|
t(s) ATRV VPCM
|
||||||
|
-------- -------- --------
|
||||||
|
0.00 11.7 12.39
|
||||||
|
0.54 11.7 12.38
|
||||||
|
1.09 11.7 12.36
|
||||||
|
1.64 12.0 12.55
|
||||||
|
2.17 11.9 12.52
|
||||||
|
2.70 12.0 12.49
|
||||||
|
3.25 12.1 12.66
|
||||||
|
3.79 12.1 12.69
|
||||||
|
4.33 12.0 12.55
|
||||||
|
4.84 12.1 12.71
|
||||||
|
5.35 12.0 12.60
|
||||||
|
5.91 10.8 11.65
|
||||||
|
6.42 11.2 11.59
|
||||||
|
6.93 11.0 11.59
|
||||||
|
7.45 11.1 11.48
|
||||||
|
7.95 10.9 11.43
|
||||||
|
8.47 10.8 11.70
|
||||||
|
8.97 11.2 11.67
|
||||||
|
9.49 11.0 11.70
|
||||||
|
10.01 11.0 11.46
|
||||||
|
10.52 11.0 11.59
|
||||||
|
11.02 11.0 11.48
|
||||||
|
11.54 11.0 11.62
|
||||||
|
12.04 10.9 11.48
|
||||||
|
12.55 11.0 11.40
|
||||||
|
13.07 11.0 11.48
|
||||||
|
13.57 10.9 11.40
|
||||||
|
14.08 11.1 11.43
|
||||||
|
14.59 10.9 11.46
|
||||||
|
15.08 11.0 11.48
|
||||||
|
15.59 11.0 11.59
|
||||||
|
16.09 10.9 11.32
|
||||||
|
16.61 11.5 12.17
|
||||||
|
17.11 11.8 ?
|
||||||
|
17.74 11.8 ?
|
||||||
|
18.37 12.0 ?
|
||||||
|
19.02 11.8 ?
|
||||||
|
19.65 12.0 ?
|
||||||
|
20.27 11.9 ?
|
||||||
|
20.90 12.0 ?
|
||||||
|
21.54 12.0 ?
|
||||||
|
22.18 12.0 ?
|
||||||
|
22.81 12.1 ?
|
||||||
|
23.45 12.2 ?
|
||||||
|
24.10 12.1 ?
|
||||||
|
24.74 12.2 ?
|
||||||
|
25.38 12.0 ?
|
||||||
|
26.01 12.0 ?
|
||||||
|
26.66 12.0 ?
|
||||||
|
27.31 12.1 ?
|
||||||
|
27.95 12.2 ?
|
||||||
|
28.59 12.1 ?
|
||||||
|
29.23 12.2 ?
|
||||||
|
29.87 12.2 ?
|
||||||
|
|
||||||
|
================================================================
|
||||||
|
6.0 POWER STROKE -- NO-START QUICK TRIAGE
|
||||||
|
================================================================
|
||||||
|
|
||||||
|
NO-CODE no-start basics to check by hand on a 6.0:
|
||||||
|
1. BATTERIES: both must be strong. Low voltage -> FICM won't boost ->
|
||||||
|
no injector fire. Load-test both; ~12.5V+ at rest, hold while cranking.
|
||||||
|
2. FICM voltage while cranking (~48V). The #1 6.0 cold no-start cause.
|
||||||
|
3. ICP (Injection Control Pressure): needs ~500 psi to fire. Big leaks =
|
||||||
|
STC fitting, oil rail O-rings, high-pressure oil hoses.
|
||||||
|
4. FUEL: lift pump (HFCM) priming, fuel filters, water-in-fuel.
|
||||||
|
5. CMP/CKP sensors (see codes above).
|
||||||
|
6. Glow plugs/relay if it's cold out (won't stop start, but hard start).
|
||||||
|
|
||||||
|
|
||||||
|
Done. (Re-run any time; codes persist until cleared.)
|
||||||
+32
-5
@@ -18,8 +18,14 @@ Pick-up notes for diagnosing the truck in the cab. Repo: `git.jpaul.io/justin/fo
|
|||||||
## What the tool does / doesn't
|
## What the tool does / doesn't
|
||||||
- DOES: read stored/pending/permanent codes, decode them (6.0 codes flagged as
|
- DOES: read stored/pending/permanent codes, decode them (6.0 codes flagged as
|
||||||
no-start suspects), clear codes (`--clear`), show battery voltage + key live PIDs.
|
no-start suspects), clear codes (`--clear`), show battery voltage + key live PIDs.
|
||||||
- DOESN'T: Ford-enhanced diesel PIDs — **ICP, FICM main/sync voltage, IPR%**.
|
- EXPERIMENTAL (`--ford`): tries a small table of community-sourced Ford 6.0
|
||||||
Those need FORScan. For those numbers tonight, measure at the FICM with a meter.
|
Mode-22 PIDs (ICP, IPR%, FICM main/sync/logic V, EBP, EOT). **PID numbers and
|
||||||
|
scaling are TENTATIVE** — raw bytes are always printed; cross-check against a
|
||||||
|
meter or FORScan before trusting a value.
|
||||||
|
- `--pid XXXX`: one-shot probe of any 16-bit Mode-22 PID; prints raw bytes plus
|
||||||
|
a few common decodings so you can eyeball the right scaling.
|
||||||
|
- DOESN'T (yet): a verified Ford-enhanced PID set the way FORScan has. We're
|
||||||
|
building toward that — see follow-ups below.
|
||||||
|
|
||||||
## 6.0 no-start priority checklist (from the triage)
|
## 6.0 no-start priority checklist (from the triage)
|
||||||
The 6.0 needs, to fire: **good batteries → FICM ~48V → ICP ~500 psi → fuel → cam/crank signal.**
|
The 6.0 needs, to fire: **good batteries → FICM ~48V → ICP ~500 psi → fuel → cam/crank signal.**
|
||||||
@@ -42,14 +48,35 @@ The 6.0 needs, to fire: **good batteries → FICM ~48V → ICP ~500 psi → fuel
|
|||||||
- Tool built + tested against the real adapter (init, all 3 DTC modes, live PIDs, clear flow).
|
- Tool built + tested against the real adapter (init, all 3 DTC modes, live PIDs, clear flow).
|
||||||
- DTC parser unit-tested incl. a fixed bug: legacy ISO/PWM multi-frame responses repeat the
|
- DTC parser unit-tested incl. a fixed bug: legacy ISO/PWM multi-frame responses repeat the
|
||||||
`43` header (was producing phantom codes) — fixed + regression-tested.
|
`43` header (was producing phantom codes) — fixed + regression-tested.
|
||||||
|
- **2026-06-29 in-cab session:** added `--watch`, `--ford`, `--pid`, and `--scan`
|
||||||
|
modes. Captured cranking voltages + ran a Mode-22 brute scan (46 PIDs hit).
|
||||||
|
Full session writeup + raw data in [diagnostics/2026-06-29-no-start/](diagnostics/2026-06-29-no-start/README.md).
|
||||||
|
**Headline:** not batteries, not fuel — almost certainly ICP / FICM / CMP.
|
||||||
|
**Unfinished:** FICM meter test on M/S/L was started but readings never logged.
|
||||||
- Pushed to `git.jpaul.io/justin/ford-obd`, branch `main`. Files: `obd_reader.py`,
|
- Pushed to `git.jpaul.io/justin/ford-obd`, branch `main`. Files: `obd_reader.py`,
|
||||||
`RUN_OBD.bat`, `README.md`, `README.txt`, `handoff.md`.
|
`RUN_OBD.bat`, `README.md`, `README.txt`, `handoff.md`, `diagnostics/`.
|
||||||
|
|
||||||
## To resume with Claude from the cab
|
## To resume with Claude from the cab
|
||||||
Mention: "6.0 Power Stroke no-start, using the ford-obd tool (git.jpaul.io/justin/ford-obd)".
|
Mention: "6.0 Power Stroke no-start, using the ford-obd tool (git.jpaul.io/justin/ford-obd)".
|
||||||
Then **paste the tool's full output** (codes + live values). Useful to also say: cranks vs.
|
Then **paste the tool's full output** (codes + live values). Useful to also say: cranks vs.
|
||||||
no-crank, hot vs. cold, what changed before it died, and FICM/ICP readings if you metered them.
|
no-crank, hot vs. cold, what changed before it died, and FICM/ICP readings if you metered them.
|
||||||
|
|
||||||
|
## To resume from the desktop (after the 2026-06-29 session)
|
||||||
|
Read [diagnostics/2026-06-29-no-start/README.md](diagnostics/2026-06-29-no-start/README.md)
|
||||||
|
first — that's the full state. Top open items:
|
||||||
|
1. Get FICM M/S/L meter readings (key-ON and during a short crank).
|
||||||
|
2. Re-probe the clean scan hits (1310, 1440-1451, 11Bx) with `--pid XXXX`
|
||||||
|
for uncontaminated data, then map them to known engine conditions.
|
||||||
|
3. Look at FORScan via the CyanLabs mirror to capture ground-truth PIDs.
|
||||||
|
|
||||||
## Open follow-ups (when off the truck)
|
## Open follow-ups (when off the truck)
|
||||||
- FORScan from the CyanLabs mirror once forscan.org is back, for ICP/FICM/IPR PIDs on the same adapter.
|
- FORScan from the CyanLabs mirror once forscan.org is back — useful as the
|
||||||
- Optional: add a few known Ford Mode-22 enhanced PIDs to the tool (verify PID numbers first).
|
ground truth for verifying our Mode-22 PID table.
|
||||||
|
- **Verify** every entry in `FORD_60_PIDS` (obd_reader.py) against either a
|
||||||
|
meter reading or FORScan, one at a time. As each is confirmed, drop the
|
||||||
|
"TENTATIVE" warning for that row.
|
||||||
|
- **Option 3**: brute-force scan of the Mode-22 PID space (e.g. `0x1000`-
|
||||||
|
`0x14FF`) and log which PIDs return data, so we can fingerprint what this
|
||||||
|
PCM exposes without external references. Hook it in as `--scan`.
|
||||||
|
- Add `--watch` mode that streams ATRV + PID 0142 (and the FICM PIDs once
|
||||||
|
verified) at ~5 Hz so we can watch the voltage sag during cranking.
|
||||||
|
|||||||
+338
-11
@@ -11,14 +11,20 @@ Scope (what a generic ELM327 CAN do, engine off / KOEO):
|
|||||||
* Read key KOEO live PIDs (coolant, IAT, MAP, module voltage, RPM...)
|
* Read key KOEO live PIDs (coolant, IAT, MAP, module voltage, RPM...)
|
||||||
* Battery voltage at the OBD port (ATRV)
|
* Battery voltage at the OBD port (ATRV)
|
||||||
|
|
||||||
What it CANNOT do: Ford-enhanced diesel PIDs (ICP, FICM sync/main volts, IPR%).
|
Experimental: with --ford it also tries a handful of community-sourced
|
||||||
Those need FORScan's Ford Mode-22 PID set. This tool covers the generic basics
|
Ford-enhanced Mode-22 PIDs (ICP, IPR%, FICM main/sync/logic voltage, EBP,
|
||||||
so you can read codes and triage tonight.
|
EOT). The PID numbers and scaling are TENTATIVE and need to be verified
|
||||||
|
against a known-good reading (meter or FORScan). Raw bytes are always
|
||||||
|
printed so you can sanity-check. Wrong PID = "no response", nothing
|
||||||
|
written to the truck.
|
||||||
|
|
||||||
Usage (Windows):
|
Usage (Windows):
|
||||||
python obd_reader.py # auto-detect the COM port
|
python obd_reader.py # auto-detect the COM port
|
||||||
python obd_reader.py COM5 # force a port
|
python obd_reader.py COM5 # force a port
|
||||||
python obd_reader.py COM5 9600 # force port + baud
|
python obd_reader.py COM5 9600 # force port + baud
|
||||||
|
python obd_reader.py --ford # + try Ford 6.0 Mode-22 PIDs
|
||||||
|
python obd_reader.py --pid 1430 # probe one Mode-22 PID, show raw
|
||||||
|
python obd_reader.py --clear # erase stored + pending DTCs
|
||||||
|
|
||||||
Requires: pip install pyserial
|
Requires: pip install pyserial
|
||||||
"""
|
"""
|
||||||
@@ -110,6 +116,61 @@ NO_START_CODES = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Ford 6.0L Power Stroke Mode-22 ("enhanced") PIDs.
|
||||||
|
#
|
||||||
|
# A generic ELM327 CAN'T natively decode Ford-enhanced data (ICP, FICM, IPR%)
|
||||||
|
# the way FORScan can, but the wire protocol is the same: we send Mode 22
|
||||||
|
# ("read data by identifier") with a 16-bit PID, and the PCM replies with
|
||||||
|
# raw bytes that we scale into engineering units.
|
||||||
|
#
|
||||||
|
# WARNING: every entry below is TENTATIVE. The PID numbers and scaling
|
||||||
|
# formulas are drawn from public 6.0 community references (FORScan extended
|
||||||
|
# PID dumps, diesel forum threads) and have NOT been verified against this
|
||||||
|
# specific truck. Treat decoded values as suspect until they're cross-
|
||||||
|
# checked against a meter or a known-good FORScan reading. To help with
|
||||||
|
# that, the tool ALWAYS prints the raw response bytes next to the decode.
|
||||||
|
#
|
||||||
|
# Wrong PIDs are safe -- the PCM just answers "no data" or a negative
|
||||||
|
# response (0x7F). Nothing is written to the truck.
|
||||||
|
#
|
||||||
|
# Each entry: (pid_hex, short_name, units, decoder|None, notes)
|
||||||
|
# pid_hex : 4 hex chars (the 16-bit Mode-22 PID)
|
||||||
|
# decoder : callable(list[int]) -> float, or None to show raw only
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
def _u16(b):
|
||||||
|
return (b[0] << 8) + b[1]
|
||||||
|
|
||||||
|
|
||||||
|
FORD_60_PIDS = [
|
||||||
|
# --- Injection Control Pressure (need ~500+ psi to fire) ---
|
||||||
|
("1209", "ICP", "psi", lambda b: _u16(b),
|
||||||
|
"Injection Control Pressure (need ~500+ psi to fire)"),
|
||||||
|
("121A", "ICP_DES", "psi", lambda b: _u16(b),
|
||||||
|
"ICP desired (commanded)"),
|
||||||
|
("1430", "ICP_V", "V", lambda b: _u16(b) / 1000.0,
|
||||||
|
"ICP sensor raw voltage"),
|
||||||
|
|
||||||
|
# --- Injection Pressure Regulator duty ---
|
||||||
|
("120B", "IPR", "%", lambda b: round(b[0] * 100 / 255, 1),
|
||||||
|
"IPR duty (high = trying hard to make ICP)"),
|
||||||
|
|
||||||
|
# --- FICM voltages -- THE 6.0 no-start metric (~48V cranking) ---
|
||||||
|
("1228", "FICM_MPWR", "V", lambda b: _u16(b) / 1000.0,
|
||||||
|
"FICM Main Power -- want ~48V cranking, <45V = suspect"),
|
||||||
|
("1229", "FICM_SYNC", "V", lambda b: _u16(b) / 1000.0,
|
||||||
|
"FICM Sync Power"),
|
||||||
|
("122A", "FICM_LPWR", "V", lambda b: _u16(b) / 1000.0,
|
||||||
|
"FICM Logic Power (~12V)"),
|
||||||
|
|
||||||
|
# --- Exhaust back pressure / oil temp (handy, not no-start critical) ---
|
||||||
|
("121C", "EBP", "psi", lambda b: _u16(b) / 100.0,
|
||||||
|
"Exhaust Back Pressure"),
|
||||||
|
("1310", "EOT", "C", lambda b: b[0] - 40,
|
||||||
|
"Engine Oil Temperature"),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# ELM327 plumbing
|
# ELM327 plumbing
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
@@ -187,6 +248,32 @@ class ELM:
|
|||||||
d = self.protocol.replace("A", "").strip()
|
d = self.protocol.replace("A", "").strip()
|
||||||
return d[:1] in ("6", "7", "8", "9")
|
return d[:1] in ("6", "7", "8", "9")
|
||||||
|
|
||||||
|
def mode22(self, pid_hex, timeout=3.0):
|
||||||
|
"""Send a Mode 22 ("read data by identifier") request.
|
||||||
|
pid_hex: 4 hex chars (e.g. '1430') -- accepts '0x', spaces, lowercase.
|
||||||
|
timeout: serial-read timeout in seconds (lower for scanning).
|
||||||
|
Returns the data bytes AFTER the '62 <hi> <lo>' echo, or None on
|
||||||
|
no-data / error / negative response (0x7F)."""
|
||||||
|
pid_hex = pid_hex.replace("0x", "").replace("0X", "").replace(" ", "").strip().upper()
|
||||||
|
if len(pid_hex) != 4 or any(c not in "0123456789ABCDEF" for c in pid_hex):
|
||||||
|
return None
|
||||||
|
lines = self.cmd("22" + pid_hex, read_timeout=timeout)
|
||||||
|
joined = "".join(lines).upper().replace(" ", "")
|
||||||
|
if any(s in joined for s in ("NODATA", "ERROR", "UNABLE", "STOPPED", "CANERROR", "BUSERROR")):
|
||||||
|
return None
|
||||||
|
data = hexbytes(lines)
|
||||||
|
p_hi = int(pid_hex[:2], 16)
|
||||||
|
p_lo = int(pid_hex[2:], 16)
|
||||||
|
# Positive response: 62 <pid_hi> <pid_lo> <data...>
|
||||||
|
for i in range(len(data) - 2):
|
||||||
|
if data[i] == 0x62 and data[i + 1] == p_hi and data[i + 2] == p_lo:
|
||||||
|
return data[i + 3:]
|
||||||
|
# Negative response: 7F 22 <nrc>
|
||||||
|
for i in range(len(data) - 1):
|
||||||
|
if data[i] == 0x7F and data[i + 1] == 0x22:
|
||||||
|
return None
|
||||||
|
return None
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
try:
|
try:
|
||||||
self.ser.close()
|
self.ser.close()
|
||||||
@@ -315,6 +402,163 @@ def live_data(elm):
|
|||||||
return rows
|
return rows
|
||||||
|
|
||||||
|
|
||||||
|
def read_ford_pids(elm, pids=None):
|
||||||
|
"""Run a batch of Ford 6.0 Mode-22 PIDs and print decoded + raw bytes.
|
||||||
|
pids: list of FORD_60_PIDS entries to query (default: all)."""
|
||||||
|
if pids is None:
|
||||||
|
pids = FORD_60_PIDS
|
||||||
|
print("\n" + "-" * 64)
|
||||||
|
print(" FORD 6.0 ENHANCED (Mode 22) -- TENTATIVE / UNVERIFIED")
|
||||||
|
print("-" * 64)
|
||||||
|
print(" PID numbers and scaling are community-sourced and NOT yet")
|
||||||
|
print(" verified on this truck. Raw bytes shown for sanity-checking.")
|
||||||
|
print(" 'no response' = wrong PID or this PCM doesn't expose it.")
|
||||||
|
print()
|
||||||
|
any_response = False
|
||||||
|
for pid, name, unit, decode, notes in pids:
|
||||||
|
raw = elm.mode22(pid)
|
||||||
|
if raw is None or len(raw) == 0:
|
||||||
|
print(f" {name:10} ({pid}) no response -- {notes}")
|
||||||
|
continue
|
||||||
|
any_response = True
|
||||||
|
raw_hex = " ".join(f"{b:02X}" for b in raw)
|
||||||
|
decoded = "(no decoder)"
|
||||||
|
if decode is not None:
|
||||||
|
try:
|
||||||
|
val = decode(raw)
|
||||||
|
decoded = f"{val:>8.2f} {unit}"
|
||||||
|
except Exception:
|
||||||
|
decoded = "(decode err)"
|
||||||
|
print(f" {name:10} ({pid}) {decoded:>14} raw=[{raw_hex}]")
|
||||||
|
if not any_response:
|
||||||
|
print("\n >> Nothing answered. Either none of these PID numbers")
|
||||||
|
print(" match this PCM, or the bus isn't accepting Mode 22 in")
|
||||||
|
print(" the current state. Try with the key in RUN and the")
|
||||||
|
print(" ECU connected (protocol negotiated above).")
|
||||||
|
|
||||||
|
|
||||||
|
def probe_pid(elm, pid_hex):
|
||||||
|
"""One-shot Mode-22 probe for manual exploration. Prints raw + a few
|
||||||
|
common decodings so you can eyeball which scaling fits."""
|
||||||
|
print("\n" + "-" * 64)
|
||||||
|
print(f" Mode-22 probe: PID {pid_hex.upper()}")
|
||||||
|
print("-" * 64)
|
||||||
|
raw = elm.mode22(pid_hex)
|
||||||
|
if raw is None:
|
||||||
|
print(" no response (wrong PID, or module doesn't expose it).")
|
||||||
|
return
|
||||||
|
raw_hex = " ".join(f"{b:02X}" for b in raw)
|
||||||
|
print(f" raw bytes : [{raw_hex}] (len={len(raw)})")
|
||||||
|
if len(raw) >= 1:
|
||||||
|
print(f" as u8 : {raw[0]} ({raw[0] * 100 / 255:.1f}% if duty)")
|
||||||
|
print(f" as temp : {raw[0] - 40} C (raw-40, OBD-II convention)")
|
||||||
|
if len(raw) >= 2:
|
||||||
|
u = (raw[0] << 8) + raw[1]
|
||||||
|
print(f" as u16 : {u} ({u/1000:.3f} V if mV, {u/100:.2f} if x100)")
|
||||||
|
if len(raw) >= 4:
|
||||||
|
u32 = (raw[0] << 24) + (raw[1] << 16) + (raw[2] << 8) + raw[3]
|
||||||
|
print(f" as u32 : {u32}")
|
||||||
|
|
||||||
|
|
||||||
|
def watch_loop(elm, seconds=20, with_ford=False):
|
||||||
|
"""Stream battery + module voltage as fast as we can for N seconds.
|
||||||
|
Designed for cranking: start it, then turn the key.
|
||||||
|
|
||||||
|
with_ford=True also streams Mode-22 FICM/ICP PIDs -- only enable once
|
||||||
|
those PIDs are verified for this PCM, otherwise each 'no response'
|
||||||
|
timeout starves the sample rate."""
|
||||||
|
stream_pids = []
|
||||||
|
if with_ford:
|
||||||
|
stream_pids = [
|
||||||
|
("1228", "FICM_M", "V", lambda b: (b[0] << 8 | b[1]) / 1000.0),
|
||||||
|
("1229", "FICM_S", "V", lambda b: (b[0] << 8 | b[1]) / 1000.0),
|
||||||
|
("122A", "FICM_L", "V", lambda b: (b[0] << 8 | b[1]) / 1000.0),
|
||||||
|
("1209", "ICP", "psi", lambda b: (b[0] << 8 | b[1])),
|
||||||
|
("120B", "IPR", "%", lambda b: round(b[0] * 100 / 255, 1)),
|
||||||
|
]
|
||||||
|
print("\n" + "=" * 64)
|
||||||
|
print(f" WATCH MODE ({seconds}s) -- Ctrl-C to stop early")
|
||||||
|
print("=" * 64)
|
||||||
|
print(" ATRV = battery V at OBD port, VPCM = PCM/module V (PID 0142).")
|
||||||
|
if with_ford:
|
||||||
|
print(" Mode-22 PIDs included -- '-' means no response.")
|
||||||
|
print(" TURN KEY TO START NOW (or whenever you're ready).\n")
|
||||||
|
|
||||||
|
headers = ["t(s)", "ATRV", "VPCM"] + [f"{n}({u})" for _, n, u, _ in stream_pids]
|
||||||
|
print(" " + " ".join(f"{h:>8}" for h in headers))
|
||||||
|
print(" " + " ".join("-" * 8 for _ in headers))
|
||||||
|
|
||||||
|
start = time.time()
|
||||||
|
end = start + seconds
|
||||||
|
try:
|
||||||
|
while time.time() < end:
|
||||||
|
t = time.time() - start
|
||||||
|
atrv = " ".join(elm.cmd("ATRV", read_timeout=1.0)).replace("V", "").strip()
|
||||||
|
vpcm_raw = read_pid(elm, "42", 2)
|
||||||
|
vpcm = "?" if vpcm_raw is None else f"{((vpcm_raw[0] << 8) + vpcm_raw[1]) / 1000:.2f}"
|
||||||
|
row = [f"{t:6.2f}", atrv or "?", vpcm]
|
||||||
|
for pid, _, _, decode in stream_pids:
|
||||||
|
raw = elm.mode22(pid)
|
||||||
|
if raw is None or len(raw) < 2:
|
||||||
|
row.append("-")
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
row.append(f"{decode(raw):.2f}")
|
||||||
|
except Exception:
|
||||||
|
row.append("err")
|
||||||
|
print(" " + " ".join(f"{c:>8}" for c in row), flush=True)
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
print("\n (stopped)")
|
||||||
|
|
||||||
|
|
||||||
|
def scan_mode22(elm, start, end, log_path=None):
|
||||||
|
"""Brute-force scan Mode-22 PIDs over [start, end] (inclusive, ints).
|
||||||
|
Logs every PID that returns data. Safe: Mode 22 is read-only by
|
||||||
|
definition. Writes hits to log_path as it goes so we don't lose them
|
||||||
|
if the bus drops mid-scan."""
|
||||||
|
# Tune ELM for fast scanning: max adaptive timing, short response wait
|
||||||
|
elm.cmd("ATAT2")
|
||||||
|
elm.cmd("ATST19") # 25 * 4ms = 100ms ECU response wait
|
||||||
|
total = end - start + 1
|
||||||
|
print("\n" + "=" * 64)
|
||||||
|
print(f" SCAN Mode-22 PIDs {start:04X} - {end:04X} ({total} PIDs)")
|
||||||
|
print("=" * 64)
|
||||||
|
print(f" Logging hits to: {log_path}" if log_path else " (no log file)")
|
||||||
|
print(" Safe: Mode 22 is read-only. Will print every PID that answers.\n")
|
||||||
|
|
||||||
|
if log_path:
|
||||||
|
with open(log_path, "w") as f:
|
||||||
|
f.write(f"# Mode-22 scan {start:04X}-{end:04X}\n")
|
||||||
|
f.write("# pid_hex len raw_bytes\n")
|
||||||
|
|
||||||
|
hits = 0
|
||||||
|
t0 = time.time()
|
||||||
|
for i, pid in enumerate(range(start, end + 1)):
|
||||||
|
pid_hex = f"{pid:04X}"
|
||||||
|
raw = elm.mode22(pid_hex, timeout=0.6)
|
||||||
|
if raw is not None and len(raw) > 0:
|
||||||
|
raw_hex = " ".join(f"{b:02X}" for b in raw)
|
||||||
|
line = f" HIT {pid_hex} len={len(raw):2d} raw=[{raw_hex}]"
|
||||||
|
print(line, flush=True)
|
||||||
|
hits += 1
|
||||||
|
if log_path:
|
||||||
|
with open(log_path, "a") as f:
|
||||||
|
f.write(f"{pid_hex} {len(raw)} {raw_hex}\n")
|
||||||
|
if (i + 1) % 100 == 0:
|
||||||
|
elapsed = time.time() - t0
|
||||||
|
rate = (i + 1) / elapsed if elapsed > 0 else 0
|
||||||
|
remain = (total - i - 1) / rate if rate > 0 else 0
|
||||||
|
print(f" ... {i+1}/{total} scanned in {elapsed:.0f}s ({rate:.1f}/s), "
|
||||||
|
f"~{remain:.0f}s remaining, {hits} hits so far", flush=True)
|
||||||
|
|
||||||
|
elapsed = time.time() - t0
|
||||||
|
print(f"\n Done. {hits} responding PIDs in {elapsed:.0f}s.")
|
||||||
|
# Restore default-ish timing
|
||||||
|
elm.cmd("ATAT1")
|
||||||
|
elm.cmd("ATST32")
|
||||||
|
return hits
|
||||||
|
|
||||||
|
|
||||||
def clear_codes(elm):
|
def clear_codes(elm):
|
||||||
"""OBD-II mode 04: clear DTCs + freeze frame, reset monitors.
|
"""OBD-II mode 04: clear DTCs + freeze frame, reset monitors.
|
||||||
Returns True if the ECU acknowledged ('44')."""
|
Returns True if the ECU acknowledged ('44')."""
|
||||||
@@ -348,12 +592,79 @@ def find_ports():
|
|||||||
# Main
|
# Main
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
def main():
|
def main():
|
||||||
args = [a for a in sys.argv[1:] if not a.startswith("-")]
|
raw_args = sys.argv[1:]
|
||||||
verbose = "-v" in sys.argv or "--verbose" in sys.argv
|
verbose = "-v" in raw_args or "--verbose" in raw_args
|
||||||
do_clear = "--clear" in sys.argv
|
do_clear = "--clear" in raw_args
|
||||||
|
do_ford = "--ford" in raw_args or "--diesel" in raw_args
|
||||||
|
|
||||||
port = args[0] if len(args) >= 1 else None
|
# --pid XXXX : one-shot Mode-22 probe of an arbitrary 16-bit PID
|
||||||
baud = int(args[1]) if len(args) >= 2 else 38400
|
probe = None
|
||||||
|
if "--pid" in raw_args:
|
||||||
|
i = raw_args.index("--pid")
|
||||||
|
if i + 1 < len(raw_args):
|
||||||
|
probe = raw_args[i + 1]
|
||||||
|
|
||||||
|
# --watch [N] : stream voltages + FICM/ICP PIDs for N seconds (default 20)
|
||||||
|
do_watch = "--watch" in raw_args
|
||||||
|
watch_secs = 20
|
||||||
|
if do_watch:
|
||||||
|
i = raw_args.index("--watch")
|
||||||
|
if i + 1 < len(raw_args):
|
||||||
|
try:
|
||||||
|
watch_secs = int(raw_args[i + 1])
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# --scan START-END : brute-force scan Mode-22 PIDs. Default 1000-14FF.
|
||||||
|
do_scan = "--scan" in raw_args
|
||||||
|
scan_start, scan_end = 0x1000, 0x14FF
|
||||||
|
scan_log = None
|
||||||
|
if do_scan:
|
||||||
|
i = raw_args.index("--scan")
|
||||||
|
if i + 1 < len(raw_args) and "-" in raw_args[i + 1] and not raw_args[i + 1].startswith("-"):
|
||||||
|
try:
|
||||||
|
a, b = raw_args[i + 1].split("-", 1)
|
||||||
|
scan_start, scan_end = int(a, 16), int(b, 16)
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
if "--scan-log" in raw_args:
|
||||||
|
i = raw_args.index("--scan-log")
|
||||||
|
if i + 1 < len(raw_args):
|
||||||
|
scan_log = raw_args[i + 1]
|
||||||
|
|
||||||
|
# Positional args: [port] [baud] -- skip flags and their values
|
||||||
|
pos = []
|
||||||
|
i = 0
|
||||||
|
while i < len(raw_args):
|
||||||
|
a = raw_args[i]
|
||||||
|
if a == "--pid" and i + 1 < len(raw_args):
|
||||||
|
i += 2 # always consumes next arg
|
||||||
|
continue
|
||||||
|
if a == "--scan-log" and i + 1 < len(raw_args):
|
||||||
|
i += 2
|
||||||
|
continue
|
||||||
|
if a == "--watch":
|
||||||
|
if i + 1 < len(raw_args) and raw_args[i + 1].isdigit():
|
||||||
|
i += 2
|
||||||
|
else:
|
||||||
|
i += 1
|
||||||
|
continue
|
||||||
|
if a == "--scan":
|
||||||
|
# Consume next arg only if it looks like a range "AAAA-BBBB"
|
||||||
|
if (i + 1 < len(raw_args) and "-" in raw_args[i + 1]
|
||||||
|
and not raw_args[i + 1].startswith("-")):
|
||||||
|
i += 2
|
||||||
|
else:
|
||||||
|
i += 1
|
||||||
|
continue
|
||||||
|
if a.startswith("-"):
|
||||||
|
i += 1
|
||||||
|
continue
|
||||||
|
pos.append(a)
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
port = pos[0] if len(pos) >= 1 else None
|
||||||
|
baud = int(pos[1]) if len(pos) >= 2 else 38400
|
||||||
|
|
||||||
print("=" * 64)
|
print("=" * 64)
|
||||||
print(" OBD-II Code Reader - ELM327 / 6.0 Power Stroke triage")
|
print(" OBD-II Code Reader - ELM327 / 6.0 Power Stroke triage")
|
||||||
@@ -431,6 +742,22 @@ def main():
|
|||||||
for label, val in live_data(elm):
|
for label, val in live_data(elm):
|
||||||
print(f" {label:22} {val}")
|
print(f" {label:22} {val}")
|
||||||
|
|
||||||
|
# ---- Ford 6.0 enhanced PIDs (Mode 22) ----
|
||||||
|
if do_ford:
|
||||||
|
read_ford_pids(elm)
|
||||||
|
|
||||||
|
# ---- One-shot manual Mode-22 probe ----
|
||||||
|
if probe:
|
||||||
|
probe_pid(elm, probe)
|
||||||
|
|
||||||
|
# ---- Watch mode: stream voltages for N seconds ----
|
||||||
|
if do_watch:
|
||||||
|
watch_loop(elm, seconds=watch_secs)
|
||||||
|
|
||||||
|
# ---- Brute-force Mode-22 scan ----
|
||||||
|
if do_scan:
|
||||||
|
scan_mode22(elm, scan_start, scan_end, log_path=scan_log)
|
||||||
|
|
||||||
# ---- Optional clear (mode 04), only with --clear ----
|
# ---- Optional clear (mode 04), only with --clear ----
|
||||||
if do_clear:
|
if do_clear:
|
||||||
run_clear(elm, all_codes)
|
run_clear(elm, all_codes)
|
||||||
|
|||||||
Reference in New Issue
Block a user