Just4Trionic - CAN and BDM FLASH programmer for Saab cars

Dependencies:   mbed

t7utils.cpp

Committer:
Just4pLeisure
Date:
2011-06-07
Revision:
3:92dae9083c83
Child:
4:682d96ff6d79

File content as of revision 3:92dae9083c83:

/*******************************************************************************

t7utils.cpp
(c) 2011 by Sophie Dexter
portions (c) Tomi Liljemark (firstname.surname@gmail.com)

This C++ module provides functions for communicating simple messages to and from
the T7 ECU

********************************************************************************

WARNING: Use at your own risk, sadly this software comes with no guarantees.
This software is provided 'free' and in good faith, but the author does not
accept liability for any damage arising from its use.

*******************************************************************************/

#include "t7utils.h"


//
// t7_initialise
//
// sends an initialisation message to the T7 ECU
// but doesn't displays anything.
//
// inputs:    none
// return:    bool TRUE if there was a message, FALSE if no message.
//


bool t7_initialise() {
    // send a can message to the T7 requesting that it initialises CAN communication with Just4Trionic
    char T7TxMsg[] = T7INITMSG;
    if (!can_send_timeout (T7CMNDID, T7TxMsg, 8, T7MESSAGETIMEOUT))
        return FALSE;
    // wait for the T7 to reply
    char T7RxMsg[8];
    // if a message is not received, has the wrong id
    if (!can_wait_timeout(T7RESPID, T7RxMsg, 8, T7MESSAGETIMEOUT))
        return FALSE;
    /* DEBUG info...
        for (int i = 0; i < 8; i++ ) printf("0x%02X ", T7RxMsg[i] );
        printf(" init\r\n");
    */
    return TRUE;
}

//
// t7_authenticate
//
// sends an authentication message to the T7 ECU
// but doesn't displays anything.
//
// inputs:    none
// return:    bool TRUE if there was a message, FALSE if no message.
//

bool t7_authenticate() {
    uint16_t seed, key;
//    uint16_t i;
    char T7TxAck[] = T7ACK_MSG;
    char T7TxMsg[] = T7SEC_MSG;
    char T7TxKey[] = T7KEY_MSG;
    char T7RxMsg[8];
    // Send "Request Seed" to Trionic7
    if (!can_send_timeout (T7SEC_ID, T7TxMsg, 8, T7MESSAGETIMEOUT))
        return FALSE;
    // wait for the T7 to reply
    // Read "Seed"
    // if a message is not received id return false
    if (!can_wait_timeout(T7SEC_RX, T7RxMsg, 8, T7MESSAGETIMEOUT))
        return FALSE;
    /* DEBUG info...
        for (i = 0; i < 8; i++ ) printf("0x%02X ", T7RxMsg[i] );
        printf(" seed\r\n");
    */
    // Send Ack
    T7TxAck[3] = T7RxMsg[0] & 0xBF;
    if (!can_send_timeout (T7ACK_ID, T7TxAck, 8, T7MESSAGETIMEOUT))
        return FALSE;
    // Send "Key", try two different methods of calculating the key
    seed = T7RxMsg[5] << 8 | T7RxMsg[6];
    for (int method = 0; method < 2; method++ ) {
        key = seed << 2;
        key &= 0xFFFF;
        key ^= ( method ? 0x4081 : 0x8142 );
        key -= ( method ? 0x1F6F : 0x2356 );
        key &= 0xFFFF;
        T7TxKey[5] = ( key >> 8 ) & 0xFF;
        T7TxKey[6] = key & 0xFF;
        if (!can_send_timeout (T7SEC_ID, T7TxKey, 8, T7MESSAGETIMEOUT))
            return FALSE;
        // Wait for response
        // if a message is not received id return false
        if (!can_wait_timeout(T7SEC_RX, T7RxMsg, 8, T7MESSAGETIMEOUT))
            return FALSE;
        /* DEBUG info...
                for (i = 0; i < 8; i++ ) printf("0x%02X ", T7RxMsg[i] );
                printf(" key %d 0x%02X 0x%02X\r\n", method, T7RxMsg[3], T7RxMsg[5]);
        */
        // Send Ack
        T7TxAck[3] = T7RxMsg[0] & 0xBF;
        if (!can_send_timeout (T7ACK_ID, T7TxAck, 8, T7MESSAGETIMEOUT)) {
            /* DEBUG info...
                        printf("Key ACK message timeout\r\n");
            */
            return FALSE;
        }
        if ( T7RxMsg[3] == 0x67 && T7RxMsg[5] == 0x34 ) {
            /* DEBUG info...
                        printf("Key %d Accepted\r\n", method);
            */
            return TRUE;
        } else {
            /* DEBUG info...
                        printf("Key %d Failed\r\n", method);
            */
        }
    }
    return FALSE;
}
//
// t7_dump
//
// dumps the T7 BIN File
// but doesn't displays anything.
//
// inputs:    none
// return:    bool TRUE if there was a message, FALSE if no message.
//

bool t7_dump() {
    uint32_t received;
    uint8_t byte_count, retries, i;
    char T7_dump_jumpa[] = T7DMPJP1A;
    char T7_dump_jumpb[] = T7DMPJP1B;
    char T7_dump_ack[] = T7DMP_ACK;
    char T7_dump_data[] = T7DMPDATA;
    char T7_dump_end[] = T7DMP_END;
    char T7RxMsg[8];

    printf("Creating FLASH dump file...\r\n");
    FILE *fp = fopen("/local/original.bin", "w");    // Open "original.bin" on the local file system for writing
    if (!fp) {
        perror ("The following error occured");
        return TERM_ERR;
    }

    timer.reset();
    timer.start();

    received = 0;
    printf("       %% complete.\r");
    while (received < T7FLASHSIZE) {
//        T7_dump_jumpa[7] = ((T7FLASHSIZE - received) < 0xEF) ? (T7FLASHSIZE - received) : 0xEF;
        T7_dump_jumpb[2] = (received >> 16) & 0xFF;
        T7_dump_jumpb[3] = (received >> 8) & 0xFF;
        T7_dump_jumpb[4] = received & 0xFF;
        // Send read address and length to Trionic
        if (!can_send_timeout (T7SEC_ID, T7_dump_jumpa, 8, T7MESSAGETIMEOUT)) {
            printf("err t7utils line: %d\r\n", __LINE__ );
            fclose(fp);
            return FALSE;
        }
        if (!can_send_timeout (T7SEC_ID, T7_dump_jumpb, 8, T7MESSAGETIMEOUT)) {
            printf("err t7utils line: %d\r\n", __LINE__ );
            fclose(fp);
            return FALSE;
        }
        // Wait for a response
        if (!can_wait_timeout(T7SEC_RX, T7RxMsg, 8, T7MESSAGETIMEOUT)) {
            printf("err t7utils line: %d\r\n", __LINE__ );
            fclose(fp);
            return FALSE;
        }
        /* DEBUG info...
            for (i = 0; i < 8; i++ ) printf("0x%02X ", T7RxMsg[i] );
            printf(" seed\r\n");
        */
        // Send Ack
        T7_dump_ack[3] = T7RxMsg[0] & 0xBF;
        if (!can_send_timeout (T7ACK_ID, T7_dump_ack, 8, T7MESSAGETIMEOUT)) {
            printf("ERROR Asking1: %5.1f %% done\r\n", 100*(float)received/(float)T7FLASHSIZE);
            printf("err t7utils line: %d\r\n", __LINE__ );
            fclose(fp);
            return FALSE;
        }
        if ((T7RxMsg[3] != 0x6C) ||(T7RxMsg[4] != 0xF0)) {
            printf("ERROR Asking2: %5.1f %% done\r\n", 100*(float)received/(float)T7FLASHSIZE);
            printf("err t7utils line: %d\r\n", __LINE__ );
            fclose(fp);
            return FALSE;
        }
        // Ask T7 ECU to start sending data
        for (retries = 0 ; retries <10 ; retries++ ) {
            if (!can_send_timeout (T7SEC_ID, T7_dump_data, 8, T7MESSAGETIMEOUT)) {
                printf("err t7utils line: %d\r\n", __LINE__ );
                fclose(fp);
                return FALSE;
            }
            // Read mesages from the T7 ECU
            byte_count = 0;
            T7RxMsg[0] = 0x00;
            while (T7RxMsg[0] != 0x80 && T7RxMsg[0] != 0xC0) {
                if (!can_wait_timeout(T7SEC_RX, T7RxMsg, 8, T7MESSAGETIMEOUT))
                    break;
                // Need to process the received data here!
                // Send Ack
                T7_dump_ack[3] = T7RxMsg[0] & 0xBF;
                if (!can_send_timeout (T7ACK_ID, T7_dump_ack, 8, T7MESSAGETIMEOUT)) {
                    printf("ERROR processing: %5.1f %% done\r\n", 100*(float)received/(float)T7FLASHSIZE);
                    printf("err t7utils line: %d\r\n", __LINE__ );
                    fclose(fp);
                    return FALSE;
                }
//                /* DEBUG info...
//                for (i = 0; i < 8; i++ ) printf("0x%02X ", T7RxMsg[i] );
//                for (i = 2; i < 8; i++ ) printf("%c ", T7RxMsg[i] );
//                printf(" data\r\n");
                for (i = 2; i < 8; i++ )
                    file_buffer[byte_count++] = (T7RxMsg[i]);
//                */
            }
            // Success if these conditions met
            if (T7RxMsg[0] == 0x80 || T7RxMsg[0] == 0xC0)
                break;
//            printf("retries: %d\r\n", retries);
        }
        if (retries > 9) {
            printf("err t7utils line: %d\r\n", __LINE__ );
            printf("Retries: %d, Done: %5.2f %%\r\n", retries, 100*(float)received/(float)T7FLASHSIZE );
            fclose(fp);
            return FALSE;
        }
//        received += 0xEF;
        received += 0x80;
//        printf("Retries: %d, Done: %5.2f %%\r\n", retries, 100*(float)received/(float)T7FLASHSIZE );
        printf("%6.2f\r", 100*(float)received/(float)T7FLASHSIZE );
        fwrite((file_buffer + 3), 1, 0x80, fp);
        if (ferror (fp)) {
            fclose (fp);
            printf ("Error writing to the FLASH BIN file.\r\n");
            return TERM_ERR;
        }
    }
    printf("\n");
    // Send Message to T7 ECU to say that we have finished
    if (!can_send_timeout (T7SEC_ID, T7_dump_end, 8, T7MESSAGETIMEOUT)) {
        fclose(fp);
        return FALSE;
    }
    // Wait for response
    if (!can_wait_timeout(T7SEC_RX, T7RxMsg, 8, T7MESSAGETIMEOUT)) {
        fclose(fp);
        return FALSE;
    }
// Send Ack
    T7_dump_ack[3] = T7RxMsg[0] & 0xBF;
    if (!can_send_timeout (T7ACK_ID, T7_dump_ack, 8, T7MESSAGETIMEOUT)) {
        printf("ERROR closing1: %5.1f %% done\r\n", 100*(float)received/(float)T7FLASHSIZE);
        printf("err t7utils line: %d\r\n", __LINE__ );
        fclose(fp);
        return FALSE;
    }
    if (T7RxMsg[3] != 0xC2) {
        printf("ERROR closing2: %5.1f %% done\r\n", 100*(float)received/(float)T7FLASHSIZE);
        printf("err t7utils line: %d\r\n", __LINE__ );
        fclose(fp);
        return FALSE;
    }
    timer.stop();
    printf("SUCCESS! Getting the FLASH dump took %#.1f seconds.\r\n",timer.read());
    fclose(fp);
    return TRUE;
}

bool t7_erase() {
    char T7_erase_msga[]   = { 0x40, 0xA1, 0x02, 0x31, 0x52, 0x00, 0x00, 0x00 };
    char T7_erase_msgb[]   = { 0x40, 0xA1, 0x02, 0x31, 0x53, 0x00, 0x00, 0x00 };
    char T7_erase_confirm[]   = { 0x40, 0xA1, 0x01, 0x3E, 0x00, 0x00, 0x00, 0x00 };
    char T7_erase_ack[]     = { 0x40, 0xA1, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00 };
    char data[8];
    int i;

    printf("Erasing T7 ECU FLASH...\r\n");

    data[3] = 0;
    i = 0;
    while ( data[3] != 0x71 && i < 10) {
        // Send "Request to ERASE" to Trionic
        if (!can_send_timeout (T7SEC_ID, T7_erase_msga, 8, T7MESSAGETIMEOUT)) {
            printf("err t7utils line: %d\r\n", __LINE__ );
            return FALSE;
        }
        if (!can_wait_timeout(T7SEC_RX, data, 8, T7MESSAGETIMEOUT)) {
            printf("err t7utils line: %d\r\n", __LINE__ );
            return FALSE;
        }
        T7_erase_ack[3] = data[0] & 0xBF;
        if (!can_send_timeout (T7ACK_ID, T7_erase_ack, 8, T7MESSAGETIMEOUT)) {
            printf("err t7utils line: %d\r\n", __LINE__ );
            return FALSE;
        }
        wait_ms(100);
        i++;
        printf(".");
    }
    printf("\r\n");
    // Check to see if erase operation lasted longer than 1 sec...
    if (i >=10) {
        printf("Second Message took too long'\r\n");
        return FALSE;
    }
    data[3] = 0;
    i = 0;
    while ( data[3] != 0x71 && i < 200) {
        // Send "Request to ERASE" to Trionic
        if (!can_send_timeout (T7SEC_ID, T7_erase_msgb, 8, T7MESSAGETIMEOUT)) {
            printf("err t7utils line: %d\r\n", __LINE__ );
            return FALSE;
        }
        if (!can_wait_timeout(T7SEC_RX, data, 8, T7MESSAGETIMEOUT)) {
            printf("err t7utils line: %d\r\n", __LINE__ );
            return FALSE;
        }
        T7_erase_ack[3] = data[0] & 0xBF;
        if (!can_send_timeout (T7ACK_ID, T7_erase_ack, 8, T7MESSAGETIMEOUT)) {
            printf("err t7utils line: %d\r\n", __LINE__ );
            return FALSE;
        }
        wait_ms(100);
        i++;
        printf(".");
    }
    printf("\r\n");
    // Check to see if erase operation lasted longer than 20 sec...
    if (i >=200) {
        printf("Second Message took too long'\r\n");
        return FALSE;
    }

    // Confirm erase was successful?
    // (Note: no acknowledgements used for some reason)
    if (!can_send_timeout (T7SEC_ID, T7_erase_confirm, 8, T7MESSAGETIMEOUT)) {
        printf("err t7utils line: %d\r\n", __LINE__ );
        return FALSE;
    }
    if (!can_wait_timeout(T7SEC_RX, data, 8, T7MESSAGETIMEOUT)) {
        printf("err t7utils line: %d\r\n", __LINE__ );
        return FALSE;
    }
    if ( data[3] != 0x7E ) {
        printf("err t7utils line: %d\r\n", __LINE__ );
        return FALSE;
    }
    wait_ms(100);
    if (!can_send_timeout (T7SEC_ID, T7_erase_confirm, 8, T7MESSAGETIMEOUT)) {
        printf("err t7utils line: %d\r\n", __LINE__ );
        return FALSE;
    }
    if (!can_wait_timeout(T7SEC_RX, data, 8, T7MESSAGETIMEOUT)) {
        printf("err t7utils line: %d\r\n", __LINE__ );
        return FALSE;
    }
    if ( data[3] != 0x7E ) {
        printf("err t7utils line: %d\r\n", __LINE__ );
        return FALSE;
    }
    printf("SUCCESS: The FLASH has been erased.\r\n");
    return TRUE;
}

bool t7_flash() {
    char T7_flash_jumpa[]   = T7FLAJP1A;
    char T7_flash_jumpb[]   = T7FLAJP1B;
    char T7_flash_end[]     = T7FLA_END;
    char T7_flash_exit[]    = T7FLAEXIT;
    char T7_flash_ack[]     = T7FLA_ACK;
    char data[8];
    int i, k;

    // fopen modified.hex here?
    // need lots of fcloses though
    printf("Checking the FLASH BIN file...\r\n");
    FILE *fp = fopen("/local/modified.hex", "r");    // Open "modified.hex" on the local file system for reading
    if (!fp) {
        printf("Error: I could not find the BIN file MODIFIED.HEX\r\n");;
        return TERM_ERR;
    }
    // obtain file size - it should match the size of the FLASH chips:
    fseek (fp , 0 , SEEK_END);
    uint32_t file_size = ftell (fp);
    rewind (fp);

    // read the initial stack pointer value in the BIN file - it should match the value expected for the type of ECU
    uint8_t stack_byte = 0;
    uint32_t stack_long = 0;
    if (!fread(&stack_byte,1,1,fp)) return TERM_ERR;
    stack_long |= (stack_byte << 24);
    if (!fread(&stack_byte,1,1,fp)) return TERM_ERR;
    stack_long |= (stack_byte << 16);
    if (!fread(&stack_byte,1,1,fp)) return TERM_ERR;
    stack_long |= (stack_byte << 8);
    if (!fread(&stack_byte,1,1,fp)) return TERM_ERR;
    stack_long |= stack_byte;
    rewind (fp);

    if (file_size != T7FLASHSIZE || stack_long != T7POINTER) {
        fclose(fp);
        printf("The BIN file does not appear to be for a T7 ECU :-(\r\n");
        printf("BIN file size: %#010x, FLASH chip size: %#010x, Pointer: %#010x.\r\n", file_size, T7FLASHSIZE, stack_long);
        return TERM_ERR;
    }

    timer.reset();
    timer.start();

    // Send "Request Download - tool to module" to Trionic
    if (!can_send_timeout (T7SEC_ID, T7_flash_jumpa, 8, T7MESSAGETIMEOUT)) {
        printf("err t7utils line: %d\r\n", __LINE__ );
        fclose(fp);
        return FALSE;
    }
    if (!can_send_timeout (T7SEC_ID, T7_flash_jumpb, 8, T7MESSAGETIMEOUT)) {
        printf("err t7utils line: %d\r\n", __LINE__ );
        fclose(fp);
        return FALSE;
    }
    if (!can_wait_timeout(T7SEC_RX, data, 8, T7MESSAGETIMEOUT)) {
        printf("err t7utils line: %d\r\n", __LINE__ );
        fclose(fp);
        return FALSE;
    }
    T7_flash_ack[3] = data[0] & 0xBF;
    if (!can_send_timeout (T7ACK_ID, T7_flash_ack, 8, T7MESSAGETIMEOUT)) {
        printf("err t7utils line: %d\r\n", __LINE__ );
        fclose(fp);
        return FALSE;
    }
    if ( data[3] != 0x74 ) {
        printf("Cannot Update FLASH, message refused.\r\n");
        printf("err t7utils line: %d\r\n", __LINE__ );
        fclose(fp);
        return FALSE;
    }

    uint32_t address = 0;

    printf("       %% complete.\r");
    while (address < T7FLASHSIZE) {

        data[0] = 0x4A; // 0x40 send, | 0x0A (10) messages to follow
//        data[0] = 0x42; // 0x40 send, | 0x02 (2) messages to follow
//        data[0] = 0x40; // 0x40 send, | 0x00 (0) messages to follow
        data[1] = 0xA1;
        data[2] = 0x41; // length+1 (64 Bytes)
//        data[2] = 0x11; // length+1 (16 Bytes)
//        data[2] = 0x05; // length+1 (4 Bytes)
        data[3] = 0x36; // Data Transfer
        for ( k = 4; k < 8; k++ )
            //data[k] = *(bin + bin_count++);
            if (!fread(&data[k],1,1,fp)) {
                fclose(fp);
                printf("Error reading the BIN file MODIFIED.HEX");
                return FALSE;
            }
//      /* DEBUG info...
//        for (k = 0; k < 8; k++ ) printf("0x%02X ", data[k] );
//        for (k = 2; k < 8; k++ ) printf("%c ", data[k] );
//        printf(" data\r\n");

        if (!can_send_timeout (T7SEC_ID, data, 8, T7MESSAGETIMEOUT)) {
            printf("err t7utils line: %d\r\n", __LINE__ );
            fclose(fp);
            return FALSE;
        }
//*
        for (i = 9; i>=0; i--) {
//        for (i = 1; i>=0; i--) {
            data[0] = i;
            // data[1] = 0xA1;
            for ( k = 2; k < 8; k++ )
                //data[k] = *(bin + bin_count++);
                if (!fread(&data[k],1,1,fp)) {
                    fclose(fp);
                    printf("Error reading the BIN file MODIFIED.HEX");
                    return FALSE;
                }
//            /* DEBUG info...
//            for (k = 0; k < 8; k++ ) printf("0x%02X ", data[k] );
//            for (k = 2; k < 8; k++ ) printf("%c ", data[k] );
//            printf(" data\r\n");

//            printf("%6.2f\r", 100*(float)address/(float)T7FLASHSIZE );
            wait_ms(1);
            if (!can_send_timeout (T7SEC_ID, data, 8, T7MESSAGETIMEOUT)) {
                printf("err t7utils line: %d\r\n", __LINE__ );
                fclose(fp);
                return FALSE;
            }
        }
//*/
        address += 0x40;
//        address += 0x10;
//        address += 0x04;
        if (!can_wait_timeout(T7SEC_RX, data, 8, T7LONGERTIMEOUT)) {
            printf("err t7utils line: %d\r\n", __LINE__ );
            fclose(fp);
            return FALSE;
        }
        // Send acknowledgement
        T7_flash_ack[3] = data[0] & 0xBF;
        if (!can_send_timeout (T7ACK_ID, T7_flash_ack, 8, T7MESSAGETIMEOUT)) {
            printf("err t7utils line: %d\r\n", __LINE__ );
            fclose(fp);
            return FALSE;
        }
        if ( data[3] != 0x76 ) {
            printf("err t7utils line: %d\r\n", __LINE__ );
            fclose(fp);
            return FALSE;
        }
        if (!(address % 0x80))
            printf("%6.2f\r", 100*(float)address/(float)T7FLASHSIZE );
    }
    printf("\n");
/*
    // Send "Request Data Transfer Exit" to Trionic
    if (!can_send_timeout (T7SEC_ID, T7_flash_end, 8, T7MESSAGETIMEOUT)) {
        printf("err t7utils line: %d\r\n", __LINE__ );
        fclose(fp);
        return FALSE;
    }
    if (!can_wait_timeout(T7SEC_RX, data, 8, T7MESSAGETIMEOUT)) {
        printf("err t7utils line: %d\r\n", __LINE__ );
        fclose(fp);
        return FALSE;
    }
    T7_flash_ack[3] = data[0] & 0xBF;
    if (!can_send_timeout (T7ACK_ID, T7_flash_ack, 8, T7MESSAGETIMEOUT)) {
        printf("err t7utils line: %d\r\n", __LINE__ );
        fclose(fp);
        return FALSE;
    }
    if ( data[3] != 0x77 ) {
        printf("Cannot Update FLASH, message refused.\r\n");
        printf("err t7utils line: %d\r\n", __LINE__ );
        fclose(fp);
        return FALSE;
    }
    // Send "Request Data Transfer Exit" to Trionic
    if (!can_send_timeout (T7SEC_ID, T7_flash_exit, 8, T7MESSAGETIMEOUT)) {
        printf("err t7utils line: %d\r\n", __LINE__ );
        fclose(fp);
        return FALSE;
    }
    if (!can_wait_timeout(T7SEC_RX, data, 8, T7MESSAGETIMEOUT)) {
        printf("err t7utils line: %d\r\n", __LINE__ );
        fclose(fp);
        return FALSE;
    }
    T7_flash_ack[3] = data[0] & 0xBF;
    if (!can_send_timeout (T7ACK_ID, T7_flash_ack, 8, T7MESSAGETIMEOUT)) {
        printf("err t7utils line: %d\r\n", __LINE__ );
        fclose(fp);
        return FALSE;
    }
    if ( data[3] != 0x71 ) {
        printf("Cannot Update FLASH, message refused.\r\n");
        printf("err t7utils line: %d\r\n", __LINE__ );
        fclose(fp);
        return FALSE;
    }
*/
    timer.stop();
    printf("SUCCESS! Programming the FLASH took %#.1f seconds.\r\n",timer.read());
    fclose(fp);
    return TRUE;
}