Skip to content

Instantly share code, notes, and snippets.

What would you like to do?
Notes from hacking the ODB2 protocols on my 2005 Saturn Ion

Hacking my 2005 Saturn Ion


I spent some time over the holiday break playing around with the on-board diagnostic port on my Saturn Ion. There are two communiction busses in play, and the first is the low speed SAW J1850 VPW that seems to handle the little ancillary things. The most interesting being the instrument cluster lights.

I'll be diving into the higher speed CAN data eventually (probably when it's not -29°C here, but for now here's the list of what I've found. I'd like to think I did an exhaustive search of all the things that can be poked (trunk, signals, heating, radio) but I have the base trim level that year, so there may be other bits in the premium model I'm just not able to find.


For those not used to the headers in SAW J1850, the three bytes are broken down like so:


While reading the "Endpoints" as I've called them here, you should probably keep the priority, use the destination, and put whatever you want in the origin. I believe the standard is to use 0xF1 for a diagnostic reader.

Instrument Cluster Startup:

The instrument cluster always has power and has two modes it can be turned on either to simply show the trip and milage, or for you to set the speedometer, tach, etc. In the second mode however, if a paired vehicle identification number is not provided it will show "PWR STR" and "Service Vehicle". The airbag and parking break lights will also stay lit. You'll have to send the matching ASCII encoded VIN to the cluster before it will properly show milage and get the odometer working.

Endpoint: 28 FF 40

06 XX

XX = Power on mode

	03 = Sleep mode
	06 = Lights on, no control possible
	07 = Lights on, control possible. Will error without VIN check
	08 = Reset indicators, keep stepper motors ready. Resets VIN error state
	09 = No idea, but it cycles a relay that engages in the steering column

Instrument Cluster VIN Check:

You'll need to provide the last 16 ASCII encoded digits of the vehicle identification number before the cluster will work properly. There may be a way to reprogram this, but I'm not sure at the moment. I'm curious if the "01" may be the mode and what "02" might do. I'll have to pull the VIN from the parts car and see what's up there.

Endpoint: A8 FB 40

30 01

Example: "1G8A

Instrument Cluster Indicators:

These can only be set after the ignition is fully engaged. You can have multiple text indicators enabled, but I'm not sure what the upper limit is. If you properly set a target, data will be echoed back to you. If it doesn't exist, nothing makes its way back. For those endpoints that didn't seem to do anything, I've added "??" though some were referenced during ignition startup.

I wonder if they're for higher-trim models with ABS and the like.

What's interesting to me is that there is an option to flash "Change Oil" which is normally shown after you've travelled a certain distance. It's just a counter for 5,000KM or so and I thought it would be handled locally in the instrument cluster. That might mean that resetting the counter may send a message back. Having some physical button to push data on the system could be useful. I'll investigate that when I get the chance.

Lastly, I haven't found an example of passing custom text to the dash. If it's possible, I haven't seen an example of it. I don't really want to fuzz my dash in case it gets into some broken state. Taking that thing apart really doesn't seem much fun at the moment.

Endpoint: 8A EA 58

XX YY ZZ -> Enable or Disable various instruments lights and text commands
XX = Mode (A0 on, 20 off)
YY = Target
ZZ = Blink when A0 and ZZ > 48 slower. If ZZ < 48, light is solid

YY Target Legend:

A6 = TXT: Trunk
B7 = Down engine? It's an engine with a down arrow in it
C9 = TXT: Power Steering
CB = TXT: Transmission Hot
CC = TXT: Check gas cap
CD = ??
E2 = Battery
7E = ??
82 = TXT: Change oil?!
83 = Oil light
89 = ??
8A = TXT: Transmission Cold
8E = TXT: Check Gauge ;D
8F = TXT: Service Vehicle
90 = Seatbelt light
91 = Highbeams
94 = Airbag light
97 = Emergency break
98 = Emergency break
9C = TXT: Coolant
9D = ??


Check engine (Dedicated wire for this)
Engine security lockout (Ditto here)
TXT: Reset (seems built-in when resetting oil life)

Unknown data found for this endpoint:

01 00 01 -> This seems to show up when error text cycles or is cleared. Replay onto the bus does nothing.
01 00 04 -> Ditto here. They alternate back and forth though.
81 00 01
81 00 04
A1 82
A1 89
A1 B7
21 8C
21 95
21 9A
21 9B

Driver-side door:

Endpoint: 8A C7 40

A3 22 -> Open
23 22 -> Close

Nothing for other doors on the vehicle.

Brightness for dash text and needles:

Endpoint: A8 DF 40

91 XX -> Set brightness (00 to FF)
11 00 -> Max brightness (always)

The brightness dial doesn't pipe directly to the can bus. Or, that's my guess because if the lights are off, you'll see nothing here.

Sending 91 XX only adjusted text display and needle brightness. Radio, instrument backlighting no effect. It wasn't found on CAN either. My guess is that it must be directly connected.

Shifter safety lockout solenoid:

The safety lockout normally disengages when you place your foot on the break pedal so you don't accidentally kick your car into neutral. You can just hit this yourself via the bus.

Endpoint: 68 33 10

A2 -> Unlock shifter
22 -> Lock shifter

89 32 40 62 02 -> Unknown, sent on both commands

Random junk for this endjunk: (found in text, unsure of purpose)

88 33 40 3C 00 47 

Fuel Gauge

Endpoint: A8 83 10

12 XX

XX is the position. From 00 to FF
	Example: 50% = 7F
	Max: 100% = FF

Heat Gauge

Endpoint: 68 49 10

10 XX

XX is the position. From 00 to FF are accepted, but physically won't pass 90
	Example: 50% = 90
	Max: 100% = A9

This is the only gauge that supports a number higher than its physical


Endpoint: 88 29 10

02 XX YY

XX is the current speed as kilometers per hour divided by two
	Example: 100KM/h = 32
	Max: 198KM/h = 63, any higher is ignored

YY no idea, but it runs the gamut from 00 to FF


Endpoint: 88 1B 10

10 XX YY

XX is the engine RPM in hundreds
	Example: 1000 RPM = 10
	Max: 7900 RPM = 79, any higher is ignored

YY no idea, but also runs the gamut like the speedo

Throttle (Or, gas pedal at least)

Endpoint: 68 13 10

11 XX

XX = Peadle position (00 released, F6 fully engaged)

Gear Shifter

Endpoint: 88 3B 10

03 40 -> Park
03 01 -> Reverse
03 80 -> Neutral
03 04 -> Drive (does not change for overdrive)

Unaccounted for: (data while driving)

  17x 88 3B 10 03 02
  26x 88 3B 10 03 04
  27x 88 3B 10 03 08
   6x 88 3B 10 03 10
   6x 88 3B 10 03 40

A9 3A 40 43 -> Unknown, sent after all events

Door Chime:

Endpoint: 68 96 40

91 XX YY - Chime XX times with YY chime
11 YY 00 - Mute chime

YY can be 50 (fastest), 9c (fast), or 5d (slow)

Parking Break

Endpoint: 88 33 40

A0 -> Engaged
20 -> Released

Data Providers

10, 40, 60 and 80 seem to be the devices sending data out on the bus. Not sure what other computers there are connected to this bus.

GMLan Data

This is a big barf of info until I can sit down and organize it

	150 -- I have no idea!
		D0 - 00, 13, 40, 53, 80, 93, C0 D3
		D1 - 00, FF
		D2 - 53-56
		D3 - 00-FF
		D4 - 00, 2B, 2C, 3F
		D5 - 00, 01, FD, FE, FF
		D6 - A9, AA, AB, AC, EF, F0
		D7 - 00-FF (mostly at the two extremes)
	151 -- Engine
		D0 - 00, 02
		D1 - 15-9F, A1, C0, FF? 
		D2,D3 - RPM (x50)
		D4 - 00-0B
		D5 - 00-FF
		D6 - 00-FF
		D7 - 00-FFish with some weird stepping

	110 -- Throttle control
		D0 - 00
		D1,D2 - RPM (x50)
		D3 - Requested throttle (adjusted)
		D4 - Raw sensor 1 value?
		D5 - Current position (1F for starting, 58 when engine at rest)
		D6 - Raw sensor 2 value?
		D7 - 00

	300 -- Transmission?
		D0 - 00, 04
		D1 - 00, 01, 02, 40, 41, 42, 49, 4A
			01 = ?
			02 = Drive
			03 = ?
			04 = ?
			09 = Park / Neutral
			08 = Reverse
		D3,D4 - Running time? Counts up faster when revving
			00 = Locked
			04 = Unlocked

	320 -- Transmission?
		D0 - 04, 05, 06?
			01 = ?
			02 = Drive
			03 = ?
			04 = ?
			08 = Reverse
			09 = Neutral			
			0A = Park
			43 = Engine off
			23 = Engine running
			61 = ?
			62 = ?
			63 = ?
			83 = ?
		D3 - 15-75, A1, FF? Torque?
			0A = Park
			08 = Reverse
			09 = Neutral
			04 = Drive
			03 = Drive I
			02 = Drive L
		D5 - 00
		D6 - 00
		D7 - 3E, 3F, 40-49?

	380 -- Ingition position
		D0 - 00
		D1 - 00 off, 01 acc, 02 running, 03 starting

	520 -- Unknown
		D0 - 00
		D1 - 3B, 3C, 3D
		D2 - 04, 08, 0C, 10

	510 -- Temperatures?
		D0 - 00
		D1 - Coolant    (-40degC)
		D2 - Air Intake (-40degC)
		D3 - 32?
		D4 - 59?
		D5 - C6, C7, C8, C9, CC?
		D6 - F2, F8, FF, FD?
		D7 - 28, 34, 3D-54, 7A? Seems like another temperature. Starts low for awhile, climbs, stays

This comment has been minimized.

Copy link

@cpufreak cpufreak commented Nov 14, 2019

stumbled across this by accident. as an owner of an '06 Ion this was an interesting read. I'd wonder how mine would differ given it's a manual and having a MPH dash. would the data still be in kmh that way? also one of the other things I've seen the dash text display is "PWR STR" which you don't seem to have been able to find at all


This comment has been minimized.

Copy link
Owner Author

@RandomInsano RandomInsano commented Nov 18, 2019


This comment has been minimized.

Copy link

@cpufreak cpufreak commented Nov 18, 2019

from my research, US Automakers metricized their engineering back in the 80's, so yeah, quite possible it's the same. however, in your case where there was data for the PRND21, would mine be RN12345(maybe even 6 cause the Redline was a 6 speed?)

one thing to note, I can tell ya right now I really wonder if you did anything similar here to the '07, the 2007's used a totally new gen II Ecotec engine, and thus a completely new ECM. wonder how different that would have been.

And that sucks, that would have been something I'd be interested in, but alas, seems any small car on this continent gets into a wreck lol. And indeed they are, those plastic panels man lmao.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment