The I-Bus (Information Bus) is BMW’s vehicle communication protocol used in E38, E39, E46, E53, E83, and E85 models. BlueBus implements a complete I-Bus stack to communicate with various vehicle modules.
Protocol specifications
The I-Bus uses the following electrical and timing specifications:
- Baud rate: 9600 bps
- Parity: Even
- Data bits: 8
- Stop bits: 1
- Voltage: 12V differential signaling via TH3122 transceiver
Hardware interface
BlueBus connects to the I-Bus using a TH3122 transceiver chip:
ibus.uart = UARTInit(
IBUS_UART_MODULE,
IBUS_UART_RX_RPIN,
IBUS_UART_TX_RPIN,
IBUS_UART_RX_PRIORITY,
IBUS_UART_TX_PRIORITY,
UART_BAUD_9600,
UART_PARITY_EVEN
);
The TH3122 provides:
- Bus arbitration and collision detection
- Voltage level conversion
- STATUS output indicating bus activity
Packet structure
I-Bus messages follow a standardized packet format:
[Source] [Length] [Destination] [Command] [Data...] [Checksum]
Packet fields
Each field serves a specific purpose:
| Field | Offset | Size | Description |
|---|
| Source | 0 | 1 byte | Module address sending the message |
| Length | 1 | 1 byte | Number of bytes following (excluding checksum) |
| Destination | 2 | 1 byte | Target module address (or 0xBF for broadcast) |
| Command | 3 | 1 byte | Command or message type |
| Data | 4+ | Variable | Command-specific payload (0-42 bytes) |
| Checksum | Last | 1 byte | XOR of all preceding bytes |
Packet example
A CD changer status message:
18 0A 68 39 00 02 00 01 00 01 01 01 4D
Breaking down this packet:
- 0x18: Source (CDC)
- 0x0A: Length (10 bytes following)
- 0x68: Destination (Radio)
- 0x39: Command (CDC status response)
- 0x00-0x01: Status data
- 0x4D: Checksum
Device addresses
BlueBus communicates with numerous I-Bus modules, each with a unique address defined in ibus.h:21-52:
Common modules
- 0x00 - GM (Body module)
- 0x18 - CDC (CD Changer) - BlueBus masquerades as this device
- 0x3B - GT (Graphics Terminal/Navigation)
- 0x50 - MFL (Multi-function steering wheel)
- 0x68 - RAD (Radio)
- 0x80 - IKE (Instrument cluster)
- 0xC0 - MID (Multi-info display)
- 0xD0 - LCM (Light control module)
- 0xF0 - BMBT (Board monitor)
- 0xFF - LOC (Local/BlueBus)
BlueBus uses the CDC address (0x18) since a CD changer will never be present when BlueBus is installed. This allows seamless integration with the vehicle’s audio system.
Broadcast address
The global broadcast address 0xBF sends messages to all modules:
#define IBUS_DEVICE_GLO 0xBF /* Global, broadcast address */
Message processing
The I-Bus processing loop in ibus.c:915-1091 handles all incoming messages:
Reception flow
- Byte reception: Characters arrive in the UART RX queue
- Buffer assembly: Bytes accumulate in
rxBuffer until length is satisfied
- Checksum validation: XOR validation using
IBusValidateChecksum()
- Self-message detection: Filters out echo of transmitted messages
- Module routing: Messages dispatched to appropriate handler functions
if (srcSystem == IBUS_DEVICE_RAD) {
IBusHandleRADMessage(ibus, pkt);
}
if (srcSystem == IBUS_DEVICE_IKE) {
IBusHandleIKEMessage(ibus, pkt);
}
Checksum calculation
The checksum is a simple XOR of all bytes:
static uint8_t IBusValidateChecksum(uint8_t *msg)
{
uint8_t chk = 0;
uint8_t msgSize = msg[1] + 2;
for (idx = 0; idx < msgSize; idx++) {
chk = chk ^ msg[idx];
}
return (chk == 0);
}
A valid message produces a checksum of 0x00 when all bytes (including the checksum byte) are XORed together.
Message transmission
Transmitting messages requires careful timing to avoid bus collisions:
Transmit buffer
BlueBus uses a 24-slot ring buffer for outgoing messages:
uint8_t txBuffer[IBUS_TX_BUFFER_SIZE][IBUS_MAX_MSG_LENGTH];
uint8_t txBufferReadIdx;
uint8_t txBufferWriteIdx;
Bus arbitration
Before transmitting, the system checks the TH3122 STATUS pin:
if (IBUS_UART_STATUS == 0) {
// Bus is idle, safe to transmit
for (idx = 0; idx < msgLen; idx++) {
ibus->uart.registers->uxtxreg = ibus->txBuffer[ibus->txBufferReadIdx][idx];
while ((ibus->uart.registers->uxsta & (1 << 9)) != 0);
}
}
Message timing
To ensure reliable communication:
- TX wait: 7ms minimum between messages (
IBUS_TX_BUFFER_WAIT)
- RX timeout: 70ms to detect incomplete messages (
IBUS_RX_BUFFER_TIMEOUT)
- TX timeout: 250ms maximum wait for bus access (
IBUS_TX_TIMEOUT_WAIT)
Message types
BlueBus handles numerous I-Bus message types:
CDC messages
BlueBus emulates a CD changer to integrate with the radio:
#define IBUS_COMMAND_CDC_REQUEST 0x38
#define IBUS_COMMAND_CDC_RESPONSE 0x39
The radio sends requests:
- 0x00 - Get status
- 0x01 - Stop playing
- 0x03 - Start playing
- 0x0A - Change track
- 0x06 - Change CD
BlueBus responds with status packets showing:
- Playback state (playing/paused/stopped)
- Current disc and track numbers
- Function mode (normal/scan/random)
Ignition status
The IKE broadcasts ignition status:
#define IBUS_CMD_IKE_IGN_STATUS_RESP 0x11
#define IBUS_IGNITION_OFF 0x00
#define IBUS_IGNITION_KLR 0x01 // Accessory
#define IBUS_IGNITION_KL15 0x03 // Ignition on
#define IBUS_IGNITION_KL50 0x07 // Starter
BlueBus uses this to manage power states and automatic connection.
Multiple modules send button press events:
BMBT (On-board monitor)
MFL (Steering wheel)
MID (Multi-info display)
#define IBUS_CMD_BMBT_BUTTON0 0x47
#define IBUS_CMD_BMBT_BUTTON1 0x48
#define IBUS_DEVICE_BMBT_BUTTON_NEXT 0x00
#define IBUS_DEVICE_BMBT_BUTTON_PREV 0x10
#define IBUS_DEVICE_BMBT_BUTTON_PLAY_PAUSE 0x14
#define IBUS_DEVICE_BMBT_BUTTON_TEL_PRESS 0x08
#define IBUS_MFL_CMD_BTN_PRESS 0x3B
#define IBUS_MFL_BTN_EVENT_NEXT_REL 0x21
#define IBUS_MFL_BTN_EVENT_PREV_REL 0x28
#define IBUS_MFL_BTN_EVENT_VOICE_PRESS 0x80
#define IBUS_MFL_BTN_EVENT_VOICE_HOLD 0x90
#define IBUS_MID_BUTTON_PRESS 0x31
#define IBUS_MID_BTN_TEL_RIGHT_RELEASE 0x4D
#define IBUS_MID_BTN_TEL_LEFT_RELEASE 0x4C
Text display
BlueBus sends text to various displays:
// Radio display
#define IBUS_CMD_RAD_UPDATE_MAIN_AREA 0x23
// IKE display
#define IBUS_CMD_IKE_OBC_TEXT 0x24
// Navigation screen
#define IBUS_CMD_GT_WRITE_INDEX 0x60
#define IBUS_CMD_GT_WRITE_ZONE 0x62
Each display has specific text formatting requirements and character limits.
Module detection
BlueBus automatically detects which modules are present on the bus:
static void IBusHandleModuleStatus(IBus_t *ibus, uint8_t module)
{
if (module == IBUS_DEVICE_BMBT && ibus->moduleStatus.BMBT == 0) {
ibus->moduleStatus.BMBT = 1;
LogInfo(LOG_SOURCE_IBUS, "BMBT Detected");
EventTriggerCallback(IBUS_EVENT_MODULE_STATUS_RESP, &module);
}
}
Detected modules include:
- BMBT (Board monitor)
- DSP (Amplifier)
- GT (Navigation)
- MID (Multi-info display)
- PDC (Park distance control)
- IRIS (Integrated radio information system)
Module status request
Modules respond to status requests:
#define IBUS_CMD_MOD_STATUS_REQ 0x01
#define IBUS_CMD_MOD_STATUS_RESP 0x02
BlueBus broadcasts status requests on startup to identify available modules.
Vehicle data
The I-Bus provides access to extensive vehicle data:
Sensor values
The IKE (instrument cluster) broadcasts sensor data:
// Temperature updates (0x19)
ibus->coolantTemperature = pkt[IBUS_PKT_DB2];
ibus->ambientTemperature = pkt[IBUS_PKT_DB1];
// Speed and RPM (0x18)
// Gear position (0x13)
ibus->gearPosition = pkt[IBUS_PKT_DB2] >> 4;
PDC sensors
Park distance control sensor values:
typedef struct IBUSPDCStatus_t {
uint8_t status: 1;
uint8_t frontLeft;
uint8_t frontCenterLeft;
uint8_t frontCenterRight;
uint8_t frontRight;
uint8_t rearLeft;
uint8_t rearCenterLeft;
uint8_t rearCenterRight;
uint8_t rearRight;
} IBUSPDCStatus_t;
Light status
The LCM (Light control module) reports lighting status:
#define IBUS_LCM_LIGHT_STATUS_RESP 0x5B
#define IBUS_LCM_DIMMER_STATUS 0x5C
ibus->lmDimmerVoltage = pkt[IBUS_LM_IO_DIMMER_OFFSET];
ibus->lmPhotoVoltage = pkt[IBUS_LM_IO_PHOTO_OFFSET];
This enables automatic dimming based on vehicle lighting.
Diagnostics
The I-Bus supports diagnostic queries:
#define IBUS_CMD_DIA_JOB_REQUEST 0x0C
#define IBUS_CMD_DIA_DIAG_RESPONSE 0xA0
BlueBus queries modules for:
- Module identification
- Hardware/software versions
- Diagnostic index
- I/O status
Example diagnostic response parsing:
if (pkt[IBUS_PKT_CMD] == IBUS_CMD_DIA_DIAG_RESPONSE &&
pkt[IBUS_PKT_LEN] == 0x22) {
uint8_t hardwareVersion = IBusGetNavHWVersion(pkt);
uint8_t softwareVersion = IBusGetNavSWVersion(pkt);
uint8_t gtVersion = IBusGetNavType(pkt);
}
This allows BlueBus to adapt to different module variants and capabilities.