Just4Trionic - CAN and BDM FLASH programmer for Saab cars

Dependencies:   mbed

T5Utils.cpp

Committer:
Just4pLeisure
Date:
2010-05-19
Revision:
0:e0b964252a05

File content as of revision 0:e0b964252a05:

/*******************************************************************************

T5Utils.cpp - By Sophie Dexter, April 2010

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() {
    CANOpen ();
    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() {
    CANClose ();
    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 (!CANWaitTimeout(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 (!CANWaitTimeout(RESPID, T5RxMsg, 8, T5CHECKSUMTIMEOUT)) 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 (CANSendTimeout (CMNDID, T5TxMsg, 8, T5MESSAGETIMEOUT));
}

//
// T5WriteCmnd is unfinished
//
bool T5WriteCmnd(unsigned int addr, char data) {
    return FALSE;
}

// T5ReadRAM
//
// Reads 6 bytes of the adaption data from the SRAM in the T5 ECU.
//
// 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.
//
char *T5ReadRAM(char *data, unsigned int addr) {
    T5RAMCmnd(addr);
    T5WaitRAM(data);
    return data;
}

// T5ReadFLASH
//
// Reads 6 bytes of the FLASH in the T5 ECU.
//
// 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.
//
char *T5ReadFLASH(char *data, unsigned int addr) {
    T5RAMCmnd(addr);
    T5WaitRAM(data);
    return data;
}

//
// T5RAMCmnd
//
// Sends a command to the ECU asking the T5 ECU to send some SRAM data
//
// inputs:    the address to read SRAM data from in the T5 ECU
// return:    bool TRUE if the message was sent within the timeout period,
//                 FALSE if the message couldn't be sent.
//
bool T5RAMCmnd(unsigned int addr) {
    char T5TxMsg[] = T5RAMCMND;
    T5TxMsg[1] = ((char)(addr >> 24));         // high high byte of address
    T5TxMsg[2] = ((char)(addr >> 16));         // high low byte of address
    T5TxMsg[3] = ((char)(addr >> 8));          // low high byte of address
    T5TxMsg[4] = ((char)(addr));               // low low byte of address
    return (CANSendTimeout (CMNDID, T5TxMsg, 8, T5MESSAGETIMEOUT));
}

//
// T5WaitRAM
//
// Waits for the T5 ECU to send some SRAM data
//
// 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.
// return:    a pointer to an array of 6 bytes for storing the data read from the T5 ECU.
//
char *T5WaitRAM(char *data) {
    char T5RxMsg[8];
    CANWaitTimeout(RESPID, T5RxMsg, 8, T5MESSAGETIMEOUT);
//    if (T5RxMsg[0] != 0xC6) return FALSE;
//    if (T5RxMsg[0] != 0x0C) return FALSE;
    for (int i=2; i<8; i++)
        data[7-i] = T5RxMsg[i];
    return data;
}

// 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 (CANSendTimeout (CMNDID, T5TxMsg, 8, T5MESSAGETIMEOUT));
}

//
// T5SendBootAddress
//
// 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 T5SendBootAddress(unsigned int addr, int len) {
    char T5TxMsg[] = T5_BTCMND;
    T5TxMsg[1] = ((char)(addr >> 24));         // high high byte of address
    T5TxMsg[2] = ((char)(addr >> 16));         // high low byte of address
    T5TxMsg[3] = ((char)(addr >> 8));          // low high byte of address
    T5TxMsg[4] = ((char)(addr));               // low low byte of address
    T5TxMsg[5] = ((char)(len));                // number of bytes to upload (sent in following messages)
    return (CANSendTimeout (CMNDID, T5TxMsg, 8, T5MESSAGETIMEOUT));
}

// 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 T5SendBootFrame (char *frame) {
    return (CANSendTimeout (CMNDID, frame, 8, T5MESSAGETIMEOUT));
}

//
// 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 (unsigned int addr) {
    char T5TxMsg[] = T5JMPCMND;
    T5TxMsg[3] = ((char)(addr >> 8));          // low byte of address
    T5TxMsg[4] = ((char)(addr));               // high byte of address
    return (CANSendTimeout (CMNDID, T5TxMsg, 8, T5MESSAGETIMEOUT));
}

//
// T5BootCSumCmnd
//
// Send the checksum command to Bootloader
//
// inputs:    none
// return:    bool TRUE if message was sent OK,
//                 FALSE if message could not be sent.
//
bool T5BootCSumCmnd() {
    char T5TxMsg[] = T5SUMCMND;
    return (CANSendTimeout (CMNDID, T5TxMsg, 8, T5MESSAGETIMEOUT));
}

//
// T5BootResetCmnd
//
// 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 T5BootResetCmnd() {
    char T5TxMsg[] = T5RSTCMND;
    return (CANSendTimeout (CMNDID, T5TxMsg, 8, T5MESSAGETIMEOUT));
}

//
// T5BootFLASHType
//
// Send 'get FLASH chip types' command to the Bootloader
//
// inputs:    none
// return:    bool TRUE if message was sent OK,
//                 FALSE if message could not be sent.
//
bool T5BootFLASHType() {
    char T5TxMsg[] = T5TYPCMND;
    return (CANSendTimeout (CMNDID, T5TxMsg, 8, T5MESSAGETIMEOUT));
}

//
// T5BootEraseCmnd
//
// Send 'erase FLASH chip types' command to the Bootloader
//
// inputs:    none
// return:    bool TRUE if message was sent OK,
//                 FALSE if message could not be sent.
//
bool T5BootEraseCmnd() {
    char T5TxMsg[] = T5ERACMND;
    return (CANSendTimeout (CMNDID, T5TxMsg, 8, T5MESSAGETIMEOUT));
}

//
// T5BootDumpFLASHCmnd
//
// Send 'Dump FLASH BIN file' command
//
// inputs:    none
// return:    bool TRUE if message was sent OK,
//                 FALSE if message could not be sent.
//
extern bool T5BootDumpFLASHCmnd() {
    char T5TxMsg[] = T5DMPCMND;
    return (CANSendTimeout (CMNDID, T5TxMsg, 8, T5MESSAGETIMEOUT));
}

//
// T5WaitFLASH
//
// Waits for the T5 ECU to send 4 bytes of FLASH data when dumping the FLASH
//
// CAN messages look like this:
// A6,04,dd,dd,dd,dd,08,08
// A6 - means FLASH dump type message
//    04 - means (at least) 4 more bytes still to come
//       dd,dd,dd,dd are 4 data bytes
// The last message looks like this:
// A6,00,dd,dd,dd,dd,08,08
// A6 - means FLASH dump type message
//    00 - means no more bytes after this CAN message
//       dd,dd,dd,dd are the last 4 data bytes
//
// inputs:    a pointer to an array of 8 bytes for the CAN message containing FLASH data.
// return:    a pointer to an array of 8 bytes for the CAN message containing FLASH data.
//
char *T5WaitFLASH(char *data) {
    char T5RxMsg[8];
    CANWaitTimeout(RESPID, T5RxMsg, 8, T5MESSAGETIMEOUT);
//    if (T5RxMsg[0] != 0xC6) return FALSE;
//    if (T5RxMsg[0] != 0x0C) return FALSE;
    for (int i=0; i<8; i++)
        data[i] = T5RxMsg[i];
    return data;
}

//
// T5BootResetCmnd
//
// Send 'C3 - Get last address' command to the Bootloader
//
// inputs:    none
// return:    bool TRUE if message was sent OK,
//                 FALSE if message could not be sent.
//
bool T5BootC3Command() {
    char T5TxMsg[] = T5EOFCMND;
    return (CANSendTimeout (CMNDID, T5TxMsg, 8, T5MESSAGETIMEOUT));
}