Sophie Dexter
/
Just4Trionic
Just4Trionic - CAN and BDM FLASH programmer for Saab cars
Embed:
(wiki syntax)
Show/hide line numbers
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 }
Generated on Fri Jul 15 2022 00:43:05 by 1.7.2