Sophie Dexter
/
Just4Trionic
Just4Trionic - CAN and BDM FLASH programmer for Saab cars
t5utils.cpp
- Committer:
- Just4pLeisure
- Date:
- 2016-04-23
- Revision:
- 6:2fbcbebed28c
- Parent:
- 3:92dae9083c83
File content as of revision 6:2fbcbebed28c:
/******************************************************************************* t5utils.cpp (c) 2010 by Sophie Dexter This C++ module provides functions for communicating simple messages to and from the T5 ECU ******************************************************************************** WARNING: Use at your own risk, sadly this software comes with no guarantees. This software is provided 'free' and in good faith, but the author does not accept liability for any damage arising from its use. *******************************************************************************/ #include "t5utils.h" // // T5Open enables the CAN chip and sets the CAN speed to 615 kbits. // // This function is a 'quick fix' for now. // // inputs: none // return: bool TRUE if all went OK, // bool T5Open() { can_open (); return TRUE; } // // T5Close disables the CAN chip. // // This function is a 'quick fix' for now. // // inputs: none // return: bool TRUE if all went OK, // bool T5Close() { can_close (); return TRUE; } // // T5WaitResponse // // Waits for a response message with the correct message id from the T5 ECU. // The response is a single ascii character from the symboltable. // // Returns an error ('BELL' character) if: // a response is not received before the timeout // the message length is less than 8 bytes (all messages should be 8 bytes) // the message type is incorrect // // inputs: none // return: a single char that is the response from the T5 ECU // char T5WaitResponse() { char T5RxMsg[8]; if (!can_wait_timeout(RESPID, T5RxMsg, 8, T5MESSAGETIMEOUT)) return '\a'; if (T5RxMsg[0] != 0xC6) return '\a'; return T5RxMsg[2]; } // // // T5WaitResponsePrint // // Waits for a response message with the correct message id from the T5 ECU and displays the whole message: // // wiiildddddddddddddddd // iii - is the CAN message id // l - is the message length, should always be 8 for T5 messages // dd,dd,dd,dd,dd,dd,dd,dd are the CAN message data bytes // // Returns an error if: // a response is not received before the timeout // the message length is less than 8 bytes (all messages should be 8 bytes) // the message type is incorrect // // Inputs: none // return: bool TRUE if a qualifying message was received // FALSE if a message wasn't received in time, had the wrong id etc... // bool T5WaitResponsePrint() { char T5RxMsg[8]; if (!can_wait_timeout(RESPID, T5RxMsg, 8, T5MESSAGETIMEOUT)) return FALSE; printf("w%03x8", RESPID); for (char i=0; i<8; i++) { printf("%02x", T5RxMsg[i]); } printf("\n\r"); return TRUE; } // T5GetSymbol // // Reads a single symbol name (in the symbol table) from the T5 ECU. // T5GetSymbol sends ACK messages to the T5 ECU and stores the // reply characters in a string until a '\n' character is received // when the function returns with the pointer to that string. // // inputs: a pointer to the string used to store the symbol name. // return: a pointer to the string used to store the symbol name. // char *T5GetSymbol(char *s) { do { if (T5Ack()) { } *s = T5WaitResponse(); } while (*s++ != '\n'); *s = '\0'; return s; } // T5ReadCmnd // // Sends a 'read' type command to the T5 ECU. 'read' commands are used to read something from the T5 ECU. // // inputs: a 'char' which is the type of 'read' requested (e.g. symbol table, version etc). // return: bool TRUE if the message was sent within the timeout period, // FALSE if the message couldn't be sent. // bool T5ReadCmnd(char c) { char T5TxMsg[] = T5_RDCMND; T5TxMsg[1] = c; return (can_send_timeout (CMNDID, T5TxMsg, 8, T5MESSAGETIMEOUT)); } // // T5WriteCmnd is unfinished // bool T5WriteCmnd(unsigned int addr, char data) { return FALSE; } // t5_can_read_data // // Reads 6 bytes of the data from the SRAM or FLASH in the T5 ECU. // // There is something back-to-front about the way this works, but it does :-) // // inputs: a pointer to an array of 6 bytes for storing the data read from the T5 ECU. // the address to read SRAM data from in the T5 ECU // return: a pointer to an array of 6 bytes for storing the data read from the T5 ECU. // bool TRUE if the message was sent within the timeout period, // FALSE if the message couldn't be sent. // bool t5_can_read_data(char *data, uint32_t addr) { // send a can message to the T5 with the address we want to read from char T5TxMsg[] = T5RAMCMND; T5TxMsg[1] = ((uint8_t)(addr >> 24)); // high high byte of address T5TxMsg[2] = ((uint8_t)(addr >> 16)); // high low byte of address T5TxMsg[3] = ((uint8_t)(addr >> 8)); // low high byte of address T5TxMsg[4] = ((uint8_t)(addr)); // low low byte of address // if the message cannot be sent then there is a problem if (!can_send_timeout (CMNDID, T5TxMsg, 8, T5MESSAGETIMEOUT)) return FALSE; // wait for the T5 to reply with some data char T5RxMsg[8]; // if a message is not received, has the wrong type or indicates an error then there is a problem if ((!can_wait_timeout(RESPID, T5RxMsg, 8, T5MESSAGETIMEOUT)) || (T5RxMsg[0] != T5TxMsg[0]) || (T5RxMsg[1] != 0x00)) return FALSE; for (int i=2; i<8; i++) data[7-i] = T5RxMsg[i]; return TRUE; } // T5Ack // // Sends an 'ACK' message to the T5 ECU to prompt the T5 to send the next // ascii character from the symboltable // // Returns an error if: // the 'ACK' message cannot be sent before the timeout // // inputs: none // return: bool TRUE if message was sent OK, // FALSE if message could not be sent. bool T5Ack() { char T5TxMsg[] = T5ACKCMND; return (can_send_timeout (CMNDID, T5TxMsg, 8, T5MESSAGETIMEOUT)); } // // t5_can_send_boot_address // // Send an address where 'bootloader' or FLASH CAN messages are uploaded to. // The number of bytes (up to 0x7F) that will be sent in the following CAN messages is also sent. // // inputs: an unsigned int, the address where messages should be sent. // an int, the number of bytes (up to 0x7F) that will be sent in the following CAN messages. // return: bool TRUE if message was sent OK, // FALSE if message could not be sent. // bool t5_can_send_boot_address(uint32_t addr, uint8_t len) { // send a can message to the T5 with the address and number of bytes we are going to send char T5TxMsg[] = T5_BTCMND; T5TxMsg[1] = ((uint8_t)(addr >> 24)); // high high byte of address T5TxMsg[2] = ((uint8_t)(addr >> 16)); // high low byte of address T5TxMsg[3] = ((uint8_t)(addr >> 8)); // low high byte of address T5TxMsg[4] = ((uint8_t)(addr)); // low low byte of address T5TxMsg[5] = (len); // number of bytes to upload (sent in following messages) // if the message cannot be sent then there is a problem if (!can_send_timeout (CMNDID, T5TxMsg, 8, T5MESSAGETIMEOUT)) return FALSE; // wait for the T5 to reply char T5RxMsg[8]; // if a message is not received, has the wrong type or indicates an error then there is a problem return ((!can_wait_timeout(RESPID, T5RxMsg, 8, T5MESSAGETIMEOUT)) || (T5RxMsg[0] != T5TxMsg[0]) || (T5RxMsg[1] != 0x00)) ? FALSE : TRUE; } // // t5_can_send_boot_frame // // Upload 'bootloader' or new FLASH byts to T5 ECU in CAN messages // // The CAN messages are made up of 1 byte which is added to the address given in the T5SendBootAddress meaassge // followed by 7 bytes of data. // The first byte normally starts at 0x00 and increases by 7 in following messages until another T5SendBootAddress message is sent e.g. // 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. // 07,dd,dd,dd,dd,dd,dd,dd,dd // 0E,dd,dd,dd,dd,dd,dd,dd,dd (0x0E is 14) // 15,dd,dd,dd,dd,dd,dd,dd,dd (0x15 is 21) // etc. // // inputs: a pointer to an array of 8 bytes to be sent to the T5 ECU SRAM or FLASH. // return: bool TRUE if message was sent OK, // FALSE if message could not be sent. // bool t5_can_send_boot_frame (char *T5TxMsg) { // send a can message to the T5 with the bytes we are sending if (!can_send_timeout (CMNDID, T5TxMsg, 8, T5MESSAGETIMEOUT)) return FALSE; // wait for the T5 to reply char T5RxMsg[8]; // if a message is not received, has the wrong type or indicates an error then there is a problem return ((!can_wait_timeout(RESPID, T5RxMsg, 8, T5MESSAGETIMEOUT)) || (T5RxMsg[0] != T5TxMsg[0]) || (T5RxMsg[1] != 0x00)) ? FALSE : TRUE; } // // T5StartBootLoader // // Send the jump to address to the T5 ECU for starting the 'bootloader'. // The jump address must be somewhere in RAM (addresses 0x0000 to 0x8000). // (The start address comes from the S7/8/9 line in the S19 file.) // // inputs: an unsigned int, the address to jump to start of 'bootloader'. // return: bool TRUE if message was sent OK, // FALSE if message could not be sent. // bool T5StartBootLoader (uint32_t addr) { char T5TxMsg[] = T5JMPCMND; T5TxMsg[3] = ((uint8_t)(addr >> 8)); // low byte of address T5TxMsg[4] = ((uint8_t)(addr)); // high byte of address return (can_send_timeout (CMNDID, T5TxMsg, 8, T5MESSAGETIMEOUT)); } // // t5_boot_checksum_command // // Send the checksum command to Bootloader // // inputs: none // return: bool TRUE if message was sent OK, // FALSE if message could not be sent. // bool t5_boot_checksum_command(uint32_t* result) { *result = 0; // send a can message to the T5 requesting that it calculates the BIN file checksum char T5TxMsg[] = T5SUMCMND; if (!can_send_timeout (CMNDID, T5TxMsg, 8, T5MESSAGETIMEOUT)) return FALSE; // wait for the T5 to reply char T5RxMsg[8]; // if a message is not received, has the wrong type or indicates an error then there is a problem if ((!can_wait_timeout(RESPID, T5RxMsg, 8, T5CHECKSUMTIMEOUT)) || (T5RxMsg[0] != T5TxMsg[0]) || (T5RxMsg[1] != 0x00)) return FALSE; // get the checksum for (uint8_t i=0; i<4; i++) { *result <<= 8; *result |= T5RxMsg[i+2]; } return TRUE; } // // t5_boot_reset_command // // Send 'exit and restart T5' command to the Bootloader // // inputs: none // return: bool TRUE if message was sent OK, // FALSE if message could not be sent. // bool t5_boot_reset_command() { // send a can message to the T5 telling it to reset the ECU char T5TxMsg[] = T5RSTCMND; if (!can_send_timeout (CMNDID, T5TxMsg, 8, T5MESSAGETIMEOUT)) return FALSE; // wait for the T5 to reply char T5RxMsg[8]; // if a message is not received, has the wrong type or indicates an error then there is a problem return ((!can_wait_timeout(RESPID, T5RxMsg, 8, T5MESSAGETIMEOUT)) || (T5RxMsg[0] != T5TxMsg[0]) || (T5RxMsg[1] != 0x00)) ? FALSE : TRUE; // if ((!can_wait_timeout(RESPID, T5RxMsg, 8, T5MESSAGETIMEOUT)) || (T5RxMsg[0] != T5TxMsg[0]) || (T5RxMsg[1] != 0x00)) // return FALSE; // wait for the T5 to reset // if a message is not received, has the wrong type or indicates an error then there is a problem // return (!can_wait_timeout(RSETID, T5RxMsg, 8, T5MESSAGETIMEOUT)) // ? FALSE : TRUE; } //----------------------------------------------------------------------------- /** t5_boot_get_flash_type Send 'get FLASH chip types' command to the Bootloader @param result start address of T5.x FLASH make FLASH chip manufacturer code type FLASH chip type code @return bool TRUE if message was sent OK, FALSE if message could not be sent. */ bool t5_boot_get_flash_type(uint32_t* result, uint8_t* make, uint8_t* type) { *result = 0; *make = 0; *type = 0; // send a can message to the T5 requesting that it tells us the type of FLASH chips char T5TxMsg[] = T5TYPCMND; if (!can_send_timeout (CMNDID, T5TxMsg, 8, T5MESSAGETIMEOUT)) return FALSE; // wait for the T5 to reply char T5RxMsg[8]; // if a message is not received, has the wrong type or indicates an error then there is a problem if ((!can_wait_timeout(RESPID, T5RxMsg, 8, T5MESSAGETIMEOUT)) || (T5RxMsg[0] != T5TxMsg[0]) || (T5RxMsg[1] != 0x00)) return FALSE; // get the start address for (uint8_t i=0; i<4; i++) { *result <<= 8; *result |= T5RxMsg[i+2]; } // get the manufacture code *make = T5RxMsg[6]; // get the FLASH type code *type = T5RxMsg[7]; return TRUE; } //----------------------------------------------------------------------------- /** t5_boot_erase_command Send 'erase FLASH chip types' command to the Bootloader @param none @return bool TRUE if message was sent OK, FALSE if message could not be sent. */ bool t5_boot_erase_command() { // send a can message to the T5 telling it to erase the FLASH chips char T5TxMsg[] = T5ERACMND; if (!can_send_timeout (CMNDID, T5TxMsg, 8, T5MESSAGETIMEOUT)) return FALSE; // wait for the T5 to reply char T5RxMsg[8]; // if a message is not received, has the wrong type or indicates an error then there is a problem return ((!can_wait_timeout(RESPID, T5RxMsg, 8, T5ERASETIMEOUT)) || (T5RxMsg[0] != T5TxMsg[0]) || (T5RxMsg[1] != 0x00)) ? FALSE : TRUE; } //----------------------------------------------------------------------------- /** t5_boot_c3_command Send 'C3 - Get last address' command to the Bootloader @param result last address of T5 FLASH mode might indicate if bootloader is loaded @return bool TRUE if message was sent OK, FALSE if message could not be sent. */ bool t5_boot_c3_command(uint32_t* result, uint16_t* mode) { *result = 0; *mode = 0; // send a can message to the T5 requesting that it tells us the last address of FLASH char T5TxMsg[] = T5EOFCMND; if (!can_send_timeout (CMNDID, T5TxMsg, 8, T5MESSAGETIMEOUT)) return FALSE; // wait for the T5 to reply char T5RxMsg[8]; // if a message is not received, has the wrong type or indicates an error then there is a problem if ((!can_wait_timeout(RESPID, T5RxMsg, 8, T5MESSAGETIMEOUT)) || (T5RxMsg[0] != T5TxMsg[0]) || (T5RxMsg[1] != 0x00)) return FALSE; // get the checksum for (uint8_t i=0; i<4; i++) { *result <<= 8; *result |= T5RxMsg[i+2]; } for (uint8_t i=0; i<2; i++) { *mode <<= 8; *mode |= T5RxMsg[i+6]; } return TRUE; }