Sophie Dexter
/
Just4Trionic
Just4Trionic - CAN and BDM FLASH programmer for Saab cars
t5can.cpp@6:2fbcbebed28c, 2016-04-23 (annotated)
- Committer:
- Just4pLeisure
- Date:
- Sat Apr 23 18:31:40 2016 +0000
- Revision:
- 6:2fbcbebed28c
- Parent:
- 5:1775b4b13232
Version 1.6 Faster T7 P-BUS FLASHing algorithm, longer T8 erase timeout fixed BDM register display function
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
Just4pLeisure | 1:d5452e398b76 | 1 | /******************************************************************************* |
Just4pLeisure | 1:d5452e398b76 | 2 | |
Just4pLeisure | 1:d5452e398b76 | 3 | trionic5.cpp - CAN Bus functions for Just4Trionic by Just4pLeisure |
Just4pLeisure | 1:d5452e398b76 | 4 | (c) 2010 by Sophie Dexter |
Just4pLeisure | 1:d5452e398b76 | 5 | |
Just4pLeisure | 1:d5452e398b76 | 6 | This C++ module provides functions for reading and writing the FLASH chips and |
Just4pLeisure | 1:d5452e398b76 | 7 | SRAM in Trionic5 ECUs. (Writing the adaption data back to SRAM not done yet). |
Just4pLeisure | 1:d5452e398b76 | 8 | |
Just4pLeisure | 1:d5452e398b76 | 9 | Some functions need an additional 'bootloader' program to be sent to the T5 ECU |
Just4pLeisure | 1:d5452e398b76 | 10 | before they can be used. These functions are: Identifying the T5 ECU type and |
Just4pLeisure | 1:d5452e398b76 | 11 | FLASH chips, dumping the FLASH chips, erasing the FLASH chips, writing to the |
Just4pLeisure | 1:d5452e398b76 | 12 | FLASH chips and calculating the FLASH chips' checksum. |
Just4pLeisure | 1:d5452e398b76 | 13 | |
Just4pLeisure | 1:d5452e398b76 | 14 | My version of the bootloader, BOOTY.S19, includes some features not in other |
Just4pLeisure | 1:d5452e398b76 | 15 | bootloaders; identifying the ECU and FLASH chip types, a 'safer' way of dumping |
Just4pLeisure | 1:d5452e398b76 | 16 | the FLASH chips and the ability to program AMD 29F010 type FLASH chips |
Just4pLeisure | 1:d5452e398b76 | 17 | |
Just4pLeisure | 1:d5452e398b76 | 18 | ******************************************************************************** |
Just4pLeisure | 1:d5452e398b76 | 19 | |
Just4pLeisure | 1:d5452e398b76 | 20 | WARNING: Use at your own risk, sadly this software comes with no guarantees. |
Just4pLeisure | 1:d5452e398b76 | 21 | This software is provided 'free' and in good faith, but the author does not |
Just4pLeisure | 1:d5452e398b76 | 22 | accept liability for any damage arising from its use. |
Just4pLeisure | 1:d5452e398b76 | 23 | |
Just4pLeisure | 1:d5452e398b76 | 24 | *******************************************************************************/ |
Just4pLeisure | 1:d5452e398b76 | 25 | |
Just4pLeisure | 1:d5452e398b76 | 26 | #include "t5can.h" |
Just4pLeisure | 1:d5452e398b76 | 27 | |
Just4pLeisure | 1:d5452e398b76 | 28 | // constants |
Just4pLeisure | 1:d5452e398b76 | 29 | #define CMD_BUF_LENGTH 32 ///< command buffer size |
Just4pLeisure | 1:d5452e398b76 | 30 | |
Just4pLeisure | 1:d5452e398b76 | 31 | // static variables |
Just4pLeisure | 1:d5452e398b76 | 32 | static char cmd_buffer[CMD_BUF_LENGTH]; ///< command string buffer |
Just4pLeisure | 1:d5452e398b76 | 33 | |
Just4pLeisure | 1:d5452e398b76 | 34 | //static uint32_t cmd_addr; ///< address (optional) |
Just4pLeisure | 1:d5452e398b76 | 35 | //static uint32_t cmd_value; ///< value (optional) |
Just4pLeisure | 1:d5452e398b76 | 36 | //static uint32_t cmd_result; ///< result |
Just4pLeisure | 1:d5452e398b76 | 37 | |
Just4pLeisure | 1:d5452e398b76 | 38 | static uint32_t flash_start = 0; |
Just4pLeisure | 1:d5452e398b76 | 39 | |
Just4pLeisure | 1:d5452e398b76 | 40 | // private functions |
Just4pLeisure | 1:d5452e398b76 | 41 | uint8_t execute_t5_cmd(); |
Just4pLeisure | 1:d5452e398b76 | 42 | void t5_can_show_help(); |
Just4pLeisure | 1:d5452e398b76 | 43 | void t5_can_show_full_help(); |
Just4pLeisure | 1:d5452e398b76 | 44 | |
Just4pLeisure | 5:1775b4b13232 | 45 | void t5_can() |
Just4pLeisure | 5:1775b4b13232 | 46 | { |
Just4pLeisure | 1:d5452e398b76 | 47 | // Start the CAN bus system |
Just4pLeisure | 1:d5452e398b76 | 48 | // Note that at the moment this is only for T5 ECUs at 615 kbits |
Just4pLeisure | 1:d5452e398b76 | 49 | can_open(); |
Just4pLeisure | 1:d5452e398b76 | 50 | can_set_speed(615000); |
Just4pLeisure | 1:d5452e398b76 | 51 | |
Just4pLeisure | 1:d5452e398b76 | 52 | t5_can_show_help(); |
Just4pLeisure | 1:d5452e398b76 | 53 | |
Just4pLeisure | 1:d5452e398b76 | 54 | // main loop |
Just4pLeisure | 1:d5452e398b76 | 55 | *cmd_buffer = '\0'; |
Just4pLeisure | 1:d5452e398b76 | 56 | char ret; |
Just4pLeisure | 1:d5452e398b76 | 57 | char rx_char; |
Just4pLeisure | 1:d5452e398b76 | 58 | while (true) { |
Just4pLeisure | 1:d5452e398b76 | 59 | // read chars from USB |
Just4pLeisure | 1:d5452e398b76 | 60 | // send received messages to the pc over USB connection |
Just4pLeisure | 1:d5452e398b76 | 61 | // This function displays any CAN messages that are 'missed' by the other functions |
Just4pLeisure | 1:d5452e398b76 | 62 | // Can messages might be 'missed' because they are received after a 'timeout' period |
Just4pLeisure | 1:d5452e398b76 | 63 | // or because they weren't expected, e.g. if the T5 ECU resets for some reason |
Just4pLeisure | 1:d5452e398b76 | 64 | t5_can_show_can_message(); |
Just4pLeisure | 1:d5452e398b76 | 65 | if (pc.readable()) { |
Just4pLeisure | 1:d5452e398b76 | 66 | // turn Error LED off for next command |
Just4pLeisure | 1:d5452e398b76 | 67 | led4 = 0; |
Just4pLeisure | 1:d5452e398b76 | 68 | rx_char = pc.getc(); |
Just4pLeisure | 1:d5452e398b76 | 69 | switch (rx_char) { |
Just4pLeisure | 1:d5452e398b76 | 70 | // 'ESC' key to go back to mbed Just4Trionic 'home' menu |
Just4pLeisure | 1:d5452e398b76 | 71 | case '\e': |
Just4pLeisure | 1:d5452e398b76 | 72 | can_close(); |
Just4pLeisure | 1:d5452e398b76 | 73 | return; |
Just4pLeisure | 1:d5452e398b76 | 74 | // end-of-command reached |
Just4pLeisure | 1:d5452e398b76 | 75 | case TERM_OK : |
Just4pLeisure | 1:d5452e398b76 | 76 | // execute command and return flag via USB |
Just4pLeisure | 1:d5452e398b76 | 77 | timer.reset(); |
Just4pLeisure | 1:d5452e398b76 | 78 | timer.start(); |
Just4pLeisure | 1:d5452e398b76 | 79 | ret = execute_t5_cmd(); |
Just4pLeisure | 1:d5452e398b76 | 80 | pc.putc(ret); |
Just4pLeisure | 3:92dae9083c83 | 81 | printf("Completed in %.3f seconds.\r\n", timer.read()); |
Just4pLeisure | 1:d5452e398b76 | 82 | // reset command buffer |
Just4pLeisure | 1:d5452e398b76 | 83 | *cmd_buffer = '\0'; |
Just4pLeisure | 1:d5452e398b76 | 84 | // light up LED |
Just4pLeisure | 1:d5452e398b76 | 85 | // ret == TERM_OK ? led_on(LED_ACT) : led_on(LED_ERR); |
Just4pLeisure | 1:d5452e398b76 | 86 | ret == TERM_OK ? led3 = 1 : led4 = 1; |
Just4pLeisure | 1:d5452e398b76 | 87 | break; |
Just4pLeisure | 1:d5452e398b76 | 88 | // another command char |
Just4pLeisure | 1:d5452e398b76 | 89 | default: |
Just4pLeisure | 1:d5452e398b76 | 90 | // store in buffer if space permits |
Just4pLeisure | 1:d5452e398b76 | 91 | if (StrLen(cmd_buffer) < CMD_BUF_LENGTH - 1) { |
Just4pLeisure | 1:d5452e398b76 | 92 | StrAddc(cmd_buffer, rx_char); |
Just4pLeisure | 1:d5452e398b76 | 93 | } |
Just4pLeisure | 1:d5452e398b76 | 94 | break; |
Just4pLeisure | 1:d5452e398b76 | 95 | } |
Just4pLeisure | 1:d5452e398b76 | 96 | } |
Just4pLeisure | 1:d5452e398b76 | 97 | } |
Just4pLeisure | 1:d5452e398b76 | 98 | } |
Just4pLeisure | 1:d5452e398b76 | 99 | |
Just4pLeisure | 1:d5452e398b76 | 100 | //----------------------------------------------------------------------------- |
Just4pLeisure | 1:d5452e398b76 | 101 | /** |
Just4pLeisure | 1:d5452e398b76 | 102 | Executes a command and returns result flag (does not transmit the flag |
Just4pLeisure | 1:d5452e398b76 | 103 | itself). |
Just4pLeisure | 1:d5452e398b76 | 104 | |
Just4pLeisure | 1:d5452e398b76 | 105 | @return command flag (success / failure) |
Just4pLeisure | 1:d5452e398b76 | 106 | */ |
Just4pLeisure | 5:1775b4b13232 | 107 | uint8_t execute_t5_cmd() |
Just4pLeisure | 5:1775b4b13232 | 108 | { |
Just4pLeisure | 1:d5452e398b76 | 109 | |
Just4pLeisure | 1:d5452e398b76 | 110 | |
Just4pLeisure | 1:d5452e398b76 | 111 | // uint8_t cmd_length = strlen(cmd_buffer); |
Just4pLeisure | 1:d5452e398b76 | 112 | // command groups |
Just4pLeisure | 1:d5452e398b76 | 113 | switch (*cmd_buffer) { |
Just4pLeisure | 1:d5452e398b76 | 114 | // CHECK_ARGLENGTH(0); |
Just4pLeisure | 1:d5452e398b76 | 115 | // Get the Symbol Table |
Just4pLeisure | 1:d5452e398b76 | 116 | case 's': |
Just4pLeisure | 1:d5452e398b76 | 117 | return t5_can_get_symbol_table() |
Just4pLeisure | 1:d5452e398b76 | 118 | ? TERM_OK : TERM_ERR; |
Just4pLeisure | 1:d5452e398b76 | 119 | case 'S': |
Just4pLeisure | 1:d5452e398b76 | 120 | return T5ReadCmnd(T5SYMBOLS) |
Just4pLeisure | 1:d5452e398b76 | 121 | ? TERM_OK : TERM_ERR; |
Just4pLeisure | 1:d5452e398b76 | 122 | |
Just4pLeisure | 1:d5452e398b76 | 123 | // Get the Trionic5 software version string |
Just4pLeisure | 1:d5452e398b76 | 124 | case 'v': |
Just4pLeisure | 1:d5452e398b76 | 125 | return t5_can_get_version() |
Just4pLeisure | 1:d5452e398b76 | 126 | ? TERM_OK : TERM_ERR; |
Just4pLeisure | 1:d5452e398b76 | 127 | case 'V': |
Just4pLeisure | 1:d5452e398b76 | 128 | return T5ReadCmnd(T5VERSION) |
Just4pLeisure | 1:d5452e398b76 | 129 | ? TERM_OK : TERM_ERR; |
Just4pLeisure | 1:d5452e398b76 | 130 | |
Just4pLeisure | 1:d5452e398b76 | 131 | // Read Adaption Data from RAM and write it to a file |
Just4pLeisure | 1:d5452e398b76 | 132 | case 'r': |
Just4pLeisure | 1:d5452e398b76 | 133 | case 'R': |
Just4pLeisure | 1:d5452e398b76 | 134 | return t5_can_get_adaption_data() |
Just4pLeisure | 1:d5452e398b76 | 135 | ? TERM_OK : TERM_ERR; |
Just4pLeisure | 1:d5452e398b76 | 136 | |
Just4pLeisure | 1:d5452e398b76 | 137 | // CR - send CR type message |
Just4pLeisure | 1:d5452e398b76 | 138 | case '\0': |
Just4pLeisure | 1:d5452e398b76 | 139 | return T5ReadCmnd(CR) |
Just4pLeisure | 1:d5452e398b76 | 140 | ? TERM_OK : TERM_ERR; |
Just4pLeisure | 1:d5452e398b76 | 141 | |
Just4pLeisure | 1:d5452e398b76 | 142 | // Get a single symbol from the Symbol Table |
Just4pLeisure | 1:d5452e398b76 | 143 | case 'a': |
Just4pLeisure | 1:d5452e398b76 | 144 | char symbol[40]; |
Just4pLeisure | 1:d5452e398b76 | 145 | T5GetSymbol(symbol); |
Just4pLeisure | 1:d5452e398b76 | 146 | printf("%s",symbol); |
Just4pLeisure | 1:d5452e398b76 | 147 | return TERM_OK; |
Just4pLeisure | 1:d5452e398b76 | 148 | |
Just4pLeisure | 1:d5452e398b76 | 149 | // Just send an 'ACK' message |
Just4pLeisure | 1:d5452e398b76 | 150 | case 'A': |
Just4pLeisure | 1:d5452e398b76 | 151 | return T5Ack() |
Just4pLeisure | 1:d5452e398b76 | 152 | ? TERM_OK : TERM_ERR; |
Just4pLeisure | 1:d5452e398b76 | 153 | |
Just4pLeisure | 1:d5452e398b76 | 154 | // Send a Bootloader file to the T5 ECU |
Just4pLeisure | 1:d5452e398b76 | 155 | case 'b': |
Just4pLeisure | 5:1775b4b13232 | 156 | return (t5_can_send_boot_loader() && can_set_speed(1000000)) |
Just4pLeisure | 5:1775b4b13232 | 157 | ? TERM_OK : TERM_ERR; |
Just4pLeisure | 1:d5452e398b76 | 158 | case 'B': |
Just4pLeisure | 5:1775b4b13232 | 159 | return (t5_can_send_boot_loader_S19() && can_set_speed(1000000)) |
Just4pLeisure | 1:d5452e398b76 | 160 | ? TERM_OK : TERM_ERR; |
Just4pLeisure | 1:d5452e398b76 | 161 | |
Just4pLeisure | 1:d5452e398b76 | 162 | // Get Checksum from ECU (Bootloader must be uploaded first) |
Just4pLeisure | 1:d5452e398b76 | 163 | case 'c': |
Just4pLeisure | 1:d5452e398b76 | 164 | case 'C': |
Just4pLeisure | 1:d5452e398b76 | 165 | return t5_can_get_checksum() |
Just4pLeisure | 1:d5452e398b76 | 166 | ? TERM_OK : TERM_ERR; |
Just4pLeisure | 1:d5452e398b76 | 167 | |
Just4pLeisure | 1:d5452e398b76 | 168 | // Exit the BootLoader and restart the T5 ECU |
Just4pLeisure | 1:d5452e398b76 | 169 | case 'q': |
Just4pLeisure | 1:d5452e398b76 | 170 | case 'Q': |
Just4pLeisure | 3:92dae9083c83 | 171 | return (t5_can_bootloader_reset() && can_set_speed(615000)) |
Just4pLeisure | 1:d5452e398b76 | 172 | ? TERM_OK : TERM_ERR; |
Just4pLeisure | 1:d5452e398b76 | 173 | |
Just4pLeisure | 1:d5452e398b76 | 174 | // Erase the FLASH chips |
Just4pLeisure | 1:d5452e398b76 | 175 | case 'e': |
Just4pLeisure | 1:d5452e398b76 | 176 | case 'E': |
Just4pLeisure | 1:d5452e398b76 | 177 | return t5_can_erase_flash() |
Just4pLeisure | 1:d5452e398b76 | 178 | ? TERM_OK : TERM_ERR; |
Just4pLeisure | 1:d5452e398b76 | 179 | |
Just4pLeisure | 1:d5452e398b76 | 180 | // Read back the FLASH chip types |
Just4pLeisure | 1:d5452e398b76 | 181 | case 't': |
Just4pLeisure | 1:d5452e398b76 | 182 | case 'T': |
Just4pLeisure | 1:d5452e398b76 | 183 | return t5_can_get_start_and_chip_types(&flash_start) |
Just4pLeisure | 1:d5452e398b76 | 184 | ? TERM_OK : TERM_ERR; |
Just4pLeisure | 1:d5452e398b76 | 185 | |
Just4pLeisure | 1:d5452e398b76 | 186 | // DUMP the T5 ECU BIN file stored in the FLASH chips |
Just4pLeisure | 1:d5452e398b76 | 187 | case 'd': |
Just4pLeisure | 1:d5452e398b76 | 188 | // NOTE 'd' command Just4TESTING! only dumps T5.5 ECU |
Just4pLeisure | 1:d5452e398b76 | 189 | return t5_can_dump_flash(T55FLASHSTART) |
Just4pLeisure | 1:d5452e398b76 | 190 | ? TERM_OK : TERM_ERR; |
Just4pLeisure | 1:d5452e398b76 | 191 | case 'D': |
Just4pLeisure | 5:1775b4b13232 | 192 | // if (!t5_can_send_boot_loader_S19()) |
Just4pLeisure | 1:d5452e398b76 | 193 | if (!t5_can_send_boot_loader()) |
Just4pLeisure | 1:d5452e398b76 | 194 | return TERM_ERR; |
Just4pLeisure | 3:92dae9083c83 | 195 | can_set_speed(1000000); |
Just4pLeisure | 1:d5452e398b76 | 196 | if (!t5_can_get_start_and_chip_types(&flash_start)) { |
Just4pLeisure | 1:d5452e398b76 | 197 | t5_can_bootloader_reset(); |
Just4pLeisure | 3:92dae9083c83 | 198 | can_set_speed(615000); |
Just4pLeisure | 1:d5452e398b76 | 199 | return TERM_ERR; |
Just4pLeisure | 1:d5452e398b76 | 200 | } |
Just4pLeisure | 3:92dae9083c83 | 201 | return (t5_can_dump_flash(flash_start) && t5_can_bootloader_reset() && can_set_speed(615000)) |
Just4pLeisure | 1:d5452e398b76 | 202 | ? TERM_OK : TERM_ERR; |
Just4pLeisure | 1:d5452e398b76 | 203 | |
Just4pLeisure | 1:d5452e398b76 | 204 | // Send a FLASH update file to the T5 ECU |
Just4pLeisure | 1:d5452e398b76 | 205 | case 'f': |
Just4pLeisure | 5:1775b4b13232 | 206 | // NOTE 'f' command Just4TESTING! only FLASHes T5.5 ECU (with S19 type file) |
Just4pLeisure | 5:1775b4b13232 | 207 | //return t5_can_send_flash_s19_update(T55FLASHSTART) |
Just4pLeisure | 5:1775b4b13232 | 208 | return t5_can_send_flash_bin_update(T55FLASHSTART) |
Just4pLeisure | 1:d5452e398b76 | 209 | ? TERM_OK : TERM_ERR; |
Just4pLeisure | 1:d5452e398b76 | 210 | case 'F': |
Just4pLeisure | 5:1775b4b13232 | 211 | // if (!t5_can_send_boot_loader_S19()) |
Just4pLeisure | 1:d5452e398b76 | 212 | if (!t5_can_send_boot_loader()) |
Just4pLeisure | 1:d5452e398b76 | 213 | return TERM_ERR; |
Just4pLeisure | 3:92dae9083c83 | 214 | can_set_speed(1000000); |
Just4pLeisure | 1:d5452e398b76 | 215 | if (!t5_can_get_start_and_chip_types(&flash_start)) { |
Just4pLeisure | 1:d5452e398b76 | 216 | t5_can_bootloader_reset(); |
Just4pLeisure | 3:92dae9083c83 | 217 | can_set_speed(615000); |
Just4pLeisure | 1:d5452e398b76 | 218 | return TERM_ERR; |
Just4pLeisure | 1:d5452e398b76 | 219 | } |
Just4pLeisure | 1:d5452e398b76 | 220 | if (!t5_can_get_checksum()) |
Just4pLeisure | 1:d5452e398b76 | 221 | led4 = 1; |
Just4pLeisure | 1:d5452e398b76 | 222 | if (!t5_can_erase_flash()) { |
Just4pLeisure | 1:d5452e398b76 | 223 | t5_can_bootloader_reset(); |
Just4pLeisure | 3:92dae9083c83 | 224 | can_set_speed(615000); |
Just4pLeisure | 1:d5452e398b76 | 225 | return TERM_ERR; |
Just4pLeisure | 1:d5452e398b76 | 226 | } |
Just4pLeisure | 3:92dae9083c83 | 227 | return (t5_can_send_flash_bin_update(flash_start) && t5_can_get_checksum() && t5_can_bootloader_reset() && can_set_speed(615000)) |
Just4pLeisure | 1:d5452e398b76 | 228 | ? TERM_OK : TERM_ERR; |
Just4pLeisure | 1:d5452e398b76 | 229 | |
Just4pLeisure | 1:d5452e398b76 | 230 | // Send the C3 message - should get last used address 0x7FFFF |
Just4pLeisure | 1:d5452e398b76 | 231 | case '3': |
Just4pLeisure | 1:d5452e398b76 | 232 | return t5_can_get_last_address() |
Just4pLeisure | 1:d5452e398b76 | 233 | ? TERM_OK : TERM_ERR; |
Just4pLeisure | 1:d5452e398b76 | 234 | |
Just4pLeisure | 1:d5452e398b76 | 235 | // Print help |
Just4pLeisure | 1:d5452e398b76 | 236 | case 'h': |
Just4pLeisure | 1:d5452e398b76 | 237 | t5_can_show_help(); |
Just4pLeisure | 1:d5452e398b76 | 238 | return TERM_OK; |
Just4pLeisure | 1:d5452e398b76 | 239 | case 'H': |
Just4pLeisure | 1:d5452e398b76 | 240 | t5_can_show_full_help(); |
Just4pLeisure | 1:d5452e398b76 | 241 | return TERM_OK; |
Just4pLeisure | 1:d5452e398b76 | 242 | default: |
Just4pLeisure | 1:d5452e398b76 | 243 | t5_can_show_help(); |
Just4pLeisure | 1:d5452e398b76 | 244 | break; |
Just4pLeisure | 1:d5452e398b76 | 245 | } |
Just4pLeisure | 1:d5452e398b76 | 246 | // unknown command |
Just4pLeisure | 1:d5452e398b76 | 247 | return TERM_ERR; |
Just4pLeisure | 1:d5452e398b76 | 248 | } |
Just4pLeisure | 1:d5452e398b76 | 249 | |
Just4pLeisure | 1:d5452e398b76 | 250 | // |
Just4pLeisure | 1:d5452e398b76 | 251 | // Trionic5ShowHelp |
Just4pLeisure | 1:d5452e398b76 | 252 | // |
Just4pLeisure | 1:d5452e398b76 | 253 | // Displays a list of things that can be done with the T5 ECU. |
Just4pLeisure | 1:d5452e398b76 | 254 | // |
Just4pLeisure | 1:d5452e398b76 | 255 | // inputs: none |
Just4pLeisure | 1:d5452e398b76 | 256 | // return: none |
Just4pLeisure | 1:d5452e398b76 | 257 | // |
Just4pLeisure | 5:1775b4b13232 | 258 | void t5_can_show_help() |
Just4pLeisure | 5:1775b4b13232 | 259 | { |
Just4pLeisure | 1:d5452e398b76 | 260 | printf("Trionic 5 Command Menu\r\n"); |
Just4pLeisure | 1:d5452e398b76 | 261 | printf("======================\r\n"); |
Just4pLeisure | 5:1775b4b13232 | 262 | printf("D - DUMP the T5.x ECU FLASH to a file 'ORIGINAL.BIN'\r\n"); |
Just4pLeisure | 5:1775b4b13232 | 263 | printf("F - FLASH the update file 'MODIFIED.BIN' to the T5.x\r\n"); |
Just4pLeisure | 1:d5452e398b76 | 264 | printf("\r\n"); |
Just4pLeisure | 1:d5452e398b76 | 265 | printf("r - read SRAM and write it to ADAPTION.RAM file\r\n"); |
Just4pLeisure | 1:d5452e398b76 | 266 | printf("s - read Symbol Table and write it to SYMBOLS.TXT\r\n"); |
Just4pLeisure | 1:d5452e398b76 | 267 | printf("v - read T5 ECU software version, display it and write it to VERSION.TXT\r\n"); |
Just4pLeisure | 1:d5452e398b76 | 268 | printf("\r\n"); |
Just4pLeisure | 1:d5452e398b76 | 269 | printf("'ESC' - Return to Just4Trionic Main Menu\r\n"); |
Just4pLeisure | 1:d5452e398b76 | 270 | printf("\r\n"); |
Just4pLeisure | 1:d5452e398b76 | 271 | printf("h - Show this help menu\r\n"); |
Just4pLeisure | 1:d5452e398b76 | 272 | printf("\r\n"); |
Just4pLeisure | 1:d5452e398b76 | 273 | return; |
Just4pLeisure | 1:d5452e398b76 | 274 | } |
Just4pLeisure | 1:d5452e398b76 | 275 | // |
Just4pLeisure | 1:d5452e398b76 | 276 | // t5_can_show_full_help |
Just4pLeisure | 1:d5452e398b76 | 277 | // |
Just4pLeisure | 1:d5452e398b76 | 278 | // Displays a complete list of things that can be done with the T5 ECU. |
Just4pLeisure | 1:d5452e398b76 | 279 | // |
Just4pLeisure | 1:d5452e398b76 | 280 | // inputs: none |
Just4pLeisure | 1:d5452e398b76 | 281 | // return: none |
Just4pLeisure | 1:d5452e398b76 | 282 | // |
Just4pLeisure | 5:1775b4b13232 | 283 | void t5_can_show_full_help() |
Just4pLeisure | 5:1775b4b13232 | 284 | { |
Just4pLeisure | 1:d5452e398b76 | 285 | printf("Trionic 5 Command Menu\r\n"); |
Just4pLeisure | 1:d5452e398b76 | 286 | printf("======================\r\n"); |
Just4pLeisure | 5:1775b4b13232 | 287 | printf("D - DUMP the T5.x ECU FLASH to a file 'ORIGINAL.BIN'\r\n"); |
Just4pLeisure | 5:1775b4b13232 | 288 | printf("F - FLASH the update file 'MODIFIED.BIN' to the T5.x\r\n"); |
Just4pLeisure | 1:d5452e398b76 | 289 | printf("\r\n"); |
Just4pLeisure | 1:d5452e398b76 | 290 | printf("b - upload and start MyBooty.S19 bootloader\r\n"); |
Just4pLeisure | 1:d5452e398b76 | 291 | printf("c - get T5 ECU FLASH checksum (need to upload BOOTY.S19 before using this command)\r\n"); |
Just4pLeisure | 1:d5452e398b76 | 292 | printf("d - dump the T5 FLASH BIN file and write it to ORIGINAL.BIN\r\n"); |
Just4pLeisure | 1:d5452e398b76 | 293 | printf("e - erase the FLASH chips in the T5 ECU\r\n"); |
Just4pLeisure | 5:1775b4b13232 | 294 | printf("f - FLASH the update file MODIFIED.BIN to the T5 ECU\r\n"); |
Just4pLeisure | 1:d5452e398b76 | 295 | printf("r - read SRAM and write it to ADAPTION.RAM file\r\n"); |
Just4pLeisure | 1:d5452e398b76 | 296 | printf("s - read Symbol Table, display it and write it to SYMBOLS.TXT\r\n"); |
Just4pLeisure | 1:d5452e398b76 | 297 | printf("v - read T5 ECU software version, display it and write it to VERSION.TXT\r\n"); |
Just4pLeisure | 1:d5452e398b76 | 298 | printf("q - exit the bootloader and reset the T5 ECU\r\n"); |
Just4pLeisure | 1:d5452e398b76 | 299 | printf("t - read the FLASH chip type in the T5 ECU\r\n"); |
Just4pLeisure | 1:d5452e398b76 | 300 | printf("3 - read the last used FLASH address in the T5 ECU\r\n"); |
Just4pLeisure | 1:d5452e398b76 | 301 | printf("S - send 's' message (to get symbol table)\r\n"); |
Just4pLeisure | 1:d5452e398b76 | 302 | printf("V - send 'S' message (to get software version)\r\n"); |
Just4pLeisure | 1:d5452e398b76 | 303 | printf("'Enter' Key - send an CR message\r\n"); |
Just4pLeisure | 1:d5452e398b76 | 304 | printf("a - send an ACK\r\n"); |
Just4pLeisure | 1:d5452e398b76 | 305 | printf("A - read a single symbol from the symbol table\r\n"); |
Just4pLeisure | 1:d5452e398b76 | 306 | printf("\r\n"); |
Just4pLeisure | 1:d5452e398b76 | 307 | printf("'ESC' - Return to Just4Trionic Main Menu\r\n"); |
Just4pLeisure | 1:d5452e398b76 | 308 | printf("\r\n"); |
Just4pLeisure | 1:d5452e398b76 | 309 | printf("H - Show this help menu\r\n"); |
Just4pLeisure | 1:d5452e398b76 | 310 | printf("\r\n"); |
Just4pLeisure | 1:d5452e398b76 | 311 | return; |
Just4pLeisure | 1:d5452e398b76 | 312 | } |
Just4pLeisure | 1:d5452e398b76 | 313 | |
Just4pLeisure | 1:d5452e398b76 | 314 | // |
Just4pLeisure | 1:d5452e398b76 | 315 | // t5_can_show_can_message |
Just4pLeisure | 1:d5452e398b76 | 316 | // |
Just4pLeisure | 1:d5452e398b76 | 317 | // Displays a CAN message in the RX buffer if there is one. |
Just4pLeisure | 1:d5452e398b76 | 318 | // |
Just4pLeisure | 1:d5452e398b76 | 319 | // inputs: none |
Just4pLeisure | 1:d5452e398b76 | 320 | // return: bool TRUE if there was a message, FALSE if no message. |
Just4pLeisure | 1:d5452e398b76 | 321 | // |
Just4pLeisure | 5:1775b4b13232 | 322 | bool t5_can_show_can_message() |
Just4pLeisure | 5:1775b4b13232 | 323 | { |
Just4pLeisure | 1:d5452e398b76 | 324 | CANMessage can_MsgRx; |
Just4pLeisure | 1:d5452e398b76 | 325 | if (can.read(can_MsgRx)) { |
Just4pLeisure | 1:d5452e398b76 | 326 | printf("w%03x%d", can_MsgRx.id, can_MsgRx.len); |
Just4pLeisure | 1:d5452e398b76 | 327 | for (char i=0; i<can_MsgRx.len; i++) { |
Just4pLeisure | 1:d5452e398b76 | 328 | printf("%02x", can_MsgRx.data[i]); |
Just4pLeisure | 1:d5452e398b76 | 329 | } |
Just4pLeisure | 1:d5452e398b76 | 330 | printf(" %c ", can_MsgRx.data[2]); |
Just4pLeisure | 1:d5452e398b76 | 331 | printf("\r\n"); |
Just4pLeisure | 1:d5452e398b76 | 332 | return TRUE; |
Just4pLeisure | 1:d5452e398b76 | 333 | } |
Just4pLeisure | 1:d5452e398b76 | 334 | return FALSE; |
Just4pLeisure | 1:d5452e398b76 | 335 | } |
Just4pLeisure | 1:d5452e398b76 | 336 | |
Just4pLeisure | 1:d5452e398b76 | 337 | // |
Just4pLeisure | 1:d5452e398b76 | 338 | // t5_can_get_symbol_table |
Just4pLeisure | 1:d5452e398b76 | 339 | // |
Just4pLeisure | 1:d5452e398b76 | 340 | // Gets the T5 ECU symbol table. |
Just4pLeisure | 1:d5452e398b76 | 341 | // The Symbol Table is saved to a file, symbols.txt, on the mbed 'local' file system 'disk'. |
Just4pLeisure | 1:d5452e398b76 | 342 | // |
Just4pLeisure | 1:d5452e398b76 | 343 | // inputs: none |
Just4pLeisure | 1:d5452e398b76 | 344 | // return: bool TRUE if there all went OK, FALSE if there was an error |
Just4pLeisure | 1:d5452e398b76 | 345 | // |
Just4pLeisure | 5:1775b4b13232 | 346 | bool t5_can_get_symbol_table() |
Just4pLeisure | 5:1775b4b13232 | 347 | { |
Just4pLeisure | 1:d5452e398b76 | 348 | printf("Saving the symbol table file\r\n"); |
Just4pLeisure | 1:d5452e398b76 | 349 | FILE *fp = fopen("/local/symbols.txt", "w"); // Open "symbols.txt" on the local file system for writing |
Just4pLeisure | 1:d5452e398b76 | 350 | if (!fp) { |
Just4pLeisure | 1:d5452e398b76 | 351 | perror ("The following error occured"); |
Just4pLeisure | 1:d5452e398b76 | 352 | return FALSE; |
Just4pLeisure | 1:d5452e398b76 | 353 | } |
Just4pLeisure | 1:d5452e398b76 | 354 | char symbol[40]; |
Just4pLeisure | 1:d5452e398b76 | 355 | T5ReadCmnd(T5SYMBOLS); |
Just4pLeisure | 1:d5452e398b76 | 356 | if (T5WaitResponse() != '>') { |
Just4pLeisure | 1:d5452e398b76 | 357 | fclose(fp); |
Just4pLeisure | 1:d5452e398b76 | 358 | return FALSE; |
Just4pLeisure | 1:d5452e398b76 | 359 | } |
Just4pLeisure | 1:d5452e398b76 | 360 | T5ReadCmnd(CR); |
Just4pLeisure | 1:d5452e398b76 | 361 | if (T5WaitResponse() != '>') { |
Just4pLeisure | 1:d5452e398b76 | 362 | fclose(fp); |
Just4pLeisure | 1:d5452e398b76 | 363 | return FALSE; |
Just4pLeisure | 1:d5452e398b76 | 364 | } |
Just4pLeisure | 1:d5452e398b76 | 365 | do { |
Just4pLeisure | 1:d5452e398b76 | 366 | T5GetSymbol(symbol); |
Just4pLeisure | 1:d5452e398b76 | 367 | // printf("%s",symbol); |
Just4pLeisure | 1:d5452e398b76 | 368 | if (fprintf(fp,"%s",symbol) < 0) { |
Just4pLeisure | 1:d5452e398b76 | 369 | fclose (fp); |
Just4pLeisure | 1:d5452e398b76 | 370 | printf ("ERROR Writing to the symbols.txt file!\r\n"); |
Just4pLeisure | 1:d5452e398b76 | 371 | return FALSE; |
Just4pLeisure | 1:d5452e398b76 | 372 | }; |
Just4pLeisure | 1:d5452e398b76 | 373 | } while (!StrCmp(symbol,"END\r\n")); |
Just4pLeisure | 1:d5452e398b76 | 374 | fclose(fp); |
Just4pLeisure | 1:d5452e398b76 | 375 | return TRUE; |
Just4pLeisure | 1:d5452e398b76 | 376 | } |
Just4pLeisure | 1:d5452e398b76 | 377 | |
Just4pLeisure | 1:d5452e398b76 | 378 | // |
Just4pLeisure | 1:d5452e398b76 | 379 | // t5_can_get_version |
Just4pLeisure | 1:d5452e398b76 | 380 | // |
Just4pLeisure | 1:d5452e398b76 | 381 | // Gets the T5 software version string. |
Just4pLeisure | 1:d5452e398b76 | 382 | // The software version is is sent to the PC and saved to a file, version.txt, on the mbed 'local' file system 'disk'. |
Just4pLeisure | 1:d5452e398b76 | 383 | // |
Just4pLeisure | 1:d5452e398b76 | 384 | // inputs: none |
Just4pLeisure | 1:d5452e398b76 | 385 | // return: bool TRUE if there all went OK, FALSE if there was an error |
Just4pLeisure | 1:d5452e398b76 | 386 | // |
Just4pLeisure | 5:1775b4b13232 | 387 | bool t5_can_get_version() |
Just4pLeisure | 5:1775b4b13232 | 388 | { |
Just4pLeisure | 1:d5452e398b76 | 389 | FILE *fp = fopen("/local/version.txt", "w"); // Open "version.txt" on the local file system for writing |
Just4pLeisure | 1:d5452e398b76 | 390 | if (!fp) { |
Just4pLeisure | 1:d5452e398b76 | 391 | perror ("The following error occured"); |
Just4pLeisure | 1:d5452e398b76 | 392 | return FALSE; |
Just4pLeisure | 1:d5452e398b76 | 393 | } |
Just4pLeisure | 1:d5452e398b76 | 394 | char symbol[40]; |
Just4pLeisure | 1:d5452e398b76 | 395 | T5ReadCmnd(T5VERSION); |
Just4pLeisure | 1:d5452e398b76 | 396 | if (T5WaitResponse() != '>') { |
Just4pLeisure | 1:d5452e398b76 | 397 | fclose(fp); |
Just4pLeisure | 1:d5452e398b76 | 398 | return FALSE; |
Just4pLeisure | 1:d5452e398b76 | 399 | } |
Just4pLeisure | 1:d5452e398b76 | 400 | T5ReadCmnd(CR); |
Just4pLeisure | 1:d5452e398b76 | 401 | if (T5WaitResponse() != '>') { |
Just4pLeisure | 1:d5452e398b76 | 402 | fclose(fp); |
Just4pLeisure | 1:d5452e398b76 | 403 | return FALSE; |
Just4pLeisure | 1:d5452e398b76 | 404 | } |
Just4pLeisure | 1:d5452e398b76 | 405 | T5GetSymbol(symbol); |
Just4pLeisure | 1:d5452e398b76 | 406 | printf("%s",symbol); |
Just4pLeisure | 1:d5452e398b76 | 407 | if (fprintf(fp,"%s",symbol) < 0) { |
Just4pLeisure | 1:d5452e398b76 | 408 | fclose (fp); |
Just4pLeisure | 1:d5452e398b76 | 409 | printf ("ERROR Writing to the version.txt file!\r\n"); |
Just4pLeisure | 1:d5452e398b76 | 410 | return FALSE; |
Just4pLeisure | 1:d5452e398b76 | 411 | }; |
Just4pLeisure | 1:d5452e398b76 | 412 | fclose(fp); |
Just4pLeisure | 1:d5452e398b76 | 413 | printf("The version.txt file has been saved.\r\n"); |
Just4pLeisure | 1:d5452e398b76 | 414 | return TRUE; |
Just4pLeisure | 1:d5452e398b76 | 415 | } |
Just4pLeisure | 1:d5452e398b76 | 416 | |
Just4pLeisure | 1:d5452e398b76 | 417 | // |
Just4pLeisure | 1:d5452e398b76 | 418 | // Trionic5GetAdaptionData |
Just4pLeisure | 1:d5452e398b76 | 419 | // |
Just4pLeisure | 1:d5452e398b76 | 420 | // Gets the adaption data from the T5's SRAM. |
Just4pLeisure | 1:d5452e398b76 | 421 | // The adaption data is stored in a hex file, adaption.RAM, on the mbed 'local' file system 'disk'. |
Just4pLeisure | 1:d5452e398b76 | 422 | // |
Just4pLeisure | 1:d5452e398b76 | 423 | // Reading the Adaption data from SRAM takes about 6.5 seconds. |
Just4pLeisure | 1:d5452e398b76 | 424 | // |
Just4pLeisure | 1:d5452e398b76 | 425 | // inputs: none |
Just4pLeisure | 1:d5452e398b76 | 426 | // return: bool TRUE if all went OK, FALSE if there was an error. |
Just4pLeisure | 1:d5452e398b76 | 427 | // |
Just4pLeisure | 5:1775b4b13232 | 428 | bool t5_can_get_adaption_data() |
Just4pLeisure | 5:1775b4b13232 | 429 | { |
Just4pLeisure | 1:d5452e398b76 | 430 | printf("Saving the SRAM adaption data.\r\n"); |
Just4pLeisure | 1:d5452e398b76 | 431 | FILE *fp = fopen("/local/adaption.RAM", "w"); // Open "adaption.RAM" on the local file system for writing |
Just4pLeisure | 1:d5452e398b76 | 432 | if (!fp) { |
Just4pLeisure | 1:d5452e398b76 | 433 | printf("ERROR: Unable to open a file for the adaption data!\r\n"); |
Just4pLeisure | 1:d5452e398b76 | 434 | return FALSE; |
Just4pLeisure | 1:d5452e398b76 | 435 | } |
Just4pLeisure | 1:d5452e398b76 | 436 | unsigned int address = 5; // Mysterious reason for starting at 5 !!! |
Just4pLeisure | 1:d5452e398b76 | 437 | char RAMdata[6]; |
Just4pLeisure | 1:d5452e398b76 | 438 | while (address < T5RAMSIZE) { |
Just4pLeisure | 1:d5452e398b76 | 439 | if (!t5_can_read_data(RAMdata, address)) { |
Just4pLeisure | 1:d5452e398b76 | 440 | fclose (fp); |
Just4pLeisure | 1:d5452e398b76 | 441 | printf ("Error reading from the CAN bus.\r\n"); |
Just4pLeisure | 1:d5452e398b76 | 442 | return FALSE; |
Just4pLeisure | 1:d5452e398b76 | 443 | } |
Just4pLeisure | 1:d5452e398b76 | 444 | address += 6; |
Just4pLeisure | 1:d5452e398b76 | 445 | if (fwrite(RAMdata, 1, 6, fp) != 6) { |
Just4pLeisure | 1:d5452e398b76 | 446 | fclose (fp); |
Just4pLeisure | 1:d5452e398b76 | 447 | printf ("Error writing to the SRAM adaption file.\r\n"); |
Just4pLeisure | 1:d5452e398b76 | 448 | return FALSE; |
Just4pLeisure | 1:d5452e398b76 | 449 | } |
Just4pLeisure | 1:d5452e398b76 | 450 | } |
Just4pLeisure | 1:d5452e398b76 | 451 | // There are a few more bytes to get because because the SRAM file is not an exact multiple of 6 bytes! |
Just4pLeisure | 1:d5452e398b76 | 452 | // the % (modulo) mathematics function tells us how many bytes there are still to get |
Just4pLeisure | 1:d5452e398b76 | 453 | if (!t5_can_read_data(RAMdata, (T5RAMSIZE - 1))) { |
Just4pLeisure | 1:d5452e398b76 | 454 | fclose (fp); |
Just4pLeisure | 1:d5452e398b76 | 455 | printf ("Error reading from the CAN bus.\r\n"); |
Just4pLeisure | 1:d5452e398b76 | 456 | return FALSE; |
Just4pLeisure | 1:d5452e398b76 | 457 | } |
Just4pLeisure | 1:d5452e398b76 | 458 | if (fwrite((RAMdata + 6 - (T5RAMSIZE % 6)), 1, (T5RAMSIZE % 6), fp) != (T5RAMSIZE % 6)) { |
Just4pLeisure | 1:d5452e398b76 | 459 | fclose (fp); |
Just4pLeisure | 1:d5452e398b76 | 460 | printf ("Error writing to the SRAM adaption file.\r\n"); |
Just4pLeisure | 1:d5452e398b76 | 461 | return FALSE; |
Just4pLeisure | 1:d5452e398b76 | 462 | } |
Just4pLeisure | 1:d5452e398b76 | 463 | fclose(fp); |
Just4pLeisure | 1:d5452e398b76 | 464 | return TRUE; |
Just4pLeisure | 1:d5452e398b76 | 465 | } |
Just4pLeisure | 1:d5452e398b76 | 466 | |
Just4pLeisure | 1:d5452e398b76 | 467 | // |
Just4pLeisure | 1:d5452e398b76 | 468 | // t5_can_send_boot_loader |
Just4pLeisure | 1:d5452e398b76 | 469 | // |
Just4pLeisure | 1:d5452e398b76 | 470 | // Sends a 'bootloader' file, booty.s19 to the T5 ECU. |
Just4pLeisure | 1:d5452e398b76 | 471 | // The 'bootloader' is stored on the mbed 'local' file system 'disk' and must be in S19 format. |
Just4pLeisure | 1:d5452e398b76 | 472 | // |
Just4pLeisure | 1:d5452e398b76 | 473 | // The 'bootloader' is then able to dump or reFLASH the T5 ECU FLASH chips - this is the whole point of the exercise :-) |
Just4pLeisure | 1:d5452e398b76 | 474 | // |
Just4pLeisure | 1:d5452e398b76 | 475 | // Sending the 'bootloader' to the T5 ECU takes just over 1 second. |
Just4pLeisure | 1:d5452e398b76 | 476 | // |
Just4pLeisure | 1:d5452e398b76 | 477 | // inputs: none |
Just4pLeisure | 1:d5452e398b76 | 478 | // return: bool TRUE if all went OK, |
Just4pLeisure | 1:d5452e398b76 | 479 | // FALSE if the 'bootloader' wasn't sent for some reason. |
Just4pLeisure | 1:d5452e398b76 | 480 | // |
Just4pLeisure | 5:1775b4b13232 | 481 | bool t5_can_send_boot_loader() |
Just4pLeisure | 5:1775b4b13232 | 482 | { |
Just4pLeisure | 5:1775b4b13232 | 483 | uint32_t BootloaderSize = sizeof(T5BootLoader); |
Just4pLeisure | 5:1775b4b13232 | 484 | uint32_t address = MYBOOTY_START; // Start and execute from address of T5Bootloader |
Just4pLeisure | 5:1775b4b13232 | 485 | uint32_t count = 0; // progress count of bootloader bytes transferred |
Just4pLeisure | 5:1775b4b13232 | 486 | char msg[8]; // Construct the bootloader frame for uploading |
Just4pLeisure | 5:1775b4b13232 | 487 | |
Just4pLeisure | 5:1775b4b13232 | 488 | printf("Starting the bootloader.\r\n"); |
Just4pLeisure | 5:1775b4b13232 | 489 | while (count < BootloaderSize) { |
Just4pLeisure | 5:1775b4b13232 | 490 | // send a bootloader address message |
Just4pLeisure | 5:1775b4b13232 | 491 | if (!t5_can_send_boot_address((address+count), MYBOOTY_CHUNK)) return FALSE; |
Just4pLeisure | 5:1775b4b13232 | 492 | // send bootloader frames |
Just4pLeisure | 5:1775b4b13232 | 493 | // 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 |
Just4pLeisure | 5:1775b4b13232 | 494 | // are repeated from the previous frame. This is OK because the T5 ECU knows how many bytes to expect (because the count of bytes |
Just4pLeisure | 5:1775b4b13232 | 495 | // is sent with the upload address) and ignores any extra bytes in the last frame. |
Just4pLeisure | 5:1775b4b13232 | 496 | for (uint8_t i=0; i<MYBOOTY_CHUNK; i++) { |
Just4pLeisure | 5:1775b4b13232 | 497 | msg[1+(i%7)] = T5BootLoader[count+i]; |
Just4pLeisure | 5:1775b4b13232 | 498 | if (i%7 == 0) msg[0]=i; // set the index number |
Just4pLeisure | 5:1775b4b13232 | 499 | if ((i%7 == 6) || (i == MYBOOTY_CHUNK-1 )) { |
Just4pLeisure | 5:1775b4b13232 | 500 | if (!t5_can_send_boot_frame(msg)) return FALSE; |
Just4pLeisure | 5:1775b4b13232 | 501 | } |
Just4pLeisure | 5:1775b4b13232 | 502 | } |
Just4pLeisure | 5:1775b4b13232 | 503 | count += MYBOOTY_CHUNK; |
Just4pLeisure | 5:1775b4b13232 | 504 | } |
Just4pLeisure | 5:1775b4b13232 | 505 | // These two lines really shouldn't be necessary but for some reason the first start |
Just4pLeisure | 5:1775b4b13232 | 506 | // command is ignored and a short delay is required before repeating. Using only a |
Just4pLeisure | 5:1775b4b13232 | 507 | // delay, even a very long one, doesn't work. |
Just4pLeisure | 5:1775b4b13232 | 508 | // |
Just4pLeisure | 5:1775b4b13232 | 509 | // NOTE: This measure isn't required when uploading an external S19 bootloader file! |
Just4pLeisure | 5:1775b4b13232 | 510 | // |
Just4pLeisure | 5:1775b4b13232 | 511 | T5StartBootLoader(address); |
Just4pLeisure | 5:1775b4b13232 | 512 | wait_ms(1); |
Just4pLeisure | 5:1775b4b13232 | 513 | // |
Just4pLeisure | 5:1775b4b13232 | 514 | return T5StartBootLoader(address); |
Just4pLeisure | 5:1775b4b13232 | 515 | } |
Just4pLeisure | 5:1775b4b13232 | 516 | |
Just4pLeisure | 5:1775b4b13232 | 517 | |
Just4pLeisure | 5:1775b4b13232 | 518 | // |
Just4pLeisure | 5:1775b4b13232 | 519 | // t5_can_send_boot_loader_S19 |
Just4pLeisure | 5:1775b4b13232 | 520 | // |
Just4pLeisure | 5:1775b4b13232 | 521 | // Sends a 'bootloader' file, booty.s19 to the T5 ECU. |
Just4pLeisure | 5:1775b4b13232 | 522 | // The 'bootloader' is stored on the mbed 'local' file system 'disk' and must be in S19 format. |
Just4pLeisure | 5:1775b4b13232 | 523 | // |
Just4pLeisure | 5:1775b4b13232 | 524 | // The 'bootloader' is then able to dump or reFLASH the T5 ECU FLASH chips - this is the whole point of the exercise :-) |
Just4pLeisure | 5:1775b4b13232 | 525 | // |
Just4pLeisure | 5:1775b4b13232 | 526 | // Sending the 'bootloader' to the T5 ECU takes just over 1 second. |
Just4pLeisure | 5:1775b4b13232 | 527 | // |
Just4pLeisure | 5:1775b4b13232 | 528 | // inputs: none |
Just4pLeisure | 5:1775b4b13232 | 529 | // return: bool TRUE if all went OK, |
Just4pLeisure | 5:1775b4b13232 | 530 | // FALSE if the 'bootloader' wasn't sent for some reason. |
Just4pLeisure | 5:1775b4b13232 | 531 | // |
Just4pLeisure | 5:1775b4b13232 | 532 | bool t5_can_send_boot_loader_S19() |
Just4pLeisure | 5:1775b4b13232 | 533 | { |
Just4pLeisure | 1:d5452e398b76 | 534 | printf("Starting the bootloader.\r\n"); |
Just4pLeisure | 1:d5452e398b76 | 535 | FILE *fp = fopen("/local/MyBooty.S19", "r"); // Open "booty.s19" on the local file system for reading |
Just4pLeisure | 1:d5452e398b76 | 536 | if (!fp) { |
Just4pLeisure | 1:d5452e398b76 | 537 | printf("Error: I could not find the bootloader file MyBooty.S19\r\n"); |
Just4pLeisure | 1:d5452e398b76 | 538 | return FALSE; |
Just4pLeisure | 1:d5452e398b76 | 539 | } |
Just4pLeisure | 1:d5452e398b76 | 540 | int c = 0; // for some reason fgetc returns an int instead of a char |
Just4pLeisure | 1:d5452e398b76 | 541 | uint8_t count = 0; // count of bytes in the S-record can be 0xFF = 255 in decimal |
Just4pLeisure | 1:d5452e398b76 | 542 | uint8_t asize = 0; // 2,3 or 4 bytes in address |
Just4pLeisure | 1:d5452e398b76 | 543 | uint32_t address = 0; // address to put S-record |
Just4pLeisure | 1:d5452e398b76 | 544 | uint8_t checksum = 0; // checksum check at the end of each S-record line |
Just4pLeisure | 1:d5452e398b76 | 545 | char msg[8]; // Construct the bootloader frame for uploading |
Just4pLeisure | 1:d5452e398b76 | 546 | bool sent = FALSE; |
Just4pLeisure | 1:d5452e398b76 | 547 | |
Just4pLeisure | 1:d5452e398b76 | 548 | while (!sent) { |
Just4pLeisure | 1:d5452e398b76 | 549 | // get characters until we get an 'S' (throws away \n,\r characters and other junk) |
Just4pLeisure | 1:d5452e398b76 | 550 | do c = fgetc (fp); |
Just4pLeisure | 1:d5452e398b76 | 551 | while (c != 'S' && c != EOF); |
Just4pLeisure | 1:d5452e398b76 | 552 | // if (c == EOF) return '\a'; |
Just4pLeisure | 1:d5452e398b76 | 553 | c = fgetc(fp); // get the S-record type 1/2/3 5 7/8/9 (Return if EOF reached) |
Just4pLeisure | 1:d5452e398b76 | 554 | // if ((c = fgetc(fp)) == EOF) return '\a'; // get the S-record type 1/2/3 5 7/8/9 (Return if EOF reached) |
Just4pLeisure | 1:d5452e398b76 | 555 | switch (c) { |
Just4pLeisure | 1:d5452e398b76 | 556 | case '0': |
Just4pLeisure | 1:d5452e398b76 | 557 | break; // Skip over S0 header record |
Just4pLeisure | 1:d5452e398b76 | 558 | |
Just4pLeisure | 1:d5452e398b76 | 559 | case '1': |
Just4pLeisure | 1:d5452e398b76 | 560 | case '2': |
Just4pLeisure | 1:d5452e398b76 | 561 | case '3': |
Just4pLeisure | 1:d5452e398b76 | 562 | asize = 1 + c - '0'; // 2, 3 or 4 bytes for address |
Just4pLeisure | 1:d5452e398b76 | 563 | address = 0; |
Just4pLeisure | 1:d5452e398b76 | 564 | // get the number of bytes (in ascii format) in this S-record line |
Just4pLeisure | 1:d5452e398b76 | 565 | // there must be at least the address and the checksum so return with an error if less than this! |
Just4pLeisure | 1:d5452e398b76 | 566 | if ((c = SRecGetByte(fp)) < (asize + 1)) break; |
Just4pLeisure | 1:d5452e398b76 | 567 | // if ((c = SRecGetByte(fp)) < 3) return '\a'; |
Just4pLeisure | 1:d5452e398b76 | 568 | count = c; |
Just4pLeisure | 1:d5452e398b76 | 569 | checksum = c; |
Just4pLeisure | 1:d5452e398b76 | 570 | // get the address |
Just4pLeisure | 1:d5452e398b76 | 571 | for (uint8_t i=0; i<asize; i++) { |
Just4pLeisure | 1:d5452e398b76 | 572 | c = SRecGetByte(fp); |
Just4pLeisure | 1:d5452e398b76 | 573 | checksum += c; |
Just4pLeisure | 1:d5452e398b76 | 574 | address <<= 8; |
Just4pLeisure | 1:d5452e398b76 | 575 | address |= c; |
Just4pLeisure | 1:d5452e398b76 | 576 | count--; |
Just4pLeisure | 1:d5452e398b76 | 577 | } |
Just4pLeisure | 1:d5452e398b76 | 578 | // send a bootloader address message |
Just4pLeisure | 5:1775b4b13232 | 579 | //// printf("address %x count %x\r\n",address ,count-1 ); |
Just4pLeisure | 1:d5452e398b76 | 580 | if (!t5_can_send_boot_address(address, (count-1))) return FALSE; |
Just4pLeisure | 1:d5452e398b76 | 581 | // get and send the bootloader frames for this S-record |
Just4pLeisure | 1:d5452e398b76 | 582 | // 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 |
Just4pLeisure | 1:d5452e398b76 | 583 | // are repeated from the previous frame. This is OK because the T5 ECU knows how many bytes to expect (because the count of bytes |
Just4pLeisure | 1:d5452e398b76 | 584 | // in the S-Record is sent with the upload address) and ignores any extra bytes in the last frame. |
Just4pLeisure | 1:d5452e398b76 | 585 | for (uint8_t i=0; i<count-1; i++) { |
Just4pLeisure | 1:d5452e398b76 | 586 | c = SRecGetByte(fp); |
Just4pLeisure | 1:d5452e398b76 | 587 | checksum += c; |
Just4pLeisure | 1:d5452e398b76 | 588 | msg[1+(i%7)] = c; |
Just4pLeisure | 1:d5452e398b76 | 589 | if (i%7 == 0) msg[0]=i; // set the index number |
Just4pLeisure | 5:1775b4b13232 | 590 | if ((i%7 == 6) || (i == count - 2)) { |
Just4pLeisure | 5:1775b4b13232 | 591 | //// 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] ); |
Just4pLeisure | 1:d5452e398b76 | 592 | if (!t5_can_send_boot_frame(msg)) { |
Just4pLeisure | 1:d5452e398b76 | 593 | fclose(fp); |
Just4pLeisure | 1:d5452e398b76 | 594 | return FALSE; |
Just4pLeisure | 1:d5452e398b76 | 595 | } |
Just4pLeisure | 5:1775b4b13232 | 596 | } |
Just4pLeisure | 1:d5452e398b76 | 597 | } |
Just4pLeisure | 1:d5452e398b76 | 598 | // get the checksum |
Just4pLeisure | 1:d5452e398b76 | 599 | if ((checksum += SRecGetByte(fp)) != 0xFF) { |
Just4pLeisure | 1:d5452e398b76 | 600 | printf("Error in S-record, checksum = %2x\r\n", checksum); |
Just4pLeisure | 1:d5452e398b76 | 601 | fclose(fp); |
Just4pLeisure | 1:d5452e398b76 | 602 | return FALSE; |
Just4pLeisure | 1:d5452e398b76 | 603 | } |
Just4pLeisure | 1:d5452e398b76 | 604 | break; |
Just4pLeisure | 1:d5452e398b76 | 605 | |
Just4pLeisure | 1:d5452e398b76 | 606 | case '5': |
Just4pLeisure | 1:d5452e398b76 | 607 | break; // Skip over S5 record types |
Just4pLeisure | 1:d5452e398b76 | 608 | |
Just4pLeisure | 1:d5452e398b76 | 609 | case '7': |
Just4pLeisure | 1:d5452e398b76 | 610 | case '8': |
Just4pLeisure | 1:d5452e398b76 | 611 | case '9': |
Just4pLeisure | 1:d5452e398b76 | 612 | asize = 11 - (c - '0'); // 2, 3 or 4 bytes for address |
Just4pLeisure | 5:1775b4b13232 | 613 | address = 0; |
Just4pLeisure | 1:d5452e398b76 | 614 | // get the number of bytes (in ascii format) in this S-record line there must be just the address and the checksum |
Just4pLeisure | 1:d5452e398b76 | 615 | // so return with an error if other than this! |
Just4pLeisure | 1:d5452e398b76 | 616 | if ((c = SRecGetByte(fp)) != (asize + 1)) break; |
Just4pLeisure | 1:d5452e398b76 | 617 | // if ((c = SRecGetByte(fp)) < 3) return '\a'; |
Just4pLeisure | 1:d5452e398b76 | 618 | checksum = c; |
Just4pLeisure | 1:d5452e398b76 | 619 | // get the address |
Just4pLeisure | 1:d5452e398b76 | 620 | for (uint8_t i=0; i<asize; i++) { |
Just4pLeisure | 1:d5452e398b76 | 621 | c = SRecGetByte(fp); |
Just4pLeisure | 1:d5452e398b76 | 622 | checksum += c; |
Just4pLeisure | 1:d5452e398b76 | 623 | address <<= 8; |
Just4pLeisure | 1:d5452e398b76 | 624 | address |= c; |
Just4pLeisure | 1:d5452e398b76 | 625 | } |
Just4pLeisure | 1:d5452e398b76 | 626 | // get the checksum |
Just4pLeisure | 1:d5452e398b76 | 627 | if ((checksum += SRecGetByte(fp)) != 0xFF) { |
Just4pLeisure | 1:d5452e398b76 | 628 | fclose(fp); |
Just4pLeisure | 1:d5452e398b76 | 629 | printf("Error in S-record, checksum = %2x\r\n", checksum); |
Just4pLeisure | 1:d5452e398b76 | 630 | return FALSE; |
Just4pLeisure | 1:d5452e398b76 | 631 | } |
Just4pLeisure | 1:d5452e398b76 | 632 | T5StartBootLoader(address); |
Just4pLeisure | 1:d5452e398b76 | 633 | // T5WaitResponsePrint(); |
Just4pLeisure | 1:d5452e398b76 | 634 | sent = TRUE; |
Just4pLeisure | 1:d5452e398b76 | 635 | break; |
Just4pLeisure | 1:d5452e398b76 | 636 | |
Just4pLeisure | 1:d5452e398b76 | 637 | // Some kind of invalid S-record type so break |
Just4pLeisure | 1:d5452e398b76 | 638 | default: |
Just4pLeisure | 1:d5452e398b76 | 639 | fclose(fp); |
Just4pLeisure | 1:d5452e398b76 | 640 | printf("oops - didn't recognise that S-Record \r\n"); |
Just4pLeisure | 1:d5452e398b76 | 641 | return FALSE; |
Just4pLeisure | 1:d5452e398b76 | 642 | } |
Just4pLeisure | 1:d5452e398b76 | 643 | } |
Just4pLeisure | 1:d5452e398b76 | 644 | fclose(fp); |
Just4pLeisure | 1:d5452e398b76 | 645 | return TRUE; |
Just4pLeisure | 1:d5452e398b76 | 646 | } |
Just4pLeisure | 1:d5452e398b76 | 647 | |
Just4pLeisure | 1:d5452e398b76 | 648 | // |
Just4pLeisure | 1:d5452e398b76 | 649 | // t5_can_get_checksum |
Just4pLeisure | 1:d5452e398b76 | 650 | // |
Just4pLeisure | 1:d5452e398b76 | 651 | // Calculates the checksum of the FLASH in the T5 ECU. |
Just4pLeisure | 1:d5452e398b76 | 652 | // The 'bootloader', booty.s19, must be loaded before this function can be used. |
Just4pLeisure | 1:d5452e398b76 | 653 | // The 'bootloader' actually calculates the checksum and compares it with the |
Just4pLeisure | 1:d5452e398b76 | 654 | // value stored in the 'header' region at the end of the FLASH. |
Just4pLeisure | 1:d5452e398b76 | 655 | // |
Just4pLeisure | 1:d5452e398b76 | 656 | // The bootloader sends a single CAN message with the result e.g. |
Just4pLeisure | 1:d5452e398b76 | 657 | // w00C8C800CAFEBABE0808 |
Just4pLeisure | 1:d5452e398b76 | 658 | // 00C - T5 response messages have an CAN id of 00C |
Just4pLeisure | 1:d5452e398b76 | 659 | // 8 - All T5 messages have a message length of 8 bytes |
Just4pLeisure | 1:d5452e398b76 | 660 | // C8 - This is the checksum message type |
Just4pLeisure | 1:d5452e398b76 | 661 | // 00 - 00 means OK, the checksum calculation matches the stored value which in this case is: |
Just4pLeisure | 1:d5452e398b76 | 662 | // CAFEBABE - lol :-) |
Just4pLeisure | 1:d5452e398b76 | 663 | // |
Just4pLeisure | 1:d5452e398b76 | 664 | // w00C8C801FFFFFFFF0808 |
Just4pLeisure | 1:d5452e398b76 | 665 | // 01 - 01 means calculated value doesn't matched the stored value |
Just4pLeisure | 1:d5452e398b76 | 666 | // FFFFFFFF - in this case the stored value is FFFFFFFF - the chips might be erased |
Just4pLeisure | 1:d5452e398b76 | 667 | // |
Just4pLeisure | 1:d5452e398b76 | 668 | // Calculating the checksum takes a little under 2 seconds. |
Just4pLeisure | 1:d5452e398b76 | 669 | // |
Just4pLeisure | 1:d5452e398b76 | 670 | // inputs: none |
Just4pLeisure | 1:d5452e398b76 | 671 | // return: bool TRUE if all went OK, |
Just4pLeisure | 1:d5452e398b76 | 672 | // |
Just4pLeisure | 5:1775b4b13232 | 673 | bool t5_can_get_checksum() |
Just4pLeisure | 5:1775b4b13232 | 674 | { |
Just4pLeisure | 1:d5452e398b76 | 675 | uint32_t checksum = 0; |
Just4pLeisure | 1:d5452e398b76 | 676 | if (!t5_boot_checksum_command(&checksum)) { |
Just4pLeisure | 1:d5452e398b76 | 677 | printf("Error The ECU's checksum is wrong!\r\n"); |
Just4pLeisure | 1:d5452e398b76 | 678 | return FALSE; |
Just4pLeisure | 1:d5452e398b76 | 679 | } |
Just4pLeisure | 1:d5452e398b76 | 680 | printf("The FLASH checksum value is %#010x.\r\n", checksum); |
Just4pLeisure | 1:d5452e398b76 | 681 | return TRUE; |
Just4pLeisure | 1:d5452e398b76 | 682 | } |
Just4pLeisure | 1:d5452e398b76 | 683 | |
Just4pLeisure | 1:d5452e398b76 | 684 | // |
Just4pLeisure | 1:d5452e398b76 | 685 | // t5_can_bootloader_reset |
Just4pLeisure | 1:d5452e398b76 | 686 | // |
Just4pLeisure | 1:d5452e398b76 | 687 | // Exit the Bootloader and restart the T5 ECU |
Just4pLeisure | 1:d5452e398b76 | 688 | // |
Just4pLeisure | 1:d5452e398b76 | 689 | // inputs: none |
Just4pLeisure | 1:d5452e398b76 | 690 | // outputs: bool TRUE if all went OK. |
Just4pLeisure | 1:d5452e398b76 | 691 | // |
Just4pLeisure | 5:1775b4b13232 | 692 | bool t5_can_bootloader_reset() |
Just4pLeisure | 5:1775b4b13232 | 693 | { |
Just4pLeisure | 1:d5452e398b76 | 694 | printf("Exiting the bootloader and restarting the T5 ECU.\r\n"); |
Just4pLeisure | 1:d5452e398b76 | 695 | if (!t5_boot_reset_command()) { |
Just4pLeisure | 1:d5452e398b76 | 696 | printf("Error trying to reset the T5 ECU!\r\n"); |
Just4pLeisure | 1:d5452e398b76 | 697 | return FALSE; |
Just4pLeisure | 1:d5452e398b76 | 698 | } |
Just4pLeisure | 1:d5452e398b76 | 699 | return TRUE; |
Just4pLeisure | 1:d5452e398b76 | 700 | } |
Just4pLeisure | 1:d5452e398b76 | 701 | |
Just4pLeisure | 1:d5452e398b76 | 702 | // |
Just4pLeisure | 1:d5452e398b76 | 703 | // t5_can_get_start_and_chip_types |
Just4pLeisure | 1:d5452e398b76 | 704 | // |
Just4pLeisure | 1:d5452e398b76 | 705 | // Gets the FLASH chip type fitted. |
Just4pLeisure | 1:d5452e398b76 | 706 | // |
Just4pLeisure | 1:d5452e398b76 | 707 | // NOTE the bootloader must be loaded in order to use this function. |
Just4pLeisure | 1:d5452e398b76 | 708 | // |
Just4pLeisure | 1:d5452e398b76 | 709 | // CAN messages from the T5 ECU with FLASH data look like this: |
Just4pLeisure | 1:d5452e398b76 | 710 | // |
Just4pLeisure | 1:d5452e398b76 | 711 | // C9,00,aa,aa,aa,aa,mm,dd, |
Just4pLeisure | 1:d5452e398b76 | 712 | // |
Just4pLeisure | 1:d5452e398b76 | 713 | // C9 lets us know its a FLASH id message |
Just4pLeisure | 1:d5452e398b76 | 714 | // |
Just4pLeisure | 1:d5452e398b76 | 715 | // aa,aa,aa,aa is the FLASH start address which we can use to work out if this is a T5.2 or T5.5 ECU |
Just4pLeisure | 1:d5452e398b76 | 716 | // 0x00020000 - T5.2 |
Just4pLeisure | 1:d5452e398b76 | 717 | // 0x00040000 - T5.5 |
Just4pLeisure | 1:d5452e398b76 | 718 | // |
Just4pLeisure | 1:d5452e398b76 | 719 | // mm = Manufacturer id. These can be: |
Just4pLeisure | 1:d5452e398b76 | 720 | // 0x89 - Intel |
Just4pLeisure | 1:d5452e398b76 | 721 | // 0x31 - CSI/CAT |
Just4pLeisure | 1:d5452e398b76 | 722 | // 0x01 - AMD |
Just4pLeisure | 1:d5452e398b76 | 723 | // 0x1F - Atmel |
Just4pLeisure | 1:d5452e398b76 | 724 | // |
Just4pLeisure | 1:d5452e398b76 | 725 | // dd = Device id. These can be: |
Just4pLeisure | 1:d5452e398b76 | 726 | // 0xB8 - Intel _or_ CSI 28F512 (Fiited by Saab in T5.2) |
Just4pLeisure | 1:d5452e398b76 | 727 | // 0xB4 - Intel _or_ CSI 28F010 (Fitted by Saab in T5.5) |
Just4pLeisure | 1:d5452e398b76 | 728 | // 0x25 - AMD 28F512 (Fiited by Saab in T5.2) |
Just4pLeisure | 1:d5452e398b76 | 729 | // 0xA7 - AMD 28F010 (Fitted by Saab in T5.5) |
Just4pLeisure | 1:d5452e398b76 | 730 | // 0x20 - AMD 29F010 (Some people have put these in their T5.5) |
Just4pLeisure | 1:d5452e398b76 | 731 | // 0x5D - Atmel 29C512 (Some people mave have put these in their T5.2) |
Just4pLeisure | 1:d5452e398b76 | 732 | // 0xD5 - Atmel 29C010 (Some people have put these in their T5.5) |
Just4pLeisure | 1:d5452e398b76 | 733 | // |
Just4pLeisure | 1:d5452e398b76 | 734 | // mm = 0xFF, dd == 0xF7 probably means that the programming voltage isn't right. |
Just4pLeisure | 1:d5452e398b76 | 735 | // |
Just4pLeisure | 1:d5452e398b76 | 736 | // Finding out which ECU type and FLASH chips are fitted takes under a second. |
Just4pLeisure | 1:d5452e398b76 | 737 | // |
Just4pLeisure | 1:d5452e398b76 | 738 | // inputs: start T5 ecu start address |
Just4pLeisure | 1:d5452e398b76 | 739 | // return: bool TRUE if all went OK. |
Just4pLeisure | 1:d5452e398b76 | 740 | // |
Just4pLeisure | 5:1775b4b13232 | 741 | bool t5_can_get_start_and_chip_types(uint32_t* start) |
Just4pLeisure | 5:1775b4b13232 | 742 | { |
Just4pLeisure | 1:d5452e398b76 | 743 | *start = 0; |
Just4pLeisure | 1:d5452e398b76 | 744 | uint8_t make = 0; |
Just4pLeisure | 1:d5452e398b76 | 745 | uint8_t type = 0; |
Just4pLeisure | 1:d5452e398b76 | 746 | if (!t5_boot_get_flash_type(start, &make, &type)) { |
Just4pLeisure | 1:d5452e398b76 | 747 | printf("Error trying to find out the ECU's first address and FLASH chip type!\r\n"); |
Just4pLeisure | 1:d5452e398b76 | 748 | return FALSE; |
Just4pLeisure | 1:d5452e398b76 | 749 | } |
Just4pLeisure | 1:d5452e398b76 | 750 | printf("This is a T5.%s ECU with ", ((*start == T52FLASHSTART) ? "2" : "5")); |
Just4pLeisure | 1:d5452e398b76 | 751 | switch (make) { |
Just4pLeisure | 1:d5452e398b76 | 752 | case AMD: |
Just4pLeisure | 1:d5452e398b76 | 753 | printf("AMD "); |
Just4pLeisure | 1:d5452e398b76 | 754 | break; |
Just4pLeisure | 1:d5452e398b76 | 755 | case CSI: |
Just4pLeisure | 1:d5452e398b76 | 756 | printf("CSI "); |
Just4pLeisure | 1:d5452e398b76 | 757 | break; |
Just4pLeisure | 1:d5452e398b76 | 758 | case INTEL: |
Just4pLeisure | 1:d5452e398b76 | 759 | printf("INTEL "); |
Just4pLeisure | 1:d5452e398b76 | 760 | break; |
Just4pLeisure | 5:1775b4b13232 | 761 | case ATMEL: |
Just4pLeisure | 5:1775b4b13232 | 762 | printf("ATMEL "); |
Just4pLeisure | 5:1775b4b13232 | 763 | break; |
Just4pLeisure | 5:1775b4b13232 | 764 | case SST: |
Just4pLeisure | 5:1775b4b13232 | 765 | printf("SST "); |
Just4pLeisure | 5:1775b4b13232 | 766 | break; |
Just4pLeisure | 5:1775b4b13232 | 767 | case ST: |
Just4pLeisure | 5:1775b4b13232 | 768 | printf("ST "); |
Just4pLeisure | 5:1775b4b13232 | 769 | break; |
Just4pLeisure | 5:1775b4b13232 | 770 | case AMIC: |
Just4pLeisure | 5:1775b4b13232 | 771 | printf("AMIC "); |
Just4pLeisure | 5:1775b4b13232 | 772 | break; |
Just4pLeisure | 1:d5452e398b76 | 773 | default: |
Just4pLeisure | 5:1775b4b13232 | 774 | printf("\r\nUNKNOWN Manufacturer Id: %02x - Also check pin65 has enough volts!\r\n", make); |
Just4pLeisure | 1:d5452e398b76 | 775 | } |
Just4pLeisure | 1:d5452e398b76 | 776 | switch (type) { |
Just4pLeisure | 1:d5452e398b76 | 777 | case AMD28F512: |
Just4pLeisure | 1:d5452e398b76 | 778 | case INTEL28F512: |
Just4pLeisure | 1:d5452e398b76 | 779 | printf("28F512 FLASH chips.\r\n"); |
Just4pLeisure | 1:d5452e398b76 | 780 | break; |
Just4pLeisure | 5:1775b4b13232 | 781 | case ATMEL29C512: |
Just4pLeisure | 5:1775b4b13232 | 782 | printf("29C512 FLASH chips.\r\n"); |
Just4pLeisure | 5:1775b4b13232 | 783 | break; |
Just4pLeisure | 5:1775b4b13232 | 784 | case ATMEL29C010: |
Just4pLeisure | 5:1775b4b13232 | 785 | printf("29C010 FLASH chips.\r\n"); |
Just4pLeisure | 5:1775b4b13232 | 786 | break; |
Just4pLeisure | 1:d5452e398b76 | 787 | case AMD28F010: |
Just4pLeisure | 1:d5452e398b76 | 788 | case INTEL28F010: |
Just4pLeisure | 1:d5452e398b76 | 789 | printf("28F010 FLASH chips.\r\n"); |
Just4pLeisure | 1:d5452e398b76 | 790 | break; |
Just4pLeisure | 1:d5452e398b76 | 791 | case AMD29F010: |
Just4pLeisure | 5:1775b4b13232 | 792 | case SST39SF010: |
Just4pLeisure | 5:1775b4b13232 | 793 | // case ST29F010: // Same as AMD29F010 |
Just4pLeisure | 5:1775b4b13232 | 794 | case AMICA29010L: |
Just4pLeisure | 1:d5452e398b76 | 795 | printf("29F010 FLASH chips.\r\n"); |
Just4pLeisure | 1:d5452e398b76 | 796 | break; |
Just4pLeisure | 1:d5452e398b76 | 797 | default: |
Just4pLeisure | 5:1775b4b13232 | 798 | printf("UNKNOWN Device Id: %02x - Also check pin65 has enough volts!\r\n", type); |
Just4pLeisure | 1:d5452e398b76 | 799 | return FALSE; |
Just4pLeisure | 1:d5452e398b76 | 800 | } |
Just4pLeisure | 1:d5452e398b76 | 801 | return TRUE; |
Just4pLeisure | 1:d5452e398b76 | 802 | } |
Just4pLeisure | 1:d5452e398b76 | 803 | |
Just4pLeisure | 1:d5452e398b76 | 804 | // |
Just4pLeisure | 1:d5452e398b76 | 805 | // t5_can_erase_flash |
Just4pLeisure | 1:d5452e398b76 | 806 | // |
Just4pLeisure | 1:d5452e398b76 | 807 | // Erases the FLASH Chips. |
Just4pLeisure | 1:d5452e398b76 | 808 | // |
Just4pLeisure | 1:d5452e398b76 | 809 | // NOTE the bootloader must be loaded in order to use this function. |
Just4pLeisure | 1:d5452e398b76 | 810 | // |
Just4pLeisure | 1:d5452e398b76 | 811 | // CAN messages from the T5 ECU with FLASH erase command look like this: |
Just4pLeisure | 1:d5452e398b76 | 812 | // |
Just4pLeisure | 1:d5452e398b76 | 813 | // C0,cc,08,08,08,08,08,08 |
Just4pLeisure | 1:d5452e398b76 | 814 | // |
Just4pLeisure | 1:d5452e398b76 | 815 | // C0 tells us this is a response to the FLASH erase command. |
Just4pLeisure | 1:d5452e398b76 | 816 | // |
Just4pLeisure | 1:d5452e398b76 | 817 | // cc is a code that tells us what happened: |
Just4pLeisure | 1:d5452e398b76 | 818 | // 00 - FLASH was erased OK |
Just4pLeisure | 1:d5452e398b76 | 819 | // 01 - Could not erase FLASH chips to 0xFF |
Just4pLeisure | 1:d5452e398b76 | 820 | // 02 - Could not write 0x00 to 28F FLASH chips |
Just4pLeisure | 1:d5452e398b76 | 821 | // 03 - Unrecognised FLASH chip type (or maybe programming voltage isn't right) |
Just4pLeisure | 1:d5452e398b76 | 822 | // 04 - Intel chips found, but unrecognised type |
Just4pLeisure | 1:d5452e398b76 | 823 | // 05 - AMD chips found, but unrecognised type |
Just4pLeisure | 1:d5452e398b76 | 824 | // 06 - CSI/Catalyst chips found, but unrecognised type |
Just4pLeisure | 1:d5452e398b76 | 825 | // 07 - Atmel chips found - Atmel chips don't need to be erased |
Just4pLeisure | 1:d5452e398b76 | 826 | // |
Just4pLeisure | 1:d5452e398b76 | 827 | // Erasing 28F type FLASH chips takes around 22 seconds. 29F chips take around 4 seconds. |
Just4pLeisure | 1:d5452e398b76 | 828 | // |
Just4pLeisure | 1:d5452e398b76 | 829 | // inputs: none |
Just4pLeisure | 1:d5452e398b76 | 830 | // return: bool TRUE if all went OK. |
Just4pLeisure | 1:d5452e398b76 | 831 | // |
Just4pLeisure | 5:1775b4b13232 | 832 | bool t5_can_erase_flash() |
Just4pLeisure | 5:1775b4b13232 | 833 | { |
Just4pLeisure | 1:d5452e398b76 | 834 | printf("Erasing the FLASH chips.\r\n"); |
Just4pLeisure | 1:d5452e398b76 | 835 | if (!t5_boot_erase_command()) { |
Just4pLeisure | 1:d5452e398b76 | 836 | printf("Error The ECU's FLASH has not been erased!\r\n"); |
Just4pLeisure | 1:d5452e398b76 | 837 | return FALSE; |
Just4pLeisure | 1:d5452e398b76 | 838 | } |
Just4pLeisure | 1:d5452e398b76 | 839 | return TRUE; |
Just4pLeisure | 1:d5452e398b76 | 840 | } |
Just4pLeisure | 1:d5452e398b76 | 841 | |
Just4pLeisure | 1:d5452e398b76 | 842 | // |
Just4pLeisure | 1:d5452e398b76 | 843 | // t5_can_dump_flash |
Just4pLeisure | 1:d5452e398b76 | 844 | // |
Just4pLeisure | 1:d5452e398b76 | 845 | // Dumps the FLASH chip BIN file, original.bin to the mbed 'disk' |
Just4pLeisure | 1:d5452e398b76 | 846 | // |
Just4pLeisure | 1:d5452e398b76 | 847 | // NOTE the bootloader must be loaded in order to use this function. |
Just4pLeisure | 1:d5452e398b76 | 848 | // |
Just4pLeisure | 1:d5452e398b76 | 849 | // Dumping FLASH chips in a T5.5 ECU takes around 35 seconds. |
Just4pLeisure | 1:d5452e398b76 | 850 | // Dumping T5.2 ECUs should take about half of this time |
Just4pLeisure | 1:d5452e398b76 | 851 | // |
Just4pLeisure | 1:d5452e398b76 | 852 | // inputs: start start address of the T5.x FLASH |
Just4pLeisure | 1:d5452e398b76 | 853 | |
Just4pLeisure | 1:d5452e398b76 | 854 | // return: bool TRUE if all went OK, FALSE if there was an error. |
Just4pLeisure | 1:d5452e398b76 | 855 | // |
Just4pLeisure | 5:1775b4b13232 | 856 | bool t5_can_dump_flash(uint32_t start) |
Just4pLeisure | 5:1775b4b13232 | 857 | { |
Just4pLeisure | 1:d5452e398b76 | 858 | printf("Saving the original FLASH BIN file.\r\n"); |
Just4pLeisure | 1:d5452e398b76 | 859 | FILE *fp = fopen("/local/original.bin", "w"); // Open "original.bin" on the local file system for writing |
Just4pLeisure | 1:d5452e398b76 | 860 | if (!fp) { |
Just4pLeisure | 1:d5452e398b76 | 861 | perror ("The following error occured"); |
Just4pLeisure | 1:d5452e398b76 | 862 | return FALSE; |
Just4pLeisure | 1:d5452e398b76 | 863 | } |
Just4pLeisure | 1:d5452e398b76 | 864 | uint32_t address = start + 5; // Mysterious reason for starting at 5 !!! |
Just4pLeisure | 1:d5452e398b76 | 865 | char FLASHdata[6]; |
Just4pLeisure | 5:1775b4b13232 | 866 | printf(" 0.00 %% complete.\r"); |
Just4pLeisure | 1:d5452e398b76 | 867 | while (address < TRIONICLASTADDR) { |
Just4pLeisure | 1:d5452e398b76 | 868 | if (!t5_can_read_data(FLASHdata, address)) { |
Just4pLeisure | 1:d5452e398b76 | 869 | fclose (fp); |
Just4pLeisure | 1:d5452e398b76 | 870 | printf ("Error reading from the CAN bus.\r\n"); |
Just4pLeisure | 1:d5452e398b76 | 871 | return FALSE; |
Just4pLeisure | 1:d5452e398b76 | 872 | } |
Just4pLeisure | 1:d5452e398b76 | 873 | address += 6; |
Just4pLeisure | 1:d5452e398b76 | 874 | if (fwrite(FLASHdata, 1, 6, fp) != 6) { |
Just4pLeisure | 1:d5452e398b76 | 875 | fclose (fp); |
Just4pLeisure | 1:d5452e398b76 | 876 | printf ("Error writing to the FLASH BIN file.\r\n"); |
Just4pLeisure | 1:d5452e398b76 | 877 | return FALSE; |
Just4pLeisure | 1:d5452e398b76 | 878 | } |
Just4pLeisure | 5:1775b4b13232 | 879 | printf("%6.2f\r", 100*(float)(address-start)/(float)(TRIONICLASTADDR - start) ); |
Just4pLeisure | 1:d5452e398b76 | 880 | } |
Just4pLeisure | 1:d5452e398b76 | 881 | // There are a few more bytes to get because because the bin file is not an exact multiple of 6 bytes! |
Just4pLeisure | 1:d5452e398b76 | 882 | // the % (modulo) mathematics function tells us how many bytes there are still to get |
Just4pLeisure | 1:d5452e398b76 | 883 | if (!t5_can_read_data(FLASHdata, (TRIONICLASTADDR))) { |
Just4pLeisure | 1:d5452e398b76 | 884 | fclose (fp); |
Just4pLeisure | 1:d5452e398b76 | 885 | printf ("Error reading from the CAN bus.\r\n"); |
Just4pLeisure | 1:d5452e398b76 | 886 | return FALSE; |
Just4pLeisure | 1:d5452e398b76 | 887 | } |
Just4pLeisure | 1:d5452e398b76 | 888 | if (fwrite((FLASHdata + 6 - ((TRIONICLASTADDR - start +1) % 6)), 1, ((TRIONICLASTADDR - start +1) % 6), fp) != ((TRIONICLASTADDR - start +1) % 6)) { |
Just4pLeisure | 1:d5452e398b76 | 889 | fclose (fp); |
Just4pLeisure | 1:d5452e398b76 | 890 | printf ("Error writing to the FLASH BIN file.\r\n"); |
Just4pLeisure | 1:d5452e398b76 | 891 | return FALSE; |
Just4pLeisure | 1:d5452e398b76 | 892 | } |
Just4pLeisure | 5:1775b4b13232 | 893 | printf("100.00 %% complete.\r\n"); |
Just4pLeisure | 1:d5452e398b76 | 894 | fclose(fp); |
Just4pLeisure | 1:d5452e398b76 | 895 | return TRUE; |
Just4pLeisure | 1:d5452e398b76 | 896 | } |
Just4pLeisure | 1:d5452e398b76 | 897 | |
Just4pLeisure | 1:d5452e398b76 | 898 | |
Just4pLeisure | 1:d5452e398b76 | 899 | // |
Just4pLeisure | 1:d5452e398b76 | 900 | // t5_can_send_flash_bin_update |
Just4pLeisure | 1:d5452e398b76 | 901 | // |
Just4pLeisure | 5:1775b4b13232 | 902 | // Sends a FLASH update file, modified.bin to the T5 ECU. |
Just4pLeisure | 1:d5452e398b76 | 903 | // The FLASH update file is stored on the local file system and must be in hex format. |
Just4pLeisure | 1:d5452e398b76 | 904 | // |
Just4pLeisure | 1:d5452e398b76 | 905 | // FLASHing a T5.5 ECU takes around 40 seconds. FLASHing T5.2 ECUs should take about half of this time |
Just4pLeisure | 1:d5452e398b76 | 906 | // |
Just4pLeisure | 1:d5452e398b76 | 907 | // inputs: start start address of the T5.x FLASH |
Just4pLeisure | 1:d5452e398b76 | 908 | |
Just4pLeisure | 1:d5452e398b76 | 909 | // return: bool TRUE if all went OK, |
Just4pLeisure | 1:d5452e398b76 | 910 | // FALSE if the FLASH update failed for some reason. |
Just4pLeisure | 1:d5452e398b76 | 911 | // |
Just4pLeisure | 5:1775b4b13232 | 912 | bool t5_can_send_flash_bin_update(uint32_t start) |
Just4pLeisure | 5:1775b4b13232 | 913 | { |
Just4pLeisure | 1:d5452e398b76 | 914 | printf("Programming the FLASH chips.\r\n"); |
Just4pLeisure | 5:1775b4b13232 | 915 | FILE *fp = fopen("/local/modified.bin", "r"); // Open "modified.bin" on the local file system for reading |
Just4pLeisure | 1:d5452e398b76 | 916 | if (!fp) { |
Just4pLeisure | 5:1775b4b13232 | 917 | printf("Error: I could not find the BIN file MODIFIED.BIN\r\n"); |
Just4pLeisure | 1:d5452e398b76 | 918 | return FALSE; |
Just4pLeisure | 1:d5452e398b76 | 919 | } |
Just4pLeisure | 1:d5452e398b76 | 920 | |
Just4pLeisure | 1:d5452e398b76 | 921 | // obtain file size - it should match the size of the FLASH chips: |
Just4pLeisure | 1:d5452e398b76 | 922 | fseek (fp , 0 , SEEK_END); |
Just4pLeisure | 1:d5452e398b76 | 923 | uint32_t file_size = ftell (fp); |
Just4pLeisure | 1:d5452e398b76 | 924 | rewind (fp); |
Just4pLeisure | 1:d5452e398b76 | 925 | |
Just4pLeisure | 1:d5452e398b76 | 926 | // read the initial stack pointer value in the BIN file - it should match the value expected for the type of ECU |
Just4pLeisure | 1:d5452e398b76 | 927 | uint8_t stack_byte = 0; |
Just4pLeisure | 1:d5452e398b76 | 928 | uint32_t stack_long = 0; |
Just4pLeisure | 1:d5452e398b76 | 929 | if (!fread(&stack_byte,1,1,fp)) return TERM_ERR; |
Just4pLeisure | 1:d5452e398b76 | 930 | stack_long |= (stack_byte << 24); |
Just4pLeisure | 1:d5452e398b76 | 931 | if (!fread(&stack_byte,1,1,fp)) return TERM_ERR; |
Just4pLeisure | 1:d5452e398b76 | 932 | stack_long |= (stack_byte << 16); |
Just4pLeisure | 1:d5452e398b76 | 933 | if (!fread(&stack_byte,1,1,fp)) return TERM_ERR; |
Just4pLeisure | 1:d5452e398b76 | 934 | stack_long |= (stack_byte << 8); |
Just4pLeisure | 1:d5452e398b76 | 935 | if (!fread(&stack_byte,1,1,fp)) return TERM_ERR; |
Just4pLeisure | 1:d5452e398b76 | 936 | stack_long |= stack_byte; |
Just4pLeisure | 1:d5452e398b76 | 937 | rewind (fp); |
Just4pLeisure | 1:d5452e398b76 | 938 | |
Just4pLeisure | 1:d5452e398b76 | 939 | if (start == T52FLASHSTART && (file_size != T52FLASHSIZE || stack_long != T5POINTER)) { |
Just4pLeisure | 1:d5452e398b76 | 940 | fclose(fp); |
Just4pLeisure | 1:d5452e398b76 | 941 | printf("The BIN file does not appear to be for a T5.2 ECU :-(\r\n"); |
Just4pLeisure | 1:d5452e398b76 | 942 | printf("BIN file size: %#10x, FLASH chip size: %#010x, Pointer: %#10x.\r\n", file_size, T52FLASHSIZE, stack_long); |
Just4pLeisure | 1:d5452e398b76 | 943 | return TERM_ERR; |
Just4pLeisure | 1:d5452e398b76 | 944 | } |
Just4pLeisure | 1:d5452e398b76 | 945 | if (start == T55FLASHSTART && (file_size != T55FLASHSIZE || stack_long != T5POINTER)) { |
Just4pLeisure | 1:d5452e398b76 | 946 | fclose(fp); |
Just4pLeisure | 1:d5452e398b76 | 947 | printf("The BIN file does not appear to be for a T5.5 ECU :-(\r\n"); |
Just4pLeisure | 1:d5452e398b76 | 948 | printf("BIN file size: %#10x, FLASH chip size: %#010x, Pointer: %#10x.\r\n", file_size, T55FLASHSIZE, stack_long); |
Just4pLeisure | 1:d5452e398b76 | 949 | return TERM_ERR; |
Just4pLeisure | 1:d5452e398b76 | 950 | } |
Just4pLeisure | 1:d5452e398b76 | 951 | |
Just4pLeisure | 1:d5452e398b76 | 952 | char msg[8]; // Construct the bootloader frame for uploading |
Just4pLeisure | 1:d5452e398b76 | 953 | uint32_t curr_addr = start; // address to put FLASH data |
Just4pLeisure | 1:d5452e398b76 | 954 | uint8_t byte_value = 0; |
Just4pLeisure | 1:d5452e398b76 | 955 | |
Just4pLeisure | 5:1775b4b13232 | 956 | printf(" 0.00 %% complete.\r"); |
Just4pLeisure | 1:d5452e398b76 | 957 | while (curr_addr <= TRIONICLASTADDR) { |
Just4pLeisure | 1:d5452e398b76 | 958 | |
Just4pLeisure | 1:d5452e398b76 | 959 | // send a bootloader address message |
Just4pLeisure | 1:d5452e398b76 | 960 | if (!t5_can_send_boot_address(curr_addr, 0x80)) { |
Just4pLeisure | 1:d5452e398b76 | 961 | fclose(fp); |
Just4pLeisure | 5:1775b4b13232 | 962 | printf("\r\nError sending Block Start message. Address: %08x\r\n",curr_addr); |
Just4pLeisure | 1:d5452e398b76 | 963 | return FALSE; |
Just4pLeisure | 1:d5452e398b76 | 964 | } |
Just4pLeisure | 1:d5452e398b76 | 965 | // Construct and send the bootloader frames |
Just4pLeisure | 1:d5452e398b76 | 966 | // 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 |
Just4pLeisure | 1:d5452e398b76 | 967 | // are repeated from the previous frame. This is OK because the T5 ECU knows how many bytes to expect (because the count of bytes |
Just4pLeisure | 1:d5452e398b76 | 968 | // in the S-Record is sent with the upload address) and ignores any extra bytes in the last frame. |
Just4pLeisure | 1:d5452e398b76 | 969 | for (uint8_t i=0; i<0x80; i++) { |
Just4pLeisure | 1:d5452e398b76 | 970 | if (!fread(&byte_value,1,1,fp)) { |
Just4pLeisure | 1:d5452e398b76 | 971 | fclose(fp); |
Just4pLeisure | 5:1775b4b13232 | 972 | printf("\r\nError reading the BIN file MODIFIED.BIN\r\n"); |
Just4pLeisure | 1:d5452e398b76 | 973 | return FALSE; |
Just4pLeisure | 1:d5452e398b76 | 974 | } |
Just4pLeisure | 1:d5452e398b76 | 975 | msg[1+(i%7)] = byte_value; |
Just4pLeisure | 1:d5452e398b76 | 976 | if (i%7 == 0) msg[0]=i; // set the index number |
Just4pLeisure | 1:d5452e398b76 | 977 | if ((i%7 == 6) || (i == 0x80 - 1)) |
Just4pLeisure | 1:d5452e398b76 | 978 | if (!t5_can_send_boot_frame(msg)) { |
Just4pLeisure | 1:d5452e398b76 | 979 | fclose(fp); |
Just4pLeisure | 5:1775b4b13232 | 980 | printf("\r\nError sending a Block data message. Address: %08x, Index: %02x\r\n",curr_addr, i); |
Just4pLeisure | 1:d5452e398b76 | 981 | return FALSE; |
Just4pLeisure | 1:d5452e398b76 | 982 | } |
Just4pLeisure | 5:1775b4b13232 | 983 | |
Just4pLeisure | 1:d5452e398b76 | 984 | } |
Just4pLeisure | 5:1775b4b13232 | 985 | curr_addr += 0x80; |
Just4pLeisure | 5:1775b4b13232 | 986 | printf("%6.2f\r", 100*(float)(curr_addr - start)/(float)(TRIONICLASTADDR - start) ); |
Just4pLeisure | 1:d5452e398b76 | 987 | } |
Just4pLeisure | 5:1775b4b13232 | 988 | printf("100.00 %% complete.\r\n"); |
Just4pLeisure | 1:d5452e398b76 | 989 | fclose(fp); |
Just4pLeisure | 1:d5452e398b76 | 990 | return TRUE; |
Just4pLeisure | 1:d5452e398b76 | 991 | } |
Just4pLeisure | 1:d5452e398b76 | 992 | |
Just4pLeisure | 1:d5452e398b76 | 993 | // |
Just4pLeisure | 1:d5452e398b76 | 994 | // t5_can_send_flash_s19_update |
Just4pLeisure | 1:d5452e398b76 | 995 | // |
Just4pLeisure | 1:d5452e398b76 | 996 | // Sends a FLASH update file, modified.s19 to the T5 ECU. |
Just4pLeisure | 1:d5452e398b76 | 997 | // The FLASH update file is stored on the local file system and must be in S19 format. |
Just4pLeisure | 1:d5452e398b76 | 998 | // |
Just4pLeisure | 1:d5452e398b76 | 999 | // FLASHing a T5.5 ECU takes around 60 seconds. FLASHing T5.2 ECUs should take about half of this time |
Just4pLeisure | 1:d5452e398b76 | 1000 | // |
Just4pLeisure | 1:d5452e398b76 | 1001 | // inputs: start start address of the T5.x FLASH |
Just4pLeisure | 1:d5452e398b76 | 1002 | |
Just4pLeisure | 1:d5452e398b76 | 1003 | // return: bool TRUE if all went OK, |
Just4pLeisure | 1:d5452e398b76 | 1004 | // FALSE if the FLASH update failed for some reason. |
Just4pLeisure | 1:d5452e398b76 | 1005 | // |
Just4pLeisure | 5:1775b4b13232 | 1006 | bool t5_can_send_flash_s19_update(uint32_t start) |
Just4pLeisure | 5:1775b4b13232 | 1007 | { |
Just4pLeisure | 1:d5452e398b76 | 1008 | printf("Programming the FLASH chips.\r\n"); |
Just4pLeisure | 1:d5452e398b76 | 1009 | FILE *fp = fopen("/local/modified.s19", "r"); // Open "modified.s19" on the local file system for reading |
Just4pLeisure | 1:d5452e398b76 | 1010 | if (!fp) { |
Just4pLeisure | 1:d5452e398b76 | 1011 | printf("Error: I could not find the BIN file MODIFIED.S19\r\n"); |
Just4pLeisure | 1:d5452e398b76 | 1012 | return FALSE; |
Just4pLeisure | 1:d5452e398b76 | 1013 | } |
Just4pLeisure | 1:d5452e398b76 | 1014 | int c = 0; // for some reason fgetc returns an int instead of a char |
Just4pLeisure | 1:d5452e398b76 | 1015 | uint8_t count = 0; // count of bytes in the S-record can be 0xFF = 255 in decimal |
Just4pLeisure | 1:d5452e398b76 | 1016 | uint8_t asize = 0; // 2,3 or 4 bytes in address |
Just4pLeisure | 1:d5452e398b76 | 1017 | uint32_t address = 0; // address to put S-record |
Just4pLeisure | 1:d5452e398b76 | 1018 | uint8_t checksum = 0; // checksum check at the end |
Just4pLeisure | 1:d5452e398b76 | 1019 | char msg[8]; // Construct the bootloader frame for uploading |
Just4pLeisure | 1:d5452e398b76 | 1020 | bool sent = FALSE; |
Just4pLeisure | 1:d5452e398b76 | 1021 | |
Just4pLeisure | 1:d5452e398b76 | 1022 | while (!sent) { |
Just4pLeisure | 1:d5452e398b76 | 1023 | |
Just4pLeisure | 1:d5452e398b76 | 1024 | do c = fgetc (fp); // get characters until we get an 'S' (throws away \n,\r characters and other junk) |
Just4pLeisure | 1:d5452e398b76 | 1025 | while (c != 'S' && c != EOF); |
Just4pLeisure | 1:d5452e398b76 | 1026 | // if (c == EOF) return '\a'; |
Just4pLeisure | 1:d5452e398b76 | 1027 | c = fgetc(fp); // get the S-record type 1/2/3 5 7/8/9 (Return if EOF reached) |
Just4pLeisure | 1:d5452e398b76 | 1028 | // if ((c = fgetc(fp)) == EOF) return '\a'; // get the S-record type 1/2/3 5 7/8/9 (Return if EOF reached) |
Just4pLeisure | 1:d5452e398b76 | 1029 | switch (c) { |
Just4pLeisure | 1:d5452e398b76 | 1030 | case '0': |
Just4pLeisure | 1:d5452e398b76 | 1031 | break; // Skip over S0 header record |
Just4pLeisure | 1:d5452e398b76 | 1032 | |
Just4pLeisure | 1:d5452e398b76 | 1033 | case '1': |
Just4pLeisure | 1:d5452e398b76 | 1034 | case '2': |
Just4pLeisure | 1:d5452e398b76 | 1035 | case '3': |
Just4pLeisure | 1:d5452e398b76 | 1036 | asize = 1 + c - '0'; // 2, 3 or 4 bytes for address |
Just4pLeisure | 1:d5452e398b76 | 1037 | address = 0; |
Just4pLeisure | 1:d5452e398b76 | 1038 | // get the number of bytes (in ascii format) in this S-record line |
Just4pLeisure | 1:d5452e398b76 | 1039 | // there must be at least the address and the checksum so return with an error if less than this! |
Just4pLeisure | 1:d5452e398b76 | 1040 | if ((c = SRecGetByte(fp)) < (asize + 1)) { |
Just4pLeisure | 1:d5452e398b76 | 1041 | fclose(fp); |
Just4pLeisure | 1:d5452e398b76 | 1042 | printf("Error in S-record address"); |
Just4pLeisure | 1:d5452e398b76 | 1043 | return FALSE; |
Just4pLeisure | 1:d5452e398b76 | 1044 | } |
Just4pLeisure | 1:d5452e398b76 | 1045 | count = c; |
Just4pLeisure | 1:d5452e398b76 | 1046 | checksum = c; |
Just4pLeisure | 1:d5452e398b76 | 1047 | // get the address |
Just4pLeisure | 1:d5452e398b76 | 1048 | for (uint8_t i=0; i<asize; i++) { |
Just4pLeisure | 1:d5452e398b76 | 1049 | c = SRecGetByte(fp); |
Just4pLeisure | 1:d5452e398b76 | 1050 | checksum += c; |
Just4pLeisure | 1:d5452e398b76 | 1051 | address <<= 8; |
Just4pLeisure | 1:d5452e398b76 | 1052 | address |= c; |
Just4pLeisure | 1:d5452e398b76 | 1053 | count--; |
Just4pLeisure | 1:d5452e398b76 | 1054 | } |
Just4pLeisure | 1:d5452e398b76 | 1055 | // send a bootloader address message - Adding the start address that was supplied (for T5.2/T5.5) |
Just4pLeisure | 1:d5452e398b76 | 1056 | if (!t5_can_send_boot_address((address + start), (count - 1))) { |
Just4pLeisure | 1:d5452e398b76 | 1057 | fclose(fp); |
Just4pLeisure | 1:d5452e398b76 | 1058 | printf("Error sending CAN message"); |
Just4pLeisure | 1:d5452e398b76 | 1059 | return FALSE; |
Just4pLeisure | 1:d5452e398b76 | 1060 | } |
Just4pLeisure | 1:d5452e398b76 | 1061 | // get and send the bootloader frames for this S-record |
Just4pLeisure | 1:d5452e398b76 | 1062 | // 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 |
Just4pLeisure | 1:d5452e398b76 | 1063 | // are repeated from the previous frame. This is OK because the T5 ECU knows how many bytes to expect (because the count of bytes |
Just4pLeisure | 1:d5452e398b76 | 1064 | // in the S-Record is sent with the upload address) and ignores any extra bytes in the last frame. |
Just4pLeisure | 1:d5452e398b76 | 1065 | for (uint8_t i=0; i<count-1; i++) { |
Just4pLeisure | 1:d5452e398b76 | 1066 | c = SRecGetByte(fp); |
Just4pLeisure | 1:d5452e398b76 | 1067 | checksum += c; |
Just4pLeisure | 1:d5452e398b76 | 1068 | msg[1+(i%7)] = c; |
Just4pLeisure | 1:d5452e398b76 | 1069 | if (i%7 == 0) msg[0]=i; // set the index number |
Just4pLeisure | 1:d5452e398b76 | 1070 | if ((i%7 == 6) || (i == count - 2)) |
Just4pLeisure | 1:d5452e398b76 | 1071 | if (!t5_can_send_boot_frame(msg)) { |
Just4pLeisure | 1:d5452e398b76 | 1072 | fclose(fp); |
Just4pLeisure | 1:d5452e398b76 | 1073 | printf("Error sending CAN message"); |
Just4pLeisure | 1:d5452e398b76 | 1074 | return FALSE; |
Just4pLeisure | 1:d5452e398b76 | 1075 | } |
Just4pLeisure | 1:d5452e398b76 | 1076 | } |
Just4pLeisure | 1:d5452e398b76 | 1077 | // get the checksum |
Just4pLeisure | 1:d5452e398b76 | 1078 | if ((checksum += SRecGetByte(fp)) != 0xFF) { |
Just4pLeisure | 1:d5452e398b76 | 1079 | fclose(fp); |
Just4pLeisure | 1:d5452e398b76 | 1080 | printf("Error in S-record, checksum = %2x\r\n", checksum); |
Just4pLeisure | 1:d5452e398b76 | 1081 | return FALSE; |
Just4pLeisure | 1:d5452e398b76 | 1082 | } |
Just4pLeisure | 1:d5452e398b76 | 1083 | break; |
Just4pLeisure | 1:d5452e398b76 | 1084 | |
Just4pLeisure | 1:d5452e398b76 | 1085 | case '5': |
Just4pLeisure | 1:d5452e398b76 | 1086 | break; // Skip over S5 record types |
Just4pLeisure | 1:d5452e398b76 | 1087 | |
Just4pLeisure | 1:d5452e398b76 | 1088 | case '7': |
Just4pLeisure | 1:d5452e398b76 | 1089 | case '8': |
Just4pLeisure | 1:d5452e398b76 | 1090 | case '9': |
Just4pLeisure | 1:d5452e398b76 | 1091 | sent = TRUE; |
Just4pLeisure | 1:d5452e398b76 | 1092 | break; |
Just4pLeisure | 1:d5452e398b76 | 1093 | |
Just4pLeisure | 1:d5452e398b76 | 1094 | // Some kind of invalid S-record type so break |
Just4pLeisure | 1:d5452e398b76 | 1095 | default: |
Just4pLeisure | 1:d5452e398b76 | 1096 | printf("oops - didn't recognise that S-Record\r\n"); |
Just4pLeisure | 1:d5452e398b76 | 1097 | fclose(fp); |
Just4pLeisure | 1:d5452e398b76 | 1098 | return FALSE; |
Just4pLeisure | 1:d5452e398b76 | 1099 | } |
Just4pLeisure | 1:d5452e398b76 | 1100 | } |
Just4pLeisure | 1:d5452e398b76 | 1101 | fclose(fp); |
Just4pLeisure | 1:d5452e398b76 | 1102 | return TRUE; |
Just4pLeisure | 1:d5452e398b76 | 1103 | } |
Just4pLeisure | 1:d5452e398b76 | 1104 | |
Just4pLeisure | 1:d5452e398b76 | 1105 | // |
Just4pLeisure | 1:d5452e398b76 | 1106 | // t5_can_get_last_address |
Just4pLeisure | 1:d5452e398b76 | 1107 | // |
Just4pLeisure | 1:d5452e398b76 | 1108 | // Sends a C3 Message to the T5 ECU. The reply should contain the last used FLASH address |
Just4pLeisure | 1:d5452e398b76 | 1109 | // which is always 0x0007FFFF |
Just4pLeisure | 1:d5452e398b76 | 1110 | // |
Just4pLeisure | 1:d5452e398b76 | 1111 | // The last 2 bytes of the message might be useful to work out whether or not the bootloader |
Just4pLeisure | 1:d5452e398b76 | 1112 | // has been loaded. The 'mode' value will be 0x0808 when the bootloader is running or 0x89b8 |
Just4pLeisure | 1:d5452e398b76 | 1113 | // when it isn't. |
Just4pLeisure | 1:d5452e398b76 | 1114 | // |
Just4pLeisure | 1:d5452e398b76 | 1115 | // inputs: none |
Just4pLeisure | 1:d5452e398b76 | 1116 | // return: bool TRUE if all went OK, |
Just4pLeisure | 1:d5452e398b76 | 1117 | // |
Just4pLeisure | 5:1775b4b13232 | 1118 | bool t5_can_get_last_address() |
Just4pLeisure | 5:1775b4b13232 | 1119 | { |
Just4pLeisure | 1:d5452e398b76 | 1120 | uint32_t last_address = 0; |
Just4pLeisure | 1:d5452e398b76 | 1121 | uint16_t mode = 0; |
Just4pLeisure | 1:d5452e398b76 | 1122 | if (!t5_boot_c3_command(&last_address, &mode)) { |
Just4pLeisure | 1:d5452e398b76 | 1123 | printf("Error trying to find out the ECU's last address and mode!\r\n"); |
Just4pLeisure | 1:d5452e398b76 | 1124 | return FALSE; |
Just4pLeisure | 1:d5452e398b76 | 1125 | } |
Just4pLeisure | 1:d5452e398b76 | 1126 | printf("The Last used FLASH address is: %#010x, mode %#06x\r\n", last_address, mode); |
Just4pLeisure | 1:d5452e398b76 | 1127 | return TRUE; |
Just4pLeisure | 1:d5452e398b76 | 1128 | } |