Arduino Renault ECU Decoder & IMMO emulator

1: standard
2: advanced1
3: advanced2
4: semiauto
5: clear by code
6: set by code
>>5
5: clearing by code
Give code
>>1234
Cycle 1234
...
//(c) 2020 Janne Kivijakola

#define IMMO_PIN 2
#define IMMO_PIN_ACTIVE_STATE HIGH
#define PWR_PIN 3
#define PWR_PIN_ACTIVE_STATE HIGH

unsigned long DELAY_TIME = 12500; // 12.5 msec

void setup()
{
    Serial.begin(115200);
    Serial.print("\n\nStart\n");
    pinMode(IMMO_PIN, OUTPUT);
    digitalWrite(IMMO_PIN, !IMMO_PIN_ACTIVE_STATE);
    pinMode(PWR_PIN, OUTPUT);
    digitalWrite(PWR_PIN, !PWR_PIN_ACTIVE_STATE);
}

void loop()
{
    char serialByte = 0;
    Serial.println("\n1: standard");
    Serial.println("2: advanced1");
    Serial.println("3: advanced2");
    Serial.println("4: semiauto");
    Serial.println("5: clear by code");
    Serial.println("6: set by code (IMMO emulator)");
    Serial.print(">>");
    while (serialByte < '0' || serialByte > '6')
    {
        if (Serial.available() > 0)
        {
            serialByte = Serial.read();
        }
    }
    Serial.println(serialByte);
    switch (serialByte)
    {
    case '1':
        standard();
        break;
    case '2':
        advanced1();
        break;
    case '3':
        advanced2();
        break;
    case '4':
        semiauto();
        break;
    case '5':
        clearbycode();
        break;
    case '6':
        setcode();
        break;
    }

}

void standard()
{
  
    Serial.println("\n1: standard");
        while (Serial.available() > 0)
        Serial.read();
    process(16, 2, 0, 0, 0);
}

void advanced1()
{
    Serial.println("2: advanced1");
        while (Serial.available() > 0)
        Serial.read();
    process(16, 5, 0, 0, 0);
}

void advanced2()
{
    Serial.println("3: advanced2");
        while (Serial.available() > 0)
        Serial.read();
    process(48, 6, 0, 0, 0);
}

void semiauto()
{
    Serial.println("4: semiauto");
        while (Serial.available() > 0)
        Serial.read();
    process(16, 7, 1, 0, 0);
}

void clearbycode()
{
    int code = 472;
    Serial.println("5: clearing by code");
    code = readInteger();

    process(48, 2, 0, code, 0);
}

void setcode()
{
    int code = 0;
    Serial.println("5: setting code");
    while(code<=0)
      code = readInteger();
    
    process(48, 2, 0, code, 1);
}
int readInteger()
{
    char serialByte = 0;
    int receivedBytes = 0;
    char serbuffer[10] ={};
    Serial.print("Give code\n>>");
    while (Serial.available() > 0)
        Serial.read();
    while (1)
    {
        if (Serial.available() > 0)
        {
            serialByte = Serial.read();
            if((serialByte >= '0' && serialByte <= '9')||receivedBytes > 4)
            {
                serbuffer[receivedBytes++] = serialByte;
            }
            else
                break;
        }
       
    }
    Serial.println(serbuffer);
    return atoi(serbuffer);
}

void process(int resetStateBits, int rounds, int mode, int myOwnCode, int setCode)
{
    unsigned long delayStart = 0;
    int counter = 1;
    int bitsRemaining = 0;
    int currentRound = 0;
    unsigned long pipeline = 0;
    int resetStateRemaining = 0;
    int dataWidth = 22;
    if (mode == 1)
    {
        dataWidth = 9;
    }

    if(myOwnCode!=0)
    {
      counter = myOwnCode;
      resetStateRemaining = resetStateBits;
    }

    delayStart = micros();

    while (1)
    {
        int immoPinState = 0;
        if (((micros() - delayStart) >= DELAY_TIME))
        {
            delayStart += DELAY_TIME;

            if (!bitsRemaining)
            {
                if (Serial.available() > 0)
                    return;

                if (!mode)
                    bitsRemaining = 32;
                else
                    bitsRemaining = 18;

                if (currentRound >= rounds && myOwnCode == 0)
                {

                    counter++;
                    currentRound = 0;
                    resetStateRemaining = resetStateBits;
                }
                unsigned long A=1;
                if(setCode==1)
                {
                    A=0;
                }

                if (!mode)

                /*
                 * IGN __-------------------------------------------------___-------------------------------------------------__
                 * IMMO__SSS_AIIIBJJJJCKKKKDLLLLE_SSS_AIIIBJJJJCKKKKDLLLLE___SSS_AIIIBJJJJCKKKKDLLLLE_SSS_AIIIBJJJJCKKKKDLLLLE
                 *            round1                    round2                       round1                    round2
                 *                         counter1                                             counter2
                 * A: Clear code bit                        
                 * B,C,D,E: Sync bits
                 * I,J,K,L: Data bits
                 * S: 
                 */
                                              
                    pipeline = A << 19 //A 
                            | ((counter & 0x7000UL) << 4) //III
                            | (1UL & ~(0x1UL & (counter >> 12))) << 15 //B
                            | ((counter & 0x0f00) << 3) //JJJJ
                            | (1 & ~(0x1 & (counter >> 8))) << 10 //C
                            | ((counter & 0x00f0) << 2) //KKKK
                            | (1 & ~(0x1 & (counter >> 4))) << 5 //D
                            | ((counter & 0x000f) << 1) //LLLL
                            | (1 & ~(0x1 & (counter >> 0))) << 0; //E
                else

                 /*
                 * IGN __---------------------------------------...___---------------------------------------...
                 * IMMO__SSS_IIIIIIII_SSS_IIIIIIII_SSS_IIIIIIII_...___SSS_IIIIIIII_SSS_IIIIIIII_SSS_IIIIIIII_...
                 *            round1      round2        round3             round1       round2        round3
                 *                         counter1                                     counter2
                 */
                    pipeline = ((counter + 1) & 0x00ffUL) << 13;//IIIIIIII

                if (currentRound == 0)
                {
                    Serial.print("Cycle ");
                    Serial.print(counter);
                    Serial.print(" / ");

                    if (mode == 0)
                    {
                        Serial.print("6562");
                    }
                    else
                    {
                        int code = (counter & 3) + 1
                                + 10 * (((counter >> 2) & 3) + 1)
                                + 100 * (((counter >> 4) & 3) + 1)
                                + 1000 * (((counter >> 6) & 3) + 1);
                        Serial.print("255");
                        Serial.print(" code: ");
                        Serial.print(code);
                    }

                    Serial.print("\n");

                    if ((counter == 6562 && mode == 0)
                            || (counter == 255 && mode == 1))
                    {
                        Serial.print("DONE\n");
                        return;
                    }
                }
                currentRound++;
            }

            if (resetStateRemaining)
            {
                digitalWrite(PWR_PIN, !PWR_PIN_ACTIVE_STATE);
                resetStateRemaining--;
            }
            else
            {
                //start bits
                if (bitsRemaining > dataWidth)
                    immoPinState = 1;
                //data streaming
                else
                {
                    immoPinState = (pipeline & 0x100000UL) >> 20;
                    pipeline <<= 1;
                }
                if (immoPinState)
                {
                    digitalWrite(IMMO_PIN, IMMO_PIN_ACTIVE_STATE);
                }
                else
                {
                    digitalWrite(IMMO_PIN, !IMMO_PIN_ACTIVE_STATE);
                }
                digitalWrite(PWR_PIN, PWR_PIN_ACTIVE_STATE);
                bitsRemaining--;
            }

        }
    }
}

Koodi tallennettuna ECU:n flashiin

Dekoodaussekvenssi