Sophie Dexter
/
Just4Trionic
Just4Trionic - CAN and BDM FLASH programmer for Saab cars
Diff: t5utils.cpp
- Revision:
- 1:d5452e398b76
- Child:
- 3:92dae9083c83
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/t5utils.cpp Tue Sep 14 21:02:04 2010 +0000 @@ -0,0 +1,411 @@ +/******************************************************************************* + +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 + 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; +} \ No newline at end of file