Just4Trionic - CAN and BDM FLASH programmer for Saab cars

Dependencies:   mbed

gmlan.cpp

Committer:
Just4pLeisure
Date:
2013-09-11
Revision:
4:682d96ff6d79
Child:
5:1775b4b13232

File content as of revision 4:682d96ff6d79:

#include "gmlan.h"

void GMLANTesterPresentAll()
{
    char GMLANMsg[] = GMLANTesterPresentFunctional;
    can_send_timeout(GMLANALLNODES, GMLANMsg, 3, GMLANPTCT);
    ACTIVITYLEDON;
}

void GMLANTesterPresentT8()
{
    char GMLANMsg[] = GMLANTesterPresentPhysical;
    can_send_timeout(T8RequestId, GMLANMsg, 8, GMLANPTCT);
    can_wait_timeout(T8ResponseId, GMLANMsg, 8, GMLANPTCT);
    ACTIVITYLEDON;
}

// All steps needed in preparation for using a bootloader ('Utility File' in GMLAN parlance)
bool GMLANprogrammingSetupProcess()
{
    printf("Starting Diagnostic session\r\n");
    if (!GMLANinitiateDiagnostic(GMLANdisableAllDTCs)) {
        printf("Unable to start Diagnostic session\r\n");
        return FALSE;
    }
    printf("Disabling Normal Communincation Messages\r\n");
    if (!GMLANdisableNormalCommunication()) {
        printf("Unable to tell T8 to disable normal communication messages\r\n");
        return FALSE;
    }
    printf("Report Programmed State\r\n");
    if (!GMLANReportProgrammedState()) {
        printf("Unable to determine ECU programmed state\r\n");
        return FALSE;
    }
    printf("Requesting program mode\r\n");
    if (!GMLANProgrammingMode(GMLANRequestProgrammingNormal)) {
        printf("Unable to request programming mode\r\n");
        return FALSE;
    }
    printf("Starting program session\r\n");
    if (!GMLANProgrammingMode(GMLANEnableProgrammingMode)) {
        printf("Unable to start program session\r\n");
        return FALSE;
    }
    return TRUE;
}


// All steps needed to transfer and start a bootloader ('Utility File' in GMLAN parlance)
bool GMLANprogrammingUtilityFileProcess(char UtilityFile[])
{
    uint16_t i = 0, j = 0, k = 0;
    uint32_t StartAddress = 0x102400;
    uint16_t txpnt = 0;
    char iFrameNumber = 0x21;
    char GMLANMsg[8];
    //char BootLoader[] = T8Bootloader;
//
    printf("Waiting for Permission to send bootloader\r\n");
    if (!GMLANRequestDownload(GMLANRequestDownloadModeNormal)) {
        printf("Unable to request Bootloader Upload\r\n");
        return FALSE;
    }
    printf("Sending Bootloader\r\n");
    printf("  0.00 %% complete.\r");
//
    for (i=0; i<0x46; i++) {
        if (!GMLANDataTransferFirstFrame(0xF0, GMLANDOWNLOAD, StartAddress)) {
            printf("Unable to start Bootloader Upload\r\n");
            return FALSE;
        }
        iFrameNumber = 0x21;
        for (j=0; j < 0x22; j++) {
            GMLANMsg[0] = iFrameNumber;
            for (k=1; k<8; k++)
                GMLANMsg[k] = UtilityFile[txpnt++];
#ifdef DEBUG
            for (k = 0; k < 8; k++ ) printf("0x%02X ", GMLANMsg[k] );
            printf("\r\n");
#endif
            if (!can_send_timeout(T8RequestId, GMLANMsg, 8, GMLANPTCT)) {
                printf("Unable to send Bootloader\r\n");
                return FALSE;
            }
            ++iFrameNumber &= 0x2F;
            wait_ms(1);
//            wait_us(500);
        }
        if (!can_wait_timeout(T8ResponseId, GMLANMsg, 8, GMLANPTCT)) {
            printf("I didn't receive a block acknowledge message\r\n");
            return FALSE;
        }
        while (GMLANMsg[0] == 0x03 && GMLANMsg[1] == 0x7F && GMLANMsg[2] == 0x36 && GMLANMsg[3] == 0x78) {
            printf("I'm waiting for a BootLoader Block to upload\r\n");
            if (!can_wait_timeout(T8ResponseId, GMLANMsg, 8, GMLANPTCTENHANCED)) {
                printf("I didn't receive a block acknowledge message after enhanced timeout\r\n");
                return FALSE;
            }
        }
#ifdef DEBUG
        for (k = 0; k < 8; k++ ) printf("0x%02X ", GMLANMsg[k] );
        printf("\r\n");
#endif
        if ( GMLANMsg[0] == 0x03 && GMLANMsg[1] == 0x7F && GMLANMsg[2] == 0x36 ) {
            GMLANShowReturnCode(GMLANMsg[3]);
            return FALSE;
        }
        if (GMLANMsg[0] != 0x01 && GMLANMsg[1] != 0x76) {
            printf("EXITING due to an unexpected CAN message\r\n");
            return FALSE;
        }
        GMLANTesterPresentT8();
        ACTIVITYLEDON;
        StartAddress += 0xea;
        printf("%6.2f\r", 100*(float)txpnt/(float)(16384+(70*4)) );
    }
    wait_ms(1);
    if (!GMLANDataTransferFirstFrame(0x0A, GMLANDOWNLOAD, StartAddress)) {
        printf("Unable to finish Bootloader Upload\r\n");
        return FALSE;
    }
    iFrameNumber = 0x21;
    GMLANMsg[0] = iFrameNumber;
    for (k=0; k<7; k++) {
        GMLANMsg[k+1] = UtilityFile[txpnt++];
    }
    if (!can_send_timeout(T8RequestId, GMLANMsg, 8, GMLANPTCT)) {
        printf("Unable to finish sending Bootloader\r\n");
        return FALSE;
    }
    if (!can_wait_timeout(T8ResponseId, GMLANMsg, 8, GMLANPTCT))
        return FALSE;
#ifdef DEBUG
    for (k = 0; k < 8; k++ ) printf("0x%02X ", GMLANMsg[k] );
    printf("\r\n");
#endif
    printf("%6.2f\r\n", (float)100 );
    printf("Starting the bootloader\r\n");
    if (!GMLANDataTransfer(0x06, GMLANEXECUTE, 0x00102460)) {
        printf("Unable to start the Bootloader\r\n");
        return FALSE;
    }
    wait_ms(500);
    return TRUE;
}

bool GMLANinitiateDiagnostic(char level)
{
    char GMLANMsg[] = GMLANinitiateDiagnosticOperation;
    GMLANMsg[2] = level;
    if (!can_send_timeout(T8RequestId, GMLANMsg, 3, GMLANPTCT))
        return FALSE;
    if (!can_wait_timeout(T8ResponseId, GMLANMsg, 8, GMLANPTCT))
        return FALSE;
    while (GMLANMsg[0] == 0x03 && GMLANMsg[1] == 0x7F && GMLANMsg[2] == 0x10 && GMLANMsg[3] == 0x78)
        if (!can_wait_timeout(T8ResponseId, GMLANMsg, 8, GMLANPTCTENHANCED))
            return FALSE;
#ifdef DEBUG
    for (char k = 0; k < 8; k++ ) printf("0x%02X ", GMLANMsg[k] );
    printf("\r\n");
#endif
    if ( GMLANMsg[0] == 0x03 && GMLANMsg[1] == 0x7F && GMLANMsg[2] == 0x10 )
        GMLANShowReturnCode(GMLANMsg[3]);
    return (GMLANMsg[0] == 0x01 && GMLANMsg[1] == 0x50) ? TRUE : FALSE;
}


bool GMLANdisableNormalCommunication()
{
    char GMLANMsg[] = GMLANdisableCommunication;
    if (!can_send_timeout(T8RequestId, GMLANMsg, 2, GMLANPTCT))
        return FALSE;
    if (!can_wait_timeout(T8ResponseId, GMLANMsg, 8, GMLANPTCT))
        return FALSE;
    while (GMLANMsg[0] == 0x7F && GMLANMsg[2] == 0x78)
        if (!can_wait_timeout(T8ResponseId, GMLANMsg, 8, GMLANPTCTENHANCED))
            return FALSE;
#ifdef DEBUG
    for (char k = 0; k < 8; k++ ) printf("0x%02X ", GMLANMsg[k] );
    printf("\r\n");
#endif
    if ( GMLANMsg[0] == 0x03 && GMLANMsg[1] == 0x7F && GMLANMsg[2] == 0x28 )
        GMLANShowReturnCode(GMLANMsg[3]);
    return (GMLANMsg[0] == 0x01 && GMLANMsg[1] == 0x68) ? TRUE : FALSE;
}


bool GMLANReportProgrammedState()
{
    char GMLANMsg[] = GMLANReportProgrammed;
    if (!can_send_timeout(T8RequestId, GMLANMsg, 2, GMLANPTCT))
        return FALSE;
    if (!can_wait_timeout(T8ResponseId, GMLANMsg, 8, GMLANPTCT))
        return FALSE;
    while (GMLANMsg[0] == 0x7F && GMLANMsg[2] == 0x78)
        if (!can_wait_timeout(T8ResponseId, GMLANMsg, 8, GMLANPTCTENHANCED))
            return FALSE;
#ifdef DEBUG
    for (char k = 0; k < 8; k++ ) printf("0x%02X ", GMLANMsg[k] );
    printf("\r\n");
#endif
    if ( GMLANMsg[0] == 0x03 && GMLANMsg[1] == 0x7F && GMLANMsg[2] == 0xA2 )
        GMLANShowReturnCode(GMLANMsg[3]);
    return (GMLANMsg[0] == 0x02 && GMLANMsg[1] == 0xE2) ? TRUE : FALSE;
}


bool GMLANProgrammingMode(char mode)
{
    char GMLANMsg[] = GMLANProgramming;
    GMLANMsg[2] = mode;
#ifdef DEBUG
    for (char k = 0; k < 8; k++ ) printf("0x%02X ", GMLANMsg[k] );
    printf("\r\n");
#endif
    if (!can_send_timeout(T8RequestId, GMLANMsg, 3, GMLANPTCT))
        return FALSE;
    if (mode == GMLANEnableProgrammingMode)
        return TRUE;                            // No response expected when enabling program mode
    if (!can_wait_timeout(T8ResponseId, GMLANMsg, 8, GMLANPTCT))
        return FALSE;
    while (GMLANMsg[0] == 0x7F && GMLANMsg[2] == 0x78)
        if (!can_wait_timeout(T8ResponseId, GMLANMsg, 8, GMLANPTCTENHANCED))
            return FALSE;
#ifdef DEBUG
    for (char k = 0; k < 8; k++ ) printf("0x%02X ", GMLANMsg[k] );
    printf("\r\n");
#endif
    if ( GMLANMsg[0] == 0x03 && GMLANMsg[1] == 0x7F && GMLANMsg[2] == 0xA5 )
        GMLANShowReturnCode(GMLANMsg[3]);
    return (GMLANMsg[0] == 0x01 && GMLANMsg[1] == 0xE5) ? TRUE : FALSE;
}

bool GMLANSecurityAccessRequest(char level, uint16_t& seed)
{
    char GMLANMsg[] = GMLANSecurityAccessSeed;
    GMLANMsg[2] = level;
#ifdef DEBUG
    for (char k = 0; k < 8; k++ ) printf("0x%02X ", GMLANMsg[k] );
    printf("\r\n");
#endif
    if (!can_send_timeout(T8RequestId, GMLANMsg, 3, GMLANPTCT))
        return FALSE;
    if (!can_wait_timeout(T8ResponseId, GMLANMsg, 8, GMLANPTCT))
        return FALSE;
    while (GMLANMsg[0] == 0x7F && GMLANMsg[2] == 0x78)
        if (!can_wait_timeout(T8ResponseId, GMLANMsg, 8, GMLANPTCTENHANCED))
            return FALSE;
#ifdef DEBUG
    for (char k = 0; k < 8; k++ ) printf("0x%02X ", GMLANMsg[k] );
    printf("\r\n");
#endif
    seed = GMLANMsg[3] << 8 | GMLANMsg[4];
    if ( GMLANMsg[0] == 0x03 && GMLANMsg[1] == 0x7F && GMLANMsg[2] == 0x27 )
        GMLANShowReturnCode(GMLANMsg[3]);
    return (GMLANMsg[0] == 0x04 && GMLANMsg[1] == 0x67 && GMLANMsg[2] == level) ? TRUE : FALSE;
}

bool GMLANSecurityAccessSendKey(char level, uint16_t key)
{
    char GMLANMsg[] = GMLANSecurityAccessKey;
    GMLANMsg[2] = level+1;
    GMLANMsg[3] = (key >> 8) & 0xFF;
    GMLANMsg[4] = key & 0xFF;
#ifdef DEBUG
    for (char k = 0; k < 8; k++ ) printf("0x%02X ", GMLANMsg[k] );
    printf("\r\n");
#endif
    if (!can_send_timeout(T8RequestId, GMLANMsg, 5, GMLANPTCT))
        return FALSE;
    if (!can_wait_timeout(T8ResponseId, GMLANMsg, 8, GMLANPTCT))
        return FALSE;
    while (GMLANMsg[0] == 0x7F && GMLANMsg[2] == 0x78)
        if (!can_wait_timeout(T8ResponseId, GMLANMsg, 8, GMLANPTCTENHANCED))
            return FALSE;
#ifdef DEBUG
    for (char k = 0; k < 8; k++ ) printf("0x%02X ", GMLANMsg[k] );
    printf("\r\n");
#endif
    if ( GMLANMsg[0] == 0x03 && GMLANMsg[1] == 0x7F && GMLANMsg[2] == 0x27 )
        GMLANShowReturnCode(GMLANMsg[3]);
    return (GMLANMsg[0] == 0x02 && GMLANMsg[1] == 0x67 && GMLANMsg[2] == level+1) ? TRUE : FALSE;
}

bool GMLANRequestDownload(char dataFormatIdentifier)
{
    char GMLANMsg[] = GMLANRequestDownloadMessage;
    GMLANMsg[2] = dataFormatIdentifier;
#ifdef DEBUG
    for (char k = 0; k < 8; k++ ) printf("0x%02X ", GMLANMsg[k] );
    printf("\r\n");
#endif
    if (!can_send_timeout(T8RequestId, GMLANMsg, 7, GMLANPTCT))
        return FALSE;
    if (!can_wait_timeout(T8ResponseId, GMLANMsg, 8, GMLANPTCT))
        return FALSE;
//    while (GMLANMsg[0] == 0x7F && GMLANMsg[2] == 0x78)
    while (GMLANMsg[0] == 0x03 && GMLANMsg[1] == 0x7F && GMLANMsg[2] == 0x34 && GMLANMsg[3] == 0x78) {
        printf("Erasing\r\n");
        GMLANTesterPresentT8();
        ACTIVITYLEDON;
        if (!can_wait_timeout(T8ResponseId, GMLANMsg, 8, GMLANPTCTENHANCED))
            return FALSE;
    }
#ifdef DEBUG
    for (char k = 0; k < 8; k++ ) printf("0x%02X ", GMLANMsg[k] );
    printf("\r\n");
#endif
    if ( GMLANMsg[0] == 0x03 && GMLANMsg[1] == 0x7F && GMLANMsg[2] == 0x34 )
        GMLANShowReturnCode(GMLANMsg[3]);
    return (GMLANMsg[0] == 0x01 && GMLANMsg[1] == 0x74) ? TRUE : FALSE;
}


bool GMLANDataTransfer(char length, char function, uint32_t address)
{
    char GMLANMsg[8];
    GMLANMsg[0] = length;
    GMLANMsg[1] = 0x36;
    GMLANMsg[2] = function;
    GMLANMsg[3] = (char) (address >> 24);
    GMLANMsg[4] = (char) (address >> 16);
    GMLANMsg[5] = (char) (address >> 8);
    GMLANMsg[6] = (char) (address);
    GMLANMsg[7] = 0xaa;
#ifdef DEBUG
    for (char k = 0; k < 8; k++ ) printf("0x%02X ", GMLANMsg[k] );
    printf("\r\n");
#endif
    if (!can_send_timeout(T8RequestId, GMLANMsg, 8, GMLANPTCT))
        return FALSE;
    if (!can_wait_timeout(T8ResponseId, GMLANMsg, 8, GMLANPTCT))
        return FALSE;
    while (GMLANMsg[0] == 0x7F && GMLANMsg[2] == 0x78)
        if (!can_wait_timeout(T8ResponseId, GMLANMsg, 8, GMLANPTCTENHANCED))
            return FALSE;
#ifdef DEBUG
    for (char k = 0; k < 8; k++ ) printf("0x%02X ", GMLANMsg[k] );
    printf("\r\n");
#endif
    if ( GMLANMsg[0] == 0x03 && GMLANMsg[1] == 0x7F && GMLANMsg[2] == 0x36 )
        GMLANShowReturnCode(GMLANMsg[3]);
    return (GMLANMsg[0] == 0x01 && GMLANMsg[1] == 0x76) ? TRUE : FALSE;
}


bool GMLANDataTransferFirstFrame(char length, char function, uint32_t address)
{
    char GMLANMsg[8];
    GMLANMsg[0] = 0x10;
    GMLANMsg[1] = length;
    GMLANMsg[2] = 0x36;
    GMLANMsg[3] = function;
    GMLANMsg[4] = (char) (address >> 24);
    GMLANMsg[5] = (char) (address >> 16);
    GMLANMsg[6] = (char) (address >> 8);
    GMLANMsg[7] = (char) (address);
#ifdef DEBUG
    for (char k = 0; k < 8; k++ ) printf("0x%02X ", GMLANMsg[k] );
    printf("\r\n");
#endif
    if (!can_send_timeout(T8RequestId, GMLANMsg, 8, GMLANPTCT))
        return FALSE;
    if (!can_wait_timeout(T8ResponseId, GMLANMsg, 8, GMLANPTCT))
        return FALSE;
    while (GMLANMsg[0] == 0x7F && GMLANMsg[2] == 0x78)
        if (!can_wait_timeout(T8ResponseId, GMLANMsg, 8, GMLANPTCTENHANCED))
            return FALSE;
#ifdef DEBUG
    for (char k = 0; k < 8; k++ ) printf("0x%02X ", GMLANMsg[k] );
    printf("\r\n");
#endif
    if ( GMLANMsg[0] == 0x03 && GMLANMsg[1] == 0x7F && GMLANMsg[2] == 0x36 )
        GMLANShowReturnCode(GMLANMsg[3]);
    return (GMLANMsg[0] == 0x30 && GMLANMsg[1] == 0x00 && GMLANMsg[2] == 0x00) ? TRUE : FALSE;
}


bool GMLANDataTransferConsecutiveFrame(char framenumber, char data[7])
{
    char GMLANMsg[8];
    GMLANMsg[0] = framenumber;
    for (char k = 0; k < 7; k++ )
        GMLANMsg[k+1] = data[k];
#ifdef DEBUG
    for (char k = 0; k < 8; k++ ) printf("0x%02X ", GMLANMsg[k] );
    printf("\r\n");
#endif
    return (can_send_timeout(T8RequestId, GMLANMsg, 8, GMLANPTCT)) ? TRUE : FALSE;
}

bool GMLANReturnToNormalMode()
{
    char GMLANMsg[] = GMLANRetrunToNormalModeMessage;
    if (!can_send_timeout(T8RequestId, GMLANMsg, 2, GMLANPTCT))
        return FALSE;
    if (!can_wait_timeout(T8ResponseId, GMLANMsg, 8, GMLANPTCT))
        return FALSE;
    while (GMLANMsg[0] == 0x7F && GMLANMsg[2] == 0x78)
        if (!can_wait_timeout(T8ResponseId, GMLANMsg, 8, GMLANPTCTENHANCED))
            return FALSE;
#ifdef DEBUG
    for (char k = 0; k < 8; k++ ) printf("0x%02X ", GMLANMsg[k] );
    printf("\r\n");
#endif
    if ( GMLANMsg[0] == 0x03 && GMLANMsg[1] == 0x7F && GMLANMsg[2] == 0x28 )
        GMLANShowReturnCode(GMLANMsg[3]);
    return (GMLANMsg[0] == 0x01 && GMLANMsg[1] == 0x60) ? TRUE : FALSE;
}


void GMLANShowReturnCode(char returnCode)
{
    switch (returnCode) {
        case 0x11 :
            printf("0x11 - ServiceNotSupported\r\n");
            break;
        case 0x12 :
            printf("0x12 - SubFunctionNotSupported-InvalidFormat\r\n");
            break;
        case 0x22 :
            printf("0x22 - ConditionsNotCorrectOrRequestSequenceError\r\n");
            break;
        case 0x31 :
            printf("0x31 - RequestOutOfRange\r\n");
            break;
        case 0x35 :
            printf("0x35 - InvalidKey\r\n");
            break;
        case 0x36 :
            printf("0x36 - ExceededNumberOfAttempts, ECU is now locked!\r\n");
            break;
        case 0x37 :
            printf("0x37 - RequiredTimeDelayNotExpired\r\n");
            break;
        case 0x78 :
            printf("0x78 - RequestCorrectlyReceived-ResponsePending\r\n");
            break;
        case 0x81 :
            printf("0x81 - SchedulerFull\r\n");
            break;
        case 0x83 :
            printf("0x83 - VoltageOutOfRangeFault\r\n");
            break;
        case 0x85 :
            printf("0x85 - GeneralProgrammingFailure\r\n");
            break;
        case 0x99 :
            printf("0x99 - ReadyForDownload-DTCStored\r\n");
            break;
        case 0xE3 :
            printf("0xE3 - DeviceControlLimitsExceeded\r\n");
            break;
        default :
            printf("Unknown failure Return Code ?!?\r\n");
    }
}