Just4Trionic - CAN and BDM FLASH programmer for Saab cars

Dependencies:   mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers t8utils.cpp Source File

t8utils.cpp

00001 /*******************************************************************************
00002 
00003 t7utils.cpp
00004 (c) 2011, 2012 by Sophie Dexter
00005 portions (c) Tomi Liljemark (firstname.surname@gmail.com)
00006 
00007 This C++ module provides functions for communicating simple messages to and from
00008 the T7 ECU
00009 
00010 ********************************************************************************
00011 
00012 WARNING: Use at your own risk, sadly this software comes with no guarantees.
00013 This software is provided 'free' and in good faith, but the author does not
00014 accept liability for any damage arising from its use.
00015 
00016 *******************************************************************************/
00017 
00018 #include "t8utils.h"
00019 
00020 Timer   TesterPresent;
00021 
00022 
00023 //
00024 // t8_initialise
00025 //
00026 // sends an initialisation message to the T7 ECU
00027 // but doesn't displays anything.
00028 //
00029 // inputs:    none
00030 // return:    bool TRUE if there was a message, FALSE if no message.
00031 //
00032 
00033 
00034 bool t8_initialise()
00035 {
00036     return TRUE;
00037 }
00038 
00039 bool t8_show_VIN()
00040 {
00041     uint32_t i;
00042     char T8TxFlo[] = T8FLOCTL;
00043     char T8TxMsg[] = T8REQVIN;
00044     char T8RxMsg[8];
00045     printf("Requesting VIN from T8...\r\n");
00046     // Send "Request VIN" to Trionic8
00047     if (!can_send_timeout (T8TSTRID, T8TxMsg, 8, T8MESSAGETIMEOUT))
00048         return FALSE;
00049     // wait for the T8 to reply
00050     // Read "Seed"
00051     // if a message is not received id return false
00052     if (!can_wait_timeout(T8ECU_ID, T8RxMsg, 8, T8MESSAGETIMEOUT))
00053         return FALSE;
00054     //* DEBUG info...
00055     for (i = 0; i < 8; i++ ) printf("0x%02X ", T8RxMsg[i] );
00056     printf("\r\n");
00057     for (i = 5; i < 8; i++ ) printf("%c", T8RxMsg[i] );
00058     printf("\r\n");
00059     // Send Trionic8 a "Flow Control Message to get the rest of the VIN
00060     if (!can_send_timeout (T8TSTRID, T8TxFlo, 8, T8MESSAGETIMEOUT))
00061         return FALSE;
00062     if (!can_wait_timeout(T8ECU_ID, T8RxMsg, 8, T8MESSAGETIMEOUT))
00063         return FALSE;
00064     //* DEBUG info...
00065     for (i = 0; i < 8; i++ ) printf("0x%02X ", T8RxMsg[i] );
00066     printf("\r\n");
00067     for (i = 1; i < 8; i++ ) printf("%c", T8RxMsg[i] );
00068     printf("\r\n");
00069     if (!can_wait_timeout(T8ECU_ID, T8RxMsg, 8, T8MESSAGETIMEOUT))
00070         return FALSE;
00071     //* DEBUG info...
00072     for (i = 0; i < 8; i++ ) printf("0x%02X ", T8RxMsg[i] );
00073     printf("\r\n");
00074     for (i = 1; i < 8; i++ ) printf("%c", T8RxMsg[i] );
00075     printf("\r\n");
00076     //*/
00077     return TRUE;
00078 }
00079 
00080 bool t8_write_VIN()
00081 {
00082 
00083     char SetVin10[] = {0x10,0x13,0x3B,0x90,0x59,0x53,0x33,0x46};
00084     char SetVin21[] = {0x21,0x46,0x34,0x35,0x53,0x38,0x33,0x31};
00085 //  char SetVin22[] = {0x22,0x30,0x30,0x32,0x33,0x34,0x30,0xaa};  // Original
00086     char SetVin22[] = {0x22,0x30,0x30,0x34,0x33,0x32,0x31,0x00};
00087     char T8RxMsg[8];
00088     char k = 0;
00089 
00090 //    GMLANTesterPresent(T8REQID, T8RESPID);
00091 //    wait_ms(2000);
00092 //
00093 //    printf("Requesting Security Access\r\n");
00094 //    if (!t8_authenticate(0x01)) {
00095 //        printf("Unable to get Security Access\r\n");
00096 //        return FALSE;
00097 //    }
00098 //    printf("Security Access Granted\r\n");
00099 //
00100 //    GMLANTesterPresent(T8REQID, T8RESPID);
00101 //    wait_ms(2000);
00102 //
00103 //    GMLANTesterPresent(T8REQID, T8RESPID);
00104 //    wait_ms(2000);
00105 //
00106     if (!can_send_timeout (T8TSTRID, SetVin10, 8, T8MESSAGETIMEOUT)) {
00107         printf("Unable to write VIN\r\n");
00108         return FALSE;
00109     }
00110     for (k = 0; k < 8; k++ ) printf("0x%02X ", SetVin10[k] );
00111     printf("\r\n");
00112     if (!can_wait_timeout(T8ECU_ID, T8RxMsg, 8, T8MESSAGETIMEOUT))
00113         return FALSE;
00114     for (k = 0; k < 8; k++ ) printf("0x%02X ", T8RxMsg[k] );
00115     printf("\r\n");
00116 //    wait_ms(100);
00117     if (!can_send_timeout (T8TSTRID, SetVin21, 8, T8MESSAGETIMEOUT)) {
00118         printf("Unable to write VIN\r\n");
00119         return FALSE;
00120     }
00121     for (k = 0; k < 8; k++ ) printf("0x%02X ", SetVin21[k] );
00122     printf("\r\n");
00123 //    wait_ms(100);
00124     if (!can_send_timeout (T8TSTRID, SetVin22, 8, T8MESSAGETIMEOUT)) {
00125         printf("Unable to write VIN\r\n");
00126         return FALSE;
00127     }
00128     for (k = 0; k < 8; k++ ) printf("0x%02X ", SetVin22[k] );
00129     printf("\r\n");
00130     if (!can_wait_timeout(T8ECU_ID, T8RxMsg, 8, T8MESSAGETIMEOUT))
00131         return FALSE;
00132     for (k = 0; k < 8; k++ ) printf("0x%02X ", T8RxMsg[k] );
00133     printf("\r\n");
00134     return TRUE;
00135 //    GMLANTesterPresent(T8REQID, T8RESPID);
00136 //    wait_ms(2000);
00137 //
00138 }
00139 
00140 //
00141 // t8_authenticate
00142 //
00143 // sends an authentication message to the T7 ECU
00144 // but doesn't display anything.
00145 //
00146 // inputs:    none
00147 // return:    bool TRUE if there was a message, FALSE if no message.
00148 //
00149 
00150 bool t8_authenticate(uint32_t ReqID, uint32_t RespID, char level)
00151 {
00152     uint16_t i, seed, key;
00153 //    if (!GMLANSecurityAccessRequest(ReqID, RespID, level, seed)) {
00154 //        printf("Unable to request SEED value for security access\r\n");
00155 //        return FALSE;
00156 //    }
00157 
00158     for (i=0; i < 20; i++) {
00159         if (GMLANSecurityAccessRequest(ReqID, RespID, level, seed))
00160             break;
00161         wait(1);
00162         GMLANTesterPresent(ReqID, RespID);
00163     }
00164     if (i == 20) {
00165         printf("Unable to request SEED value for security access\r\n");
00166         return FALSE;
00167     }
00168 
00169     if ( seed == 0x0000 ) {
00170         printf("T8 ECU is already unlocked\r\n");
00171         return TRUE;
00172     }
00173     key = (seed >> 5) | (seed << 11);
00174     key += 0xB988;
00175     if (level == 0xFD) {
00176         key /= 3;
00177         key ^= 0x8749;
00178         key += 0x0ACF;
00179         key ^= 0x81BF;
00180     } else if (level == 0xFB) {
00181         key ^= 0x8749;
00182         key += 0x06D3;
00183         key ^= 0xCFDF;
00184     }
00185     /* CIM KEY CALCULATION
00186         uint16_t key = (seed + 0x9130);
00187         key = (key >> 8) | (key << 8);
00188         key -= 0x3FC7;
00189     */
00190     wait_ms(1);
00191     if (!GMLANSecurityAccessSendKey(ReqID, RespID, level, key)) {
00192         printf("Unable to send KEY value for security access\r\n");
00193         return FALSE;
00194     }
00195     printf("Key Accepted\r\n");
00196     wait_ms(500);       // was 5
00197     return TRUE;
00198 }
00199 
00200 
00201 //
00202 // t8_dump
00203 //
00204 // dumps the T8 BIN File
00205 // but doesn't displays anything.
00206 //
00207 // inputs:    none
00208 // return:    bool TRUE if there was a message, FALSE if no message.
00209 //
00210 
00211 bool t8_dump()
00212 {
00213     uint32_t i = 0, k = 0;
00214     char T8TxMsg[8];
00215     char T8RxMsg[8];
00216 
00217     timer.reset();
00218     timer.start();
00219     printf("Creating FLASH dump file...\r\n");
00220 
00221 //
00222     if (!GMLANprogrammingSetupProcess(T8REQID, T8RESPID))
00223         return FALSE;
00224 //
00225     printf("Requesting Security Access\r\n");
00226     if (!t8_authenticate(T8REQID, T8RESPID, 0x01)) {
00227         printf("Unable to get Security Access\r\n");
00228         return FALSE;
00229     }
00230     printf("Security Access Granted\r\n");
00231 //
00232     if(!GMLANprogrammingUtilityFileProcess(T8REQID, T8RESPID, T8BootloaderRead))
00233         return FALSE;
00234 //
00235 //
00236     printf("Downloading FLASH BIN file...\r\n");
00237     printf("Creating FLASH dump file...\r\n");
00238     FILE *fp = fopen("/local/original.bin", "w");    // Open "original.bin" on the local file system for writing
00239     if (!fp) {
00240         perror ("The following error occured");
00241         return TERM_ERR;
00242     }
00243     printf("  0.00 %% complete.\r");
00244     TesterPresent.start();
00245 
00246 // It is possible to save some time by only reading the program code and CAL data
00247 // This is just a rough calculation, and slight overestimate of the number of blocks of data needed to send the BIN file
00248     T8TxMsg[0] = 0x06;
00249     T8TxMsg[1] = 0x21;
00250     T8TxMsg[2] = 0x80;  // Blocksize
00251     T8TxMsg[3] = 0x00;  // This address (0x020140) points to the Header at the end of the BIN
00252     T8TxMsg[4] = 0x02;
00253     T8TxMsg[5] = 0x01;
00254     T8TxMsg[6] = 0x40;
00255     T8TxMsg[7] = 0xaa;
00256     if (!can_send_timeout (T8TSTRID, T8TxMsg, 7, T8MESSAGETIMEOUT)) {
00257         printf("Unable to download FLASH\r\n");
00258         return FALSE;
00259     }
00260     if (!can_wait_timeout(T8ECU_ID, T8RxMsg, 8, T8MESSAGETIMEOUT))
00261         return FALSE;
00262     uint32_t EndAddress = (T8RxMsg[5] << 16) | (T8RxMsg[6] << 8) | T8RxMsg[7];
00263     EndAddress += 0x200;    // Add some bytes for the Footer itself and to account for division rounded down later
00264     char T8TxFlo[] = T8FLOCTL;
00265     can_send_timeout (T8TSTRID, T8TxFlo, 8, T8MESSAGETIMEOUT);
00266     for (i = 0; i < 0x12; i++) {
00267         if (!can_wait_timeout(T8ECU_ID, T8RxMsg, 8, T8MESSAGETIMEOUT))
00268             return FALSE;
00269     }
00270     printf("Reading your BIN file adjusted for footer = 0x%06X Bytes\r\n", EndAddress );
00271 
00272     for ( uint32_t StartAddress = 0x0; StartAddress < EndAddress; StartAddress +=0x80 ) {     // 0x100000
00273         T8TxMsg[0] = 0x06;
00274         T8TxMsg[1] = 0x21;
00275         T8TxMsg[2] = 0x80;  // Blocksize
00276         T8TxMsg[3] = (char) (StartAddress >> 24);
00277         T8TxMsg[4] = (char) (StartAddress >> 16);
00278         T8TxMsg[5] = (char) (StartAddress >> 8);
00279         T8TxMsg[6] = (char) (StartAddress);
00280         T8TxMsg[7] = 0xaa;
00281 #ifdef DEBUG
00282         printf("block %#.3f\r\n",timer.read());
00283 #endif
00284         if (!can_send_timeout (T8TSTRID, T8TxMsg, 7, T8MESSAGETIMEOUT)) {
00285             printf("Unable to download FLASH\r\n");
00286             return FALSE;
00287         }
00288         if (!can_wait_timeout(T8ECU_ID, T8RxMsg, 8, T8MESSAGETIMEOUT))
00289             return FALSE;
00290 #ifdef DEBUG
00291         printf("first %#.3f\r\n",timer.read());
00292 #endif
00293         uint32_t txpnt = 0;
00294         for (k = 4; k < 8; k++ ) file_buffer[txpnt++] = T8RxMsg[k];
00295 
00296         uint8_t DataFrames = 0x12;
00297         char iFrameNumber = 0x21;
00298         char T8TxFlo[] = T8FLOCTL;
00299         can_send_timeout (T8TSTRID, T8TxFlo, 8, T8MESSAGETIMEOUT);
00300 #ifdef DEBUG
00301         printf("flowCtrl %#.3f\r\n",timer.read());
00302 #endif
00303         for (i = 0; i < DataFrames; i++) {
00304             if (!can_wait_timeout(T8ECU_ID, T8RxMsg, 8, T8MESSAGETIMEOUT))
00305                 return FALSE;
00306 #ifdef DEBUG
00307             printf("Consec %#.3f\r\n",timer.read());
00308 #endif
00309             iFrameNumber++;
00310             for (k = 1; k < 8; k++ ) file_buffer[txpnt++] = T8RxMsg[k];
00311         }
00312         fwrite((file_buffer), 1, 0x80, fp);
00313         if (ferror (fp)) {
00314             fclose (fp);
00315             printf ("Error writing to the FLASH BIN file.\r\n");
00316             return TERM_ERR;
00317         }
00318         printf("%6.2f\r", (100.0*(float)StartAddress)/(float)(EndAddress) );
00319         if (TesterPresent.read_ms() > 2000) {
00320             GMLANTesterPresent(T8REQID, T8RESPID);
00321             TesterPresent.reset();
00322         }
00323     }
00324 
00325     for (uint32_t i = 0; i < 0x80; i++)
00326         file_buffer[i] = 0xFF;
00327     while ( ftell(fp) < 0x100000 ) {
00328 //  for ( uint32_t StartAddress = EndAddress; StartAddress < 0x100000; StartAddress +=0x80 ) {
00329         fwrite((file_buffer), 1, 0x80, fp);
00330         if (ferror (fp)) {
00331             fclose (fp);
00332             printf ("Error writing to the FLASH BIN file.\r\n");
00333             return TERM_ERR;
00334         }
00335     }
00336 
00337     printf("%6.2f\r\n", (float)100 );
00338     timer.stop();
00339     printf("SUCCESS! Getting the FLASH dump took %#.1f seconds.\r\n",timer.read());
00340     fclose(fp);
00341     return TRUE;
00342 }
00343 
00344 
00345 bool t8_flash()
00346 {
00347     uint32_t i = 0, j = 0, k = 0;
00348 
00349     timer.reset();
00350     timer.start();
00351     printf("FLASHing T8 BIN file...\r\n");
00352 
00353 //
00354     if (!GMLANprogrammingSetupProcess(T8REQID, T8RESPID))
00355         return FALSE;
00356 //
00357     printf("Requesting Security Access\r\n");
00358     if (!t8_authenticate(T8REQID, T8RESPID, 0x01)) {
00359         printf("Unable to get Security Access\r\n");
00360         return FALSE;
00361     }
00362     printf("Security Access Granted\r\n");
00363 //
00364 // All steps needed to transfer and start a bootloader ('Utility File' in GMLAN parlance)
00365 //    const uint8_t BootLoader[] = T8BootloaderProg;
00366 //    if(!GMLANprogrammingUtilityFileProcess(T8REQID, T8RESPID, BootLoader))
00367     if(!GMLANprogrammingUtilityFileProcess(T8REQID, T8RESPID, T8BootLoaderWrite))
00368         return FALSE;
00369 //
00370     uint32_t StartAddress = 0x020000;
00371     uint32_t txpnt = 0;
00372     char iFrameNumber = 0x21;
00373     char GMLANMsg[8];
00374     char data2Send[0xE0];
00375 //
00376     // fopen modified.bin here, check it is OK and work out how much data I need to send
00377     // need lots of fcloses though
00378     printf("Checking the FLASH BIN file...\r\n");
00379     FILE *fp = fopen("/local/modified.bin", "r");    // Open "modified.bin" on the local file system for reading
00380     if (!fp) {
00381         printf("Error: I could not find the BIN file MODIFIED.BIN\r\n");;
00382         return TERM_ERR;
00383     }
00384     // obtain file size - it should match the size of the FLASH chips:
00385     fseek (fp , 0 , SEEK_END);
00386     uint32_t file_size = ftell (fp);
00387     rewind (fp);
00388 
00389     // read the initial stack pointer value in the BIN file - it should match the value expected for the type of ECU
00390     uint32_t stack_long = 0;
00391     if (!fread(&stack_long,4,1,fp)) {
00392         fclose(fp);
00393         return TERM_ERR;
00394     }
00395     stack_long = (stack_long >> 24) | ((stack_long << 8) & 0x00FF0000) | ((stack_long >> 8) & 0x0000FF00) |  (stack_long << 24);
00396 //
00397     if (file_size != T8FLASHSIZE || stack_long != T8POINTER) {
00398         fclose(fp);
00399         printf("The BIN file does not appear to be for a T8 ECU :-(\r\n");
00400         printf("BIN file size: %#010x, FLASH chip size: %#010x, Pointer: %#010x.\r\n", file_size, T7FLASHSIZE, stack_long);
00401         return TERM_ERR;
00402     }
00403 // It is possible to save some time by only sending the program code and CAL data
00404 // This is just a rough calculation, and slight overestimate of the number of blocks of data needed to send the BIN file
00405     uint32_t blocks2Send;
00406     fseek(fp,0x020140,SEEK_SET);
00407     if (!fread(&blocks2Send,4,1,fp)) {
00408         fclose(fp);
00409         return TERM_ERR;
00410     }
00411     blocks2Send = (blocks2Send >> 24) | ((blocks2Send << 8) & 0x00FF0000) | ((blocks2Send >> 8) & 0x0000FF00) |  (blocks2Send << 24);
00412     printf("Start address of BIN file's Footer area = 0x%06X\r\n", blocks2Send );
00413     blocks2Send += 0x200;       // Add some bytes for the Footer itself and to account for division rounded down later
00414     blocks2Send -= 0x020000;    // Remove 0x020000 because we don't send the bootblock and adaptation blocks
00415     printf("Amount of data to send BIN file adjusted for footer = 0x%06X Bytes\r\n", blocks2Send );
00416     blocks2Send /= 0xE0;
00417     printf("Number of Blocks of 0xE0 Bytes needed to send BIN file = 0x%04X\r\n", blocks2Send );
00418 // Move BIN file pointer to start of data
00419     fseek (fp , 0x020000 , SEEK_SET);
00420 // Erase the FLASH
00421     printf("Waiting for FLASH to be Erased\r\n");
00422     if (!GMLANRequestDownload(T8REQID, T8RESPID, GMLANRequestDownloadModeEncrypted)) {
00423         fclose(fp);
00424         printf("Unable to erase the FLASH chip!\r\n");
00425         return FALSE;
00426     }
00427 // Now send the BIN file
00428     GMLANTesterPresent(T8REQID, T8RESPID);
00429     TesterPresent.start();
00430     printf("Sending FLASH BIN file\r\n");
00431     printf("  0.00 %% complete.\r");
00432     for (i=0; i<blocks2Send; i++) {
00433         // get a block of 0xE0 bytes in an array called data2Send
00434         if (!fread(data2Send,0xE0,1,fp)) {
00435             fclose(fp);
00436             printf("\r\nError reading the BIN file MODIFIED.BIN\r\n");
00437             return FALSE;
00438         }
00439         // encrypt data2Send array by XORing with 6 different values in a ring (modulo function)
00440         char key[6] = { 0x39, 0x68, 0x77, 0x6D, 0x47, 0x39 };
00441         for ( j = 0; j < 0xE0; j++ )
00442             data2Send[j] ^= key[(((0xE0*i)+j) % 6)];
00443         // Send the block of data
00444         if (!GMLANDataTransferFirstFrame(T8REQID, T8RESPID, 0xE6, GMLANDOWNLOAD, StartAddress)) {
00445             fclose(fp);
00446             printf("\r\nUnable to start BIN File Upload\r\n");
00447             return FALSE;
00448         }
00449         // Send 0x20 messages of 0x07 bytes each (0x20 * 0x07 = 0xE0)
00450         txpnt = 0;
00451         iFrameNumber = 0x21;
00452         for (j=0; j < 0x20; j++) {
00453             GMLANMsg[0] = iFrameNumber;
00454             for (k=1; k<8; k++)
00455                 GMLANMsg[k] = data2Send[txpnt++];
00456             if (!can_send_timeout(T8REQID, GMLANMsg, 8, GMLANPTCT)) {
00457                 fclose(fp);
00458                 printf("\r\nUnable to send BIN File\r\n");
00459                 return FALSE;
00460             }
00461             ++iFrameNumber &= 0x2F;
00462             wait_us(1000);   // can be as low as 250 for an ECU on its own, but need 1000 (1ms) to work in a car (use a longer delay to be ultrasafe??? )
00463         }
00464         if (!GMLANDataTransferBlockAcknowledge(T8RESPID)) {
00465             fclose(fp);
00466             return FALSE;
00467         }
00468         if (TesterPresent.read_ms() > 2000) {
00469             GMLANTesterPresent(T8REQID, T8RESPID);
00470             TesterPresent.reset();
00471         }
00472         StartAddress += 0xE0;
00473         printf("%6.2f\r", (100.0*(float)i)/(float)(blocks2Send) );
00474     }
00475 // FLASHing complete
00476     printf("%6.2f\r\n", (float)100 );
00477 // End programming session and return to normal mode
00478     if (!GMLANReturnToNormalMode(T8REQID, T8RESPID)) {
00479         fclose(fp);
00480         printf("UH-OH! T8 ECU did not Return To Normal Mode!!\r\n");
00481         return FALSE;
00482     }
00483     timer.stop();
00484     printf("SUCCESS! FLASHing the BIN file took %#.1f seconds.\r\n",timer.read());
00485     fclose(fp);
00486     return TRUE;
00487 }
00488 
00489 bool t8_recover()
00490 {
00491     uint32_t i = 0, j = 0, k = 0;
00492 
00493     timer.reset();
00494     timer.start();
00495     printf("Recovering your T8 ECU ...\r\n");
00496 //
00497     if (!GMLANprogrammingSetupProcess(T8USDTREQID, T8UUDTRESPID))
00498         return FALSE;
00499 //
00500     printf("Requesting Security Access\r\n");
00501     if (!t8_authenticate(T8USDTREQID, T8UUDTRESPID, 0x01)) {
00502         printf("Unable to get Security Access\r\n");
00503         return FALSE;
00504     }
00505     printf("Security Access Granted\r\n");
00506 //
00507 //    const uint8_t BootLoader[] = T8BootloaderProg;
00508 //    if(!GMLANprogrammingUtilityFileProcess(T8USDTREQID, T8UUDTRESPID, BootLoader))
00509     if(!GMLANprogrammingUtilityFileProcess(T8USDTREQID, T8UUDTRESPID, T8BootLoaderWrite))
00510         return FALSE;
00511 //
00512 
00513 
00514 // All steps needed to transfer and start a bootloader ('Utility File' in GMLAN parlance)
00515     uint32_t StartAddress = 0x020000;
00516     uint32_t txpnt = 0;
00517     char iFrameNumber = 0x21;
00518     char GMLANMsg[8];
00519     char data2Send[0xE0];
00520 //
00521     // fopen modified.bin here, check it is OK and work out how much data I need to send
00522     // need lots of fcloses though
00523     printf("Checking the FLASH BIN file...\r\n");
00524     FILE *fp = fopen("/local/modified.bin", "r");    // Open "modified.bin" on the local file system for reading
00525     if (!fp) {
00526         printf("Error: I could not find the BIN file MODIFIED.BIN\r\n");;
00527         return TERM_ERR;
00528     }
00529     // obtain file size - it should match the size of the FLASH chips:
00530     fseek (fp , 0 , SEEK_END);
00531     uint32_t file_size = ftell (fp);
00532     rewind (fp);
00533 
00534     // read the initial stack pointer value in the BIN file - it should match the value expected for the type of ECU
00535     uint32_t stack_long = 0;
00536     if (!fread(&stack_long,4,1,fp)) {
00537         fclose(fp);
00538         return TERM_ERR;
00539     }
00540     stack_long = (stack_long >> 24) | ((stack_long << 8) & 0x00FF0000) | ((stack_long >> 8) & 0x0000FF00) |  (stack_long << 24);
00541 //
00542     if (file_size != T8FLASHSIZE || stack_long != T8POINTER) {
00543         fclose(fp);
00544         printf("The BIN file does not appear to be for a T8 ECU :-(\r\n");
00545         printf("BIN file size: %#010x, FLASH chip size: %#010x, Pointer: %#010x.\r\n", file_size, T7FLASHSIZE, stack_long);
00546         return TERM_ERR;
00547     }
00548 // It is possible to save some time by only sending the program code and CAL data
00549 // This is just a rough calculation, and slight overestimate of the number of blocks of data needed to send the BIN file
00550     uint32_t blocks2Send;
00551     fseek(fp,0x020140,SEEK_SET);
00552     if (!fread(&blocks2Send,4,1,fp)) {
00553         fclose(fp);
00554         return TERM_ERR;
00555     }
00556     blocks2Send = (blocks2Send >> 24) | ((blocks2Send << 8) & 0x00FF0000) | ((blocks2Send >> 8) & 0x0000FF00) |  (blocks2Send << 24);
00557     printf("Start address of BIN file's Footer area = 0x%06X\r\n", blocks2Send );
00558     blocks2Send += 0x200;       // Add some bytes for the Footer itself and to account for division rounded down later
00559     blocks2Send -= 0x020000;    // Remove 0x020000 because we don't send the bootblock and adaptation blocks
00560     printf("Amount of data to send BIN file adjusted for footer = 0x%06X Bytes\r\n", blocks2Send );
00561     blocks2Send /= 0xE0;
00562     printf("Number of Blocks of 0xE0 Bytes needed to send BIN file = 0x%04X\r\n", blocks2Send );
00563 // Move BIN file pointer to start of data
00564     fseek (fp , 0x020000 , SEEK_SET);
00565 // Erase the FLASH
00566     printf("Waiting for FLASH to be Erased\r\n");
00567     if (!GMLANRequestDownload(T8REQID, T8RESPID, GMLANRequestDownloadModeEncrypted)) {
00568         fclose(fp);
00569         printf("Unable to erase the FLASH chip!\r\n");
00570         return FALSE;
00571     }
00572 // Now send the BIN file
00573     GMLANTesterPresent(T8REQID, T8RESPID);
00574     TesterPresent.start();
00575     printf("Sending FLASH BIN file\r\n");
00576     printf("  0.00 %% complete.\r");
00577     for (i=0; i<blocks2Send; i++) {
00578         // get a block of 0xE0 bytes in an array called data2Send
00579         if (!fread(data2Send,0xE0,1,fp)) {
00580             fclose(fp);
00581             printf("\r\nError reading the BIN file MODIFIED.BIN\r\n");
00582             return FALSE;
00583         }
00584         // encrypt data2Send array by XORing with 6 different values in a ring (modulo function)
00585         char key[6] = { 0x39, 0x68, 0x77, 0x6D, 0x47, 0x39 };
00586         for ( j = 0; j < 0xE0; j++ )
00587             data2Send[j] ^= key[(((0xE0*i)+j) % 6)];
00588         // Send the block of data
00589         if (!GMLANDataTransferFirstFrame(T8REQID, T8RESPID, 0xE6, GMLANDOWNLOAD, StartAddress)) {
00590             fclose(fp);
00591             printf("\r\nUnable to start BIN File Upload\r\n");
00592             return FALSE;
00593         }
00594         // Send 0x20 messages of 0x07 bytes each (0x20 * 0x07 = 0xE0)
00595         txpnt = 0;
00596         iFrameNumber = 0x21;
00597         for (j=0; j < 0x20; j++) {
00598             GMLANMsg[0] = iFrameNumber;
00599             for (k=1; k<8; k++)
00600                 GMLANMsg[k] = data2Send[txpnt++];
00601             if (!can_send_timeout(T8REQID, GMLANMsg, 8, GMLANPTCT)) {
00602                 fclose(fp);
00603                 printf("\r\nUnable to send BIN File\r\n");
00604                 return FALSE;
00605             }
00606             ++iFrameNumber &= 0x2F;
00607             wait_us(1000);   // was 250 use 1000 or wait_ms(1) to be ultrasafe
00608         }
00609         if (!GMLANDataTransferBlockAcknowledge(T8RESPID)) {
00610             fclose(fp);
00611             return FALSE;
00612         }
00613         if (TesterPresent.read_ms() > 2000) {
00614             GMLANTesterPresent(T8REQID, T8RESPID);
00615             TesterPresent.reset();
00616         }
00617         StartAddress += 0xE0;
00618         printf("%6.2f\r", (100.0*(float)i)/(float)(blocks2Send) );
00619     }
00620 // FLASHing complete
00621     printf("%6.2f\r\n", (float)100 );
00622 // End programming session and return to normal mode
00623     if (!GMLANReturnToNormalMode(T8REQID, T8RESPID)) {
00624         fclose(fp);
00625         printf("UH-OH! T8 ECU did not Return To Normal Mode!!\r\n");
00626         return FALSE;
00627     }
00628     timer.stop();
00629     fclose(fp);
00630     printf("SUCCESS: Your T8 ECU has been recovered.\r\n");
00631     return TRUE;
00632 }