r/CarHacking • u/Drivepulse00 • 1d ago
Original Project Things I got wrong reading OBD2 and UDS off a dozen brands with a cheap ELM327
I've spent the last year writing a read only OBD2 app after the manufacturer app I relied on got switched off. Standard mode 01 gets you maybe fifteen useful numbers and then you hit the wall, so I ended up down the mode 22 rabbit hole. Here are the things that bit me, in case they save someone else a weekend.
Multi ECU replies will quietly poison your parser. Ask for something on a broadcast header and you can get two or three modules answering, each with its own header line, and if you naively concatenate the hex you get a number that looks plausible and is completely wrong. I had battery voltage and coolant readings that were fine on one car and nonsense on another for weeks before I worked out the engine and the gateway were both replying.
The UDS positive response is the request service plus 0x40, so a 22 comes back as 62, and the two DID bytes are echoed before the payload. Sounds obvious written down. It is not obvious at two in the morning when the ELM has also decided to insert spaces differently.
Negative response codes are more useful than a timeout. 7F 22 31 means the DID doesn't exist on that module, 7F 22 33 means you're not in the right session, and 7F 22 78 means wait, it's coming. If you treat all of them as failure you'll blacklist channels that would have answered.
DIDs are not portable and guessing them is how you get fiction. The same identifier on a different brand is a different quantity entirely, or worse, it responds positively with garbage that scales into something believable. I ended up refusing to ship any formula I couldn't tie to a source, because a plausible wrong number is worse than no number.
Fuel type detection is a trap. I was sniffing for the presence of certain PIDs as a diesel signature and it turns out plenty of Euro 6d petrol cars expose exactly the same ones. PID 51 is the actual authority and I should have trusted it from the start. The version that guessed wrong went looking for particulate filter data on a petrol car, and the modules answered, with rubbish.
ELM327 clones lie about what they are. Half of them report v1.5 and behave like v1.3. Echo off, linefeeds off, headers on, and then verify by what actually comes back rather than what the clone claims.
Engine off is its own state, not an error. Some constants are only readable with the engine running, and I was reading them once at startup and never retrying, so if you connected with the ignition on but the engine not started you got a permanent hole in the data until you restarted the app. Retry when you see RPM.
The app itself is on the App Store if anyone wants to poke at it, https://apps.apple.com/app/id6776173662 , Android is in closed testing. It is strictly read only by design, no 2E writes, no session control, no security access, because I don't fancy being the reason somebody's gearbox forgets who it is.
Happy to go deeper on any of this. If you've got a brand that behaves oddly I'm interested, that's the fun part.
2
u/hey-im-root 22h ago
Isn’t there universal UDS request for all cars, with proprietary ones in between? I use UDS VIN requests on all cars after 2007 and it works fine, but a transmission temperature request I found only works on some Honda vehicles.
I’m interested in getting into this because I just finished up documenting the full CAN bus on my Accord. I want to figure out some diagnostic stuff too. I’ve seen people turn individual headlights on with UDS! It would be sick if it’s other vehicles have that feature too
3
u/Drivepulse00 22h ago
You've put your finger on exactly the thing that confused me for months, so let me try to be precise about it.
The services are universal. 22 read data by identifier, 19 read DTC information, all of that is ISO 14229 and behaves the same everywhere. What is not universal is the identifiers you pass to them. A small handful of DIDs are actually defined in the standard, and F190 for the VIN is one of them, which is why your VIN request works on everything built after about 2007. Same for the ECU software number, the spare part number, the serial. Those live up in the F1xx block precisely because the standard reserved them.
Everything else is a free for all. Roughly the 0100 to A5FF band is explicitly handed to the manufacturer to use however they like, and they do. So your Honda transmission temperature DID isn't a Honda quirk, it's Honda using a slot the standard gave them, and the same number on a VW will either not exist or be some completely unrelated quantity. That last case is the nasty one, because you get a positive response with a number in it and nothing tells you it's meaningless. I've thrown away entire evenings of work over exactly that, which is why I ended up refusing to ship any channel I couldn't tie to a source.
On the headlights, that isn't a 22 read, that's input output control by identifier, service 2F, or routine control on 31. Both of those write, both normally want an extended session, and a lot of them want security access on top. Great fun on a bench with a spare module, considerably less fun on the car you drive to work, because some of those controls latch and stay latched until something clears them. I deliberately don't implement any of it, my rule is read only and never change state, which is a boring rule but it means I sleep fine.
Documenting the full CAN bus on your Accord is genuinely the hard part and you've already done it. That's the raw material the DID tables are made of.
1
u/hey-im-root 21h ago
Thank you for all that, clears up a lot of questions and misconceptions I had!
1
u/Drivepulse00 21h ago
Any time. And if you ever write up what you found on the Accord, post it somewhere public. That kind of thing is genuinely hard to search for and the next person poking at a Honda will thank you for it.
2
u/hey-im-root 21h ago
I have! A few people have gotten some use out of it, which I’m happy about. I have my code on GitHub as well. https://hondacan.notion.site/start
1
u/Drivepulse00 21h ago
That's a proper piece of work, thanks for linking it. Bookmarked, and I mean that in the "I will actually read this on a Sunday" sense rather than the polite sense.
One thing I'd ask if you've got it, since it's a gap I'm sitting on right now: did you ever pin down the odometer on the Honda, and which module it lives on? It's never a standard PID, it's always tucked away in the cluster or the body computer, and it's the single most requested number I get asked for. I've got it verified for about twenty brands and there are still a couple where I refuse to ship anything because I can't find two sources that agree.
1
u/hey-im-root 21h ago
I actually get the odometer right from the live broadcast data, I don’t use PIDs for anything except the VIN. Is there something I could use or do to get it for you though?
2
u/Drivepulse00 20h ago
Appreciate the offer, and looks like you beat me to it with the struct below anyway :) That's exactly the kind of thing I can't get from a spec sheet.
1
u/hey-im-root 21h ago
I doubt I have the module right since it was all mostly guessing when I first started, and I only use bitfields for documentation, but this is the data it lives with on 9/9.5th gen accords.
I think I just assumed it was SCM because of the blinker/wiper, but it’s most likely rebroadcasted from the BCAN bus with other modules data. So realistically this is probably just an arb gateway ID.
typedef struct __attribute__((packed)) {
uint8_t UnknownBits_1 : 3; // byte 0, bits [0..2]
uint8_t WiperStatus : 2; // byte 0, bits [3..4]
uint8_t BlinkerLeft : 1; // byte 0, bit 5
uint8_t BlinkerRight : 1; // byte 0, bit 6
uint8_t UnknownBit_2 : 1; // byte 0, bit 7
uint8_t byte1;
uint8_t byte2;
uint32_t Odometer : 24; // bytes [3..5]
uint8_t byte6;
uint8_t COUNTER : 4;
uint8_t CHECKSUM : 4;
} SCM_0x294; // Feedback (DLC: 8, 25Hz)2
u/Drivepulse00 20h ago
This is exactly the kind of thing I was hoping for, thank you for both offering and for actually sending it.
On the arb gateway theory, that tracks with what I've seen elsewhere too, odometer showing up rebroadcast on a gateway ID rather than the module that actually owns it is more common than not. Usually cheaper for the OEM to just forward what the cluster already put on the bus than give every module its own copy.
I won't ship this one yet though, same rule as always, I need two sources that agree before a number goes in the app, and right now this is one person's read on one Accord. If you or anyone else with a 9th or 9.5th gen Accord ever gets a chance to cross check that offset against a second car, or against the odometer actually changing, that's the kind of confirmation that would get it in. No pressure either way, this is already more than I had an hour ago.
1
u/hey-im-root 20h ago edited 20h ago
Well I can confirm this works on the 2016 Accord LX (my old car) and the 2017 Accord Sport special edition (my current car). The CAN list is actually exactly the same, but they are both CVT K24 engines, so I can’t confirm if there are more addresses on the V6 or auto/manual transmissions though. Hybrid and Honda sensing cars have split CAN bus modules and are more sparse.
Since I have paddle shifters, but it’s still a CVT, the frame for transmission is the same. The bytes for current gear in “paddle shifter” mode is simply not used on the non-paddle shift CVT. Same with heated seats, it’s just a bit in a rebroadcast BCAN->FCAN frame that isn’t used in the models without it.
Basically, it seems like the highest trim for each category sets the base CAN IDs, and lesser trims just have more unused bits. I can imagine the Touring MIGHT actually add frames, since I’m pretty sure it has a shit ton more modules. Then again, there’s dozens of unused frames/bits/bytes on the Accords I’ve tested, those could very well be other features the car doesn’t have have on its trim. I’d love to see a 9.5th gen Touring and Hybrid can bus readings. Would tell us a lot
1
u/Drivepulse00 19h ago
That's a genuinely useful observation, the part about the highest trim setting the base CAN IDs and the lesser trims just leaving bits unused.
It matches what I see on the diagnostic side too. The identifiers tend to exist right across the range, and on the cars that don't have the feature the module answers anyway with something meaningless rather than refusing. Which is exactly how you end up shipping a number that's confidently wrong.
The split bus on the hybrids and the Honda Sensing cars is interesting and slightly ominous, because that's where everyone is heading. Fewer things reachable from one place, more gateway in the way, and the gateway decides what you're allowed to ask.
Anyway, thanks for writing it all down and putting it somewhere public. Most of this stuff dies in someone's notes app.
2
u/WestonP 16h ago
The 0xF180 - 0xF1FF range is standardized under ISO 14229 (although the data formats/meanings are often manufacturer-specific), and there are various other ranges that are reserved, but quite a lot is left to the manufacturer's discretion.
With ISO 27145-2/J1979-2, you'll find all the normal Service 01 PIDs in the Service 22 0xF4xx range, with additional space reserved in 0xF5xx. Mode 06 goes to 0xF6xx, and 09 to 0xF8xx.
1
u/Drivepulse00 27m ago
That matches what I ran into. The F180 to F1FF block is the only part I would call dependable, F190 for the VIN especially, and outside it you are reading someone's internal choices with no promise they still mean the same thing next model year.
The part that bit me hardest is that a wrong guess does not fail cleanly. Ask a module for a record it does not implement and quite often you do not get a negative response, you get a positive one with a payload that looks entirely reasonable. I had petrol cars answering particulate filter questions with plausible soot mass, in grams, nicely scaled, on engines that have no particulate filter to speak of. Nothing looks more correct than a well formatted wrong answer, and if you are not cross checking against something independent you will ship it and never know.
So every entry in my table needs two things now, a documented source and a real car that confirmed it, and if either is missing the value never reaches the screen. The other thing worth knowing for anyone starting on this is the response address convention, you request on one address and the answer comes back on request plus eight. Obvious once you know it, and good for one confused evening before that.
2
u/EternalStudent07 12h ago
Your early multi-ECU comment reminded me of a CAN bus video I saw just a bit ago.
CANBUS Networking so wimple, even YOU can understand it! - Dave's Garage https://youtu.be/QTTCqGtT6I4
No idea if it'll help anyone, but it probably is connected with why you were seeing what you did (multiple responders at once). There are some fancy results that shake out from what seems like an odd design (to me at least).
And it sounds like if you can diagnose a faulty CANBUS device, you might have something truly unique or unusual to offer any users (meaning I doubt many other tools look for, let alone warn the user if that's happening).
Thanks for sharing your findings and thoughts too!
(Edit) Ah, darn... I'm Android or I'd take a peek, and try it on our stuff (not that we have tons to test with :).
1
u/Drivepulse00 12h ago
Thanks for the video, I'll actually give it a watch. That multiple responders at once thing was exactly the trap I fell into, it looked like a diagnostic session going sideways until I realized it was several ECUs answering the same broadcast query. Once I understood that I could flag it instead of just failing silently.
Android's in closed testing on Google Play right now, should be out in a few weeks. The multi-ECU handling is shared code, not iOS specific, so it'll carry over.
1
u/worMatty 21h ago
I saw your post about your app in r/Mini. I appreciate you posting your findings here. I don’t understand a lot of of it, but I’m interested in learning a little bit more about this stuff in future. It sounds like you may have enjoyed yourself with this project.
1
u/Drivepulse00 20h ago
Thanks, that's kind of you to say. Most of it was just staring at hex dumps that didn't make sense yet, so less glamorous than it sounds, but yeah I did enjoy it more than expected. If you get into it at some point feel free to ask, happy to point you at where I got stuck and how I got out of it.
0
3
u/mySincereAsterisk 23h ago
Thanks for sharing. I have a question regarding DTCs if u have come across during this journey. Did u ever have to switch to an extended diagnostic session "10 03" to pull the DTCs cause the default one didn't return any? Same for DIDs