in part 1 of this series, i covered the basics for how to interface with a vehicle bus using an inexpensive USB or Bluetooth ELM327-based scan tool. in part 2 below, i’ll go over how to actually use that hardware interface to collect and analyze data with the intention of discovering how to interact with the vehicle in some specific way.
for my own first project, i wanted to know how to intercept the steering wheel radio remote-control button press events. i replaced my factory radio with a Motorola Xoom 10″ Android tablet in order to have a bigger and better GPS (and OBDII app, and better entertainment options, etc). however, touching the screen precisely while driving can be difficult (especially when bouncing around off-road). hence why i wanted the factory steering wheel buttons to still control volume, track, play/pause, etc. i’ll use this goal as an example to walk through navigating the bus data.
(the Android source code for the above is available on my GitHub: http://github.com/theksmith/Steering-Wheel-Interface)
what you’ll need
- a working vehicle bus hardware interface (the scan tool, see part 1)
- laptop or tablet with serial terminal application capable of logging to a file
- Microsoft Excel (or Apple Numbers, a Google Docs spreadsheet, MS Access, etc.)
task 1: get a baseline
the first task is to gather some baseline data – i.e. what msgs are flying around the bus when your are NOT doing whatever particular interaction you are looking to find the msg for. i tested and found that with the vehicle not running, i could still use the steering wheel buttons to control the radio. that made things a little simpler since i would be able to gather all my sample data with the engine off and the key in “run” (there are way less msgs on the bus when the vehicle is not running).
- issue the following commands (one at a time): ATL1, ATH1, ATS1, ATAL
- be sure your serial terminal app is set to log to a text file.
- issue ATMA to have the scan tool start reporting all of the bus msgs it sees.
- just press enter after a minute to stop the stream of data.
task 2: log data from the event/interaction in question
the next task is to log the bus msgs when the action you are looking for occurs. this could be when something like when the radio changes tracks, when you press the sunroof close button, etc. i wanted to know the msg for each steering wheel button. i did a data collection run for each of the 6 buttons separately. for each run, i would press the same button 5 times, trying to space the presses evenly about 1 second apart. i wanted to create some sort of pattern that would hopefully stand out in the data stream.
- repeat the steps from the previous task, while causing the event in question (or allowing it to happen if you have no control over it).
task 3: analyze the data
now you’re ready to analyze the data you collected in order to find just the bus msgs you care about. i used Excel, but you could go with any spreadsheet or database tool that you’re familiar with. the complete MS Excel spreadsheet for all the examples below can be downloaded here: 2003WJ-PCIBus-SWButtonData.xls
- paste the data from each of your baseline/test runs into separate sheets of the spreadsheet. all the bus msgs should be in the first column. add a column header called “msg“.
- on the sheet with the baseline data, add a second column with the header “count“. just fill this column with a “1” for every row.
- still on the baseline data sheet, create a pivot table that sums the count for each msg. this is just an easy way to give you a list of distinct msgs.
- now go to the sheet with your first sample data run. again use “msg” for the first column header and create a second column filled with 1′s called “count“.
- for the third column add the header “not in baseline“. for the value of every row, specify a function that places the msg from the first column into this column ONLY if that msg is not in the baseline list. the function might look something like this (my baseline data pivot table is in the sheet named “baseline”, on column “D”):
=IF(ISNA(MATCH(A2,baseline!D:D,0)), A2, “”)
you should end up with something like this, where the third column is a bunch of blank cells with only a few having msgs in them:
- now create another pivot table similar to the previous. however, for this sample run sheet, use the “not in baseline” and “count” columns. this give you a list of distinct bus msgs that occurred during your test that were NOT duplicates of msgs from the baseline run. it also tells you how many times the msg occurred. you’ve basically removed the “background noise” from your data sample. if you’re after something really simple, this might be nearly the end of your journey. for my project, i needed to compare several of the buttons to really understand what was going on.
- in the previous img, notice i had several distinct bus msgs that were not in my baseline. i had pressed the “up” button on the right side of the steering wheel 5 times for this test run, yet none of the distinct “not-in-baseline” msgs happened exactly 5 times! so i went ahead and repeated these steps for the other 2 buttons on the right side. below are the pivot tables i generated from each of the test runs.
- now for some basic deductive reasoning and a little intuition. above i’ve highlighted in red all of the msgs that occurred at least 5 times – i knew that i definitely pressed the buttons distinctly and hard enough that they should have registered for each press, but perhaps they were sending multiple msgs if i held them down just a bit too long? next i crossed out any msgs duplicated between test runs (the 3 different buttons can’t be producing the exact same msg).
- this left me with one unique msg to look at in 2 of the runs, and 2 unique msgs in the other run. however with this little data left, it was easy to spot a pattern – all 3 runs had a msg that was sent to bus ID 11. i guessed that 11 must be the radio’s ID, and the 3 distinct msgs sent it must be my 3 buttons on the right side of the steering wheel.
task 4: test your hypothesis
- you might next want to do a confirmation test, monitoring only the ID that you believe is sending the msg (ATMT#), or only the ID that the msg is destined for (ATMR#).
based on the deductions above, i thought i had the right 3 bus msgs. but why didn’t they occur exactly the number of times i pressed the buttons? i decided to perform another test, but only monitor ID 11 (the radio). hopefully my sample data would be small enough to look at directly and spot a pattern. again i tested each button separately, this time issuing the command “ATMR11” to only see msgs destined for the radio. i pressed each button 5 times again, about a second apart. this time i was extremely deliberate and consistent in how i pressed each button. check out the results:
i think what is happening is a side-effect of mechanical switches known as contact bounce or chatter. i later confirmed that holding down a switch sends regular timed repeats of the msg, whereas a quick press can send from 1 to 3 msgs in quick succession. this helps confirm my conclusion of bounce.
- another way to test your conclusions is to send the msg into the bus and physically verify the vehicle responds as expected. this would work for actions like locking/unlocking the doors, etc. i tried to replicate the “up” button on the right side of the steering wheel. if i was sending the right msg, then i would hear the radio increase volume (and see the display indicate the new level). the “up” button msg that i had monitored was “3D 11 04 00 C3“, so i used the the command “ATSH 3D 11 04” and then issued “00 C3“. sure enough, it worked!
for all of the examples so far i’ve been working with the a SAE J1850 type bus. the msg structure and sample commands should work with most other protocols except CAN-Bus. you may have already inferred part of the msg structure:
3 byte header + up to 7 data bytes + checksum
the ELM327 reports the msgs in hex, so they look like this (where PP = priority, RR = receiver ID, TT = transmitter ID, DD = data, CC = checksum):
PP RR TT DD DD DD DD DD DD DD CC
the msg structure for CAN is just a bit different, and the ELM327 has an entire set of commands specifically for working that protocol. check out the datasheet for complete info on msg structures and all the possible commands.
- walkthrough of a much more complex data gathering/analysis exercise (CAN-Bus, Mini Cooper)
you can probably surmise by now that vehicle bus hacking can prove non-trivial. it could be much more complex than my relatively straight-forward example. i’ve read that some manufactures encode longer data across multiple standard msgs using custom schemes. deciphering something like that could prove impractical. deciphering constantly changing data from a running vehicle is also challenging.
there are professional data collection and analysis tools/software, but you could also write your own. creating a simple application that time-stamps each msg in the log file would be a good start to help find patterns. adding the capability to graph msg frequency might be useful as well.
i came away from this project frustrated that the majority of data moving about in our vehicles is proprietary. it’s just another example of how society is moving away from a fix-it culture. if this type of information remains confidential, there is no hope of an individual or small repair shop fixing certain types of vehicle problems. we’re not far from a future where cars are as throw-away as iPads. one day i’ll have a Jeep that has to go to the Fiat/Chrysler Genius Bar. there i’ll find out that repairing whatever minor issue it has is too costly because everything is glued together, and that i’m better off buying the new model.
part 1 of this series: http://theksmith.com/technology/hack-vehicle-bus-cheap-easy-part-1/