This documentation applies to Ford Fiesta MK5 >2006 (MK5 restyling), with 2-DIN, 6000CD radio.
The radio sends messages to the LCD screen in the dashboard, like FM station names, CD track IDs, volume changes.
The idea was to tap into the text-to-LCD mechanism, but I ended up reversing some other interesting CANbus messages.
Tapping in the infotaiment CANbus is quite easy: just connect a CANbus interface over CANH and CANL lines that come into the QuadLock conector of the radio, no 120 Ohm terminal block resistor needed.
Personally, I used a SeedStudio CANbus Shield stacked onto an Arduino Uno R3.
Bus speed is 125 KBPS.
The IDs of either partially or fully decoded messages are:
- 0x080
- 0x1e9
- 0x201
- 0x265
- 0x285
- 0x286
- 0x2d5
- 0x2d8
- 0x2da
- 0x2db
- 0x360
- 0x420
- 0x428
- 0x433
- 0x460
- 0x4c0
- 0x4c8
- 0x4f3
A Kayak .kcd file definition file is included (incomplete).
The radio sends text to the dashboard LCD using either a short message format or an extended message format.
The short format can only be seen whenever the radio switches to AUX mode.
ID | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
---|---|---|---|---|---|---|---|---|
0x4C0 | 0x7 | 0x34 | ASCII text |
The extended format is composed by one header message containing the length of the text, and subsequent messages that provide additional text portions.
ID | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
---|---|---|---|---|---|---|---|---|
0x4C0 | 0x10 | Text length + 2 | 0x34 | ASCII text | ||||
0x4C0 | 0x21 | ASCII text |
this happens to be the ISO-TP protocol (ISO 15765-2). For the sake of completeness, after the first extended frame message, an ACK message is received (as required by the ISO-TP flow control mechansim):
ID | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
---|---|---|---|---|---|---|---|---|
0x4C8 | 0x30 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 | 0x00 |
where:
- byte 1 (0x30) tells that the source is "clear to send" the next portions of the message;
- byte 2 (0x00) tells that frames are to be sent without flow control;
- byte 3 (0x00) tells to send as fast as the source can.
Thanks to /u/thatguy147 for the ISO-TP suggestion!
The radio also shares the radio station name with a specific message.
ID | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
---|---|---|---|---|---|---|---|---|
0x1E9 | ASCII text |
When the radio is OFF this message is broadcasted.
ID | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
---|---|---|---|---|---|---|---|---|
0x4C0 | 0x2 | 0x34 | 0 |
Apparently, only mode and seek buttons near the steering column issue commands over MS-CAN, while unfortunately it seems that volume buttons are not.
ID | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
---|---|---|---|---|---|---|---|---|
0x2D5 | (unspecified) | <buttons> | (unspecified) |
buttons is a bitmask: the byte is the algebraic sum of these condition codes, whenever applicable.
Status | Code |
---|---|
Mode button | 0x10 |
Seek up | 0x40 |
Seek down | 0x80 |
The radio unit broadcasts a message containing the current volume level.
ID | 1 | 2 | 3 |
---|---|---|---|
0x2D8 | 0x00 | <volume_raw> | 0x00 |
where the real volume level can be obtained as:
volume = volume_raw/8
When the unit is not in CD playback mode, the following message is emitted:
ID | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
---|---|---|---|---|---|---|---|---|
0x2DB | 0xFF | 0xFF | 0xFF | 0xFF | 0x00 | 0x00 | 0x00 | 0x00 |
Instead, during CD playback, the message contains the track id and current seek time:
ID | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
---|---|---|---|---|---|---|---|---|
0x2DB | 0xFF | 0xFF | <track_time> | 0x00 | <track_id> | 0x00 | 0x00 |
where the current track time, in seconds, can be obtained like this:
track_seconds = track_time - 64
The radio unit tells informations about the CD presence.
ID | 1 | 2 | 3 | 4 | 5 |
---|---|---|---|---|---|
0x2DA | (unspecified) | <cd_mode> | 0x00 | <cd_drive> | 0x00 |
CD Mode | Code |
---|---|
No CD inserted | 0x2A |
CD inserted - playback | 0x4A |
CD inserted - no playback | 0x6A |
CD Drive | Code |
---|---|
No CD inserted | 0x23 |
CD loading | 0x21 |
CD inserted - no playback | 0x22 |
CD inserted - playback | 0x26 |
The car has an onboard RTC that works independently from the radio clock (it works even if the radio is disconnected at all). The date and time are broadcasted with 1 second resolution.
ID | 1 | 2 | 3 | 4 | 5 | 6 |
---|---|---|---|---|---|---|
0x80 | year (two digits) | month | day | hours | minutes | seconds |
The AirBag dashboard light is commanded either ON or OFF depending with the 5th byte of this message.
ID | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
---|---|---|---|---|---|---|---|---|
0x460 | 0x0 | 0x0 | 0x0 | 0x0 | <status> | 0x0 | 0x0 | 0x0 |
Status | Code |
---|---|
ON | 0xC0 |
OFF | 0x0 |
Doors status is signalled setting or clearing bits in the 1st byte of this message. Full lock of the doors is signalled by the 6th byte. Morover, this packet hold the status of the reverse gear in the 4th byte.
ID | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
---|---|---|---|---|---|---|---|---|
0x433 | <door_status> | (unspecified) | <reverse_gear> | (unspecified) | <lock> | (unspecified) |
door_status is a bitmask: the 1st byte is the algebraic sum of these condition codes, whenever applicable.
Status | Code |
---|---|
Front left open | 0x80 |
Front right open | 0x40 |
Trunk open | 0x08 |
reverse_gear can be interpreted as follows:
Status | Code |
---|---|
ON | 0x02 |
OFF | 0x00 |
lock can be interpreted as follows:
Status | Code |
---|---|
LOCKED | 0x10 |
UNLOCKED | 0x20 |
Arrows status is signalled setting or clearing bits in the 1st byte of this message.
ID | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
---|---|---|---|---|---|---|---|---|
0x265 | <status> | (unspecified) |
Status is a bitmask: the 1st byte is the algebraic sum of these condition codes, whenever applicable.
Status | Code |
---|---|
Left ON | 0x20 |
Right ON | 0x40 |
Periodically, the veihcle ID (lower part of VIN, so the serial number plus other codes signalling production date) is broadcasted.
ID | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
---|---|---|---|---|---|---|---|---|
0x4F3 | <vehicle ID> |
Front beams status is signalled setting or clearing bits in the 1st byte of this message. Notice that, since this message is just for dashboard LEDs, parking lights cannot be distinguished from low beams, as they share the same LED indicator.
ID | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
---|---|---|---|---|---|---|---|---|
0x286 | <status> | (unspecified) |
Status is a bitmask: the 1st byte is the algebraic sum of 0x10 and these condition codes, whenever applicable.
Status | Code |
---|---|
Handbrake | 0x10 |
Parking lights / low beams | 0x80 |
High beams | 0x40 |
Gas pedal position, engine RPM and speed (Km/h) are contained in the same packet.
ID | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
---|---|---|---|---|---|---|---|---|
0x201 | <rpm> | (unspecified) | <speed> | <0x80+gas> |
where the position of the pedal can be translated in percentage with the following formula:
gas_percent = gas*100/50944
while speed in Km/h can be obtained with:
km_h = speed/100
Brake pedal status is repeated in two different messages, with different codes.
ID | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
---|---|---|---|---|---|---|---|---|
0x420 | <coolant> | (unspecified) | <brake> | (unspecified) |
where brake can be interpreted as follows:
Brake status | Code |
---|---|
Not pressed | 0x00 |
Foot on pedal | 0x10 |
Pressed | 0x30 |
and coolant temperature can be obtained as follows:
coolant_degrees = coolant - 40
and
ID | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
---|---|---|---|---|---|---|---|---|
0x360 | (unspecified) | <brake> | (unspecified) |
where brake can be interpreted as follows:
Brake status | Code |
---|---|
Not pressed | 0x60 |
Foot on pedal | 0x68 |
Pressed | 0x78 |
Key can be either in position 1, 2 or 3.
ID | 1 | 2 | 3 |
---|---|---|---|
0x285 | <key> | (unspecified) |
where the position can be obtained reading bits 5 and 6 of the first byte:
key_position = (key & 0x30) >> 4
Battery voltage is expressed in tenths of Volt.
ID | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
---|---|---|---|---|---|---|---|
0x428 | (unspecified) | <battery> | (unspecified) |
where battery status, in volts, can be obtained as:
battery_v = battery/10