code wiki / (root) / nx_obd_dtc.nx

nx_obd_dtc.nx source

↩ module page · 107 lines · 4649 B

1// nx_obd_dtc.nx -- OBD-II diagnostic-trouble-code decoder (the AUTOMOTIVE 2// vehicle-obd capability). Decodes a 5-char DTC (e.g. "P0301") into its 3// structure -- system / SAE-generic-vs-manufacturer / subsystem / fault -- then 4// CLASSIFIES severity and routes it to the platform action rung (DIY vs pro). 5// 6// Operator (2026-06-23): "cars" -- the first-listed maintenance domain; the CIQ 7// top-build vehicle-obd-diagnostics (beat FIXD). 8// 9// THE EXCEED (on-thesis): FIXD reads the code + shows a generic blurb. We decode 10// the structure, classify severity by system+subsystem, and turn the cryptic 11// code into a routed ACTION (monitor / fix-DIY / fix-pro) via nx_maint_action -- 12// and the platform's INDEPENDENT physics (battery via electrical, oil/brakes via 13// consumable, bearings via rotating, fluids via fluid-seal) is the trust layer 14// that cross-checks the car's self-report. The OBD code is one ingest, not gospel. 15// 16// HONEST: the DTC STRUCTURE is the SAE J2012 standard (decoded exactly). The 17// severity-by-subsystem mapping is a reasoned starter heuristic (real per-code 18// severity varies; the full code DB is a data-layer follow-up #11). 19// 20// NEVER-BRICK (#26): decodes a string; no syscalls, no vehicle writes, no code 21// clearing. Read-only by construction. 22// 23// genealogy_id: project-maintenance-platform-sclass-2026-06-23 (automotive / vehicle-obd) 24// license_tier: ORIGINAL 25 26import "nx_maint_action.nx" // NX_HEALTH_* + NX_ACT_* 27 28const NX_OBD_SYS_POWERTRAIN: i64 = 0 // 'P' 29const NX_OBD_SYS_CHASSIS: i64 = 1 // 'C' 30const NX_OBD_SYS_BODY: i64 = 2 // 'B' 31const NX_OBD_SYS_NETWORK: i64 = 3 // 'U' 32const NX_OBD_SYS_N: i64 = 4 33 34struct ObdDtc { 35 system: i64, // NX_OBD_SYS_* 36 is_generic: i64, // 1 = SAE generic, 0 = manufacturer-specific 37 subsystem: i64, // 3rd hex digit (0..15) 38 fault_num: i64, // last two hex digits (0..255) 39 severity: i64, // NX_HEALTH_* 40 action: i64, // NX_ACT_* 41} 42 43// ascii hex char -> value 0..15, or -1 if not a hex digit. 44func obd_hex(c: i64) -> i64 { 45 if c >= 48 { if c <= 57 { return c - 48 } } // '0'..'9' 46 if c >= 65 { if c <= 70 { return c - 65 + 10 } } // 'A'..'F' 47 return 0 - 1 48} 49 50// severity by system + powertrain subsystem (reasoned starter heuristic). 51func obd_severity(sys: i64, sub: i64) -> i64 { 52 if sys == NX_OBD_SYS_NETWORK { return NX_HEALTH_URGENT } // lost module comms 53 if sys == NX_OBD_SYS_CHASSIS { return NX_HEALTH_DEGRADED } // ABS / brakes / steering 54 if sys == NX_OBD_SYS_BODY { return NX_HEALTH_WATCH } 55 // powertrain: 56 if sub == 3 { return NX_HEALTH_DEGRADED } // ignition / misfire (cat damage) 57 if sub == 7 { return NX_HEALTH_DEGRADED } // transmission 58 if sub == 8 { return NX_HEALTH_DEGRADED } // transmission 59 return NX_HEALTH_WATCH // fuel/air, emissions, speed, computer 60} 61 62// recommended action by system + powertrain subsystem. 63func obd_action(sys: i64, sub: i64) -> i64 { 64 if sys == NX_OBD_SYS_NETWORK { return NX_ACT_FIX_PRO } 65 if sys == NX_OBD_SYS_CHASSIS { return NX_ACT_FIX_PRO } // brakes/ABS = pro 66 if sys == NX_OBD_SYS_BODY { return NX_ACT_MONITOR } 67 // powertrain: 68 if sub == 3 { return NX_ACT_FIX_DIY } // misfire: plugs / coils, common DIY 69 if sub == 4 { return NX_ACT_FIX_DIY } // emissions: gas cap / EVAP, common DIY 70 return NX_ACT_FIX_PRO // fuel/air sensors, transmission = pro 71} 72 73// Decode a NUL-terminated 5-char DTC -> *out. Returns 1 if valid, 0 if malformed. 74func nx_obd_decode(dtc: *u8, out: *ObdDtc) -> i64 { 75 out.system = 0 76 out.is_generic = 0 77 out.subsystem = 0 78 out.fault_num = 0 79 out.severity = NX_HEALTH_UNKNOWN 80 out.action = NX_ACT_NONE 81 82 let c0: i64 = dtc[0] 83 var sys: i64 = 0 - 1 84 if c0 == 80 { sys = NX_OBD_SYS_POWERTRAIN } // 'P' 85 if c0 == 67 { sys = NX_OBD_SYS_CHASSIS } // 'C' 86 if c0 == 66 { sys = NX_OBD_SYS_BODY } // 'B' 87 if c0 == 85 { sys = NX_OBD_SYS_NETWORK } // 'U' 88 if sys < 0 { return 0 } 89 90 let d1: i64 = obd_hex(dtc[1]) 91 let d2: i64 = obd_hex(dtc[2]) 92 let d3: i64 = obd_hex(dtc[3]) 93 let d4: i64 = obd_hex(dtc[4]) 94 if d1 < 0 { return 0 } 95 if d2 < 0 { return 0 } 96 if d3 < 0 { return 0 } 97 if d4 < 0 { return 0 } 98 if dtc[5] != (0 as u8) { return 0 } // exactly 5 chars 99 100 out.system = sys 101 if d1 == 1 { out.is_generic = 0 } else { out.is_generic = 1 } // digit 1 = mfg (simplified) 102 out.subsystem = d2 103 out.fault_num = d3 * 16 + d4 104 out.severity = obd_severity(sys, d2) 105 out.action = obd_action(sys, d2) 106 return 1 107}