Read and write mileage from IPC (EEPROM)

IPC - Instrument cluster panels (like Convers+)
User avatar
Ursadon
Active member
Posts: 69
Joined: 10 Mar 2019, 19:23

Re: Read and write mileage from IPC (EEPROM)

Post by Ursadon » 13 Jul 2019, 15:38

Go4IT wrote:
13 Jul 2019, 15:17
Yes, you're right. Even the algo you formed is more compact than mine, but it is exactly the same. Reverse engineered from IPC firmware.
There is another one at 0x778 as 4 bytes. Coded with parity and CRC, multiplied by 10, giving two numbers behind comma. This seems the one shown in the TEST modus of the IPC. I only miss the one for the trip odo. It must be there also. Just for completeness ;-)

BTW: Did you manage to write the EEPROM via CAN now?
Thx for 0x778, i forgot about this value :)
I have a proof-of-concept eeprom write algo.
Since i2c mapped to 0x6000000, it easy to write to it using Secondary Bootloader (*-AA.vbf). I think, UCDS using same technique to correct odometer value.
Not native English speaker :cry:
IPC hacker, embedded cracker, tamer of bears & beers

Go4IT
Pro
Posts: 459
Joined: 08 Feb 2019, 12:25

Re: Read and write mileage from IPC (EEPROM)

Post by Go4IT » 13 Jul 2019, 17:53

Ups, sorry, typo, i mean 0x788 not 0x778 !

Go4IT
Pro
Posts: 459
Joined: 08 Feb 2019, 12:25

Re: Read and write mileage from IPC (EEPROM)

Post by Go4IT » 13 Jul 2019, 19:48

At least it is very simple to calc the ODO from the bytes. Just take the two first bytes at offset 0x774 as a word, shift this by 4 bits to right (=divide by 0x10) and multiply it by 5 and 0x80 and store this value. Then take the last byte of each of the 4-byte groups, logical and it with 0x7F and add 0x01 to the value. Add all those values to the previous stored value. Then divide that by 5 and add 1 and you got your KM value.
Example: 0x774 79 D9 FF 26 79 D9 FF A2 79 D9 FF 23 79 D9 FF A4 79 D9 FF 25

Code: Select all

KM_HIGH = (0x79D9 / 0x10) * 5 * 0x80 = 0x13 0880
KM_LOW = 0x27 + 0x23 + 0x24 + 0x25 + 0x26 = 0xB9
KM = (0x130880 + 0xB9) / 5 + 1 = 0x3CEA6 (=249.510km)

User avatar
Ursadon
Active member
Posts: 69
Joined: 10 Mar 2019, 19:23

Re: Read and write mileage from IPC (EEPROM)

Post by Ursadon » 14 Jul 2019, 02:44

Go4IT wrote:
13 Jul 2019, 19:48
At least it is very simple to calc the ODO from the bytes. Just take the two first bytes at offset 0x774 as a word, shift this by 4 bits to right (=divide by 0x10) and multiply it by 5 and 0x80 and store this value. Then take the last byte of each of the 4-byte groups, logical and it with 0x7F and add 0x01 to the value. Add all those values to the previous stored value. Then divide that by 5 and add 1 and you got your KM value.
Example: 0x774 79 D9 FF 26 79 D9 FF A2 79 D9 FF 23 79 D9 FF A4 79 D9 FF 25

Code: Select all

KM_HIGH = (0x79D9 / 0x10) * 5 * 0x80 = 0x13 0880
KM_LOW = 0x27 + 0x23 + 0x24 + 0x25 + 0x26 = 0xB9
KM = (0x130880 + 0xB9) / 5 + 1 = 0x3CEA6 (=249.510km)
You forgot to prepend KM_HIGH with inverted high halfbyte of 79D9FF26.
Otherwise the max km value is 524288+640
Not native English speaker :cry:
IPC hacker, embedded cracker, tamer of bears & beers

Go4IT
Pro
Posts: 459
Joined: 08 Feb 2019, 12:25

Re: Read and write mileage from IPC (EEPROM)

Post by Go4IT » 14 Jul 2019, 08:19

Here is a C example off how to decode mileage from bytes:

Code: Select all

BYTE g_ubMileage[20];

// CRC Table. 16 Bytes found in 1MB Flash ("7M2T-14C026-AG") at 0x4B064
BYTE g_ubCrc8Bit[16] =
{
    0x0, 0xD, 0x7, 0xA,
    0xE, 0x3, 0x9, 0x4,
    0x1, 0xC, 0x6, 0xB,
    0xF, 0x2, 0x8, 0x5,
};

// return word from mileage data entry (five entries, four bytes each) in Big Endian
WORD get_mileage_entry(int idx, int iWord)
{
    if(idx < 0 || idx > 4)
        return 0xFFFF;

    if(iWord != 0 && iWord != 1)
        return 0xFFFF;

    return (g_ubMileage[(idx * 4) + (iWord * 2) + 0] << 8) |
           (g_ubMileage[(idx * 4) + (iWord * 2) + 1] << 0);
}

// calculate 4-bit CRC of a 16-bit word
BYTE calc_crc_4bit(WORD w)
{
    BYTE ubCrc = 0xF;   
    int i;

    for(i = 0; i < 4; i++)
    {
        ubCrc = g_ubCrc8Bit[ubCrc] ^ (w & 0xF);
        w = (w >> 4);
    }

    return ubCrc;
}

// get parity bit of a byte (even/odd)
BYTE get_parity(BYTE ub)
{
    BYTE ubParity = 0;

    while(ub != 0)
    {
        ubParity++;
        ub &= (ub - ubParity);
    }

    return ubParity & 0x01;
}

// get MSB mileage bits, check for valid CRC
WORD get_mileage_entry_and_check_crc(int idx)
{
    if(idx < 0 || idx > 4)
        return 0xFFFF;

    WORD w1 = get_mileage_entry(idx, 0);
    WORD w2 = get_mileage_entry(idx, 1);

    BYTE ub = (w2 >> 8); // MSB of word
    WORD w = (w1 >> 4) | (((~ub) & 0xF0) << 8);
    BYTE ubCrc = calc_crc_4bit(w);

    if(ubCrc == (w1 & 0x0F)) // CRC valid ?
        return w;
    else
        return 0xFFFF;
}

// get LSB mileage bits, check for valid parity
WORD get_mileage_entry_and_check_parity(int idx)
{
    if(idx < 0 || idx > 4)
        return 0xFFFF;

    WORD w1 = get_mileage_entry(idx, 0);
    WORD w2 = get_mileage_entry(idx, 1);

    BYTE ub = (w2 & 0xFF); // LSB of word

    if(get_parity(ub)) // odd parity ?
        return (ub & 0x7F) + 1;
    else
        return 0;
}

void calc_mileage(BYTE *ubMileage)
{
    // copy data into buffer
    memcpy(g_ubMileage, ubMileage, sizeof(g_ubMileage));

    // calculate sum of each all five entries
    DWORD dw1sum = 0;
    WORD w2sum = 0;

    int i;
    for(i = 0; i < 5; i++)
    {
        WORD w1 = get_mileage_entry_and_check_crc(i);    // MSB of mileage
        WORD w2 = get_mileage_entry_and_check_parity(i); // LSB of mileage
        dw1sum += w1;
        w2sum += w2;
    }

    // combine MSB and LSB
    DWORD dw = (dw1sum << 7) + w2sum;

    // final calulation, 200 meter resolution
    dw = (dw / 5) + 1;
    return(dw);
}

// try it...
void main()
{
  // Test data of 249.510 km (offset 0x774)
  BYTE testdata[20] = 
  {
    0x79, 0xD9, 0xFF, 0x26,
    0x79, 0xD9, 0xFF, 0xA2,
    0x79, 0xD9, 0xFF, 0x23,
    0x79, 0xD9, 0xFF, 0xA4,
    0x79, 0xD9, 0xFF, 0x25,
  };
  WORD km = calc_mileage(testdata);
  printf("Mileage is %d km\n", km);
}

Go4IT
Pro
Posts: 459
Joined: 08 Feb 2019, 12:25

Re: Read and write mileage from IPC (EEPROM)

Post by Go4IT » 14 Jul 2019, 08:26

Ursadon wrote:
14 Jul 2019, 02:44
You forgot to prepend KM_HIGH with inverted high halfbyte of 79D9FF26.
Otherwise the max km value is 524288+640
Yes, it was a known simplyfication, just to demonstrate how the algo works :D
The beauty of this design is that EEPROM data changes for the lower bits of the milage are distributed over 5 memory locations in turn. So by writing the milage every 200 meter will result in a theoretical max. of 1 million kilometers.

Go4IT
Pro
Posts: 459
Joined: 08 Feb 2019, 12:25

Re: Read and write mileage from IPC (EEPROM)

Post by Go4IT » 14 Jul 2019, 09:15

I try to figure out how to do the reverse, calc bytes from odo (Pseudo-Code):

Code: Select all

function calc_crc(DWORD) {
  ...
}

DWORD km = 0x3CEA6;  // =249.510 km
DWORD dw = (km - 1) * 5  // =0x130939
DWORD dw1sum = dw / 0x80  // =0x2612 (equals dw >> 7)
WORD w2sum = (dw - dw1sum) & 0x7F // =0x28
WORD dw1crc = calc_crc(dw1sum)
WORD msb = (dw1crc * 0x100) | dw1sum
WORD lsb[5] = ...

Gwe89
Active member
Posts: 134
Joined: 09 Feb 2019, 21:21

Re: Read and write mileage from IPC (EEPROM)

Post by Gwe89 » 22 Sep 2019, 09:43

Hi does your new tool only work with the els27

Artist
Starter
Posts: 48
Joined: 21 Sep 2019, 08:49

Re: Read and write mileage from IPC (EEPROM)

Post by Artist » 22 Sep 2019, 09:56

Yes, the official release only supports Els 27.
You need to buy it, it's not a bad investment ...

Gwe89
Active member
Posts: 134
Joined: 09 Feb 2019, 21:21

Re: Read and write mileage from IPC (EEPROM)

Post by Gwe89 » 29 Sep 2019, 19:27

I have been changing mileage this way years ago I found where to edit by reading the eeprom and then setting mileage to 0 with ucds then reading it again then compared them both
AF 00 00 FF EF 00 06 FF 80 00 06 FF 80 00 06 FF 80 00 06 FF 80 00 06 FF 80 D0 00 00 32
sets it to 0
You do not have the required permissions to view the files attached to this post.

Post Reply