Just4Trionic - CAN and BDM FLASH programmer for Saab cars

Dependencies:   mbed

Revision:
5:1775b4b13232
Parent:
3:92dae9083c83
--- a/t5can.cpp	Wed Sep 11 11:55:51 2013 +0000
+++ b/t5can.cpp	Sat Apr 25 17:07:08 2015 +0000
@@ -42,7 +42,8 @@
 void t5_can_show_help();
 void t5_can_show_full_help();
 
-void t5_can() {
+void t5_can()
+{
     // Start the CAN bus system
     // Note that at the moment this is only for T5 ECUs at 615 kbits
     can_open();
@@ -103,7 +104,8 @@
 
     @return                    command flag (success / failure)
 */
-uint8_t execute_t5_cmd() {
+uint8_t execute_t5_cmd()
+{
 
 
 //    uint8_t cmd_length = strlen(cmd_buffer);
@@ -151,9 +153,10 @@
 
             // Send a Bootloader file to the T5 ECU
         case 'b':
+            return (t5_can_send_boot_loader() && can_set_speed(1000000))
+                   ? TERM_OK : TERM_ERR;
         case 'B':
-            return (t5_can_send_boot_loader() && can_set_speed(1000000))
-//            return (t5_can_send_boot_loader() && can_set_speed(615000))
+            return (t5_can_send_boot_loader_S19() && can_set_speed(1000000))
                    ? TERM_OK : TERM_ERR;
 
             // Get Checksum from ECU (Bootloader must be uploaded first)
@@ -186,8 +189,7 @@
             return t5_can_dump_flash(T55FLASHSTART)
                    ? TERM_OK : TERM_ERR;
         case 'D':
-            if (!t5_can_get_adaption_data())
-                return TERM_ERR;
+//            if (!t5_can_send_boot_loader_S19())
             if (!t5_can_send_boot_loader())
                 return TERM_ERR;
             can_set_speed(1000000);
@@ -201,10 +203,12 @@
 
             // Send a FLASH update file to the T5 ECU
         case 'f':
-            // NOTE 'f' command Just4TESTING! only FLASHes T5.5 ECU (with S19 type file) 
-            return t5_can_send_flash_s19_update(T55FLASHSTART)
+            // NOTE 'f' command Just4TESTING! only FLASHes T5.5 ECU (with S19 type file)
+            //return t5_can_send_flash_s19_update(T55FLASHSTART)
+            return t5_can_send_flash_bin_update(T55FLASHSTART)
                    ? TERM_OK : TERM_ERR;
         case 'F':
+//            if (!t5_can_send_boot_loader_S19())
             if (!t5_can_send_boot_loader())
                 return TERM_ERR;
             can_set_speed(1000000);
@@ -251,11 +255,12 @@
 // inputs:    none
 // return:    none
 //
-void t5_can_show_help() {
+void t5_can_show_help()
+{
     printf("Trionic 5 Command Menu\r\n");
     printf("======================\r\n");
-    printf("D - Read SRAM adaption and DUMP T5 FLASH BIN file\r\n");
-    printf("F - FLASH the update file to the T5 (and write SRAM - not done!)\r\n");
+    printf("D - DUMP the T5.x ECU FLASH to a file 'ORIGINAL.BIN'\r\n");
+    printf("F - FLASH the update file 'MODIFIED.BIN' to the T5.x\r\n");
     printf("\r\n");
     printf("r - read SRAM and write it to ADAPTION.RAM file\r\n");
     printf("s - read Symbol Table and write it to SYMBOLS.TXT\r\n");
@@ -275,17 +280,18 @@
 // inputs:    none
 // return:    none
 //
-void t5_can_show_full_help() {
+void t5_can_show_full_help()
+{
     printf("Trionic 5 Command Menu\r\n");
     printf("======================\r\n");
-    printf("D - Read SRAM adaption and DUMP T5 FLASH BIN file\r\n");
-    printf("F - FLASH the update file to the T5 (and write SRAM - not done!)\r\n");
+    printf("D - DUMP the T5.x ECU FLASH to a file 'ORIGINAL.BIN'\r\n");
+    printf("F - FLASH the update file 'MODIFIED.BIN' to the T5.x\r\n");
     printf("\r\n");
     printf("b - upload and start MyBooty.S19 bootloader\r\n");
     printf("c - get T5 ECU FLASH checksum (need to upload BOOTY.S19 before using this command)\r\n");
     printf("d - dump the T5 FLASH BIN file and write it to ORIGINAL.BIN\r\n");
     printf("e - erase the FLASH chips in the T5 ECU\r\n");
-    printf("f - FLASH the update file MODIFIED.S19 to the T5 ECU\r\n");
+    printf("f - FLASH the update file MODIFIED.BIN to the T5 ECU\r\n");
     printf("r - read SRAM and write it to ADAPTION.RAM file\r\n");
     printf("s - read Symbol Table, display it and write it to SYMBOLS.TXT\r\n");
     printf("v - read T5 ECU software version, display it and write it to VERSION.TXT\r\n");
@@ -313,7 +319,8 @@
 // inputs:    none
 // return:    bool TRUE if there was a message, FALSE if no message.
 //
-bool t5_can_show_can_message() {
+bool t5_can_show_can_message()
+{
     CANMessage can_MsgRx;
     if (can.read(can_MsgRx)) {
         printf("w%03x%d", can_MsgRx.id, can_MsgRx.len);
@@ -336,7 +343,8 @@
 // inputs:    none
 // return:    bool TRUE if there all went OK, FALSE if there was an error
 //
-bool t5_can_get_symbol_table() {
+bool t5_can_get_symbol_table()
+{
     printf("Saving the symbol table file\r\n");
     FILE *fp = fopen("/local/symbols.txt", "w");  // Open "symbols.txt" on the local file system for writing
     if (!fp) {
@@ -376,7 +384,8 @@
 // inputs:    none
 // return:    bool TRUE if there all went OK, FALSE if there was an error
 //
-bool t5_can_get_version() {
+bool t5_can_get_version()
+{
     FILE *fp = fopen("/local/version.txt", "w");  // Open "version.txt" on the local file system for writing
     if (!fp) {
         perror ("The following error occured");
@@ -416,7 +425,8 @@
 // inputs:    none
 // return:    bool TRUE if all went OK, FALSE if there was an error.
 //
-bool t5_can_get_adaption_data() {
+bool t5_can_get_adaption_data()
+{
     printf("Saving the SRAM adaption data.\r\n");
     FILE *fp = fopen("/local/adaption.RAM", "w");    // Open "adaption.RAM" on the local file system for writing
     if (!fp) {
@@ -468,7 +478,59 @@
 // return:    bool TRUE if all went OK,
 //                 FALSE if the 'bootloader' wasn't sent for some reason.
 //
-bool t5_can_send_boot_loader() {
+bool t5_can_send_boot_loader()
+{
+    uint32_t BootloaderSize = sizeof(T5BootLoader);
+    uint32_t address = MYBOOTY_START; // Start and execute from address of T5Bootloader
+    uint32_t count = 0; // progress count of bootloader bytes transferred
+    char msg[8]; // Construct the bootloader frame for uploading
+
+    printf("Starting the bootloader.\r\n");
+    while (count < BootloaderSize) {
+// send a bootloader address message
+        if (!t5_can_send_boot_address((address+count), MYBOOTY_CHUNK)) return FALSE;
+// send bootloader frames
+// NOTE the last frame sent may have less than 7 real data bytes but 7 bytes are always sent. In this case the unnecessary bytes
+// are repeated from the previous frame. This is OK because the T5 ECU knows how many bytes to expect (because the count of bytes
+// is sent with the upload address) and ignores any extra bytes in the last frame.
+        for (uint8_t i=0; i<MYBOOTY_CHUNK; i++) {
+            msg[1+(i%7)] = T5BootLoader[count+i];
+            if (i%7 == 0) msg[0]=i;     // set the index number
+            if ((i%7 == 6) || (i == MYBOOTY_CHUNK-1 )) {
+                if (!t5_can_send_boot_frame(msg)) return FALSE;
+            }
+        }
+        count += MYBOOTY_CHUNK;
+    }
+// These two lines really shouldn't be necessary but for some reason the first start
+// command is ignored and a short delay is required before repeating. Using only a
+// delay, even a very long one, doesn't work.
+//
+// NOTE: This measure isn't required when uploading an external S19 bootloader file!
+//
+    T5StartBootLoader(address);
+    wait_ms(1);
+//
+    return T5StartBootLoader(address);
+}
+
+
+//
+// t5_can_send_boot_loader_S19
+//
+// Sends a 'bootloader' file, booty.s19 to the T5 ECU.
+// The 'bootloader' is stored on the mbed 'local' file system 'disk' and must be in S19 format.
+//
+// The 'bootloader' is then able to dump or reFLASH the T5 ECU FLASH chips - this is the whole point of the exercise :-)
+//
+// Sending the 'bootloader' to the T5 ECU takes just over 1 second.
+//
+// inputs:    none
+// return:    bool TRUE if all went OK,
+//                 FALSE if the 'bootloader' wasn't sent for some reason.
+//
+bool t5_can_send_boot_loader_S19()
+{
     printf("Starting the bootloader.\r\n");
     FILE *fp = fopen("/local/MyBooty.S19", "r");    // Open "booty.s19" on the local file system for reading
     if (!fp) {
@@ -514,6 +576,7 @@
                     count--;
                 }
 // send a bootloader address message
+////                printf("address %x count %x\r\n",address ,count-1 );
                 if (!t5_can_send_boot_address(address, (count-1))) return FALSE;
 // get and send the bootloader frames for this S-record
 // NOTE the last frame sent may have less than 7 real data bytes but 7 bytes are always sent. In this case the unnecessary bytes
@@ -524,11 +587,13 @@
                     checksum += c;
                     msg[1+(i%7)] = c;
                     if (i%7 == 0) msg[0]=i;     // set the index number
-                    if ((i%7 == 6) || (i == count - 2))
+                    if ((i%7 == 6) || (i == count - 2)) {
+////                        printf("Sending %2x %2x %2x %2x %2x %2x %2x %2x \r\n", msg[0], msg[1], msg[2], msg[3], msg[4], msg[5], msg[6], msg[7] );
                         if (!t5_can_send_boot_frame(msg)) {
                             fclose(fp);
                             return FALSE;
                         }
+                    }
                 }
 // get the checksum
                 if ((checksum += SRecGetByte(fp)) != 0xFF) {
@@ -545,6 +610,7 @@
             case '8':
             case '9':
                 asize = 11 - (c - '0');  // 2, 3 or 4 bytes for address
+                address = 0;
 // get the number of bytes (in ascii format) in this S-record line there must be just the address and the checksum
 // so return with an error if other than this!
                 if ((c = SRecGetByte(fp)) != (asize + 1)) break;
@@ -604,7 +670,8 @@
 // inputs:    none
 // return:    bool TRUE if all went OK,
 //
-bool t5_can_get_checksum() {
+bool t5_can_get_checksum()
+{
     uint32_t checksum = 0;
     if (!t5_boot_checksum_command(&checksum)) {
         printf("Error The ECU's checksum is wrong!\r\n");
@@ -622,7 +689,8 @@
 // inputs:    none
 // outputs:    bool TRUE if all went OK.
 //
-bool t5_can_bootloader_reset() {
+bool t5_can_bootloader_reset()
+{
     printf("Exiting the bootloader and restarting the T5 ECU.\r\n");
     if (!t5_boot_reset_command()) {
         printf("Error trying to reset the T5 ECU!\r\n");
@@ -670,7 +738,8 @@
 // inputs:    start     T5 ecu start address
 // return:    bool      TRUE if all went OK.
 //
-bool t5_can_get_start_and_chip_types(uint32_t* start) {
+bool t5_can_get_start_and_chip_types(uint32_t* start)
+{
     *start = 0;
     uint8_t make = 0;
     uint8_t type = 0;
@@ -689,23 +758,44 @@
         case INTEL:
             printf("INTEL ");
             break;
+        case ATMEL:
+            printf("ATMEL ");
+            break;
+        case SST:
+            printf("SST ");
+            break;
+        case ST:
+            printf("ST ");
+            break;
+        case AMIC:
+            printf("AMIC ");
+            break;
         default:
-            printf("UNKNOWN FLASH chips - check pin65 has enough volts!\r\n");
+            printf("\r\nUNKNOWN Manufacturer Id: %02x - Also check pin65 has enough volts!\r\n", make);
     }
     switch (type) {
         case AMD28F512:
         case INTEL28F512:
             printf("28F512 FLASH chips.\r\n");
             break;
+        case ATMEL29C512:
+            printf("29C512 FLASH chips.\r\n");
+            break;
+        case ATMEL29C010:
+            printf("29C010 FLASH chips.\r\n");
+            break;
         case AMD28F010:
         case INTEL28F010:
             printf("28F010 FLASH chips.\r\n");
             break;
         case AMD29F010:
+        case SST39SF010:
+//        case ST29F010:      // Same as AMD29F010
+        case AMICA29010L:
             printf("29F010 FLASH chips.\r\n");
             break;
         default:
-            printf("UNKNOWN - check pin65 has enough volts!\r\n");
+            printf("UNKNOWN Device Id: %02x - Also check pin65 has enough volts!\r\n", type);
             return FALSE;
     }
     return TRUE;
@@ -739,7 +829,8 @@
 // inputs:    none
 // return:    bool TRUE if all went OK.
 //
-bool t5_can_erase_flash() {
+bool t5_can_erase_flash()
+{
     printf("Erasing the FLASH chips.\r\n");
     if (!t5_boot_erase_command()) {
         printf("Error The ECU's FLASH has not been erased!\r\n");
@@ -762,7 +853,8 @@
 
 // return:    bool TRUE if all went OK, FALSE if there was an error.
 //
-bool t5_can_dump_flash(uint32_t start) {
+bool t5_can_dump_flash(uint32_t start)
+{
     printf("Saving the original FLASH BIN file.\r\n");
     FILE *fp = fopen("/local/original.bin", "w");    // Open "original.bin" on the local file system for writing
     if (!fp) {
@@ -771,6 +863,7 @@
     }
     uint32_t address = start + 5;                  // Mysterious reason for starting at 5 !!!
     char FLASHdata[6];
+    printf("  0.00 %% complete.\r");
     while (address < TRIONICLASTADDR) {
         if (!t5_can_read_data(FLASHdata, address)) {
             fclose (fp);
@@ -783,6 +876,7 @@
             printf ("Error writing to the FLASH BIN file.\r\n");
             return FALSE;
         }
+        printf("%6.2f\r", 100*(float)(address-start)/(float)(TRIONICLASTADDR - start) );
     }
     // There are a few more bytes to get because because the bin file is not an exact multiple of 6 bytes!
     // the % (modulo) mathematics function tells us how many bytes there are still to get
@@ -796,6 +890,7 @@
         printf ("Error writing to the FLASH BIN file.\r\n");
         return FALSE;
     }
+    printf("100.00 %% complete.\r\n");
     fclose(fp);
     return TRUE;
 }
@@ -804,7 +899,7 @@
 //
 // t5_can_send_flash_bin_update
 //
-// Sends a FLASH update file, modified.hex to the T5 ECU.
+// Sends a FLASH update file, modified.bin to the T5 ECU.
 // The FLASH update file is stored on the local file system and must be in hex format.
 //
 // FLASHing a T5.5 ECU takes around 40 seconds. FLASHing T5.2 ECUs should take about half of this time
@@ -814,11 +909,12 @@
 // return:    bool      TRUE if all went OK,
 //                      FALSE if the FLASH update failed for some reason.
 //
-bool t5_can_send_flash_bin_update(uint32_t start) {
+bool t5_can_send_flash_bin_update(uint32_t start)
+{
     printf("Programming the FLASH chips.\r\n");
-    FILE *fp = fopen("/local/modified.hex", "r");    // Open "modified.s19" on the local file system for reading
+    FILE *fp = fopen("/local/modified.bin", "r");    // Open "modified.bin" on the local file system for reading
     if (!fp) {
-        printf("Error: I could not find the BIN file MODIFIED.HEX\r\n");
+        printf("Error: I could not find the BIN file MODIFIED.BIN\r\n");
         return FALSE;
     }
 
@@ -857,15 +953,15 @@
     uint32_t curr_addr = start; // address to put FLASH data
     uint8_t byte_value = 0;
 
+    printf("  0.00 %% complete.\r");
     while (curr_addr <= TRIONICLASTADDR) {
 
 // send a bootloader address message
         if (!t5_can_send_boot_address(curr_addr, 0x80)) {
             fclose(fp);
-            printf("Error sending CAN message");
+            printf("\r\nError sending Block Start message. Address: %08x\r\n",curr_addr);
             return FALSE;
         }
-        curr_addr += 0x80;
 // Construct and send the bootloader frames
 // NOTE the last frame sent may have less than 7 real data bytes but 7 bytes are always sent. In this case the unnecessary bytes
 // are repeated from the previous frame. This is OK because the T5 ECU knows how many bytes to expect (because the count of bytes
@@ -873,7 +969,7 @@
         for (uint8_t i=0; i<0x80; i++) {
             if (!fread(&byte_value,1,1,fp)) {
                 fclose(fp);
-                printf("Error reading the BIN file MODIFIED.HEX");
+                printf("\r\nError reading the BIN file MODIFIED.BIN\r\n");
                 return FALSE;
             }
             msg[1+(i%7)] = byte_value;
@@ -881,11 +977,15 @@
             if ((i%7 == 6) || (i == 0x80 - 1))
                 if (!t5_can_send_boot_frame(msg)) {
                     fclose(fp);
-                    printf("Error sending CAN message");
+                    printf("\r\nError sending a Block data message. Address: %08x, Index: %02x\r\n",curr_addr, i);
                     return FALSE;
                 }
+
         }
+        curr_addr += 0x80;
+        printf("%6.2f\r", 100*(float)(curr_addr - start)/(float)(TRIONICLASTADDR - start) );
     }
+    printf("100.00 %% complete.\r\n");
     fclose(fp);
     return TRUE;
 }
@@ -903,7 +1003,8 @@
 // return:    bool TRUE if all went OK,
 //                 FALSE if the FLASH update failed for some reason.
 //
-bool t5_can_send_flash_s19_update(uint32_t start) {
+bool t5_can_send_flash_s19_update(uint32_t start)
+{
     printf("Programming the FLASH chips.\r\n");
     FILE *fp = fopen("/local/modified.s19", "r");    // Open "modified.s19" on the local file system for reading
     if (!fp) {
@@ -1014,7 +1115,8 @@
 // inputs:    none
 // return:    bool TRUE if all went OK,
 //
-bool t5_can_get_last_address() {
+bool t5_can_get_last_address()
+{
     uint32_t last_address = 0;
     uint16_t mode = 0;
     if (!t5_boot_c3_command(&last_address, &mode)) {