Just4Trionic - CAN and BDM FLASH programmer for Saab cars

Dependencies:   mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers t5utils.cpp Source File

t5utils.cpp

00001 /*******************************************************************************
00002 
00003 t5utils.cpp
00004 (c) 2010 by Sophie Dexter
00005 
00006 This C++ module provides functions for communicating simple messages to and from
00007 the T5 ECU
00008 
00009 ********************************************************************************
00010 
00011 WARNING: Use at your own risk, sadly this software comes with no guarantees.
00012 This software is provided 'free' and in good faith, but the author does not
00013 accept liability for any damage arising from its use.
00014 
00015 *******************************************************************************/
00016 
00017 #include "t5utils.h"
00018 
00019 //
00020 // T5Open enables the CAN chip and sets the CAN speed to 615 kbits.
00021 //
00022 // This function is a 'quick fix' for now.
00023 //
00024 // inputs:    none
00025 // return:    bool TRUE if all went OK,
00026 //
00027 bool T5Open() {
00028     can_open ();
00029     return TRUE;
00030 }
00031 
00032 //
00033 // T5Close disables the CAN chip.
00034 //
00035 // This function is a 'quick fix' for now.
00036 //
00037 // inputs:    none
00038 // return:    bool TRUE if all went OK,
00039 //
00040 bool T5Close() {
00041     can_close ();
00042     return TRUE;
00043 }
00044 
00045 //
00046 // T5WaitResponse
00047 //
00048 // Waits for a response message with the correct message id from the T5 ECU.
00049 // The response is a single ascii character from the symboltable.
00050 //
00051 // Returns an error ('BELL' character) if:
00052 //      a response is not received before the timeout
00053 //      the message length is less than 8 bytes (all messages should be 8 bytes)
00054 //      the message type is incorrect
00055 //
00056 // inputs:    none
00057 // return:    a single char that is the response from the T5 ECU
00058 //
00059 char T5WaitResponse() {
00060     char T5RxMsg[8];
00061     if (!can_wait_timeout(RESPID, T5RxMsg, 8, T5MESSAGETIMEOUT)) return '\a';
00062     if (T5RxMsg[0] != 0xC6) return '\a';
00063     return T5RxMsg[2];
00064 }
00065 
00066 //
00067 //
00068 // T5WaitResponsePrint
00069 //
00070 // Waits for a response message with the correct message id from the T5 ECU and displays the whole message:
00071 //
00072 // wiiildddddddddddddddd
00073 //  iii - is the CAN message id
00074 //     l - is the message length, should always be 8 for T5 messages
00075 //      dd,dd,dd,dd,dd,dd,dd,dd are the CAN message data bytes
00076 //
00077 // Returns an error if:
00078 //      a response is not received before the timeout
00079 //      the message length is less than 8 bytes (all messages should be 8 bytes)
00080 //      the message type is incorrect
00081 //
00082 // Inputs:    none
00083 // return:    bool TRUE if a qualifying message was received
00084 //                 FALSE if a message wasn't received in time, had the wrong id etc...
00085 //
00086 bool T5WaitResponsePrint() {
00087     char T5RxMsg[8];
00088     if (!can_wait_timeout(RESPID, T5RxMsg, 8, T5MESSAGETIMEOUT)) return FALSE;
00089     printf("w%03x8", RESPID);
00090     for (char i=0; i<8; i++) {
00091         printf("%02x", T5RxMsg[i]);
00092     }
00093     printf("\n\r");
00094     return TRUE;
00095 }
00096 
00097 // T5GetSymbol
00098 //
00099 // Reads a single symbol name (in the symbol table) from the T5 ECU.
00100 // T5GetSymbol sends ACK messages to the T5 ECU and stores the
00101 // reply characters in a string until a '\n' character is received
00102 // when the function returns with the pointer to that string.
00103 //
00104 // inputs:    a pointer to the string used to store the symbol name.
00105 // return:    a pointer to the string used to store the symbol name.
00106 //
00107 char *T5GetSymbol(char *s) {
00108     do {
00109         if (T5Ack()) {
00110         }
00111         *s = T5WaitResponse();
00112     } while (*s++ != '\n');
00113     *s = '\0';
00114     return s;
00115 }
00116 
00117 // T5ReadCmnd
00118 //
00119 // Sends a 'read' type command to the T5 ECU. 'read' commands are used to read something from the T5 ECU.
00120 //
00121 // inputs:    a 'char' which is the type of 'read' requested (e.g. symbol table, version etc).
00122 // return:    bool TRUE if the message was sent within the timeout period,
00123 //                 FALSE if the message couldn't be sent.
00124 //
00125 bool T5ReadCmnd(char c) {
00126     char T5TxMsg[] = T5_RDCMND;
00127     T5TxMsg[1] = c;
00128     return (can_send_timeout (CMNDID, T5TxMsg, 8, T5MESSAGETIMEOUT));
00129 }
00130 
00131 //
00132 // T5WriteCmnd is unfinished
00133 //
00134 bool T5WriteCmnd(unsigned int addr, char data) {
00135     return FALSE;
00136 }
00137 
00138 
00139 
00140 // t5_can_read_data
00141 //
00142 // Reads 6 bytes of the data from the SRAM or FLASH in the T5 ECU.
00143 //
00144 // There is something back-to-front about the way this works, but it does :-)
00145 //
00146 // inputs:    a pointer to an array of 6 bytes for storing the data read from the T5 ECU.
00147 //            the address to read SRAM data from in the T5 ECU
00148 // return:    a pointer to an array of 6 bytes for storing the data read from the T5 ECU.
00149 //            bool TRUE if the message was sent within the timeout period,
00150 //                 FALSE if the message couldn't be sent.
00151 //
00152 bool t5_can_read_data(char *data, uint32_t addr) {
00153 
00154     // send a can message to the T5 with the address we want to read from
00155     char T5TxMsg[] = T5RAMCMND;
00156     T5TxMsg[1] = ((uint8_t)(addr >> 24));         // high high byte of address
00157     T5TxMsg[2] = ((uint8_t)(addr >> 16));         // high low byte of address
00158     T5TxMsg[3] = ((uint8_t)(addr >> 8));          // low high byte of address
00159     T5TxMsg[4] = ((uint8_t)(addr));               // low low byte of address
00160     // if the message cannot be sent then there is a problem
00161     if (!can_send_timeout (CMNDID, T5TxMsg, 8, T5MESSAGETIMEOUT))
00162         return FALSE;
00163     // wait for the T5 to reply with some data
00164     char T5RxMsg[8];
00165     // if a message is not received, has the wrong type or indicates an error then there is a problem
00166     if ((!can_wait_timeout(RESPID, T5RxMsg, 8, T5MESSAGETIMEOUT)) || (T5RxMsg[0] != T5TxMsg[0]) || (T5RxMsg[1] != 0x00))
00167         return FALSE;
00168     for (int i=2; i<8; i++)
00169         data[7-i] = T5RxMsg[i];
00170     return TRUE;
00171 }
00172 
00173 // T5Ack
00174 //
00175 // Sends an 'ACK' message to the T5 ECU to prompt the T5 to send the next
00176 // ascii character from the symboltable
00177 //
00178 // Returns an error if:
00179 //      the 'ACK' message cannot be sent before the timeout
00180 //
00181 // inputs:    none
00182 // return:    bool TRUE if message was sent OK,
00183 //                 FALSE if message could not be sent.
00184 
00185 bool T5Ack() {
00186     char T5TxMsg[] = T5ACKCMND;
00187     return (can_send_timeout (CMNDID, T5TxMsg, 8, T5MESSAGETIMEOUT));
00188 }
00189 
00190 //
00191 // t5_can_send_boot_address
00192 //
00193 // Send an address where 'bootloader' or FLASH CAN messages are uploaded to.
00194 // The number of bytes (up to 0x7F) that will be sent in the following CAN messages is also sent.
00195 //
00196 // inputs:    an unsigned int, the address where messages should be sent.
00197 //            an int, the number of bytes (up to 0x7F) that will be sent in the following CAN messages.
00198 // return:    bool TRUE if message was sent OK,
00199 //                 FALSE if message could not be sent.
00200 //
00201 bool t5_can_send_boot_address(uint32_t addr, uint8_t len) {
00202     // send a can message to the T5 with the address and number of bytes we are going to send
00203     char T5TxMsg[] = T5_BTCMND;
00204     T5TxMsg[1] = ((uint8_t)(addr >> 24));         // high high byte of address
00205     T5TxMsg[2] = ((uint8_t)(addr >> 16));         // high low byte of address
00206     T5TxMsg[3] = ((uint8_t)(addr >> 8));          // low high byte of address
00207     T5TxMsg[4] = ((uint8_t)(addr));               // low low byte of address
00208     T5TxMsg[5] = (len);                           // number of bytes to upload (sent in following messages)
00209     // if the message cannot be sent then there is a problem
00210     if (!can_send_timeout (CMNDID, T5TxMsg, 8, T5MESSAGETIMEOUT))
00211         return FALSE;
00212     // wait for the T5 to reply
00213     char T5RxMsg[8];
00214     // if a message is not received, has the wrong type or indicates an error then there is a problem
00215     return ((!can_wait_timeout(RESPID, T5RxMsg, 8, T5MESSAGETIMEOUT)) || (T5RxMsg[0] != T5TxMsg[0]) || (T5RxMsg[1] != 0x00))
00216         ? FALSE : TRUE;
00217 }
00218 
00219 //
00220 // t5_can_send_boot_frame
00221 //
00222 // Upload 'bootloader' or new FLASH byts to T5 ECU in CAN messages
00223 //
00224 // The CAN messages are made up of 1 byte which is added to the address given in the T5SendBootAddress meaassge
00225 // followed by 7 bytes of data.
00226 // The first byte normally starts at 0x00 and increases by 7 in following messages until another T5SendBootAddress message is sent e.g.
00227 // 00,dd,dd,dd,dd,dd,dd,dd,dd 'dd' bytes are the data bytes, 7 in each CAN message except the last one which may have less.
00228 // 07,dd,dd,dd,dd,dd,dd,dd,dd
00229 // 0E,dd,dd,dd,dd,dd,dd,dd,dd (0x0E is 14)
00230 // 15,dd,dd,dd,dd,dd,dd,dd,dd (0x15 is 21)
00231 // etc.
00232 //
00233 // inputs:    a pointer to an array of 8 bytes to be sent to the T5 ECU SRAM or FLASH.
00234 // return:    bool TRUE if message was sent OK,
00235 //                 FALSE if message could not be sent.
00236 //
00237 bool t5_can_send_boot_frame (char *T5TxMsg) {
00238     // send a can message to the T5 with the bytes we are sending
00239     if (!can_send_timeout (CMNDID, T5TxMsg, 8, T5MESSAGETIMEOUT))
00240         return FALSE;
00241     // wait for the T5 to reply
00242     char T5RxMsg[8];
00243     // if a message is not received, has the wrong type or indicates an error then there is a problem
00244     return ((!can_wait_timeout(RESPID, T5RxMsg, 8, T5MESSAGETIMEOUT)) || (T5RxMsg[0] != T5TxMsg[0]) || (T5RxMsg[1] != 0x00))
00245         ? FALSE : TRUE;
00246 }
00247 
00248 //
00249 // T5StartBootLoader
00250 //
00251 // Send the jump to address to the T5 ECU for starting the 'bootloader'.
00252 // The jump address must be somewhere in RAM (addresses 0x0000 to 0x8000).
00253 // (The start address comes from the S7/8/9 line in the S19 file.)
00254 //
00255 // inputs:    an unsigned int, the address to jump to start of 'bootloader'.
00256 // return:    bool TRUE if message was sent OK,
00257 //                 FALSE if message could not be sent.
00258 //
00259 bool T5StartBootLoader (uint32_t addr) {
00260     char T5TxMsg[] = T5JMPCMND;
00261     T5TxMsg[3] = ((uint8_t)(addr >> 8));          // low byte of address
00262     T5TxMsg[4] = ((uint8_t)(addr));               // high byte of address
00263     return (can_send_timeout (CMNDID, T5TxMsg, 8, T5MESSAGETIMEOUT));
00264 }
00265 
00266 //
00267 // t5_boot_checksum_command
00268 //
00269 // Send the checksum command to Bootloader
00270 //
00271 // inputs:    none
00272 // return:    bool TRUE if message was sent OK,
00273 //                 FALSE if message could not be sent.
00274 //
00275 bool t5_boot_checksum_command(uint32_t* result) {
00276     *result = 0;
00277     // send a can message to the T5 requesting that it calculates the BIN file checksum
00278     char T5TxMsg[] = T5SUMCMND;
00279     if (!can_send_timeout (CMNDID, T5TxMsg, 8, T5MESSAGETIMEOUT))
00280         return FALSE;
00281     // wait for the T5 to reply
00282     char T5RxMsg[8];
00283     // if a message is not received, has the wrong type or indicates an error then there is a problem
00284     if ((!can_wait_timeout(RESPID, T5RxMsg, 8, T5CHECKSUMTIMEOUT)) || (T5RxMsg[0] != T5TxMsg[0]) || (T5RxMsg[1] != 0x00))
00285         return FALSE;
00286 // get the checksum
00287     for (uint8_t i=0; i<4; i++) {
00288         *result <<= 8;
00289         *result |= T5RxMsg[i+2];
00290     }
00291     return TRUE;
00292 }
00293 
00294 //
00295 // t5_boot_reset_command
00296 //
00297 // Send 'exit and restart T5' command to the Bootloader
00298 //
00299 // inputs:    none
00300 // return:    bool TRUE if message was sent OK,
00301 //                 FALSE if message could not be sent.
00302 //
00303 bool t5_boot_reset_command() {
00304     // send a can message to the T5 telling it to reset the ECU
00305     char T5TxMsg[] = T5RSTCMND;
00306     if (!can_send_timeout (CMNDID, T5TxMsg, 8, T5MESSAGETIMEOUT))
00307         return FALSE;
00308     // wait for the T5 to reply
00309     char T5RxMsg[8];
00310     // if a message is not received, has the wrong type or indicates an error then there is a problem
00311     return ((!can_wait_timeout(RESPID, T5RxMsg, 8, T5MESSAGETIMEOUT)) || (T5RxMsg[0] != T5TxMsg[0]) || (T5RxMsg[1] != 0x00))
00312         ? FALSE : TRUE;
00313 //    if ((!can_wait_timeout(RESPID, T5RxMsg, 8, T5MESSAGETIMEOUT)) || (T5RxMsg[0] != T5TxMsg[0]) || (T5RxMsg[1] != 0x00))
00314 //        return FALSE;
00315     // wait for the T5 to reset
00316     // if a message is not received, has the wrong type or indicates an error then there is a problem
00317 //    return (!can_wait_timeout(RSETID, T5RxMsg, 8, T5MESSAGETIMEOUT))
00318 //        ? FALSE : TRUE;
00319 }
00320 
00321 //-----------------------------------------------------------------------------
00322 /**
00323     t5_boot_get_flash_type
00324     Send 'get FLASH chip types' command to the Bootloader
00325 
00326     @param      result      start address of T5.x FLASH
00327                 make        FLASH chip manufacturer code
00328                 type        FLASH chip type code
00329 
00330     @return     bool        TRUE if message was sent OK,
00331                             FALSE if message could not be sent.
00332 */
00333 bool t5_boot_get_flash_type(uint32_t* result, uint8_t* make, uint8_t* type) {
00334     *result = 0;
00335     *make = 0;
00336     *type = 0;
00337     // send a can message to the T5 requesting that it tells us the type of FLASH chips
00338     char T5TxMsg[] = T5TYPCMND;
00339     if (!can_send_timeout (CMNDID, T5TxMsg, 8, T5MESSAGETIMEOUT))
00340         return FALSE;
00341     // wait for the T5 to reply
00342     char T5RxMsg[8];
00343     // if a message is not received, has the wrong type or indicates an error then there is a problem
00344     if ((!can_wait_timeout(RESPID, T5RxMsg, 8, T5MESSAGETIMEOUT)) || (T5RxMsg[0] != T5TxMsg[0]) || (T5RxMsg[1] != 0x00))
00345         return FALSE;
00346     // get the start address
00347     for (uint8_t i=0; i<4; i++) {
00348         *result <<= 8;
00349         *result |= T5RxMsg[i+2];
00350     }
00351     // get the manufacture code
00352     *make = T5RxMsg[6];
00353     // get the FLASH type code
00354     *type = T5RxMsg[7];
00355     return TRUE;
00356 }
00357 
00358 //-----------------------------------------------------------------------------
00359 /**
00360     t5_boot_erase_command
00361     Send 'erase FLASH chip types' command to the Bootloader
00362 
00363     @param      none
00364 
00365     @return     bool        TRUE if message was sent OK,
00366                             FALSE if message could not be sent.
00367 */
00368 bool t5_boot_erase_command() {
00369     // send a can message to the T5 telling it to erase the FLASH chips
00370     char T5TxMsg[] = T5ERACMND;
00371     if (!can_send_timeout (CMNDID, T5TxMsg, 8, T5MESSAGETIMEOUT))
00372         return FALSE;
00373     // wait for the T5 to reply
00374     char T5RxMsg[8];
00375     // if a message is not received, has the wrong type or indicates an error then there is a problem
00376     return ((!can_wait_timeout(RESPID, T5RxMsg, 8, T5ERASETIMEOUT)) || (T5RxMsg[0] != T5TxMsg[0]) || (T5RxMsg[1] != 0x00))
00377         ? FALSE : TRUE;
00378 }
00379 
00380 //-----------------------------------------------------------------------------
00381 /**
00382     t5_boot_c3_command
00383     Send 'C3 - Get last address' command to the Bootloader
00384 
00385     @param      result      last address of T5 FLASH
00386                 mode        might indicate if bootloader is loaded
00387 
00388     @return     bool        TRUE if message was sent OK,
00389                             FALSE if message could not be sent.
00390 */
00391 bool t5_boot_c3_command(uint32_t* result, uint16_t* mode) {
00392     *result = 0;
00393     *mode = 0;
00394     // send a can message to the T5 requesting that it tells us the last address of FLASH
00395     char T5TxMsg[] = T5EOFCMND;
00396     if (!can_send_timeout (CMNDID, T5TxMsg, 8, T5MESSAGETIMEOUT))
00397         return FALSE;
00398     // wait for the T5 to reply
00399     char T5RxMsg[8];
00400     // if a message is not received, has the wrong type or indicates an error then there is a problem
00401     if ((!can_wait_timeout(RESPID, T5RxMsg, 8, T5MESSAGETIMEOUT)) || (T5RxMsg[0] != T5TxMsg[0]) || (T5RxMsg[1] != 0x00))
00402         return FALSE;
00403 // get the checksum
00404     for (uint8_t i=0; i<4; i++) {
00405         *result <<= 8;
00406         *result |= T5RxMsg[i+2];
00407     }
00408     for (uint8_t i=0; i<2; i++) {
00409         *mode <<= 8;
00410         *mode |= T5RxMsg[i+6];
00411     }
00412     return TRUE;
00413 }