Just4Trionic - CAN and BDM FLASH programmer for Saab cars

Dependencies:   mbed

Revision:
4:682d96ff6d79
Child:
5:1775b4b13232
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/t8utils.cpp	Wed Sep 11 11:55:51 2013 +0000
@@ -0,0 +1,513 @@
+/*******************************************************************************
+
+t7utils.cpp
+(c) 2011, 2012 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 "t8utils.h"
+
+Timer   TesterPresent;
+
+
+//
+// t8_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 t8_initialise()
+{
+    return TRUE;
+}
+
+bool t8_show_VIN()
+{
+    uint16_t i;
+    char T8TxFlo[] = T8FLOCTL;
+    char T8TxMsg[] = T8REQVIN;
+    char T8RxMsg[8];
+    printf("Requesting VIN from T8...\r\n");
+    // Send "Request VIN" to Trionic8
+    if (!can_send_timeout (T8TSTRID, T8TxMsg, 8, T8MESSAGETIMEOUT))
+        return FALSE;
+    // wait for the T8 to reply
+    // Read "Seed"
+    // if a message is not received id return false
+    if (!can_wait_timeout(T8ECU_ID, T8RxMsg, 8, T8MESSAGETIMEOUT))
+        return FALSE;
+    //* DEBUG info...
+    for (i = 0; i < 8; i++ ) printf("0x%02X ", T8RxMsg[i] );
+    printf("\r\n");
+    for (i = 5; i < 8; i++ ) printf("%c", T8RxMsg[i] );
+    printf("\r\n");
+    // Send Trionic8 a "Flow Control Message to get the rest of the VIN
+    if (!can_send_timeout (T8TSTRID, T8TxFlo, 8, T8MESSAGETIMEOUT))
+        return FALSE;
+    if (!can_wait_timeout(T8ECU_ID, T8RxMsg, 8, T8MESSAGETIMEOUT))
+        return FALSE;
+    //* DEBUG info...
+    for (i = 0; i < 8; i++ ) printf("0x%02X ", T8RxMsg[i] );
+    printf("\r\n");
+    for (i = 1; i < 8; i++ ) printf("%c", T8RxMsg[i] );
+    printf("\r\n");
+    if (!can_wait_timeout(T8ECU_ID, T8RxMsg, 8, T8MESSAGETIMEOUT))
+        return FALSE;
+    //* DEBUG info...
+    for (i = 0; i < 8; i++ ) printf("0x%02X ", T8RxMsg[i] );
+    printf("\r\n");
+    for (i = 1; i < 8; i++ ) printf("%c", T8RxMsg[i] );
+    printf("\r\n");
+    //*/
+    return TRUE;
+}
+
+bool t8_write_VIN()
+{
+
+    char SetVin10[] = {0x10,0x13,0x3B,0x90,0x59,0x53,0x33,0x46};
+    char SetVin21[] = {0x21,0x46,0x34,0x35,0x53,0x38,0x33,0x31};
+//  char SetVin22[] = {0x22,0x30,0x30,0x32,0x33,0x34,0x30,0xaa};  // Original
+    char SetVin22[] = {0x22,0x30,0x30,0x34,0x33,0x32,0x31,0x00};
+    char T8RxMsg[8];
+    char k = 0;
+
+//    GMLANTesterPresentT8();
+//    wait_ms(2000);
+//
+//    printf("Requesting Security Access\r\n");
+//    if (!t8_authenticate(0x01)) {
+//        printf("Unable to get Security Access\r\n");
+//        return FALSE;
+//    }
+//    printf("Security Access Granted\r\n");
+//
+//    GMLANTesterPresentT8();
+//    wait_ms(2000);
+//
+//    GMLANTesterPresentT8();
+//    wait_ms(2000);
+//
+    if (!can_send_timeout (T8TSTRID, SetVin10, 8, T8MESSAGETIMEOUT)) {
+        printf("Unable to write VIN\r\n");
+        return FALSE;
+    }
+    for (k = 0; k < 8; k++ ) printf("0x%02X ", SetVin10[k] );
+    printf("\r\n");
+    if (!can_wait_timeout(T8ECU_ID, T8RxMsg, 8, T8MESSAGETIMEOUT))
+        return FALSE;
+    for (k = 0; k < 8; k++ ) printf("0x%02X ", T8RxMsg[k] );
+    printf("\r\n");
+//    wait_ms(100);
+    if (!can_send_timeout (T8TSTRID, SetVin21, 8, T8MESSAGETIMEOUT)) {
+        printf("Unable to write VIN\r\n");
+        return FALSE;
+    }
+    for (k = 0; k < 8; k++ ) printf("0x%02X ", SetVin21[k] );
+    printf("\r\n");
+//    wait_ms(100);
+    if (!can_send_timeout (T8TSTRID, SetVin22, 8, T8MESSAGETIMEOUT)) {
+        printf("Unable to write VIN\r\n");
+        return FALSE;
+    }
+    for (k = 0; k < 8; k++ ) printf("0x%02X ", SetVin22[k] );
+    printf("\r\n");
+    if (!can_wait_timeout(T8ECU_ID, T8RxMsg, 8, T8MESSAGETIMEOUT))
+        return FALSE;
+    for (k = 0; k < 8; k++ ) printf("0x%02X ", T8RxMsg[k] );
+    printf("\r\n");
+    return TRUE;
+//    GMLANTesterPresentT8();
+//    wait_ms(2000);
+//
+}
+
+//
+// t8_authenticate
+//
+// sends an authentication message to the T7 ECU
+// but doesn't display anything.
+//
+// inputs:    none
+// return:    bool TRUE if there was a message, FALSE if no message.
+//
+
+bool t8_authenticate(char level)
+{
+    uint16_t seed, key;
+    if (!GMLANSecurityAccessRequest(level, seed)) {
+        printf("Unable to request SEED value for security access\r\n");
+        return FALSE;
+    }
+    if ( seed == 0x0000 ) {
+        printf("T8 ECU is already unlocked\r\n");
+        return TRUE;
+    }
+    key = (seed >> 5) | (seed << 11);
+    key += 0xB988;
+    if (level == 0xFD) {
+        key /= 3;
+        key ^= 0x8749;
+        key += 0x0ACF;
+        key ^= 0x81BF;
+    } else if (level == 0xFB) {
+        key ^= 0x8749;
+        key += 0x06D3;
+        key ^= 0xCFDF;
+    }
+    /* CIM KEY CALCULATION
+        uint16_t key = (seed + 0x9130);
+        key = (key >> 8) | (key << 8);
+        key -= 0x3FC7;
+    */
+    if (!GMLANSecurityAccessSendKey(level, key)) {
+        printf("Unable to send KEY value for security access\r\n");
+        return FALSE;
+    }
+    printf("Key Accepted\r\n");
+    return TRUE;
+}
+
+
+
+//
+// t8_dump
+//
+// dumps the T8 BIN File
+// but doesn't displays anything.
+//
+// inputs:    none
+// return:    bool TRUE if there was a message, FALSE if no message.
+//
+
+bool t8_dump()
+{
+    uint16_t i = 0, k = 0;
+    char T8TxMsg[8];
+    char T8RxMsg[8];
+
+    timer.reset();
+    timer.start();
+    printf("Creating FLASH dump file...\r\n");
+
+//
+    GMLANTesterPresentT8();
+//
+    if (!GMLANprogrammingSetupProcess())
+        return FALSE;
+//
+    wait_ms(500);
+    printf("Requesting Security Access\r\n");
+    if (!t8_authenticate(0x01)) {
+        printf("Unable to get Security Access\r\n");
+        return FALSE;
+    }
+    printf("Security Access Granted\r\n");
+    wait_ms(500);
+    GMLANTesterPresentT8();
+//
+    char BootLoader[] = T8Bootloader;
+    if(!GMLANprogrammingUtilityFileProcess(BootLoader))
+        return FALSE;
+//
+    uint32_t StartAddress = 0x0;
+    uint16_t txpnt = 0;
+    char iFrameNumber = 0x21;
+//
+    printf("Downloading FLASH BIN file...\r\n");
+    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;
+    }
+    printf("  0.00 %% complete.\r");
+    TesterPresent.start();
+    while (StartAddress < 0x100000) {     // 0x100000
+        T8TxMsg[0] = 0x06;
+        T8TxMsg[1] = 0x21;
+        T8TxMsg[2] = 0x80;  // Blocksize
+        T8TxMsg[3] = (char) (StartAddress >> 24);
+        T8TxMsg[4] = (char) (StartAddress >> 16);
+        T8TxMsg[5] = (char) (StartAddress >> 8);
+        T8TxMsg[6] = (char) (StartAddress);
+        T8TxMsg[7] = 0xaa;
+#ifdef DEBUG
+        printf("block %#.3f\r\n",timer.read());
+#endif
+        if (!can_send_timeout (T8TSTRID, T8TxMsg, 7, T8MESSAGETIMEOUT)) {
+            printf("Unable to download FLASH\r\n");
+            return FALSE;
+        }
+        if (!can_wait_timeout(T8ECU_ID, T8RxMsg, 8, T8MESSAGETIMEOUT))
+            return FALSE;
+#ifdef DEBUG
+        printf("first %#.3f\r\n",timer.read());
+        for (k = 0; k < 8; k++ ) printf("0x%02X ", T8RxMsg[k] );
+        printf("\r\n");
+#endif
+        txpnt = 0;
+        for (k = 4; k < 8; k++ ) file_buffer[txpnt++] = T8RxMsg[k];
+
+        uint8_t DataFrames = 0x12;
+        iFrameNumber = 0x21;
+        char T8TxFlo[] = T8FLOCTL;
+#ifdef DEBUG
+        printf("flowCtrl %#.3f\r\n",timer.read());
+#endif
+        can_send_timeout (T8TSTRID, T8TxFlo, 8, T8MESSAGETIMEOUT);
+        for (i = 0; i < DataFrames; i++) {
+            if (!can_wait_timeout(T8ECU_ID, T8RxMsg, 8, T8MESSAGETIMEOUT))
+                return FALSE;
+#ifdef DEBUG
+            printf("Consec %#.3f\r\n",timer.read());
+            for (k = 0; k < 8; k++ ) printf("0x%02X ", T8RxMsg[k] );
+            printf("\r\n");
+#endif
+            iFrameNumber++;
+            for (k = 1; k < 8; k++ ) file_buffer[txpnt++] = T8RxMsg[k];
+        }
+        fwrite((file_buffer), 1, 0x80, fp);
+        if (ferror (fp)) {
+            fclose (fp);
+            printf ("Error writing to the FLASH BIN file.\r\n");
+            return TERM_ERR;
+        }
+        StartAddress +=0x80;
+        printf("%6.2f\r", (100.0*(float)StartAddress)/(float)(0x100000) );
+        if (TesterPresent.read_ms() > 2000) {
+            GMLANTesterPresentT8();
+            TesterPresent.reset();
+            ACTIVITYLEDON;
+        }
+    }
+
+    printf("%6.2f\r\n", (float)100 );
+    timer.stop();
+    printf("SUCCESS! Getting the FLASH dump took %#.1f seconds.\r\n",timer.read());
+    fclose(fp);
+    return TRUE;
+}
+
+bool t8_erase()
+{
+    printf("Erasing T8 ECU FLASH...\r\n");
+    printf("SUCCESS: The FLASH has been erased.\r\n");
+    return TRUE;
+}
+
+bool t8_flash_raw()
+{
+    timer.reset();
+    timer.start();
+    printf("Checking the FLASH BIN file...\r\n");
+    timer.stop();
+    printf("SUCCESS! Programming the FLASH took %#.1f seconds.\r\n",timer.read());
+    return TRUE;
+}
+
+
+bool t8_flash()
+{
+    uint16_t i = 0, j = 0, k = 0;
+
+    timer.reset();
+    timer.start();
+    printf("FLASHing T8 BIN file...\r\n");
+
+//
+    GMLANTesterPresentT8();
+//
+    if (!GMLANprogrammingSetupProcess())
+        return FALSE;
+//
+    wait_ms(500);
+    printf("Requesting Security Access\r\n");
+    if (!t8_authenticate(0x01)) {
+        printf("Unable to get Security Access\r\n");
+        return FALSE;
+    }
+    printf("Security Access Granted\r\n");
+    wait_ms(500);
+    GMLANTesterPresentT8();
+//
+    char BootLoader[] = T8BootloaderProg;
+    if(!GMLANprogrammingUtilityFileProcess(BootLoader))
+        return FALSE;
+//
+
+
+// All steps needed to transfer and start a bootloader ('Utility File' in GMLAN parlance)
+//    bool GMLANprogrammingUtilityFileProcess(char UtilityFile[]) {
+//        uint16_t i = 0, j = 0, k = 0;
+    uint32_t StartAddress = 0x020000;
+    uint16_t txpnt = 0;
+    char iFrameNumber = 0x21;
+    char GMLANMsg[8];
+    char data2Send[0xE0];
+//
+    // fopen modified.hex here, check it is OK and work out how much data I need to send
+    // 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
+    uint32_t stack_long = 0;
+    if (!fread(&stack_long,4,1,fp)) return TERM_ERR;
+    stack_long = (stack_long >> 24) | ((stack_long << 8) & 0x00FF0000) | ((stack_long >> 8) & 0x0000FF00) |  (stack_long << 24);
+//
+    if (file_size != T8FLASHSIZE || stack_long != T8POINTER) {
+        fclose(fp);
+        printf("The BIN file does not appear to be for a T8 ECU :-(\r\n");
+        printf("BIN file size: %#010x, FLASH chip size: %#010x, Pointer: %#010x.\r\n", file_size, T7FLASHSIZE, stack_long);
+        return TERM_ERR;
+    }
+// It is possible to save some time by only sending the program code and CAL data
+// This is just a rough calculation, and slight overestimate of the number of blocks of data needed to send the BIN file
+    uint32_t blocks2Send;
+    fseek(fp,0x020140,SEEK_SET);
+    if (!fread(&blocks2Send,4,1,fp)) return TERM_ERR;
+    blocks2Send = (blocks2Send >> 24) | ((blocks2Send << 8) & 0x00FF0000) | ((blocks2Send >> 8) & 0x0000FF00) |  (blocks2Send << 24);
+    printf("Start address of BIN file's Footer area = 0x%06X\r\n", blocks2Send );
+    blocks2Send += 0x200;       // Add some bytes for the Footer itself and to account for division rounded down later
+    blocks2Send -= 0x020000;    // Remove 0x020000 because we don't send the bootblock and adaptation blocks
+    printf("Amount of data to send BIN file adjusted for footer = 0x%06X Bytes\r\n", blocks2Send );
+    blocks2Send /= 0xE0;
+    printf("Number of Blocks of 0xE0 Bytes needed to send BIN file = 0x%04X\r\n", blocks2Send );
+// Move BIN file pointer to start of data
+    fseek (fp , 0x020000 , SEEK_SET);
+// Erase the FLASH
+    printf("Waiting for FLASH to be Erased\r\n");
+    if (!GMLANRequestDownload(GMLANRequestDownloadModeEncrypted)) {
+        printf("Unable to erase the FLASH chip!\r\n");
+        return FALSE;
+    }
+// Now send the BIN file
+    TesterPresent.start();
+    printf("Sending FLASH BIN file\r\n");
+    printf("  0.00 %% complete.\r");
+    for (i=0; i<blocks2Send; i++) {
+        // get a block of 0xE0 bytes in an array called data2Send
+        for ( j = 0; j < 0xE0; j++ ) {
+            //data[k] = *(bin + bin_count++);
+            if (!fread(&data2Send[j],1,1,fp)) {
+                fclose(fp);
+                printf("Error reading the BIN file MODIFIED.HEX\r\n");
+                return FALSE;
+            }
+            // encrypt data2Send array by XORing with 6 different in a ring (modulo function)
+            switch ( ((0xE0*i)+j) %6) {
+                case 1:
+                    data2Send[j] ^= 0x68;
+                    break;
+                case 2:
+                    data2Send[j] ^= 0x77;
+                    break;
+                case 3:
+                    data2Send[j] ^= 0x6D;
+                    break;
+                case 4:
+                    data2Send[j] ^= 0x47;
+                    break;
+                default:        // remainder 0 and 5 both XOR with 0x39
+                    data2Send[j] ^= 0x39;
+            }
+        }
+        // Send the block of data
+        if (!GMLANDataTransferFirstFrame(0xE6, GMLANDOWNLOAD, StartAddress)) {
+            fclose(fp);
+            printf("Unable to start BIN File Upload\r\n");
+            return FALSE;
+        }
+        // Send 0x20 messages of 0x07 bytes each (0x20 * 0x07 = 0xE0)
+        txpnt = 0;
+        iFrameNumber = 0x21;
+        for (j=0; j < 0x20; j++) {
+            GMLANMsg[0] = iFrameNumber;
+            for (k=1; k<8; k++)
+                GMLANMsg[k] = data2Send[txpnt++];
+#ifdef DEBUG
+            for (k = 0; k < 8; k++ ) printf("0x%02X ", GMLANMsg[k] );
+            printf("\r\n");
+#endif
+            if (!can_send_timeout(T8RequestId, GMLANMsg, 8, GMLANPTCT)) {
+                fclose(fp);
+                printf("Unable to send BIN File\r\n");
+                return FALSE;
+            }
+            ++iFrameNumber &= 0x2F;
+//            wait_ms(1);
+            wait_us(250);
+        }
+        if (!can_wait_timeout(T8ResponseId, GMLANMsg, 8, GMLANPTCT)) {
+            fclose(fp);
+            printf("I did not receive a block acknowledge message\r\n");
+            return FALSE;
+        }
+        while (GMLANMsg[0] == 0x03 && GMLANMsg[1] == 0x7F && GMLANMsg[2] == 0x36 && GMLANMsg[3] == 0x78) {
+            printf("I'm waiting for a Block to be programmed into FLASH\r\n");
+            if (!can_wait_timeout(T8ResponseId, GMLANMsg, 8, GMLANPTCTENHANCED)) {
+                printf("I did not receive a block acknowledge message after enhanced timeout\r\n");
+                fclose(fp);
+                return FALSE;
+            }
+        }
+#ifdef DEBUG
+        for (k = 0; k < 8; k++ ) printf("0x%02X ", GMLANMsg[k] );
+        printf("\r\n");
+#endif
+        if ( GMLANMsg[0] == 0x03 && GMLANMsg[1] == 0x7F && GMLANMsg[2] == 0x36 ) {
+            GMLANShowReturnCode(GMLANMsg[3]);
+            fclose(fp);
+            return FALSE;
+        }
+        if (GMLANMsg[0] != 0x01 && GMLANMsg[1] != 0x76) {
+            printf("EXITING due to an unexpected CAN message");
+            fclose(fp);
+            return FALSE;
+        }
+        if (TesterPresent.read_ms() > 2000) {
+            GMLANTesterPresentT8();
+            TesterPresent.reset();
+            ACTIVITYLEDON;
+        }
+        StartAddress += 0xE0;
+        printf("%6.2f\r", (100.0*(float)i)/(float)(blocks2Send) );
+    }
+// FLASHing complete
+    printf("%6.2f\r\n", (float)100 );
+// End programming session and return to normal mode
+    if (!GMLANReturnToNormalMode()) {
+        fclose(fp);
+        printf("UH-OH! T8 ECU did not Return To Normal Mode!!\r\n");
+        return FALSE;
+    }
+    wait_ms(1000);
+    timer.stop();
+    printf("SUCCESS! FLASHing the BIN file took %#.1f seconds.\r\n",timer.read());
+    fclose(fp);
+    return TRUE;
+}