Skip to main content
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:
FieldOffsetSizeDescription
Source01 byteModule address sending the message
Length11 byteNumber of bytes following (excluding checksum)
Destination21 byteTarget module address (or 0xBF for broadcast)
Command31 byteCommand or message type
Data4+VariableCommand-specific payload (0-42 bytes)
ChecksumLast1 byteXOR 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

  1. Byte reception: Characters arrive in the UART RX queue
  2. Buffer assembly: Bytes accumulate in rxBuffer until length is satisfied
  3. Checksum validation: XOR validation using IBusValidateChecksum()
  4. Self-message detection: Filters out echo of transmitted messages
  5. 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.

Button presses

Multiple modules send button press events:
#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

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.

Build docs developers (and LLMs) love