Sophie Dexter
/
Just4Trionic
Just4Trionic - CAN and BDM FLASH programmer for Saab cars
Diff: t8utils.cpp
- 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; +}