comment:
A basic Bootloader communication protocol operating on 9600bps SCI instead of a UART, probably used for debugging.
SCI_exchange_packet() calls appropriate handler (found by comparing in[1] (the second byte of the request) to in_PID) every time a new packet arrives.
Every handler gets a pointer to the received packet (in[]) and a pointer to a blank packet "to be transmitted as response" (out[]) and returns the size of the output packet in Bytes.
The response packet's PID (out[1]) is it's in_PID negative (U2) (-in[1]) && 0xFF; except for handlers: PROTO1::nop_0x03, PROTO1::nop_0x19, PROTO1::write_bytes_dangerous - their out_PID is 0x01 and they don't respond with any bytes.
example:
in[] : 07 15 05 01 4B 7A 27
out[]: 08 EB 00 01 02 03 00 E3
- The greyed part is the actual body/data returned from handlers and the rest is header/footer.
- This 0x07 Bytes request goes to a handler with in_PID = 0x15 which reads 0x05 Bytes from the address 0x014B7A. The whole request is guarded by a XOR checksum 0x27.
- The 0x08 Bytes response with out_PID = 0xEB returns these bytes which happen to be {0x00, 0x01, 0x02, 0x03, 0x00}. The whole response is guarded by a XOR checksum 0xE3.
- When an error occurs while handling the request, the following response is generated:
out[]: 04 02 XX YY
The error-code field is one of the following: {
GENERAL_ERR = 0x00,
CHECKSUM_ERR = 0x02,
TIMEOUT_ERR = 0x03,
SIZE_ERR = 0x03,
OUT_OF_RANGE_ERR = 0x05
}
The whole error response is guarded by a XOR checksum 0xYY.
nop_0x03: [
in_PID: 0x03
comment:
This handler is not implemented and returns 0 (output size)
],
get_version_info: [
in_PID: 0x14
comment:
Moves an aggregated magic bytes string to output packet.
Creates "0261204420" + "F000" + "1430940" + "000" + "4399" + ".26\xff..." + "078" + "26RT5134" + "000368511" on firmware version 01119700F000P2AG.
Returns 75 (length of all strings combined)
],
read_bytes: [
in_PID: 0x15
comment:
Exactly the same as PROTO1::read_bytes2
Reads bytes from the given address in memory to the output packet.
Expects the following structured input: {
in[2] -> size of the block
in[3] -> higher byte of the address
in[4] -> middle byte of the address
in[5] -> lower byte of the address
}
Note that the MC68336 in BMS46 has a 24bit addressing IMB.
If the desired size (in[2]) is greater than 200 it returns an error packet with code 0x05 (OUT_OF_RANGE_ERR).
Normally returns the size (from in[2]).
],
write_bytes_dangerous: [
in_PID: 0x16
comment:
Writes bytes to the given address in memory from the input packet without additional checks.
It's potentially dangerous as it can overwrite itself if requested and brick the device.
It's called with XIP like most functions so it's generally safe to write to RAM.
Expects the following structured input: {
in[2] -> size of the payload
in[3] -> higher byte of the address
in[4] -> middle byte of the address
in[5] -> lower byte of the address
in[6...SIZE] -> raw bytes payload to copy
}
Note that the MC68336 in BMS46 has a 24bit addressing IMB.
Never fails.
Returns 0 (size) -> responds with a blank packet.
],
read_analog_values: [
in_PID: 0x17
comment:
Reads words from the LJURR table at a given idx to the output packet.
Note that the [L]eft [J]ustified [U]nsigned [R]esult [R]egisters table contains the raw analog sensor values directly after QADC read.
The CCW table maps idx -> channel.
For example requesting the word at idx 14 will return the raw analog value of sensor plugged in to channel 52
Further Reading: MC68336 manual QADC section.
Expects the following structured input: {
in[2] -> count of words
in[3] -> index of a starting word
}
Never fails.
The higher byte of the requested word is at an even addr starting from 0x02 and the lower byte follows in the next addr
For example when requested word is LJURR[12] == 0xabcd then out[2] = 0xab and out[3] = 0xcd.
Returns count of words (in[2]) times 2 to get the byte size of output packet.
],
nop_0x18: [
in_PID: 0x18
comment:
This handler is not implemented and returns 0 (size).
],
nop_0x19: [
in_PID: 0x19
comment:
This handler is not implemented and returns 0 (size).
],
read_received_packets: [
in_PID: 0x20
comment:
Reads at most 200 bytes from some memory region between two pointers (not selectable) to the output packet.
Maybe it outputs the last received packet (history) or the current one (for debugging).
Does not use the input packet.
Never fails.
Returns count of bytes between start_ptr and end_ptr (at most 200).
],
read_digital_values: [
in_PID: 0x21
comment:
Reads some bitfields from PORTF, then exchanges multiple SPI packets
Does not use the input packet.
Never fails.
Returns 10 (size of the SPI response).
],
get_addresses: [
in_PID: 0x22
comment:
Moves 7 in-memory pointers to the output packet.
The pointers are the same for every firmware version.
Values presented are for firmware version "01119700F000P2AG"
The pointers: {
0x01459A -> "-d6100A76000102135100261204420",
0x03FD60 -> &VIN[46],
0x03FD20 -> "4399",
0x03FD24 -> ".26",
0x03FD38 -> "078",
0x03FD3C -> "26RT5134",
0x03FD44 -> "\t000368511"
}
Does not use input packet.
Never fails.
Returns 21 (size).
],
read_bytes2: [
in_PID: 0x24
comment:
Exactly the same as PROTO1::read_bytes
Reads bytes from the given address in memory to the output packet.
Expects the following structured input: {
in[2] -> size of the block
in[3] -> higher byte of the address
in[4] -> middle byte of the address
in[5] -> lower byte of the address
}
Note that the MC68336 in BMS46 has a 24bit addressing IMB.
If the desired size (in[2]) is greater than 200 it returns an error packet with code 0x05 (OUT_OF_RANGE_ERR).
Normally returns the size (from in[2]).
],
write_bytes: [
in_PID: 0x30
comment:
Writes the given bytes to address, then returns all written bytes in output packet (all bytes are always written, so essantially no error possible).
This handler relocates special subroutine which is ran from RAM, not by XIP as most functions, so it's safe to write to every byte of ROM.
That's the main difference between it and PROTO1::write_bytes_dangerous, however this handler should not be used to write to RAM, as the handler is there.
It's recommended to use this handler for writing to ROM, and PROTO1::write_bytes_dangerous to writing to RAM (rarely useful).
Expects the following structured input: {
in[2] -> size of the block
in[3] -> higher byte of the address
in[4] -> middle byte of the address
in[5] -> lower byte of the address
in[6...SIZE] -> bytes to be written
}
Note that the MC68336 in BMS46 has a 24bit addressing IMB.
All written bytes end up in output packet in[2...SIZE], it returns the size (from in[2]).
],
thunk_test: [
in_PID: 0x40
comment:
Calls a given function passing this handler's parameters and returns it's return value.
Maybe it is used as a thunk for testing handlers of this protocol.
If the address requested is an address of a handler in this protocol, then it is just thunk-called from there.
Expects the following structured input: {
in[2] -> higher byte of the address
in[3] -> middle byte of the address
in[4] -> lower byte of the address
in[5...] -> payload to be passed to the designated handler
}
Note that the MC68336 in BMS46 has a 24bit addressing IMB.
Re-returns what the requested handler returned.
]
handler_type:
void (*)(void)
comment:
The protocol is the same as PROTO2b, but this is the Boot version that has different handlers
A periodically scheduled Bootloader job calls the appropriate handler (found by in_PID) if a new received message is available.
The max output packet size is generally 251 Bytes
This protocol uses three global variables instead of function arguments.
1. PROTO2a::in_buff
2. PROTO2a::out_buff
3. PROTO2a::message_size
The output packet's out_PID (out[2]) is one of these four values: {
0xA0 -> OKAY
0xA1 -> BUSY
0xA2 -> ERROR_ECU_REJECTED
0xB0 -> ERROR_ECU_PARAMETER
0xB1 -> ERROR_ECU_FUNCTION
0xB2 -> ERROR_ECU_NUMBER
0xFF -> ERROR_ECU_NACK
0x00 -> ERROR_ECU_UNKNOWN_STATUSBYTE
}
get_version_info: [
in_PID: 0x00
comment:
Moves an aggregated magic bytes string to the output packet.
Used by Ediabas jobs "PRUEFCODE_LESEN", "IDENT" and "IDENT_AIF"
Creates "1430940" + "61\xff..." + "4399" + "0010213510" + "F000" + "000368511" on firmware version "01119700F000P2AG".
The type of the response is OKAY.
Never fails.
Sets PROTO2a::message_size = 42 (length of all strings combined).
],
read_bytes: [
in_PID: 0x06
comment:
Reads bytes from a given address (in a given memory region) to the output packet.
If the start address belongs to the region, but the size is too big, then the output size is clamped to fit.
If no memory region is requested (0x00) then:
1. RAM_REGION is checked (0xFF8000 - 0xFF9DFF);
2. ROM_REGION is checked (0x000000 - 0x03FFFF);
If there is still no match, the handler returns empty output packet of type ERROR_ECU_PARAMETER
Expects the following structured input: {
in[3] -> type of memory region
in[4] -> higher byte of the address
in[5] -> middle byte of the address
in[6] -> lower byte of the address
in[7] -> size of the input packet
}
Note that the MC68336 in BMS46 has a 24bit addressing IMB.
The possible memory regions (in[3]): {
RAM_REGION (0xFF8000 - 0xFF9DFF) -> {0x04},
BOOT_REGION (0x000000 - 0x03FFFF) -> {0x02 OR 0x06},
FULL_REGION (0x000000 - 0xFFFFFF) -> {0x00 OR 0x0F},
INVALID_REG (0x000001 - 0x000000) -> {0x01 OR 0x03 OR 0x05 OR 0x0E}
}
Note that it tries to protect ISN (0x3F64 - 0x3F6F) and when this addr is requested it will add an offset +0x3BD4C redirecting to another magic byte.
The type of the response is OKAY.
Sets PROTO2a::message_size to the clamped size.
],
write_bytes: [
in_PID: 0x07
comment:
Writes bytes from the input packet to memory.
The handler is relocated and ran from RAM not XIP, this is similair to PROTO1::write_bytes, but with additional memory region check like PROTO2a::read_bytes
Expects the following structured input: {
in[3] -> type of memory region
in[4] -> higher byte of the address
in[5] -> middle byte of the address
in[6] -> lower byte of the address
}
Note that the MC68336 in BMS46 has a 24bit addressing IMB.
The possible memory regions (in[3]): {
RAM_REGION (0xFF8000 - 0xFF9DFF) -> {0x04},
BOOT_REGION (0x000000 - 0x03FFFF) -> {0x02 OR 0x06},
FULL_REGION (0x000000 - 0xFFFFFF) -> {0x00 OR 0x0F},
INVALID_REG (0x000001 - 0x000000) -> {0x01 OR 0x03 OR 0x05 OR 0x0E}
On error (pointer not in range) returns a blank packet with type ERROR_ECU_PARAMETER.
Sets output packet type to OKAY (most of the times), or ERROR_ECU_REJECTED if not found.
],
get_checksum: [
in_PID: 0x0A
comment:
Takes a simple 1Byte CRC16-IBM checksum of the firmware and moves that to the output packet.
This handler is used by Ediabas Job "STATUS_CODIER_CHECKSUMME"
If USER_END magic byte (0x55FFAA00) is invalid or inaccesible, it takes the checksum only on the critical 1st stage sector (0x0000 - 0x3FFF).
If there is a magic byte mismatch, returns 0xFF as checksum.
Does not use the input packet.
Never fails.
Sets output packet type (out[2]) to OKAY.
Sets the PROTO2a::message_size to 1 (only 1Byte checksum).
],
get_addresses: [
in_PID: 0x0D
comment:
Moves 24 in-memory pointers to the output packet.
Used by Ediabas job "AIF_LESEN"
The pointers are the same for every firmware version.
Values presented are for the firmware version "01119700F000P2AG"
The values: {
0x00373A -> "",
0xFFFFFF,
0xFFFFFF,
0xFFFFFF,
0xFFFFFF,
0xFFFFFF,
0xFFFFFF,
0xFFFFFF,
0xFFFFFF,
0xFFFFFF,
0xFFFFFF,
0xFFFFFF,
0xFFFFFF,
0xFFFFFF,
0xFFFFFF,
0x008010 -> "01119700F000P2AG",
0x0144B0 -> &TMP_SECRET_ARR[32],
0x00373C -> "#",
0x003FE6 -> "01119700",
0x03FCB0 -> "01119700F000",
0x03FD60 -> &VIN[46],
0x00373D -> "\xFF",
0x03FD20 -> "4399.26",
0x003F20 -> &SEED_KEY_BYTES[22]
}
Does not use the input packet.
Never fails.
Sets output packet type (out[2]) to OKAY.
Sets the PROTO2a::message_size to 72 (combined length of all magic bytes).
],
seed_key: [
in_PID: 0x90
comment:
Sends a magic seed from bytes string PROTO2a::get_version_info, then checksums it, then does a lot of set/clear bit operations.
Used by Ediabas job "SEED_KEY" with argument in[6] = 0x05
Expects the following structured input: {
in[1] -> MUST be 8 (the length of the whole input packet)
in[3] -> MUST be 'B' (0x42)
in[4] -> MUST be 'M' (0x4D)
in[5] -> MUST be 'W' (0x57)
}
Never fails.
Normally outputs a blank packet with type ERROR_ECU_REJECTED.
Sometimes outputs a 1 byte (0x00) packet with type OKAY.
],
auth_key: [
in_PID: 0x91
comment:
Check if provided key is valid and enable security access
Expects the following structured input: {
in[3] -> 1st KEY byte
in[4] -> 2nd KEY byte
in[5] -> 3rd KEY byte
in[6] -> security access level
}
Never fails.
If there is no match: outputs a blank packet of type ERROR_ECU_PARAMETER.
If the match is found: set the access level
On success returns a blank packet of type OKAY.
Sets the PROTO2a::message_size to 0.
],
handler_type:
void (*)(void)
comment:
The protocol is the same as PROTO2a, but this is the User version that has more handlers.
A periodically scheduled Userland job calls the appropriate handler (found by in_PID) if a new received message is available.
This protocol uses three global variables instead of function arguments.
1. PROTO2b::in_buff
2. PROTO2b::out_buff
3. PROTO2b::message_size
The output packet's out_PID (out[2]) is one of these four values: {
0xA0 -> OKAY
0xA1 -> BUSY
0xA2 -> ERROR_ECU_REJECTED
0xB0 -> ERROR_ECU_PARAMETER
0xB1 -> ERROR_ECU_FUNCTION
0xB2 -> ERROR_ECU_NUMBER
0xFF -> ERROR_ECU_NACK
0x00 -> ERROR_ECU_UNKNOWN_STATUSBYTE
}
get_version_info: [
in_PID: 0x00
comment:
Moves an aggregated magic bytes string to the output packet.
Used by Ediabas jobs "PRUEFCODE_LESEN", "IDENT" and "IDENT_AIF"
Creates "1430940" + "61" + "00" + "A7" + "60" + "4399" + "0010213510" + "F0000" + "000368511" on firmware version 01119700F000P2AG.
Does not use input packet.
Never fails.
Sets PROTO2b::message_size = 42 (combined length of magic bytes).
],
show_stored_DTC: [
in_PID: 0x04
comment:
Reads DTCs.
Expects the following structured input: {
in[3] -> requested size
}
If the requested size is greater or equal to 11, this handler returns a blank packet of type ERROR_ECU_PARAMETER and size 0.
Else, the current DTC_saved_count is moved to out[3]
If the requested size is greater than the current DTC_saved_count, a 0x00 byte is moved to out[4] and this handler returns with success.
If the requested size is 0, then two last DTCs are returned, first in {out[4] (hi_byte), out[5] (lo_byte)} and the second in {out[6] (hi_byte), out[7] (lo_byte)}
Else (when the requested size is in range (0, DTC_saved_count] it returns all saved DTCs, hi_byte first.
],
clear_stored_DTC: [
in_PID: 0x05
comment:
Clears DTCs
Does not use the input packet.
Never fails.
Outputs blank packet with type OKAY and size 0.
],
read_bytes: [
in_PID: 0x06
comment:
Almost the same as PROTO2a::read_bytes, but this handler additionally avoids two other regions.
Reads bytes from a given address (in a given memory region) to the output packet.
If the start address belongs to the region, but the size is too big, then the output size is clamped to fit.
If no memory region is requested (0x00) then:
1. RAM_REGION is checked (0xFF8000 - 0xFF9DFF);
2. ROM_REGION is checked (0x000000 - 0x03FFFF);
If there is still no match, the handler returns empty output packet of type ERROR_ECU_PARAMETER
Expects the following structured input: {
in[3] -> type of memory region
in[4] -> higher byte of the address
in[5] -> middle byte of the address
in[6] -> lower byte of the address
in[7] -> size of the input packet
}
Note that the MC68336 in BMS46 has a 24bit addressing IMB.
The possible ram regions (in[3]): {
RAM_REGION (0xFF8000 - 0xFF9DFF) -> {0x04},
BOOT_REGION (0x000000 - 0x03FFFF) -> {0x02 OR 0x06},
FULL_REGION (0x000000 - 0xFFFFFF) -> {0x00 OR 0x0F},
INVALID_REG (0x000001 - 0x000000) -> {0x01 OR 0x03 OR 0x05 OR 0x0E}
}
Note that it tries to protect ISN (0x3F64 - 0x3F6F) and when this addr is requested it will add an offset +0x3BD4C redirecting to another magic byte.
This version also protects two other regions:
1. ENCRYPTED_ISN (0xFF95F0 - 0xFF95FB) by applying offset -0xff8000.
2. UNKNOWN (0xFF8670 - 0xFF867B) by applying offset -0xff8000.
The type of the response out_PID (out[2]) is OKAY.
Sets PROTO2b::message_size to the clamped size.
],
write_bytes: [
in_PID: 0x07
comment:
Almost the same as PROTO2a::write_bytes.
This handler is bound-checking the pointer, relocating some blocks, and at the end returning the pointer if it was valid.
Expects the following structured input: {
in[3] -> type of memory region
in[4] -> higher byte of the address
in[5] -> middle byte of the address
in[6] -> lower byte of the address
}
Note that the MC68336 in BMS46 has a 24bit addressing IMB.
The possible ram regions (in[3]): {
RAM_REGION (0xFF8000 - 0xFF9DFF) -> {0x04},
BOOT_REGION (0x000000 - 0x03FFFF) -> {0x02 OR 0x06},
FULL_REGION (0x000000 - 0xFFFFFF) -> {0x00 OR 0x0F},
INVALID_REG (0x000001 - 0x000000) -> {0x01 OR 0x03 OR 0x05 OR 0x0E}
}
On error (pointer not in range) returns a blank packet with type out_PID (out[2]): ERROR_ECU_PARAMETER.
Sets output packet type to OKAY (most of the times), or ERROR_ECU_REJECTED when not found.
],
get_checksum: [
in_PID: 0x0A
comment:
This handler is the same as PROTO2a::get_checksum, but there are more memory regions to take checksum of.
Used by Ediabas job "STATUS_CODIER_CHECKSUMME"
Takes a simple 1Byte CRC16-IBM checksum of the firmware and moves that to the output packet.
If USER_END magic byte (0x55FFAA00) is invalid or inaccesible, it takes the checksum only on the critical 1st stage sector (0x0000 - 0x3FFF).
If there is a magic byte mismatch, returns 0xFF as checksum.
Does not use the input packet.
Never fails.
Sets output packet type to OKAY.
Sets the PROTO2b::message_size to 1 (only 1Byte checksum).
],
read_vehicle_data: [
in_PID: 0x0B
comment:
Reads some vital Vechicle info (hi_byte first for words) to the output packet.
Expects the following structured input: {
in[3] -> type of the data
}
The following types of data are supported:
0x03 (LIVE_DATA): {
out[3-4] -> Engine_RPM_Raw
out[5-6] -> Engine_Coolant_Temp
out[7-8] -> Engine_IAT
out[9] -> Engine_Load
out[10] -> Engine_Alternator_Voltage
out[11] -> Vehicle_Speed
out[12-13] -> Engine_MAF_Raw
out[14-15] -> ??
out[16] -> Engine_Timing_Advance_CYL1
out[17] -> Engine_Short_Term_Fuel_Trim2
out[18] -> ??
out[19-20] -> Engine_Ignition_Correction_??
out[21-22] -> ??
out[23-24] -> Engine_Ignition_Advance_Raw
out[25-26] -> Engine_AFR
out[27-28] -> Engine_Throttle_Position
out[29-30] -> Vehicle_Long_Term_Fuel_Trim
out[31-32] -> Engine_EGR
out[33-34] -> ??
out[35] -> ??
out[36-37] -> Engine_Last_DTC
out[38-39] -> Vehicle_Lambda1_Voltage
out[40-41] -> Engine_Throttle_Voltage_Raw
out[42-43] -> ??
out[44-45] -> ??
out[46] -> Engine_Cat1_Temp
out[47] -> ??
out[48] -> Engine_Throttle_Percentage
out[49] -> 0x00
out[50] -> 0x00
out[51] -> 0x00
out[52] -> 0x00
out[53-54] -> Vehicle_EVAP_State
out[55-56] -> Vehicle_Lambda1_Heater_PWM
out[57-58] -> ??
out[59] -> 0x00
out[60] -> Engine_Battery_Voltage
out[61-62] -> ??
out[63-64] -> ??
out[65-66] -> ??
out[67-68] -> ??
out[69-70] -> Vehicle_Lambda2_Heater_PWM
out[71-72] -> Vehicle_Lambda2_Voltage
} - message_size = 70 bytes
0x04 (CONFIG_DATA): {
} - message_size = 5 bytes
0xA2 (ENGINE_OVERSPEED_INFO): {
} - message_size = 5 bytes
0xA3: {
} - message_size = 6 bytes
On success, a packet of type OKAY is returned
Else a blank output packet of type ERROR_ECU_PARAMETER is returned.
],
actuation_control: [
in_PID: 0x0C
comment:
Provides actuation of various components.
Please note that this handler uses the oldschool boolean encoding: 0x00 = true and 0xFF = false
Every actuation handler returns status code: {
0x00 -> SUCCESS
0x01 -> INVALID_PIN
0x02 -> INVALID_DUTY_CYCLE
0x03 -> INVALID_PERIOD_DURATION
0x04 -> INVALID_CONDITIONS
}
Expects the following structured input: {
in[3] -> requested action index
in[4] -> actuation setpoint
}
The possible indices are: {
0x1F (LAMBDA2_HEATER): {
If the Lambda2 is not accessible or not equipped it returns INVALID_PIN, if the Lambda2 dewpoint is exceeded or in[4] is greater than 51, it returns INVALID_CONDITIONS, else it sets the PWM worker duty cycle to in[4] with the multiplier (in[4] * 3120) / 255
}
0x21 (LAMBDA1_HEATER): {
If the Lambda1 is not accessible or not equipped it returns INVALID_PIN, if the Lambda1 dewpoint is exceeded or in[4] is greater than 51, it returns INVALID_CONDITIONS, else it sets the PWM worker duty cycle to in[4] with the multiplier (in[4] * 3120) / 255
}
0x36 (INTAKE_FLAP): {
If the IntakeFlap is not accessible it returns INVALID_PIN, if the in[4] is 0x00 it OPENS the flap, if it's 0xFF it CLOSES the flap. Else it returns INVALID_DUTY_CYCLE
}
0x49 (??): {
It never fails
}
0x4C (??): {
It never fails
}
0x4D (??): {
It never fails
}
0x4E (DISA): {
If in[4] is 0x00, it commands the DISA valve to OPEN, if it's 0xFF it CLOSES the DISA, else returns INVALID_DUTY_CYCLE
0x51 (INJECTION_CYL4): {
If the in[4] is 0x00, it enables fuel cutoff, else checks running conditions and either enables maximum injection or returns INVALID_CONDITIONS
}
0x52 (INJECTION_CYL3): {
If the in[4] is 0x00, it enables fuel cutoff, else checks running conditions and either enables maximum injection or returns INVALID_CONDITIONS
}
0x53 (INJECTION_CYL2): {
If the in[4] is 0x00, it enables fuel cutoff, else checks running conditions and either enables maximum injection or returns INVALID_CONDITIONS
}
0x54 (INJECTION_CYL1): {
If the in[4] is 0x00, it enables fuel cutoff, else checks running conditions and either enables maximum injection or returns INVALID_CONDITIONS
}
0x58 (??): {
??
}
0x59 (??): {
??
}
0x5F (FUEL_PUMP): {
If in[4] is other than 0xFF it returns INVALID_DUTY_CYCLE, if the Vehicle Speed is not 0 or the Fuel Pump cannot be controlled, return INVALID_CONDITIONS, else check additional conditions and power up the Fuel Pump
}
0x72 (AC_COMPRESSOR): {
If in[4] is 0xFF it STOPS the AC compressor, if it's 0x00 it STARTS the compressor, else it returns INVALID_DUTY_CYCLE
}
0x74 (SECONDARY_AIR_VALVE): {
If the Secondary Air Valve is not accessible or not equipped it returns INVALID_PIN, if the in[4] is 0xFF it CLOSES the SA Valve, if it's 0x00 it OPENS the valve, else it returns INVALID_DUTY_CYCLE
}
0x91 (MIL): {
If the vehicle can't access MIL, it returns INVALID_CONDITIONS, if the in[4] is 0x00 it clears the MIL flag, if the in[4] is 0xFF it lights up the MIL, else it returns INVALID_DUTY_CYCLE
}
}
This handler returns a 2 byte output packet: out[3] = in[3] (requested actuator index repeated), out[4] = RET (one of the result values, depending on what the dispatched handler returns)
],
get_addresses: [
in_PID: 0x0D
comment:
Almost the same as PROTO2a::get_addresses, but some values are different.
Moves 24 in-memory pointers to the output packet.
Used by Ediabas job "AIF_LESEN"
The pointers are the same for every firmware version.
Values shown here are for the firmware version "01119700F000P2AG"
The values: out[0-71] {
0x01459A -> "",
0xFFFFFF,
0xFFFFFF,
0xFFFFFF,
0xFFFFFF,
0xFFFFFF,
0xFFFFFF,
0xFFFFFF,
0xFFFFFF,
0xFFFFFF,
0xFFFFFF,
0xFFFFFF,
0xFFFFFF,
0xFFFFFF,
0xFFFFFF,
0x008010 -> "01119700F000P2AG",
0x0144B0 -> &TMP_SECRET_ARR[32],
0x01459C -> "-",
0x003FE6 -> "01119700",
0x03FCB0 -> "01119700F000",
0x03FD60 -> &VIN[46],
0x01459D -> "d",
0x03FD20 -> "4399.26",
0x003F20 -> &SEED_KEY[22]
}
Does not use the input packet.
Never fails.
Sets output packet type to OKAY.
Sets the PROTO2b::message_size to 72 (combined length of all magic bytes).
],
handler_0x0E: [
in_PID: 0x0E
comment:
Reads 3 bytes that are only ever used by this handler and PROTO2b::handler_0x0F.
Maybe restoring some modification timestamp or signature.
Moves 3 bytes to the output packet of type OKAY.
Does not use the input packet.
Never fails.
],
handler_0x0F: [
in_PID: 0x0F
comment:
Writes 3 bytes that are only ever used by this hander and PROTO2b::handler_0x0E.
Maybe setting some modification timestamp or signature.
Expects the bytes in in[3...5].
Returns a blank packet of type OKAY.
Never fails.
],
handler_0x14: [
in_PID: 0x14
comment:
Expects the following structured input: {
in[3] -> count of something
}
If count 0x00 is requested, then this handler counts some matching bytes (up to 76) and writes the size + 2 words to the output packet.
the size of the packet is 5 Bytes and the type is OKAY.
Never fails.
],
handler_0x1B: [
in_PID: 0x1B
comment:
Expects the following structured input: {
in[3] -> MUST be 0xFE
in[4] -> index
}
If the index is 0x01, then this handler moves a compilation string from 0x14000 of size 96 to the output packet of type OKAY.
If the index is 0x02, then this handler moves 2 ints and 7 bytes (combined size 15 Bytes) to the output packet of type OKAY. This is used by Ediabas Job "SP_ZAEHL".
If the index is 0x14, then this handler thunk-calls handler_0x14.
If the index is 0x20, then this handler moves 40 bytes starting from 0xFF96C0 + some other 7 bytes to the output packet of size 47 and type OKAY.
If the index is 0x21, then this handler moves vital Vechicle bytes and words of combined size 51 Bytes to the output packet of type ERROR_ECU_PARAMETER
Else it returns a blank packet of type ERROR_ECU_PARAMETER.
],
handler_0x1C: [
in_PID: 0x1C
comment:
Like handler_0x1B, but read config data not real time values.
0x07 -> read adjustments
0x09 -> read adaptations
],
handler_0x22: [
in_PID: 0x22
comment:
Requires the input in[3] to be equal 0x02
Calls a function that does almost nothing.
],
handler_0x23: [
in_PID: 0x23
comment:
Requires the input in[3] to be equal 0x02
Calls a function that does almost nothing.
],
handler_0x2B: [
in_PID: 0x2B
comment:
Requires the input in[3] to be equal 0x02
Calls a function that does almost nothing.
],
read_Lambda_adjustment: [
in_PID: 0x40
comment:
This handler is used for reading Lambda adjustments.
Expects the following structured input: {
in[3]: {
0x01 -> LAMBDA1
0x02 -> LAMBDA2
}
}
If the in[3] was not a Lambda number it returns a packet of type ERROR_ECU_PARAMETER.
On success returns packet of type OKAY.
],
write_Lambda_adjustment: [
in_PID: 0x41
comment:
This handler is used for writing new Lambda adjustments.
Expects the following structured input: {
in[3]: {
0x01 -> LAMBDA1
0x02 -> LAMBDA2
}
in[4] -> new_value
}
If in[3] was not a Lambda number it returns a packet of type ERROR_ECU_PARAMETER.
If in[3] was LAMBDA1:
If Engine is not at Idle speed or Catalyser is available, returns a blank packet of type ERROR_ECU_REJECTED
Else sets Target_Lambda1_Adjustment to the new_value
If in[3] was LAMBDA2:
If Engine is not at Idle speed or new_value is greater than 0x9E or it's less than 0x62, returns a blank packet of type ERROR_ECU_REJECTED
Else sets Target_Lambda2_Adjustment to the new_value
Returns a blank packet of type OKAY on success
],
apply_Lambda_adjustment: [
in_PID: 0x42
comment:
This handler is used for programming Lambda adjustments.
Expects the following structured input: {
in[3]: {
0x01 -> LAMBDA1
0x02 -> LAMBDA2
}[>
}
If in[3] was not a Lambda number it returns a packet of type ERROR_ECU_PARAMETER
If in[3] was LAMBDA1:
If the Catalyser is available, returns a blank packet of type ERROR_ECU_REJECTED
Else applies the Target_Lambda1_Adjustment set with PROTO2b::write_Lambda_adjustment
If in[3] was LAMBDA2:
The Target_Lambda2_Adjustment is clamped to fit and then applied
On success, this handler returns a blank packet of type OKAY
],
handler_0x43: [
in_PID: 0x43
comment:
This handler clears some adaptations
It's used by the Ediabas Job "ADAP_SELEKTIV_ZURUECK"
Expects the following structured input: {
in[3] -> first bitfield
in[4] -> second bitfield
}
Always returns a blank packet of type OKAY.
Never fails.
],
get_addresses2: [
in_PID: 0x53
comment:
Moves 31 magic-bytes with in-memory pointers to the output packet
Does not use the input packet.
The pointers are the same for every firmware version
Values presented are for the firmware version 01119700F000P2AG
The values: in[0-30] {
0x33 -> '3',
"0261204420",
"078",
"26RT5134",
0x03FD3C -> "26RT5134",
0x03FD24 -> ".26",
0x03FD44 -> "\t000368511"
}
Size of the packet is 31.
Never fails.
],
write_EWS_state: [
in_PID: 0x6C
comment:
This handler checks some pre-conditions based on the given flag.
Expects the following structured input: {
in[3] -> a flag (0 or 1 or undefined)
}
Note that this function clears two bytes in the EWS every time (0xFF8680 and 0xFF86AF).
The handler checks exactly these things:
1. Is the ISN valid? Every word in ISN (0^1, 0^2, 1^2) XOR'ed must be 0:
0: ISN[0] (0x3F64 - 0x3F64)
1: ISN[1] (0x3F66 - 0x3F67)
2: ISN[2] (0x3F68 - 0x3F69)
Additionaly XOR'ing the pre-hashed pairs (0^1, 0^2, 1^2) in the same way as before must equal 0:
0: (ISN[0] ^ 0x0D0B)
1: (ISN[1] ^ 0x1D17)
2: (ISN[2] ^ 0x251F)
If the ISN is invalid, moves 3 to the output packet.
2. Is the flag bigger than 1?
This is error, return a packet of type ERROR_ECU_PARAMETER.
3. Is the EWS unlocked/valid?
If EWS locked/invalid and the flag is different than 1, a 1 is returned in output packet.
If EWS unlocked/valid and the flag is different than 0, a 2 is returned in output packet.
4. Is the Engine running?
If the engine is running return a packet of type ERROR_ECU_REJECTED.
If the error code (or success code) is in the range [0, 3], this handler moves it to the output packet of type OKAY.
If the error code (or success code) is out of range, this handler returns a blank packet with this code being the type.
],
read_EWS_state: [
in_PID: 0x6D
comment:
Read state from EWS (state can be configured with PROTO2b::write_EWS_state).
This handler checks some pre-conditions based on an internal bitfield (0xFF86AD).
Does not use the input packet.
If the error code (or success code) is in the range [0, 2], this handler moves it to the output packet of type OKAY.
If the error code (or success code) is out of range, this handler returns a blank packet with this code being the type.
],
seed_key: [
in_PID: 0x90
comment:
Almost the same as PROTO2a::seed_key
Sends a magic bytes string like handler_0x00, then checksums it, then does a lot of set/clear bit operations.
Expects the following structured input: {
in[1] -> MUST be 8 (the length of the whole input packet)
in[3] -> MUST be 'B' (0x42)
in[4] -> MUST be 'M' (0x4D)
in[5] -> MUST be 'W' (0x57)
}
Never fails.
Normally outputs a blank packet with type ERROR_ECU_REJECTED.
Sometimes outputs a 1 byte (0x00) packet with type OKAY.
],
receive_diagnose: [
in_PID: 0x9E
comment:
Receive the diagnose (or auto-test).
This handler is called by Ediabas Job "DIAGNOSE_ERHALTEN"
Does not use the input packet.
Does nothing, just returns a blank packet of type OKAY
Never fails.
],
end_diagnose: [
in_PID: 0x9F
comment:
Ends diagnostic session (or auto-test).
This handler is called by Ediabas Job "DIAGNOSE_ENDE"
Does not use the input packet.
It seems it's redundant as the same cleanup would be done anyways
Never fails.
]
comment:
A periodically scheduled Userland job calls the appropriate handler (found by in[0]) if a new received message is available.
This protocol implements 7 services [1, 7].
show_current_data: [
in_PID: 0x01
comment:
Moves live data variables (from SAE J1979 [0x00-0x3F]) to the output packet.
Expects the following structured input: {
in[4] -> index of the wanted variable
}
Possible indices are: {
0x00: {
out[5] -> 0xBE
out[6] -> 0x1F
out[7] -> 0xF8
out[8] -> 0x10
}
0x01: {
out[5]:[7-7] -> is_MIL_on
out[5]:[0-6] -> DTC_saved_count
out[6] -> 0x07 (MIS_SUP | FUEL_SUP | CCM_SUP)
out[7] -> 0x69 (CAT_SUP | EVAP_SUP | HTR_SUP)
out[8] -> Vehicle_Status_Tests_Monitor
}
0x03: {
out[5]: {
0x01 -> FUELSYSTEM1_STILL_OPEN_LOOP,
0x02 -> FUELSYSTEM1_CLOSED_LOOP,
0x04 -> FUELSYSTEM1_DRIVEN_OPEN_LOOP,
0x08 -> FUELSYSTEM1_ERROR_OPEN_LOOP
}
out[6] -> 0x00 -> FUELSYSTEM2_NONE
}
0x04 -> out[5] -> Engine_Load
0x05 -> out[5] -> Engine_Coolant_Temp
0x06 -> out[5] -> Vehicle_Short_Term_Fuel_Trim
0x07 -> out[5] -> Vehicle_Long_Term_Fuel_Trim
0x0C -> out[5] -> Engine_RPM
0x0D -> out[5] -> Vechicle_Speed
0x0E -> out[5] -> Engine_Timing_Advance_CYL1
0x0F -> out[5] -> Engine_IAT
0x10 -> out[5] -> Engine_MAF
0x11 -> out[5] -> Engine_Throttle_Percentage
0x12 -> out[5]: {
0x01 -> SECONDARY_AIR_PRE_CAT,
0x04 -> SECONDARY_AIR_OFF
}
0x13 -> out[5] -> 0x03 (BANK1_SENSOR1 | BANK1_SENSOR2)
0x14: {
out[5] -> Vehicle_Lambda1_Voltage,
out[6] -> Engine_Short_Term_Fuel_Trim
}
0x15: {
out[5] -> Vehicle_Lambda2_Voltage,
out[6] -> 0xFF
}
0x1C -> out[5] -> 0x06 (EOBD)
0x20: {
out[5] -> 0x80
out[6] -> 0x00
out[7] -> 0x00
out[8] -> 0x00
}
0x21: {
out[5-6] -> Vehicle_Distance_On_MIL (hi_byte first),
}
}
The response consists of out[3] = 0x41 (handler idx (1) + 0x40 which means successful response), out[4] = in[4] (wanted index), out[5...] (response bytes)
],
show_freeze_frame_data: [
in_PID: 0x02
comment:
Moves freeze frame variables to the output packet.
Expects the following structured input: {
in[4] -> index of the wanted variable
in[5] -> frame index (only one frame so this is unused)
}
Possible indices are: {
0x00: {
out[6] -> 0x7E
out[7] -> 0x18
out[8] -> 0x00
out[9] -> 0x00
}
0x02: {
out[6-7] -> BCD_encoded_FreezeFrame_DTC (hi_byte first or 0x00 if no DTC)
}
0x03: {
out[6] -> FreezeFrame_FuelSystem1_Status,
out[7] -> 0x00 (no FuelSystem2)
}
0x04 -> out[6] -> FreezeFrame_Engine_Load
0x05 -> out[6] -> FreezeFrame_Engine_Coolant_Temp
0x06 -> out[6] -> FreezeFrame_Engine_STFT_Bank1
0x07 -> out[6] -> FreezeFrame_Engine_LTFT_Bank1
0x0C -> out[6-7] -> FreezeFrame_Engine_RPM (hi_byte first),
0x0D -> out[6] -> FreezeFrame_Vehicle_Speed
}
The response consists of out[3] = 0x42 (handler idx (2) + 0x40 which means successful response), out[4] = in[4] (wanted index), out[5] = in[5] (frame index repeated), out[6...] (response bytes)
],
show_stored_DTC: [
in_PID: 0x03
comment:
Moves all DTCs with info to the output packets (segmented using ISO 15765-2).
Does not use the input packet.
The response consists of out[3] = 0x43 (handler idx (3) + 0x40 which means successful response), out[4...] each DTC frame has 6 bytes.
],
clear_DTC: [
in_PID: 0x04
comment:
Clears all DTCs and saved freeze frames.
Does not use the input packet.
The response consists of out[3] = 0x44 (handler idx (4) + 0x40 which means successful response)
],
show_Lambda_test_results: [
in_PID: 0x05
comment:
Reads Lambda test results
Expects the following structured input: {
in[4] -> index of a test
in[5]: {
0x01 -> TEST_LAMBDA1,
0x02 -> TEST_LAMBDA2
}
}
Possible indices are: {
0x00: {
out[6] -> 0x03
out[7] -> 0x00
out[8] -> 0x00
out[9] -> 0x00
}
0x07: {
out[6] -> Test7_LambdaX_Result (depends on in[5]),
out[7] -> 0x00 0.00V (Test7_Lambda_Min_Result),
out[8] -> 0x3D 0.31V (Test7_Lambda_Max_Result)
}
0x08: {
out[6] -> Test8_LambdaX_Result (depends on in[5]),
out[7] -> 0x7E 0.63V (Test8_Lambda_Min_Result),
out[8] -> 0xFF 1.28V (Test8_Lambda_Max_Result)
}
}
],
show_test_results: [
in_PID: 0x06
comment:
Reads some test results to the output packet.
The tests are not known, but all of them use the same "COMPONENT01" which is most definietly Lambda1 (Pre Cat)
Expects the following structured input: {
in[4] -> index of a test
}
Every index returns 7 bytes.
Possible indices are: {
0x00 -> support status bit but 5 bytes this time {0xFF, 0xE4, 0x00, 0x00, 0x00}
0x01 -> ...
0x02 -> ... (sends two packets at once)
0x03 -> ...
0x06 -> ... (sends two packets at once)
],
show_pending_DTC: [
in_PID: 0x07
comment:
Moves all Pending DTCs with info to the output packets (segmented using ISO 15765-2).
Here it does the same as OBD2::show_stored_DTC
Does not use the input packet.
The response consists of out[3] = 0x47 (handler idx (7) + 0x40 which means successful response), out[4...] each DTC frame has 6 bytes.
]