Just4Trionic - CAN and BDM FLASH programmer for Saab cars

Dependencies:   mbed

Files at this revision

API Documentation at this revision

Comitter:
Just4pLeisure
Date:
Sat Apr 25 17:07:08 2015 +0000
Parent:
4:682d96ff6d79
Child:
6:2fbcbebed28c
Commit message:
Version 1.5 Is a significant milestone.; ; Supports BDM and CAN read and write of T5.x, T7 and T8 ECU's plus T8 recovery.; A Target Resident Driver for BDM gives a big speed boost.; Supports many alternative replacement FLASH chips for T5.x ECU's;

Changed in this revision

bdm.cpp Show annotated file Show diff for this revision Revisions of this file
bdmcpu32.cpp Show annotated file Show diff for this revision Revisions of this file
bdmcpu32.h Show annotated file Show diff for this revision Revisions of this file
bdmdriver.cpp Show annotated file Show diff for this revision Revisions of this file
bdmdriver.h Show annotated file Show diff for this revision Revisions of this file
bdmtrionic.cpp Show annotated file Show diff for this revision Revisions of this file
bdmtrionic.h Show annotated file Show diff for this revision Revisions of this file
canutils.cpp Show annotated file Show diff for this revision Revisions of this file
common.h Show annotated file Show diff for this revision Revisions of this file
gmlan.cpp Show annotated file Show diff for this revision Revisions of this file
gmlan.h Show annotated file Show diff for this revision Revisions of this file
interfaces.cpp Show annotated file Show diff for this revision Revisions of this file
interfaces.h Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
t5bootloaders.h Show annotated file Show diff for this revision Revisions of this file
t5can.cpp Show annotated file Show diff for this revision Revisions of this file
t5can.h Show annotated file Show diff for this revision Revisions of this file
t7can.cpp Show annotated file Show diff for this revision Revisions of this file
t7utils.cpp Show annotated file Show diff for this revision Revisions of this file
t8bootloaders.h Show annotated file Show diff for this revision Revisions of this file
t8can.cpp Show annotated file Show diff for this revision Revisions of this file
t8utils.cpp Show annotated file Show diff for this revision Revisions of this file
t8utils.h Show annotated file Show diff for this revision Revisions of this file
--- a/bdm.cpp	Wed Sep 11 11:55:51 2013 +0000
+++ b/bdm.cpp	Sat Apr 25 17:07:08 2015 +0000
@@ -38,6 +38,10 @@
 #define CMD_BKPTHIGH        '2'             ///< pull BKPT high
 #define CMD_RESETLOW        '3'             ///< pull RESET low
 #define CMD_RESETHIGH       '4'             ///< pull RESET high
+#define CMD_BERR_LOW        '5'             ///< pull BERR low
+#define CMD_BERR_HIGH       '6'             ///< pull BERR high
+#define CMD_BERR_INPUT      '7'             ///< make BERR an input
+
 
 #define CMDGROUP_MCU        'c'             ///< target MCU management commands
 #define CMD_STOPCHIP        'S'             ///< stop
@@ -72,6 +76,7 @@
 #define CMD_WRITESYSREG     'W'             ///< write system register
 #define CMD_READADREG       'a'             ///< read A/D register
 #define CMD_WRITEADREG      'A'             ///< write A/D register
+#define CMD_DISPLAYREGS     'd'             ///< BD32 like display all registers
 
 #define CMDGROUP_TRIONIC    'T'
 #define CMD_TRIONICDUMP     'D'             ///< dumps memory contents
@@ -99,7 +104,8 @@
         return TERM_ERR
 
 
-void bdm() {
+void bdm()
+{
 
     bdm_show_help();
     // set up LED pins
@@ -167,7 +173,8 @@
 
     @return                    command flag (success / failure)
 */
-uint8_t execute_bdm_cmd() {
+uint8_t execute_bdm_cmd()
+{
     uint8_t cmd_length = strlen(cmd_buffer);
     char cmd = *(cmd_buffer + 1);
 
@@ -210,6 +217,18 @@
                     // pull RESET high
                 case CMD_RESETHIGH:
                     return reset_high();
+
+                    // pull BERR low
+                case CMD_BERR_LOW:
+                    return berr_low();
+
+                    // pull BERR high
+                case CMD_BERR_HIGH:
+                    return berr_high();
+
+                    // make BERR an input
+                case CMD_BERR_INPUT:
+                    return berr_input();
             }
             break;
 
@@ -404,16 +423,20 @@
             // registers
         case CMDGROUP_REGISTER:
             // get register code
-            if (cmd_length < 4 || !ascii2int(&cmd_addr, cmd_buffer + 3, 1)) {
+            if (cmd_length == 2 && (cmd != CMD_DISPLAYREGS)) {
                 // broken parametre
                 return TERM_ERR;
-            }
-
-            // get optional value
-            if (cmd_length > 4 &&
-                    !ascii2int(&cmd_value, cmd_buffer + 4, 8)) {
-                // broken parametre
-                return TERM_ERR;
+            } else {
+                if (cmd_length < 4 || !ascii2int(&cmd_addr, cmd_buffer + 3, 1)) {
+                    // broken parametre
+                    return TERM_ERR;
+                }
+                // get optional value
+                if (cmd_length > 4 &&
+                        !ascii2int(&cmd_value, cmd_buffer + 4, 8)) {
+                    // broken parametre
+                    return TERM_ERR;
+                }
             }
 
             switch (cmd) {
@@ -448,6 +471,85 @@
                     return (cmd_length == 12 &&
                             adreg_write((uint8_t)cmd_addr, &cmd_value) == TERM_OK) ?
                            TERM_OK : TERM_ERR;
+
+                    // Display all registers
+                case CMD_DISPLAYREGS:
+                    printf(" D0-7");
+                    for (uint8_t i = 0; i < 8; i++) {
+                        if (adreg_read(&cmd_result, i) != TERM_OK) {
+                            return TERM_ERR;
+                        }
+                        printf(" %08X", cmd_result);
+                    }
+//
+                    printf("\r\n");
+                    printf(" A0-7");
+                    for (uint8_t i = 8; i < 16; i++) {
+                        if (adreg_read(&cmd_result, i) != TERM_OK) {
+                            return TERM_ERR;
+                        }
+                        printf(" %08X", cmd_result);
+                    }
+                    printf("\r\n");
+//
+                    if (sysreg_read(&cmd_result, 0x0) != TERM_OK) {
+                        return TERM_ERR;
+                    }
+                    printf("  RPC %08X", cmd_result);
+                    if (sysreg_read(&cmd_result, 0xC) != TERM_OK) {
+                        return TERM_ERR;
+                    }
+                    printf("     USP %08X", cmd_result);
+                    if (sysreg_read(&cmd_result, 0xE) != TERM_OK) {
+                        return TERM_ERR;
+                    }
+                    printf("     SFC %08X      SR 10S--210---XNZVC\r\n", cmd_result);
+//
+                    if (sysreg_read(&cmd_result, 0x1) != TERM_OK) {
+                        return TERM_ERR;
+                    }
+                    printf("  CPC %08X", cmd_result);
+                    if (sysreg_read(&cmd_result, 0xD) != TERM_OK) {
+                        return TERM_ERR;
+                    }
+                    printf("     SSP %08X", cmd_result);
+                    if (sysreg_read(&cmd_result, 0xF) != TERM_OK) {
+                        return TERM_ERR;
+                    }
+                    printf("     DFC %08X", cmd_result);
+                    if (sysreg_read(&cmd_result, 0xB) != TERM_OK) {
+                        return TERM_ERR;
+                    }
+                    printf("    %04X ", cmd_result);
+                    for (uint32_t i = 0; i < 16; i++) {
+                        cmd_result & (1 << (15-i)) ? printf("1") : printf("0");
+                    }
+                    printf("\r\n");
+//
+                    if (sysreg_read(&cmd_result, 0xA)!= TERM_OK) {
+                        return TERM_ERR;
+                    }
+                    printf("  VBR %08X", cmd_result);
+                    if (sysreg_read(&cmd_result, 0x8)!= TERM_OK) {
+                        return TERM_ERR;
+                    }
+                    printf("   ATEMP %08X", cmd_result);
+                    if (sysreg_read(&cmd_result, 0x9) != TERM_OK) {
+                        return TERM_ERR;
+                    }
+                    printf("     FAR %08X\r\n", cmd_result);
+//
+                    printf(" !CONNNECTED:%d", PIN_NC.read());
+                    printf(" POWER:%d", PIN_PWR.read());
+                    printf(" !RESET:%d", PIN_RESET.read());
+                    printf(" !BUSERR:%d", PIN_BERR.read());
+                    printf(" BKPT/DSCLK:%d", PIN_BKPT.read());
+                    printf(" FREEZE:%d", PIN_FREEZE.read());
+                    printf(" DSO:%d", PIN_DSO.read());
+                    printf(" DSI:%d", PIN_DSI.read());
+                    printf("\r\n");
+//
+                    return TERM_OK;
             }
             break;
 
@@ -482,7 +584,8 @@
     return TERM_ERR;
 }
 
-void bdm_show_help() {
+void bdm_show_help()
+{
     printf("Just4Trionic BDM Command Menu\r\n");
     printf("=============================\r\n");
     printf("TD - and DUMP T5 FLASH BIN file\r\n");
@@ -496,7 +599,8 @@
     printf("\r\n");
     return;
 }
-void bdm_show_full_help() {
+void bdm_show_full_help()
+{
     printf("Just4Trionic BDM Command Menu\r\n");
     printf("=============================\r\n");
     printf("TD - and DUMP T5 FLASH BIN file\r\n");
@@ -512,6 +616,9 @@
     printf("a2 - pull BKPT high\r\n");
     printf("a3 - pull RESET low\r\n");
     printf("a4 - pull RESET high\r\n");
+    printf("a5 - pull BERR low\r\n");
+    printf("a6 - pull BERR high\r\n");
+    printf("a7 - make BERR an input\r\n");
     printf("\r\n");
     printf("MCU Management Commands - c\r\n");
     printf("===========================\r\n");
@@ -563,6 +670,7 @@
     printf("\r\n");
     printf("MCU Register Commands - r\r\n");
     printf("=========================\r\n");
+    printf("rd     Display all registers (like BD32)\r\n");
     printf("rrRR - read system register RR\r\n");
     printf("       00 - RPC, 01 - PCC, 0B - SR, 0C - USP, 0D - SSP\r\n");
     printf("       0e - SFC, 0f - DFC, 08 - ATEMP, 09 - FAR, 0a - VBR\r\n");
--- a/bdmcpu32.cpp	Wed Sep 11 11:55:51 2013 +0000
+++ b/bdmcpu32.cpp	Sat Apr 25 17:07:08 2015 +0000
@@ -63,8 +63,23 @@
 #define BDM_WORDSIZE        0x40        ///< word (2 bytes)
 #define BDM_LONGSIZE        0x80        ///< long word (4 bytes)
 
+// Bit-Banding memory region constants and macros
+#define RAM_BASE 0x20000000
+#define RAM_BB_BASE 0x22000000
+#define PERIHERALS_BASE 0x40000000
+#define PERIHERALS_BB_BASE 0x42000000
+#define LPC1768_AHB_BANK_0  0x2007C000
+#define LPC1768_AHB_BANK_1  0x20080000
+#define LPC1768_AHB_BANK_SIZE 0x00004000
+#define LPC1768_PERIPH_BANK 0x2009C000
+#define LPC1768_PERIPH_SIZE 0x00004000
+
+#define varBit(Variable,BitNumber) (*(uint32_t *) (RAM_BB_BASE | (((uint32_t)&Variable - RAM_BASE) << 5) | ((BitNumber) << 2)))
+#define periphBit(Peripheral,BitNumber) (*(uint32_t *) (PERIHERALS_BB_BASE | (((uint32_t)&Peripheral - PERIHERALS_BASE) << 5) | ((BitNumber) << 2)))
+#define bitAlias(Variable,BitNumber) (*(uint32_t *) (RAM_BB_BASE | (((uint32_t)&Variable - RAM_BASE) << 5) | ((BitNumber) << 2)))
+
 // static variables
-static uint32_t bdm_response;        ///< result of BDM read/write operation
+__attribute__((section("AHBSRAM0"))) static uint32_t bdm_response = 0;      ///< result of BDM read/write operation
 
 // private functions
 bool bdm_read(uint32_t* result, uint16_t cmd, const uint32_t* addr);
@@ -72,8 +87,14 @@
 //bool bdm_read_continue(uint32_t* result, const uint32_t* addr, uint16_t next_cmd);
 bool bdm_write(const uint32_t* addr, uint16_t cmd, const uint32_t* value);
 //bool bdm_write_overlap(const uint32_t* addr, uint16_t cmd, const uint32_t* value, uint16_t next_cmd);
-void bdm_clk(uint16_t value, uint8_t num_bits);
+//
+//void bdm_clk(uint16_t value, uint8_t num_bits);
+void bdm_clk_slow(uint16_t value, uint8_t num_bits);
 void bdm_clk_fast(uint16_t value, uint8_t num_bits);
+void bdm_clk_turbo(uint16_t value, uint8_t num_bits);
+void bdm_clk_nitrous(uint16_t value, uint8_t num_bits);
+void (*bdm_clk)(uint16_t value, uint8_t num_bits) = bdm_clk_slow;
+//
 void bdm_clear();
 
 //-----------------------------------------------------------------------------
@@ -82,7 +103,8 @@
 
     @return                        status flag
 */
-uint8_t stop_chip() {
+uint8_t stop_chip()
+{
     // not connected
     if (!IS_CONNECTED) {
         return TERM_ERR;
@@ -95,7 +117,11 @@
     PIN_BKPT.output();
 
     // wait for target MCU to settle
-    wait_ms(MCU_SETTLE_TIME);
+    //wait_ms(MCU_SETTLE_TIME);
+    timeout.reset();
+    timeout.start();
+    while (!IN_BDM & (timeout.read_ms() < MCU_SETTLE_TIME))
+    timeout.stop();
 
     // check if succeeded
     if (!IN_BDM) {
@@ -113,7 +139,8 @@
 
     @return                        status flag
 */
-uint8_t reset_chip() {
+uint8_t reset_chip()
+{
     // not connected
     if (!IS_CONNECTED) {
         return TERM_ERR;
@@ -148,7 +175,8 @@
 
     @return                        status flag
 */
-uint8_t run_chip(const uint32_t* addr) {
+uint8_t run_chip(const uint32_t* addr)
+{
     // check state
     if (!IN_BDM) {
         return TERM_ERR;
@@ -162,9 +190,18 @@
     bdm_clk(BDM_GO, CMD_BIT_COUNT);
 
     // set BKPT back as input
-    PIN_BKPT.input();
+//    PIN_BKPT.input();
 
     return TERM_OK;
+    // wait for target MCU to settle
+    timeout.reset();
+    timeout.start();
+//    while (!IS_RUNNING & (timeout.read_ms() < MCU_SETTLE_TIME))
+    while (IN_BDM & (timeout.read_ms() < MCU_SETTLE_TIME))
+    timeout.stop();
+
+//    return IS_RUNNING ? TERM_OK : TERM_ERR;
+    return !IN_BDM ? TERM_OK : TERM_ERR;
 }
 
 //-----------------------------------------------------------------------------
@@ -173,7 +210,8 @@
 
     @return                        status flag
 */
-uint8_t restart_chip() {
+uint8_t restart_chip()
+{
     // not connected
     if (!IS_CONNECTED) {
         return TERM_ERR;
@@ -188,11 +226,11 @@
     PIN_BKPT.output();
     PIN_RESET.output();
     // wait for target MCU to settle
-    wait_ms(MCU_SETTLE_TIME);
+    wait_ms(10*MCU_SETTLE_TIME);
     // rising edge on RESET line
     PIN_RESET.write(1);
     // wait for target MCU to settle
-    wait_ms(MCU_SETTLE_TIME);
+    wait_ms(10*MCU_SETTLE_TIME);
     // set RESET back as an input
     PIN_RESET.input();
 
@@ -213,7 +251,8 @@
 
     @return                        status flag
 */
-uint8_t step_chip() {
+uint8_t step_chip()
+{
     // not connected
     if (!IS_CONNECTED) {
         return TERM_ERR;
@@ -246,7 +285,8 @@
 /**
     Pulls BKPT pin low.
 */
-uint8_t bkpt_low() {
+uint8_t bkpt_low()
+{
     PIN_BKPT.write(0);
     PIN_BKPT.output();
 
@@ -257,7 +297,8 @@
 /**
     Pulls BKPT pin high.
 */
-uint8_t bkpt_high() {
+uint8_t bkpt_high()
+{
     PIN_BKPT.write(1);
     PIN_BKPT.output();
 
@@ -268,7 +309,8 @@
 /**
     Pulls RESET pin low.
 */
-uint8_t reset_low() {
+uint8_t reset_low()
+{
     PIN_RESET.write(0);
     PIN_RESET.output();
 
@@ -279,7 +321,8 @@
 /**
     Pulls RESET pin high.
 */
-uint8_t reset_high() {
+uint8_t reset_high()
+{
     PIN_RESET.write(1);
     PIN_RESET.output();
 
@@ -288,6 +331,41 @@
 
 //-----------------------------------------------------------------------------
 /**
+    Pulls BERR pin low.
+*/
+uint8_t berr_low()
+{
+    PIN_BERR.write(0);
+    PIN_BERR.output();
+
+    return TERM_OK;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Pulls BERR pin high.
+*/
+uint8_t berr_high()
+{
+    PIN_BERR.write(1);
+    PIN_BERR.output();
+
+    return TERM_OK;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Makes BERR pin an input.
+*/
+uint8_t berr_input()
+{
+    PIN_BERR.write(1);
+
+    return TERM_OK;
+}
+
+//-----------------------------------------------------------------------------
+/**
     Returns byte from the specified memory location; MCU must be in
     background mode.
 
@@ -296,7 +374,8 @@
 
     @return                        status flag
 */
-uint8_t memread_byte(uint8_t* result, const uint32_t* addr) {
+uint8_t memread_byte(uint8_t* result, const uint32_t* addr)
+{
     // check state
     if (!IN_BDM) {
         return TERM_ERR;
@@ -322,7 +401,8 @@
 
     @return                        status flag
 */
-uint8_t memread_word(uint16_t* result, const uint32_t* addr) {
+uint8_t memread_word(uint16_t* result, const uint32_t* addr)
+{
     // check state
     if (!IN_BDM) {
         return TERM_ERR;
@@ -348,7 +428,8 @@
 
     @return                            status flag
 */
-uint8_t memread_long(uint32_t* result, const uint32_t* addr) {
+uint8_t memread_long(uint32_t* result, const uint32_t* addr)
+{
     // check state
     if (!IN_BDM) {
         return TERM_ERR;
@@ -374,7 +455,8 @@
 
     @return                        status flag
 */
-uint8_t memdump_byte(uint8_t* result) {
+uint8_t memdump_byte(uint8_t* result)
+{
     // check state
     if (!IN_BDM) {
         return TERM_ERR;
@@ -400,7 +482,8 @@
 
     @return                        status flag
 */
-uint8_t memdump_word(uint16_t* result) {
+uint8_t memdump_word(uint16_t* result)
+{
     // check state
     if (!IN_BDM) {
         return TERM_ERR;
@@ -426,7 +509,8 @@
 
     @return                        status flag
 */
-uint8_t memdump_long(uint32_t* result) {
+uint8_t memdump_long(uint32_t* result)
+{
     // check state
     if (!IN_BDM) {
         return TERM_ERR;
@@ -452,7 +536,8 @@
 
     @return                        status flag
 */
-uint8_t memwrite_byte(const uint32_t* addr, uint8_t value) {
+uint8_t memwrite_byte(const uint32_t* addr, uint8_t value)
+{
     // check state
     if (!IN_BDM) {
         return TERM_ERR;
@@ -478,7 +563,8 @@
 
     @return                        status flag
 */
-uint8_t memwrite_word(const uint32_t* addr, uint16_t value) {
+uint8_t memwrite_word(const uint32_t* addr, uint16_t value)
+{
     // check state
     if (!IN_BDM) {
         return TERM_ERR;
@@ -504,7 +590,8 @@
 
     @return                        status flag
 */
-uint8_t memwrite_long(const uint32_t* addr, const uint32_t* value) {
+uint8_t memwrite_long(const uint32_t* addr, const uint32_t* value)
+{
     // check state
     if (!IN_BDM) {
         return TERM_ERR;
@@ -530,7 +617,8 @@
 
     @return                        status flag
 */
-uint8_t memfill_byte(uint8_t value) {
+uint8_t memfill_byte(uint8_t value)
+{
     // check state
     if (!IN_BDM) {
         return TERM_ERR;
@@ -556,7 +644,8 @@
 
     @return                        status flag
 */
-uint8_t memfill_word(uint16_t value) {
+uint8_t memfill_word(uint16_t value)
+{
     // check state
     if (!IN_BDM) {
         return TERM_ERR;
@@ -582,7 +671,8 @@
 
     @return                        status flag
 */
-uint8_t memfill_long(const uint32_t* value) {
+uint8_t memfill_long(const uint32_t* value)
+{
     // check state
     if (!IN_BDM) {
         return TERM_ERR;
@@ -606,7 +696,8 @@
 
     @return                   status flag
 */
-uint8_t memread_byte_cmd(const uint32_t* addr) {
+uint8_t memread_byte_cmd(const uint32_t* addr)
+{
 
     if (!IN_BDM) return TERM_ERR;
 
@@ -628,7 +719,8 @@
 
     @return                   status flag
 */
-uint8_t memread_word_cmd(const uint32_t* addr) {
+uint8_t memread_word_cmd(const uint32_t* addr)
+{
 
     if (!IN_BDM) return TERM_ERR;
 
@@ -651,7 +743,8 @@
 
     @return                   status flag
 */
-uint8_t memread_long_cmd(const uint32_t* addr) {
+uint8_t memread_long_cmd(const uint32_t* addr)
+{
 
     if (!IN_BDM) return TERM_ERR;
 
@@ -673,7 +766,8 @@
 
     @return                   status flag
 */
-uint8_t memwrite_byte_cmd(const uint32_t* addr) {
+uint8_t memwrite_byte_cmd(const uint32_t* addr)
+{
 
     if (!IN_BDM) return TERM_ERR;
 
@@ -695,7 +789,8 @@
 
     @return                   status flag
 */
-uint8_t memwrite_word_cmd(const uint32_t* addr) {
+uint8_t memwrite_word_cmd(const uint32_t* addr)
+{
 
     if (!IN_BDM) return TERM_ERR;
 
@@ -718,7 +813,8 @@
 
     @return                   status flag
 */
-uint8_t memwrite_long_cmd(const uint32_t* addr) {
+uint8_t memwrite_long_cmd(const uint32_t* addr)
+{
 
     if (!IN_BDM) return TERM_ERR;
 
@@ -743,7 +839,8 @@
 
     @return                     status flag
 */
-uint8_t memread_read_byte(uint8_t* result, const uint32_t* addr) {
+uint8_t memread_read_byte(uint8_t* result, const uint32_t* addr)
+{
 
     if (!IN_BDM) return TERM_ERR;
     // write the optional address
@@ -764,7 +861,8 @@
 
     @return                     status flag
 */
-uint8_t memread_write_byte(uint8_t* result, const uint32_t* addr) {
+uint8_t memread_write_byte(uint8_t* result, const uint32_t* addr)
+{
 
     if (!IN_BDM) return TERM_ERR;
     // write the optional address
@@ -785,7 +883,8 @@
 
     @return                     status flag
 */
-uint8_t memread_nop_byte(uint8_t* result, const uint32_t* addr) {
+uint8_t memread_nop_byte(uint8_t* result, const uint32_t* addr)
+{
 
     if (!IN_BDM) return TERM_ERR;
     // write the optional address
@@ -806,7 +905,8 @@
 
     @return                     status flag
 */
-uint8_t memwrite_write_byte(const uint32_t* addr, uint8_t value) {
+uint8_t memwrite_write_byte(const uint32_t* addr, uint8_t value)
+{
 
     if (!IN_BDM) return TERM_ERR;
     // write the optional address
@@ -829,7 +929,8 @@
 
     @return                     status flag
 */
-uint8_t memwrite_read_byte(const uint32_t* addr, uint8_t value) {
+uint8_t memwrite_read_byte(const uint32_t* addr, uint8_t value)
+{
 
     if (!IN_BDM) return TERM_ERR;
     // write the optional address
@@ -852,7 +953,8 @@
 
     @return                     status flag
 */
-uint8_t memwrite_nop_byte(const uint32_t* addr, uint8_t value) {
+uint8_t memwrite_nop_byte(const uint32_t* addr, uint8_t value)
+{
 
     if (!IN_BDM) return TERM_ERR;
     // write the optional address
@@ -877,15 +979,16 @@
 
     @return                     status flag
 */
-uint8_t memwrite_word_write_word(const uint32_t* addr, const uint16_t value1, const uint16_t value2) {
+uint8_t memwrite_word_write_word(const uint32_t* addr, const uint16_t value1, const uint16_t value2)
+{
     return (IN_BDM &&
-        bdm_command(BDM_WRITE + BDM_WORDSIZE) &&        // write command code
-        bdm_address(addr) &&                            // write the address
-        bdm_put((uint32_t*)&value1, BDM_WORDSIZE) &&    // write the first value
-        bdm_ready(BDM_WRITE + BDM_WORDSIZE) &&          // wait until MCU responds and overlap the next write command
-        bdm_address(addr) &&                            // write the address (same address for second word)
-        bdm_put((uint32_t*)&value2, BDM_WORDSIZE) &&    // write the second value
-        bdm_ready(BDM_NOP)) ? TERM_OK : TERM_ERR;       // wait until MCU responds
+            bdm_command(BDM_WRITE + BDM_WORDSIZE) &&        // write command code
+            bdm_address(addr) &&                            // write the address
+            bdm_put((uint32_t*)&value1, BDM_WORDSIZE) &&    // write the first value
+            bdm_ready(BDM_WRITE + BDM_WORDSIZE) &&          // wait until MCU responds and overlap the next write command
+            bdm_address(addr) &&                            // write the address (same address for second word)
+            bdm_put((uint32_t*)&value2, BDM_WORDSIZE) &&    // write the second value
+            bdm_ready(BDM_NOP)) ? TERM_OK : TERM_ERR;       // wait until MCU responds
 }
 
 //-----------------------------------------------------------------------------
@@ -901,14 +1004,15 @@
     @return                     status flag
 */
 
-uint8_t memwrite_word_read_word(uint16_t* result, const uint32_t* addr, const uint16_t value) {
+uint8_t memwrite_word_read_word(uint16_t* result, const uint32_t* addr, const uint16_t value)
+{
     return (IN_BDM &&
-        bdm_command(BDM_WRITE + BDM_WORDSIZE) &&        // write command code
-        bdm_address(addr) &&                            // write the address
-        bdm_put((uint32_t*)&value, BDM_WORDSIZE) &&     // write the value
-        bdm_ready(BDM_READ + BDM_WORDSIZE) &&           // wait until MCU responds and overlap the next read command
-        bdm_address(addr) &&                            // write the address (same address for reading the result)
-        bdm_get((uint32_t*)result, BDM_WORDSIZE, BDM_NOP)) ? TERM_OK : TERM_ERR;    // receive the response word
+            bdm_command(BDM_WRITE + BDM_WORDSIZE) &&        // write command code
+            bdm_address(addr) &&                            // write the address
+            bdm_put((uint32_t*)&value, BDM_WORDSIZE) &&     // write the value
+            bdm_ready(BDM_READ + BDM_WORDSIZE) &&           // wait until MCU responds and overlap the next read command
+            bdm_address(addr) &&                            // write the address (same address for reading the result)
+            bdm_get((uint32_t*)result, BDM_WORDSIZE, BDM_NOP)) ? TERM_OK : TERM_ERR;    // receive the response word
 }
 
 //-----------------------------------------------------------------------------
@@ -920,7 +1024,8 @@
 
     @return                     status flag
 */
-uint8_t memget_word(uint16_t* result) {
+uint8_t memget_word(uint16_t* result)
+{
 
     if (!IN_BDM) return TERM_ERR;
     // receive the response word
@@ -936,7 +1041,8 @@
 
     @return                     status flag
 */
-uint8_t memget_long(uint32_t* result) {
+uint8_t memget_long(uint32_t* result)
+{
 
     if (!IN_BDM) return TERM_ERR;
     // receive the response words
@@ -952,7 +1058,8 @@
 
     @return                        status flag
 */
-uint8_t sysreg_read(uint32_t* result, uint8_t reg) {
+uint8_t sysreg_read(uint32_t* result, uint8_t reg)
+{
     // check state
     if (!IN_BDM) {
         return TERM_ERR;
@@ -976,7 +1083,8 @@
 
     @return                        status flag
 */
-uint8_t sysreg_write(uint8_t reg, const uint32_t* value) {
+uint8_t sysreg_write(uint8_t reg, const uint32_t* value)
+{
     // check state
     if (!IN_BDM) {
         return TERM_ERR;
@@ -1001,7 +1109,8 @@
 
     @return                        status flag
 */
-uint8_t adreg_read(uint32_t* result, uint8_t reg) {
+uint8_t adreg_read(uint32_t* result, uint8_t reg)
+{
     // check state
     if (!IN_BDM) {
         return TERM_ERR;
@@ -1013,7 +1122,6 @@
         bdm_clear();
         return TERM_ERR;
     }
-
     return TERM_OK;
 }
 
@@ -1026,7 +1134,8 @@
 
     @return                        status flag
 */
-uint8_t adreg_write(uint8_t reg, const uint32_t* value) {
+uint8_t adreg_write(uint8_t reg, const uint32_t* value)
+{
     // check state
     if (!IN_BDM) {
         return TERM_ERR;
@@ -1052,7 +1161,8 @@
 
     @return                    succ / fail
 */
-bool bdm_read(uint32_t* result, uint16_t cmd, const uint32_t* addr) {
+bool bdm_read(uint32_t* result, uint16_t cmd, const uint32_t* addr)
+{
     *result = 0;
 
     // write command code
@@ -1107,7 +1217,8 @@
 
     @return                        succ / fail
 */
-bool bdm_write(const uint32_t* addr, uint16_t cmd, const uint32_t* value) {
+bool bdm_write(const uint32_t* addr, uint16_t cmd, const uint32_t* value)
+{
     // write command code
     bdm_clk(cmd, CMD_BIT_COUNT);
     if (bdm_response > BDM_NOTREADY) {
@@ -1151,25 +1262,28 @@
     return (bdm_response == BDM_CMDCMPLTE);
 }
 
-bool bdm_command (uint16_t cmd) {
+bool bdm_command (uint16_t cmd)
+{
     // write command code
-    bdm_clk_fast(cmd, CMD_BIT_COUNT);
+    bdm_clk(cmd, CMD_BIT_COUNT);
     return (bdm_response > BDM_NOTREADY) ? false : true;
 }
 
-bool bdm_address (const uint32_t* addr) {
+bool bdm_address (const uint32_t* addr)
+{
     // write an address
     // first word
-    bdm_clk_fast((uint16_t)((*addr) >> 16), CMD_BIT_COUNT);
+    bdm_clk((uint16_t)((*addr) >> 16), CMD_BIT_COUNT);
     if (bdm_response > BDM_NOTREADY) {
         return false;
     }
     // second word
-    bdm_clk_fast((uint16_t)(*addr), CMD_BIT_COUNT);
+    bdm_clk((uint16_t)(*addr), CMD_BIT_COUNT);
     return (bdm_response > BDM_NOTREADY) ? false : true;
 }
 
-bool bdm_get (uint32_t* result, uint8_t size, uint16_t next_cmd) {
+bool bdm_get (uint32_t* result, uint8_t size, uint16_t next_cmd)
+{
     // receive response words
     *result = 0;
     uint8_t wait_cnt;
@@ -1178,7 +1292,7 @@
         // wait while MCU prepares the response
         wait_cnt = ERR_COUNT;
         do {
-            bdm_clk_fast(next_cmd, CMD_BIT_COUNT);
+            bdm_clk(next_cmd, CMD_BIT_COUNT);
         } while (bdm_response == BDM_NOTREADY && --wait_cnt > 0);
 
         // save the result
@@ -1193,24 +1307,26 @@
     return true;
 }
 
-bool bdm_put (const uint32_t* value, uint8_t size) {
+bool bdm_put (const uint32_t* value, uint8_t size)
+{
     // write the value
     if (size & BDM_LONGSIZE) {
-        bdm_clk_fast((uint16_t)((*value) >> 16), CMD_BIT_COUNT);
+        bdm_clk((uint16_t)((*value) >> 16), CMD_BIT_COUNT);
         if (bdm_response > BDM_NOTREADY) {
             return false;
         }
     }
-    bdm_clk_fast((uint16_t)(*value), CMD_BIT_COUNT);
+    bdm_clk((uint16_t)(*value), CMD_BIT_COUNT);
     return (bdm_response > BDM_NOTREADY) ? false : true;
 }
 
-bool bdm_ready (uint16_t next_cmd) {
+bool bdm_ready (uint16_t next_cmd)
+{
     // wait until MCU responds
     uint8_t wait_cnt = ERR_COUNT;
     do {
         // read response
-        bdm_clk_fast(next_cmd, CMD_BIT_COUNT);
+        bdm_clk(next_cmd, CMD_BIT_COUNT);
     } while (bdm_response == BDM_NOTREADY && --wait_cnt > 0);
 
     // check if command succeeded
@@ -1220,12 +1336,74 @@
 
 //-----------------------------------------------------------------------------
 /**
+    Sets the speed at which BDM data is trransferred.
+
+    @param            mode            SLOW, FAST, TURBO, NITROUS
+*/
+void bdm_clk_mode(bdm_speed mode)
+{
+    switch (mode) {
+        case NITROUS:
+            bdm_clk = &bdm_clk_nitrous;
+            break;
+        case TURBO:
+            bdm_clk = &bdm_clk_turbo;
+            break;
+        case FAST:
+            bdm_clk = &bdm_clk_fast;
+            break;
+        case SLOW:
+        default:
+            bdm_clk = &bdm_clk_slow;
+            break;
+    }
+    return;
+}
+
+//-----------------------------------------------------------------------------
+/**
     Writes a word to target MCU via BDM line and gets the response.
 
     @param            value            value to write
     @param            num_bits        value size, bits
 */
-void bdm_clk(uint16_t value, uint8_t num_bits) {
+/*
+void bdm_clk(uint16_t value, uint8_t num_bits)
+{
+//    PIN_BKPT.output();
+    PIN_DSI.output();
+    // clock the value via BDM
+    bdm_response = ((uint32_t)value) << (32 - num_bits);
+    while (num_bits--) {
+        // falling edge on BKPT/DSCLK
+        PIN_BKPT.write(0);
+        // set DSI bit
+        PIN_DSI.write(bdm_response & 0x80000000);
+        bdm_response <<= 1;
+        // read DSO bit
+        bdm_response |= PIN_DSO.read();
+        // short delay
+//        for (uint8_t c = 1; c; c--);
+//        wait_us(1);
+        // rising edge on BKPT/DSCLK
+        PIN_BKPT.write(1);
+        // short delay
+//        for (uint8_t c = 1; c; c--);
+//        wait_us(1);
+    }
+    PIN_DSI.input();
+}
+*/
+
+//-----------------------------------------------------------------------------
+/**
+    Writes a word to target MCU via BDM line and gets the response.
+
+    @param            value            value to write
+    @param            num_bits        value size, bits
+*/
+
+void bdm_clk_slow(uint16_t value, uint8_t num_bits) {
 //    PIN_BKPT.output();
     PIN_DSI.output();
     // clock the value via BDM
@@ -1246,47 +1424,12 @@
         // rising edge on BKPT/DSCLK
         PIN_BKPT.write(1);
         // short delay
-        for (uint8_t c = 1; c; c--);
+//        for (uint8_t c = 1; c; c--);
 //        wait_us(1);
     }
     PIN_DSI.input();
 }
-
-//-----------------------------------------------------------------------------
-/**
-    Writes a word to target MCU via BDM line and gets the response.
-
-    @param            value            value to write
-    @param            num_bits        value size, bits
-*/
-/*
-void bdm_clk_fast(uint16_t value, uint8_t num_bits) {
-//    PIN_BKPT.output();
-    PIN_DSI.output();
-    // clock the value via BDM
-    bdm_response = ((uint32_t)value) << (32 - num_bits);
-//    bool dsi;
-    while (num_bits--) {
-
-        // falling edge on BKPT/DSCLK
-        PIN_BKPT.write(0);
-        // set DSI bit
-        PIN_DSI.write(bdm_response & 0x80000000);
-        bdm_response <<= 1;
-        // read DSO bit
-        bdm_response |= PIN_DSO.read();
-        // short delay
-//        for (uint8_t c = 1; c; c--);
-//        wait_us(1);
-        // rising edge on BKPT/DSCLK
-        PIN_BKPT.write(1);
-        // short delay
-        for (uint8_t c = 1; c; c--);
-//        wait_us(1);
-    }
-    PIN_DSI.input();
-}
-//*/
+//
 
 //-----------------------------------------------------------------------------
 /**
@@ -1299,60 +1442,123 @@
     @param            num_bits        value size, bits
 */
 
-//*
-void bdm_clk_fast(uint16_t value, uint8_t num_bits) {
+void bdm_clk_fast(uint16_t value, uint8_t num_bits)
+{
 
-    //Set BKPT
-//    PIN_BKPT.write(1);
-//    LPC_GPIO2->FIOSET = (1 << 4);
-//    PIN_BKPT.output();
-
-//    uint32_t mask = LPC_GPIO2->FIOMASK;
-//    LPC_GPIO2->FIOMASK = ~((1 << 4) | (1 << 2));
     //Make DSI an output
     LPC_GPIO2->FIODIR |= (1 << 2);
     // clock the value via BDM
     bdm_response = ((uint32_t)value) << (32 - num_bits);
+    // Clock BDM Data in from DSO and out to DSI
     while (num_bits--) {
         // set DSI bit
-//        LPC_GPIO2->FIOPIN = ((bool)(bdm_response & 0x80000000) << 2);
-        //if (bdm_response & 0x80000000) 
-        //    LPC_GPIO2->FIOSET = (1 << 2);
-        //else
-        //    LPC_GPIO2->FIOCLR = (1 << 2);
-            
         (bdm_response & 0x80000000) ? LPC_GPIO2->FIOSET = (1 << 2) : LPC_GPIO2->FIOCLR = (1 << 2);
-        
-        //*((volatile unsigned int *)0x23380a88) = (bool)(bdm_response & 0x80000000);
-        //*((volatile unsigned int *)0x23380a88) = bdm_response >> 31;
-        //*((volatile unsigned int *)0x23380a9c) = 1;
-        //used to set the P2.7 pin is slower (about 3 cycles) than this one
-        //GPIO2->FIOPIN=0x80
-       // falling edge on BKPT/DSCLK
+        // falling edge on BKPT/DSCLK
         LPC_GPIO2->FIOCLR = (1 << 4);
-        //*((volatile unsigned int *)0x23380a90) = 0;
-//        for (uint8_t c = 1; c; c--);
-//        // read DSO bit
+        // read DSO bit
 //        (bdm_response <<= 1) |= (bool)((LPC_GPIO0->FIOPIN) & (1 << 11));  -- OLD CONNECTION to PIN 27
         (bdm_response <<= 1) |= (bool)((LPC_GPIO2->FIOPIN) & (1 << 1));
-        //(bdm_response <<= 1) |= *((volatile unsigned int *)0x23380a84);
         // rising edge on BKPT/DSCLK
         LPC_GPIO2->FIOSET = (1 << 4);
-        //*((volatile unsigned int *)0x23380a90) = 1;
+        // introduce a delay to insure that BDM clock isn't too fast
+        for (uint8_t c = 9; c; c--);    // was 5
+    }
+    //Make DSI an input
+    LPC_GPIO2->FIODIR &= ~(1 << 2);
+}
+//-----------------------------------------------------------------------------
+
+/**
+    Writes a word to target MCU via BDM line and gets the response.
+    This 'turbo' version uses 'bit-banding' to read and write individual
+    bits directly. This should be faster than the 'fast' version because
+    the complex calculation to find the address of the BDM word 'bit-band'
+    region is only done once per call rather than several, simpler,
+    calculations and bit-shifts that the slow and fast functions do for
+    each bit.
+    
+    The 68332 must have been 'prepped' before using the 'turbo' version
+    because the BDM interface can go twice as fast once the 68332
+    clock is increased from 8 MHz to 16 MHz
+
+    @param            value            value to write
+    @param            num_bits        value size, bits
+*/
+
+void bdm_clk_turbo(uint16_t value, uint8_t num_bits)
+{
+    //Make DSI an output
+    LPC_GPIO2->FIODIR |= (1 << 2);
+    bdm_response = (uint32_t)value;
+    // calculate a pointer to the bitband alias region address of the most significant bit of the BDM word (NOTE num_bits-1) 
+    uint32_t *bdm_response_bit_alias = &bitAlias(bdm_response,num_bits-1);
+    // Clock BDM Data in from DSO and out to DSI
+    while (num_bits--) {
+        // set DSI bit (port 2, bit 2)
+        bitAlias(LPC_GPIO2->FIOPIN,2) = *bdm_response_bit_alias;
+        // falling edge on BKPT/DSCLK
+        LPC_GPIO2->FIOCLR = (1 << 4);
+        // read DSO bit (port 2, bit 1) ( -- OLD CONNECTION WAS to PIN 27 -- port 2, bit 11)
+        *bdm_response_bit_alias = bitAlias(LPC_GPIO2->FIOPIN,1);
+        // introduce a delay to insure that BDM clock isn't too fast
+        for (uint8_t c = 2; c; c--);        // was 2
+        // rising edge on BKPT/DSCLK
+        LPC_GPIO2->FIOSET = (1 << 4);
+        // point to the next bit (pointer will be decremented by sizeof pointer)
+        bdm_response_bit_alias--;
+        // introduce a delay to insure that BDM clock isn't too fast
+        for (uint8_t c = 7; c; c--);        // was 2
+    }
+    //Make DSI an input
+    LPC_GPIO2->FIODIR &= ~(1 << 2);
+}
+//-----------------------------------------------------------------------------
+
+/**
+    Writes a word to target MCU via BDM line and gets the response.
+    
+    This 'nitrous' version uses is the same as the 'turbo' version but
+    without minimal delays and will only work with the faster CPU in T8
+    once the ECU has been 'prepped'
+
+    @param            value            value to write
+    @param            num_bits        value size, bits
+*/
+
+void bdm_clk_nitrous(uint16_t value, uint8_t num_bits)
+{
+    //Make DSI an output
+    LPC_GPIO2->FIODIR |= (1 << 2);
+    bdm_response = (uint32_t)value;
+    // calculate a pointer to the bitband alias region address of the most significant bit of the BDM word (NOTE num_bits-1) 
+    uint32_t *bdm_response_bit_alias = &bitAlias(bdm_response,num_bits-1);
+    // Clock BDM Data in from DSO and out to DSI
+    while (num_bits--) {
+        // set DSI bit (port 2, bit 2)
+        bitAlias(LPC_GPIO2->FIOPIN,2) = *bdm_response_bit_alias;
+        // falling edge on BKPT/DSCLK
+        LPC_GPIO2->FIOCLR = (1 << 4);
+        // read DSO bit (port 2, bit 1) ( -- OLD CONNECTION WAS to PIN 27 -- port 2, bit 11)
+        *bdm_response_bit_alias = bitAlias(LPC_GPIO2->FIOPIN,1);
+        // introduce a delay to insure that BDM clock isn't too fast
+        //for (uint8_t c = 2; c; c--);
+        // rising edge on BKPT/DSCLK
+        LPC_GPIO2->FIOSET = (1 << 4);
+        // point to the next bit (pointer will be decremented by sizeof pointer)
+        bdm_response_bit_alias--;
+        // introduce a delay to insure that BDM clock isn't too fast
         for (uint8_t c = 1; c; c--);
     }
     //Make DSI an input
     LPC_GPIO2->FIODIR &= ~(1 << 2);
-//    LPC_GPIO2->FIOMASK = mask;
 }
+//-----------------------------------------------------------------------------
 
-//*/
-
-//-----------------------------------------------------------------------------
 /**
     Clears the BDM interface after errors.
 */
-void bdm_clear() {
+void bdm_clear()
+{
     bdm_clk (BDM_NOP, CMD_BIT_COUNT);
     bdm_clk (BDM_NOP, CMD_BIT_COUNT);
     bdm_clk (BDM_NOP, CMD_BIT_COUNT);
--- a/bdmcpu32.h	Wed Sep 11 11:55:51 2013 +0000
+++ b/bdmcpu32.h	Sat Apr 25 17:07:08 2015 +0000
@@ -31,9 +31,9 @@
 // MCU status macros
 #ifndef IGNORE_VCC_PIN
 //    #define IS_CONNECTED    (PIN_PWR)
-    #define IS_CONNECTED    (bool)((LPC_GPIO1->FIOPIN) & (1 << 30))     // PIN_POWER is p19 p1.30
+#define IS_CONNECTED    (bool)((LPC_GPIO1->FIOPIN) & (1 << 30))     // PIN_POWER is p19 p1.30
 #else
-    #define IS_CONNECTED    true
+#define IS_CONNECTED    true
 #endif    // IGNORE_VCC_PIN
 
 //#define IN_BDM              (PIN_FREEZE)
@@ -51,6 +51,18 @@
 uint8_t bkpt_high();
 uint8_t reset_low();
 uint8_t reset_high();
+uint8_t berr_low();
+uint8_t berr_high();
+uint8_t berr_input();
+
+// BDM Clock speed
+enum bdm_speed {
+    SLOW,
+    FAST,
+    TURBO,
+    NITROUS
+};
+void bdm_clk_mode(bdm_speed mode);
 
 // memory
 uint8_t memread_byte(uint8_t* result, const uint32_t* addr);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bdmdriver.cpp	Sat Apr 25 17:07:08 2015 +0000
@@ -0,0 +1,453 @@
+/*******************************************************************************
+
+bdmdriver.cpp
+(c) 2014 by Sophie Dexter
+
+BD32 like 'syscall' processor for BDM resident driver functions
+
+********************************************************************************
+
+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 "bdmdriver.h"
+
+FILE *fp = NULL;
+
+//private functions
+bool bdmSyscallPuts (void);
+bool bdmSyscallPutchar(void);
+bool bdmSyscallGets(void);
+bool bdmSyscallGetchar(void);
+bool bdmSyscallGetstat(void);
+bool bdmSyscallFopen(void);
+bool bdmSyscallFclose(void);
+bool bdmSyscallFread(void);
+bool bdmSyscallFwrite(void);
+bool bdmSyscallFtell(void);
+bool bdmSyscallFseek(void);
+bool bdmSyscallFgets(void);
+bool bdmSyscallFputs(void);
+bool bdmSyscallEval(void);
+bool bdmSyscallFreadsrec(void);
+
+//-----------------------------------------------------------------------------
+/**
+Loads the contenst of a uint8_t array into the target's memory starting at the
+specified address
+
+@param        dataArray[]       uint8_t array conataining data for BDM tartget
+@param        startAddress      Start address to load BDM memory to
+
+@return                    succ / fail
+*/
+bool bdmLoadMemory(uint8_t dataArray[], uint32_t startAddress, uint32_t dataArraySize)
+{
+//    for (uint32_t i = 0; i < sizeof(residentDriver); i++) {
+//        if(memwrite_byte(&driverAddress, residentDriver[i]) != TERM_OK) return false;
+//        driverAddress++;
+//    }
+    uint32_t driverSize = dataArraySize;
+    uint32_t driverOffset = 0;
+    uint32_t driverLong = 0;
+    uint16_t driverWord = 0;
+    uint8_t driverByte = 0;
+    // Check that there is something to send
+    if (driverSize == 0) return false;
+    // Send the first 1-4 bytes as efficiently as possible over BDM
+    switch (driverSize % 4) {
+        case 3:
+            driverWord = (dataArray[driverOffset++] << 8) | dataArray[driverOffset++];
+            if(memwrite_word(&startAddress, driverWord) != TERM_OK) return false;
+            driverByte = dataArray[driverOffset++];
+            if(memfill_byte(driverByte) != TERM_OK) return false;
+            break;
+        case 2:
+            driverWord = (dataArray[driverOffset++] << 8) | dataArray[driverOffset++];
+            if(memwrite_word(&startAddress, driverWord) != TERM_OK) return false;
+            break;
+        case 1:
+            driverByte = dataArray[driverOffset++];
+            if(memwrite_byte(&startAddress, driverByte) != TERM_OK) return false;
+            break;
+        case 0:
+            for (uint32_t i = 0; i < 4; i++) {
+                driverLong <<= 8;
+                driverLong |= dataArray[driverOffset++];
+            }
+            if(memwrite_long(&startAddress, &driverLong) != TERM_OK) return false;
+            break;
+//        default: // There shouldn't be a default case
+    }
+    // transfer the rest as 'longs' to make best use of BDM transfer speed
+//    printf("driverOffset 0x%08x, driverSize 0x%08x\r\n", driverOffset, driverSize);
+    while (driverOffset < driverSize) {
+        for (uint32_t i = 0; i < 4; i++) {
+            driverLong <<= 8;
+            driverLong |= dataArray[driverOffset++];
+        }
+        if(memfill_long(&driverLong) != TERM_OK) return false;
+    }
+//    printf("driverOffset 0x%08x, driverSize 0x%08x\r\n", driverOffset, driverSize);
+    return true;
+}
+
+//-----------------------------------------------------------------------------
+/**
+Starts a BDM resident driver at the current PC (Program Counter) or a specified
+if given. The driver is allowed to run for a maximum period, maxtime, specified
+as milliseconds.
+
+@param        addr        BDM driver address (0 to continue from current PC)
+@param        maxtime     how long to allow driver to execute (milliseconds)
+
+@return                    succ / fail
+*/
+bool bdmRunDriver(uint32_t addr, uint32_t maxtime)
+{
+    // Start BDM driver and allow it up to 200 milliseconds to update 256 Bytes
+    // Upto 25 pulses per byte, 16us per pulse, 256 Bytes
+    // 25 * 16 * 256 = 102,400us plus overhead for driver code execution time
+    // Allowing up to 200 milliseconds seems like a good allowance.
+    if (run_chip(&addr) != TERM_OK) {
+        printf("Failed to start BDM driver.\r\n");
+        return false;
+    }
+    timeout.reset();
+    timeout.start();
+    // T5 ECUs' BDM interface seem to have problems when the running the CPU and
+    // sometimes shows the CPU briefly switching between showing BDM mode or that
+    // the CPU is running.
+    // I 'debounce' the interface state to workaround this erratic bahaviour
+    for (uint32_t debounce = 0; debounce < 5; debounce++) {
+        while (IS_RUNNING) {
+            debounce = 0;
+            if (timeout.read_ms() > maxtime) {
+                printf("Driver did not return to BDM mode.\r\n");
+                timeout.stop();
+                return false;
+            }
+        }
+        wait_us(1);
+    }
+    timeout.stop();
+    return true;
+}
+
+
+//-----------------------------------------------------------------------------
+/**
+Starts a BDM resident driver at the current PC (Program Counter) or a specified
+if given. The driver is allowed to run for a maximum period, maxtime, specified
+as milliseconds.
+
+@param        addr        BDM driver address (0 to continue from current PC)
+@param        maxtime     how long to allow driver to execute (milliseconds)
+
+@return                    DONE, CONTINUE, ERROR
+
+*/
+
+uint8_t bdmProcessSyscall(void)
+{
+
+    uint32_t syscall = 0xFFFFFFFF;
+    if (adreg_read(&syscall, 0x0) != TERM_OK) {
+        printf("Failed to read BDM register.\r\n");
+        return ERROR;
+    }
+    syscall &= 0xFF;
+//    printf("SYSCALL 0x%08x\r\n", syscall);
+    switch (syscall) {
+        case QUIT:
+            if (adreg_read(&syscall, 0x1) != TERM_OK) {
+                printf("Failed to read BDM register.\r\n");
+                return ERROR;
+            }
+            return DONE;
+        case PUTS:
+            if (!bdmSyscallPuts()) return ERROR;
+            break;
+        case PUTCHAR:
+            if (!bdmSyscallPutchar()) return ERROR;
+            break;
+        case GETS:
+            if (!bdmSyscallGets()) return ERROR;
+            break;
+        case GETCHAR:
+            if (!bdmSyscallGetchar()) return ERROR;
+            break;
+        case GETSTAT:
+            if (!bdmSyscallGetstat()) return ERROR;
+            break;
+        case FOPEN:
+            if (!bdmSyscallFopen()) return ERROR;
+            break;
+        case FCLOSE:
+            if (!bdmSyscallFclose()) return ERROR;
+            break;
+        case FREAD:
+            if (!bdmSyscallFread()) return ERROR;
+            break;
+        case FWRITE:
+            if (!bdmSyscallFwrite()) return ERROR;
+            break;
+        case FTELL:
+            if (!bdmSyscallFtell()) return ERROR;
+            break;
+        case FSEEK:
+            if (!bdmSyscallFseek()) return ERROR;
+            break;
+        case FGETS:
+            if (!bdmSyscallFgets()) return ERROR;
+            break;
+        case FPUTS:
+            if (!bdmSyscallFputs()) return ERROR;
+            break;
+        case EVAL:
+            if (!bdmSyscallEval()) return ERROR;
+            break;
+        case FREADSREC:
+            if (!bdmSyscallFreadsrec()) return ERROR;
+            break;
+        default:
+            printf("!!! Unknown BDM Syscall !!!\r\n");
+            return ERROR;
+    }
+    return CONTINUE;
+}
+
+
+bool bdmSyscallPuts()
+{
+    uint32_t bdm_string_address = 0, bdm_return = 0;
+    if (adreg_read(&bdm_string_address, 0x8) != TERM_OK) {
+        printf("Failed to read BDM register.\r\n");
+        return false;
+    }
+// a loop to read chars from BDM into a string
+    char bdm_string[256];
+    for (uint32_t i = 0; i < sizeof(bdm_string); i++) {
+        bdm_string[i] = 0x0;
+    }
+    uint32_t i = 0;
+    do {
+        if (memread_byte((uint8_t*)(bdm_string+i), &bdm_string_address) != TERM_OK) {
+            printf("Failed to read BDM memory at address 0x%08x.\r\n", bdm_string_address);
+            return false;
+        }
+        bdm_string_address++;
+    } while ( (bdm_string[i++] != 0x0) && (i < sizeof(bdm_string)) );
+// print the string to stdout (USB virtual serial port)
+    printf(bdm_string);
+// Send BDM return code in D0 (always 0x0 for PUTS)
+    if (adreg_write(0x0, &bdm_return) != TERM_OK) {
+        printf("Failed to write BDM register.\r\n");
+        return false;
+    }
+    return true;
+}
+
+bool bdmSyscallPutchar()
+{
+    uint32_t bdm_character = 0, bdm_return = 0;
+    // read char from BDM
+    if (adreg_read(&bdm_character, 0x1) != TERM_OK) {
+        printf("Failed to read BDM register.\r\n");
+        return false;
+    }
+    // print the char to USB virtual serial port
+    pc.putc((char)bdm_character);
+    // Send BDM return code in D0 (always 0x0 for PUTCHAR)
+    if (adreg_write(0x0, &bdm_return) != TERM_OK) {
+        printf("Failed to write BDM register.\r\n");
+        return false;
+    }
+    return true;
+}
+
+bool bdmSyscallGets()
+{
+    printf("BDM GETS Syscall not supported.\r\n");
+    return ERROR;
+}
+
+bool bdmSyscallGetchar()
+{
+    // get a char from the USB virtual serial port
+    uint32_t bdm_return = (uint32_t)pc.getc();
+    // Send the char to BDM in D0
+    if (adreg_write(0x0, &bdm_return) != TERM_OK) {
+        printf("Failed to write BDM register.\r\n");
+        return false;
+    }
+    return true;
+}
+
+bool bdmSyscallGetstat(void)
+{
+    printf("BDM GETSTAT Syscall not supported.\r\n");
+    return false;
+}
+
+bool bdmSyscallFopen(void)
+{
+    uint32_t bdm_filename_address = 0, bdm_filemode_address = 0;
+    if (adreg_read(&bdm_filename_address, 0x8) != TERM_OK) {
+        printf("Failed to read BDM register.\r\n");
+        return false;
+    }
+    if (adreg_read(&bdm_filemode_address, 0x9) != TERM_OK) {
+        printf("Failed to read BDM register.\r\n");
+        return false;
+    }
+    // a loop to initialise the strings to 0x0
+    char filename_string[80], filemode_string[5];
+    uint32_t i = 0;
+    for (i = 0; i < sizeof(filename_string); i++) {
+        filename_string[i] = 0x0;
+    }
+    for (i = 0; i < sizeof(filemode_string); i++) {
+        filemode_string[i] = 0x0;
+    }
+    i = 0;
+    // a loop to read chars from BDM into a string
+    do {
+        if (memread_byte((uint8_t*)filename_string[i], &bdm_filename_address) != TERM_OK) {
+            printf("Failed to read BDM memory at address 0x%08x.\r\n", bdm_filename_address);
+            return false;
+        }
+        bdm_filename_address++;
+    } while ( (filename_string[i++] != 0x0) && (i < sizeof(filename_string)) );
+    do {
+        if (memread_byte((uint8_t*)filemode_string[i], &bdm_filemode_address) != TERM_OK) {
+            printf("Failed to read BDM memory at address 0x%08x.\r\n", bdm_filemode_address);
+            return false;
+        }
+        bdm_filemode_address++;
+    } while ( (filemode_string[i++] != 0x0) && (i < sizeof(filemode_string)) );
+    // Open the file
+    fp = fopen(filename_string, filemode_string);    // Open "modified.hex" on the local file system for reading
+    // Send BDM return code in D0
+    if (adreg_write(0x0, (uint32_t*)fp) != TERM_OK) {
+        printf("Failed to write BDM register.\r\n");
+        return false;
+    }
+    return true;
+}
+
+bool bdmSyscallFclose(void)
+{
+    uint32_t close_result = fclose(fp);
+    // Send BDM return code in D0
+    if (adreg_write(0x0, &close_result) != TERM_OK) {
+        printf("Failed to write BDM register.\r\n");
+        return false;
+    }
+    return true;
+}
+
+bool bdmSyscallFread(void)
+{
+    uint32_t bdm_byte_count, bdm_buffer_address, bdm_file_handle = NULL;
+    if (adreg_read(&bdm_file_handle, 0x1) != TERM_OK) {
+        printf("Failed to read BDM register.\r\n");
+        return false;
+    }
+    if (adreg_read(&bdm_byte_count, 0x2) != TERM_OK) {
+        printf("Failed to read BDM register.\r\n");
+        return false;
+    }
+    if (adreg_read(&bdm_buffer_address, 0x9) != TERM_OK) {
+        printf("Failed to read BDM register.\r\n");
+        return false;
+    }
+    uint32_t bytes_read = fread(&file_buffer[0],1,bdm_byte_count,fp);
+    for (uint32_t byte_count = 0; byte_count < bytes_read; byte_count++) {
+        if (byte_count == 0x0) {
+            if(memwrite_byte(&bdm_buffer_address, file_buffer[byte_count]) != TERM_OK) return false;
+        } else {
+            if(memfill_byte(file_buffer[byte_count]) != TERM_OK) return false;
+        }
+    }
+    if (adreg_write(0x0, &bytes_read) != TERM_OK) {
+        printf("Failed to write BDM register.\r\n");
+        return false;
+    }
+    return true;
+}
+
+bool bdmSyscallFwrite(void)
+{
+    printf("BDM FWRITE Syscall not supported.\r\n");
+    return false;
+}
+
+bool bdmSyscallFtell(void)
+{
+    printf("BDM FTELL Syscall not supported.\r\n");
+    return false;
+}
+
+bool bdmSyscallFseek(void)
+{
+    uint32_t bdm_byte_offset, bdm_file_origin, bdm_file_handle = NULL;
+    if (adreg_read(&bdm_file_handle, 0x1) != TERM_OK) {
+        printf("Failed to read BDM register.\r\n");
+        return false;
+    }
+    if (adreg_read(&bdm_byte_offset, 0x2) != TERM_OK) {
+        printf("Failed to read BDM register.\r\n");
+        return false;
+    }
+    if (adreg_read(&bdm_file_origin, 0x3) != TERM_OK) {
+        printf("Failed to read BDM register.\r\n");
+        return false;
+    }
+    uint32_t origin;
+    switch (bdm_file_origin) {
+        case 0x2:
+            origin = SEEK_END;
+            break;
+        case 0x1:
+            origin = SEEK_CUR;
+            break;
+        case 0x0:
+        default:
+            origin = SEEK_SET;
+            break;
+    }
+    uint32_t fseek_result = fseek ( fp ,bdm_byte_offset ,origin );
+    if (adreg_write(0x0, &fseek_result) != TERM_OK) {
+        printf("Failed to write BDM register.\r\n");
+        return false;
+    }
+    return true;
+}
+
+bool bdmSyscallFgets(void)
+{
+    printf("BDM FGETS Syscall not supported.\r\n");
+    return false;
+}
+
+bool bdmSyscallFputs(void)
+{
+    printf("BDM FPUTS Syscall not supported.\r\n");
+    return false;
+}
+
+bool bdmSyscallEval(void)
+{
+    printf("BDM EVAL Syscall not supported.\r\n");
+    return false;
+}
+
+bool bdmSyscallFreadsrec(void)
+{
+    printf("BDM FREADSREC Syscall not supported.\r\n");
+    return false;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bdmdriver.h	Sat Apr 25 17:07:08 2015 +0000
@@ -0,0 +1,55 @@
+/*******************************************************************************
+
+bdmdriver.cpp
+(c) 2014 by Sophie Dexter
+
+********************************************************************************
+
+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.
+
+*******************************************************************************/
+
+#ifndef __BDMDRIVER_H__
+#define __BDMDRIVER_H__
+
+#include "mbed.h"
+
+#include "common.h"
+#include "bdmcpu32.h"
+
+// public functions
+bool bdmLoadMemory(uint8_t dataArray[], uint32_t loadAddress, uint32_t dataArraySize);
+bool bdmRunDriver(uint32_t addr, uint32_t maxtime);
+uint8_t bdmProcessSyscall(void);
+
+enum bdmSyscall {
+    QUIT = 0,
+    PUTS = 1,
+    PUTCHAR = 2,
+    GETS = 3,
+    GETCHAR = 4,
+    GETSTAT = 5,
+    FOPEN = 6,
+    FCLOSE = 7,
+    FREAD = 8,
+    FWRITE = 9,
+    FTELL = 10,
+    FSEEK = 11,
+    FGETS = 12,
+    FPUTS = 13,
+    EVAL = 14,
+    FREADSREC = 15
+};
+
+enum bdmSyscallResult {
+    DONE,
+    CONTINUE,
+    ERROR    
+    };
+
+#endif    // __BDMDRIVER_H__
+//-----------------------------------------------------------------------------
+//    EOF
+//-----------------------------------------------------------------------------
\ No newline at end of file
--- a/bdmtrionic.cpp	Wed Sep 11 11:55:51 2013 +0000
+++ b/bdmtrionic.cpp	Sat Apr 25 17:07:08 2015 +0000
@@ -65,6 +65,7 @@
 bool flash_am28(const uint32_t* addr, uint16_t value);
 bool get_flash_id(uint8_t* make, uint8_t* type);
 
+bool run_bdm_driver(uint32_t addr, uint32_t maxtime);
 
 //-----------------------------------------------------------------------------
 /**
@@ -160,7 +161,14 @@
             flash_size = T7FLASHSIZE;
             break;
         case AMD29F010:
-            printf("I have found AMD29F010 type FLASH chips; I must be connected to a repaired T5.5 ECU :-)\r\n");
+        case SST39SF010:
+        case AMICA29010L:
+            printf("I have found 29/39F010 type FLASH chips; I must be connected to a repaired T5.5 ECU :-)\r\n");
+            reset_func = &reset_am29;
+            flash_size = T55FLASHSIZE;
+            break;
+        case ATMEL29C010:
+            printf("I have found Atmel 29C010 type FLASH chips; I must be connected to a repaired T5.5 ECU :-)\r\n");
             reset_func = &reset_am29;
             flash_size = T55FLASHSIZE;
             break;
@@ -176,6 +184,11 @@
             reset_func = &reset_am28;
             flash_size = T52FLASHSIZE;
             break;
+        case ATMEL29C512:
+            printf("I have found Atmel 29C512 type FLASH chips; I must be connected to a repaired T5.2 ECU :-)\r\n");
+            reset_func = &reset_am28;
+            flash_size = T52FLASHSIZE;
+            break;
         default:
             // unknown flash type
             printf("I could not work out what FLASH chips or TRIONIC ECU I am connected to :-(\r\n");
@@ -207,15 +220,11 @@
         while (byte_count < FILE_BUF_LENGTH) {
             // get long word
             if (memget_long(&long_value) != TERM_OK) return TERM_ERR;
-            addr += 4;
             // send memory value to file_buffer before saving to mbed 'disk'
-            file_buffer[byte_count] = ((uint8_t)(long_value >> 24));
-            file_buffer[byte_count+1] = ((uint8_t)(long_value >> 16));
-            file_buffer[byte_count+2] = ((uint8_t)(long_value >> 8));
-            file_buffer[byte_count+3] = ((uint8_t)long_value);
-            byte_count +=4;
-            // make the activity led twinkle
-            ACTIVITYLEDON;
+            file_buffer[byte_count++] = ((uint8_t)(long_value >> 24));
+            file_buffer[byte_count++] = ((uint8_t)(long_value >> 16));
+            file_buffer[byte_count++] = ((uint8_t)(long_value >> 8));
+            file_buffer[byte_count++] = ((uint8_t)long_value);
         }
         fwrite(file_buffer, 1, FILE_BUF_LENGTH, fp);
         if (ferror (fp)) {
@@ -224,8 +233,11 @@
             return TERM_ERR;
         }
         printf("%6.2f\r", 100*(float)addr/(float)flash_size );
+        // make the activity led twinkle
+        ACTIVITYLEDON;
+        addr += FILE_BUF_LENGTH;
     }
-    printf("\n");
+    printf("100.00\r\n");
     // should 'clear' the BDM connection here but bdm_clear won't compile from here
     // instead do a memread (or anything really) but ignore the result because it's not needed for anything
     memread_long(&long_value, &addr);
@@ -408,11 +420,19 @@
             flash_size = T7FLASHSIZE;
             break;
         case AMD29F010:
-            printf("I have found AMD29F010 type FLASH chips; I must be connected to a repaired T5.5 ECU :-)\r\n");
+        case SST39SF010:
+        case AMICA29010L:
+            printf("I have found 29/39F010 type FLASH chips; I must be connected to a repaired T5.5 ECU :-)\r\n");
             reset_func = &reset_am29;
             flash_func = &flash_am29;
             flash_size = T55FLASHSIZE;
             break;
+        case ATMEL29C010:
+            printf("I have found Atmel 29C010 type FLASH chips; I must be connected to a repaired T5.5 ECU :-)\r\n");
+            reset_func = &reset_am29;
+            flash_func = NULL;
+            flash_size = T55FLASHSIZE;
+            break;
         case AMD28F010:
         case INTEL28F010:
             printf("I have found 28F010 type FLASH chips; I must be connected to a T5.5 ECU :-)\r\n");
@@ -427,20 +447,26 @@
             flash_func = &flash_am28;
             flash_size = T52FLASHSIZE;
             break;
+        case ATMEL29C512:
+            printf("I have found Atmel 29C512 type FLASH chips; I must be connected to a repaired T5.2 ECU :-)\r\n");
+            reset_func = &reset_am29;
+            flash_func = NULL;
+            flash_size = T52FLASHSIZE;
+            break;
         default:
             // unknown flash type
             printf("I could not work out what FLASH chips or TRIONIC ECU I am connected to :-(\r\n");
             return TERM_ERR;
     }
-
     // reset the FLASH chips
-    printf("Reset the FLASH chip(s) to prepare them for Erasing\r\n");
     if (!reset_func()) return TERM_ERR;
 
+
     printf("Checking the FLASH BIN file...\r\n");
-    FILE *fp = fopen("/local/modified.hex", "r");    // Open "modified.hex" on the local file system for reading
+    FILE *fp = fopen("/local/modified.bin", "r");    // Open "modified.bin" on the local file system for reading
+//    FILE *fp = fopen("/local/original.bin", "r");    // Open "original.bin" on the local file system for reading
     if (!fp) {
-        printf("Error: I could not find the BIN file MODIFIED.HEX\r\n");;
+        printf("Error: I could not find the BIN file MODIFIED.BIN\r\n");;
         return TERM_ERR;
     }
     // obtain file size - it should match the size of the FLASH chips:
@@ -449,17 +475,13 @@
     rewind (fp);
 
     // read the initial stack pointer value in the BIN file - it should match the value expected for the type of ECU
-    uint8_t stack_byte = 0;
+    uint8_t stack_bytes[4] = {0, 0, 0, 0};
     uint32_t stack_long = 0;
-    if (!fread(&stack_byte,1,1,fp)) return TERM_ERR;
-    stack_long |= (stack_byte << 24);
-    if (!fread(&stack_byte,1,1,fp)) return TERM_ERR;
-    stack_long |= (stack_byte << 16);
-    if (!fread(&stack_byte,1,1,fp)) return TERM_ERR;
-    stack_long |= (stack_byte << 8);
-    if (!fread(&stack_byte,1,1,fp)) return TERM_ERR;
-    stack_long |= stack_byte;
+    if (!fread(&stack_bytes[0],1,4,fp)) return TERM_ERR;
     rewind (fp);
+    for(uint32_t i=0; i<4; i++) {
+        (stack_long <<= 8) |= stack_bytes[i];
+    }
 
     if (flash_size == T52FLASHSIZE && (file_size != T52FLASHSIZE || stack_long != T5POINTER)) {
         fclose(fp);
@@ -486,86 +508,801 @@
         return TERM_ERR;
     }
 
-    timer.reset();
-    timer.start();
-
     uint32_t curr_addr = 0;
 
     switch (type) {
-            // AM29Fxxx chips (retrofitted to Trionic 5.x; original to T7)
         case AMD29BL802C:
-        case AMD29F400B:
         case AMD29F400T:
         case AMD29F010:
-            printf("Erasing 29BL802/F400/010 type FLASH chips...\r\n");
-            if (!erase_am29()) {
-                printf("WARNING: An error occured when I tried to erase the FLASH chips :-(\r\n");
-                return TERM_ERR;
-            }
-            break;
-            // AM28F010 chip (Trionic 5.x original)
+        case SST39SF010:
+        case AMICA29010L:
+        case ATMEL29C010:
         case AMD28F010:
         case INTEL28F010:
         case AMD28F512:
         case INTEL28F512:
-            printf("Erasing 28F010/512 type FLASH chips...\r\n");
-            if (!erase_am28(&curr_addr, &flash_size)) {
-                printf("WARNING: An error occured when I tried to erase the FLASH chips :-(\r\n");
-                return TERM_ERR;
-            }
-            break;
-        default:
-            // unknown flash type - shouldn't get here hence "Strange!"
-            printf("Strange! I couldn't work out how to erase the FLASH chips in the TRIONIC ECU that I am connected to :-(\r\n");
-            return TERM_ERR;
-    }
+        case ATMEL29C512: {
+            // BDM FLASH Driver
+            /*
+                        uint8_t flashDriver5[] = {\
+                                                 0x60,0x00,0x04,0x08,\
+                                                 0x7C,0x2F,0x2D,0x5C,0x2A,0x0D,0x00,0x00,\
+                                                 0x02,0x03,0x00,0x03,0x41,0xFA,0xFF,0xF6,\
+                                                 0x10,0xBB,0x30,0xEE,0x70,0x01,0x52,0x43,\
+                                                 0x4E,0x75,\
+                                                 0x20,0x7C,0x00,0xFF,0xFA,0x00,0x08,0x10,\
+                                                 0x00,0x04,0x66,0x4E,0xD0,0xFC,0x00,0x04,\
+                                                 0x10,0xFC,0x00,0x7F,0x08,0x10,0x00,0x03,\
+                                                 0x67,0xFA,0xD0,0xFC,0x00,0x1C,0x42,0x10,\
+                                                 0xD0,0xFC,0x00,0x23,0x30,0xBC,0x3F,0xFF,\
+                                                 0xD0,0xFC,0x00,0x04,0x70,0x07,0x30,0xC0,\
+                                                 0x30,0xBC,0x68,0x70,0xD0,0xFC,0x00,0x06,\
+                                                 0x30,0xC0,0x30,0xFC,0x30,0x30,0x30,0xC0,\
+                                                 0x30,0xBC,0x50,0x30,0xD0,0xFC,0x01,0xBE,\
+                                                 0x70,0x40,0x30,0xC0,0x30,0x80,0x30,0x3C,\
+                                                 0x55,0xF0,0x4E,0x71,0x51,0xC8,0xFF,0xFC,\
+                                                 0x60,0x18,0xD0,0xFC,0x00,0x08,0x30,0xFC,\
+                                                 0x69,0x08,0x08,0x10,0x00,0x09,0x67,0xFA,\
+                                                 0x31,0x3C,0x68,0x08,0xD0,0xFC,0x00,0x48,\
+                                                 0x42,0x50,0x4E,0x75,\
+                                                 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
+                                                 0x00,0x00,0x2C,0x3C,0x00,0x00,0x55,0x55,\
+                                                 0x2E,0x3C,0x00,0x00,0xAA,0xAA,0x2A,0x46,\
+                                                 0x53,0x8D,0x2C,0x47,0x45,0xF8,0x00,0x00,\
+                                                 0x47,0xFA,0xFF,0xDE,0x3C,0x87,0x3A,0x86,\
+                                                 0x3C,0xBC,0x90,0x90,0x36,0xDA,0x36,0x92,\
+                                                 0x3C,0x87,0x3A,0x86,0x3C,0xBC,0xF0,0xF0,\
+                                                 0x20,0x3A,0xFF,0xC6,0x72,0x02,0x48,0x41,\
+                                                 0x74,0x01,0x0C,0x00,0x00,0x25,0x67,0x50,\
+                                                 0x0C,0x00,0x00,0xB8,0x67,0x4A,0x74,0x04,\
+                                                 0x0C,0x00,0x00,0x5D,0x67,0x42,0x74,0x01,\
+                                                 0xE3,0x99,0x0C,0x00,0x00,0xA7,0x67,0x38,\
+                                                 0x0C,0x00,0x00,0xB4,0x67,0x32,0x74,0x02,\
+                                                 0x0C,0x00,0x00,0x20,0x67,0x2A,0x0C,0x00,\
+                                                 0x00,0xA4,0x67,0x24,0x0C,0x00,0x00,0xB5,\
+                                                 0x67,0x1E,0x74,0x04,0x0C,0x00,0x00,0xD5,\
+                                                 0x67,0x16,0x74,0x03,0xE3,0x99,0x0C,0x00,\
+                                                 0x00,0x23,0x67,0x0C,0xE3,0x99,0x0C,0x00,\
+                                                 0x00,0x81,0x67,0x04,0x72,0x00,0x74,0x00,\
+                                                 0x47,0xFA,0xFF,0x6A,0x26,0x81,0x47,0xFA,\
+                                                 0xFF,0x68,0x16,0x82,0x4E,0x75,\
+                                                 0x45,0x72,0x61,0x73,0x69,0x6E,0x67,0x20,\
+                                                 0x46,0x4C,0x41,0x53,0x48,0x20,0x63,0x68,\
+                                                 0x69,0x70,0x73,0x0D,0x0A,0x00,0x41,0xFA,\
+                                                 0xFF,0xE8,0x70,0x01,0x12,0x3A,0xFF,0x44,\
+                                                 0x53,0x01,0x67,0x16,0x53,0x01,0x67,0x00,\
+                                                 0x00,0xB8,0x53,0x01,0x67,0x00,0x01,0x0A,\
+                                                 0x53,0x01,0x67,0x00,0x01,0x3A,0x60,0x00,\
+                                                 0x01,0x3A,0x4B,0xF8,0x00,0x00,0x24,0x3A,\
+                                                 0xFF,0x1E,0x26,0x02,0x3A,0xBC,0xFF,0xFF,\
+                                                 0x3A,0xBC,0xFF,0xFF,0x42,0x55,0x4A,0x35,\
+                                                 0x28,0xFF,0x67,0x28,0x7A,0x19,0x1B,0xBC,\
+                                                 0x00,0x40,0x28,0xFF,0x42,0x35,0x28,0xFF,\
+                                                 0x72,0x15,0x4E,0x71,0x51,0xC9,0xFF,0xFC,\
+                                                 0x1B,0xBC,0x00,0xC0,0x28,0xFF,0x72,0x0C,\
+                                                 0x4E,0x71,0x51,0xC9,0xFF,0xFC,0x4A,0x35,\
+                                                 0x28,0xFF,0x66,0x06,0x53,0x82,0x66,0xCC,\
+                                                 0x60,0x04,0x53,0x45,0x66,0xD0,0x42,0x55,\
+                                                 0x4A,0x55,0x4A,0x05,0x67,0x00,0x00,0xE4,\
+                                                 0x24,0x03,0x50,0xC4,0x2A,0x3C,0x03,0xE8,\
+                                                 0x03,0xE8,0x72,0x20,0x1B,0x81,0x28,0xFF,\
+                                                 0x1B,0x81,0x28,0xFF,0x32,0x3C,0x55,0xF0,\
+                                                 0x4E,0x71,0x51,0xC9,0xFF,0xFC,0x4E,0xBA,\
+                                                 0xFE,0x24,0x1B,0xBC,0x00,0xA0,0x28,0xFF,\
+                                                 0x72,0x0C,0x4E,0x71,0x51,0xC9,0xFF,0xFC,\
+                                                 0xB8,0x35,0x28,0xFF,0x66,0x08,0x48,0x45,\
+                                                 0x53,0x82,0x66,0xE6,0x60,0x04,0x53,0x45,\
+                                                 0x66,0xC8,0x42,0x55,0x4A,0x55,0x4A,0x45,\
+                                                 0x67,0x00,0x00,0x98,0x60,0x00,0x00,0x90,\
+                                                 0x70,0x01,0x42,0x83,0x1D,0x87,0x08,0x00,\
+                                                 0x1B,0x86,0x08,0x00,0x1D,0xBC,0x00,0x80,\
+                                                 0x08,0x00,0x1D,0x87,0x08,0x00,0x1B,0x86,\
+                                                 0x08,0x00,0x1D,0xBC,0x00,0x10,0x08,0x00,\
+                                                 0x2A,0x00,0x4E,0xBA,0xFD,0xD0,0x20,0x05,\
+                                                 0x1A,0x30,0x09,0x90,0x08,0x05,0x00,0x07,\
+                                                 0x66,0x20,0x08,0x05,0x00,0x05,0x67,0xE8,\
+                                                 0x1A,0x30,0x09,0x90,0x08,0x05,0x00,0x07,\
+                                                 0x66,0x10,0x1D,0x87,0x08,0x00,0x1B,0x86,\
+                                                 0x08,0x00,0x1D,0xBC,0x00,0xF0,0x08,0x00,\
+                                                 0x60,0x40,0x53,0x80,0x67,0xAE,0x60,0x36,\
+                                                 0x42,0x83,0x3C,0x87,0x3A,0x86,0x3C,0xBC,\
+                                                 0x00,0x80,0x3C,0x87,0x3A,0x86,0x3C,0xBC,\
+                                                 0x00,0x10,0x4E,0xBA,0xFD,0x88,0x3A,0x15,\
+                                                 0x08,0x05,0x00,0x07,0x66,0x18,0x08,0x05,\
+                                                 0x00,0x05,0x67,0xEE,0x3A,0x15,0x08,0x05,\
+                                                 0x00,0x07,0x66,0x0A,0x3C,0x87,0x3A,0x86,\
+                                                 0x3C,0xBC,0x00,0xF0,0x60,0x04,0x42,0x80,\
+                                                 0x60,0x02,0x70,0x01,0x4E,0x75,\
+                                                 0x47,0xFB,0x01,0x70,0x00,0x00,0x04,0x50,\
+                                                 0x28,0x49,0x24,0x3C,0x00,0x00,0x01,0x00,\
+                                                 0x12,0x3A,0xFD,0xDA,0x53,0x01,0x67,0x14,\
+                                                 0x53,0x01,0x67,0x5A,0x53,0x01,0x67,0x00,\
+                                                 0x00,0xBC,0x53,0x01,0x67,0x00,0x01,0x00,\
+                                                 0x60,0x00,0x01,0x2E,0x10,0x33,0x28,0xFF,\
+                                                 0x0C,0x00,0x00,0xFF,0x67,0x28,0x7A,0x19,\
+                                                 0x19,0xBC,0x00,0x40,0x28,0xFF,0x19,0x80,\
+                                                 0x28,0xFF,0x72,0x15,0x4E,0x71,0x51,0xC9,\
+                                                 0xFF,0xFC,0x19,0xBC,0x00,0xC0,0x28,0xFF,\
+                                                 0x72,0x0C,0x4E,0x71,0x51,0xC9,0xFF,0xFC,\
+                                                 0xB0,0x34,0x28,0xFF,0x66,0x06,0x53,0x82,\
+                                                 0x66,0xCA,0x60,0x04,0x53,0x05,0x66,0xD0,\
+                                                 0x42,0x55,0x4A,0x55,0x4A,0x05,0x67,0x00,\
+                                                 0x00,0xE8,0x60,0x00,0x00,0xE0,0x20,0x0C,\
+                                                 0xD0,0x82,0xC0,0xBC,0x00,0x00,0x00,0x01,\
+                                                 0x08,0x40,0x00,0x00,0x16,0x33,0x28,0xFF,\
+                                                 0x0C,0x03,0x00,0xFF,0x67,0x48,0x1D,0x87,\
+                                                 0x08,0x00,0x1B,0x86,0x08,0x00,0x1D,0xBC,\
+                                                 0x00,0xA0,0x08,0x00,0x19,0x83,0x28,0xFF,\
+                                                 0xC6,0x3C,0x00,0x80,0x18,0x34,0x28,0xFF,\
+                                                 0x1A,0x04,0xC8,0x3C,0x00,0x80,0xB8,0x03,\
+                                                 0x67,0x24,0x08,0x05,0x00,0x05,0x67,0xEC,\
+                                                 0x18,0x34,0x28,0xFF,0xC8,0x3C,0x00,0x80,\
+                                                 0xB8,0x03,0x67,0x12,0x1D,0x87,0x08,0x00,\
+                                                 0x1B,0x86,0x08,0x00,0x1D,0xBC,0x00,0xF0,\
+                                                 0x08,0x00,0x60,0x00,0x00,0x84,0x53,0x82,\
+                                                 0x66,0xA6,0x60,0x78,0x36,0x33,0x28,0xFE,\
+                                                 0x0C,0x43,0xFF,0xFF,0x67,0x3A,0x3C,0x87,\
+                                                 0x3A,0x86,0x3C,0xBC,0x00,0xA0,0x39,0x83,\
+                                                 0x28,0xFE,0xC6,0x7C,0x00,0x80,0x38,0x34,\
+                                                 0x28,0xFE,0x3A,0x04,0xC8,0x7C,0x00,0x80,\
+                                                 0xB8,0x43,0x67,0x1C,0x08,0x05,0x00,0x05,\
+                                                 0x67,0xEC,0x38,0x34,0x28,0xFE,0xC8,0x7C,\
+                                                 0x00,0x80,0xB8,0x43,0x67,0x0A,0x3C,0x87,\
+                                                 0x3A,0x86,0x3C,0xBC,0x00,0xF0,0x60,0x38,\
+                                                 0x55,0x82,0x66,0xB8,0x60,0x2E,0x3C,0x87,\
+                                                 0x3A,0x86,0x3C,0xBC,0xA0,0xA0,0x39,0xB3,\
+                                                 0x28,0xFE,0x28,0xFE,0x55,0x82,0x66,0xF6,\
+                                                 0x32,0x3C,0x55,0xF0,0x4E,0x71,0x51,0xC9,\
+                                                 0xFF,0xFC,0x34,0x3C,0x01,0x00,0x36,0x33,\
+                                                 0x28,0xFE,0xB6,0x74,0x28,0xFE,0x66,0x08,\
+                                                 0x55,0x82,0x66,0xF2,0x42,0x80,0x60,0x02,\
+                                                 0x70,0x01,0x4E,0x75,\
+                                                 0x4F,0xFB,0x01,0x70,0x00,0x00,0x02,0xF4,\
+                                                 0x4E,0xBA,0xFC,0x0A,0x4E,0xBA,0xFC,0x84,\
+                                                 0x4E,0xBA,0xFD,0x32,0x4A,0xFA,0x42,0x80,\
+                                                 0x22,0x40,0x4E,0xBA,0xFE,0x88,0x4A,0xFA,\
+                                                 0xD2,0xFC,0x01,0x00,0x60,0xF4
+                                                };
 
-    timer.stop();
-    printf("Erasing took %#.1f seconds.\r\n",timer.read());
-
-    printf("Programming the FLASH chips...\r\n");
+                        uint8_t flashDriver6[] = {\
+                                                0x60,0x00,0x04,0x0A,\
+                                                0x7C,0x2F,0x2D,0x5C,0x2A,0x0D,0x00,0x00,\
+                                                0x02,0x03,0x00,0x03,0x41,0xFA,0xFF,0xF6,\
+                                                0x10,0xBB,0x30,0xEE,0x70,0x01,0x4A,0xFA,\
+                                                0x52,0x43,0x4E,0x75,\
+                                                0x20,0x7C,0x00,0xFF,0xFA,0x00,0x08,0x10,\
+                                                0x00,0x04,0x66,0x4E,0xD0,0xFC,0x00,0x04,\
+                                                0x10,0xFC,0x00,0x7F,0x08,0x10,0x00,0x03,\
+                                                0x67,0xFA,0xD0,0xFC,0x00,0x1C,0x42,0x10,\
+                                                0xD0,0xFC,0x00,0x23,0x30,0xBC,0x3F,0xFF,\
+                                                0xD0,0xFC,0x00,0x04,0x70,0x07,0x30,0xC0,\
+                                                0x30,0xBC,0x68,0x70,0xD0,0xFC,0x00,0x06,\
+                                                0x30,0xC0,0x30,0xFC,0x30,0x30,0x30,0xC0,\
+                                                0x30,0xBC,0x50,0x30,0xD0,0xFC,0x01,0xBE,\
+                                                0x70,0x40,0x30,0xC0,0x30,0x80,0x30,0x3C,\
+                                                0x55,0xF0,0x4E,0x71,0x51,0xC8,0xFF,0xFC,\
+                                                0x60,0x18,0xD0,0xFC,0x00,0x08,0x30,0xFC,\
+                                                0x69,0x08,0x08,0x10,0x00,0x09,0x67,0xFA,\
+                                                0x31,0x3C,0x68,0x08,0xD0,0xFC,0x00,0x48,\
+                                                0x42,0x50,0x4E,0x75,\
+                                                0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
+                                                0x00,0x00,0x2C,0x3C,0x00,0x00,0x55,0x55,\
+                                                0x2E,0x3C,0x00,0x00,0xAA,0xAA,0x2A,0x46,\
+                                                0x53,0x8D,0x2C,0x47,0x45,0xF8,0x00,0x00,\
+                                                0x47,0xFA,0xFF,0xDE,0x3C,0x87,0x3A,0x86,\
+                                                0x3C,0xBC,0x90,0x90,0x36,0xDA,0x36,0x92,\
+                                                0x3C,0x87,0x3A,0x86,0x3C,0xBC,0xF0,0xF0,\
+                                                0x20,0x3A,0xFF,0xC6,0x72,0x02,0x48,0x41,\
+                                                0x74,0x01,0x0C,0x00,0x00,0x25,0x67,0x50,\
+                                                0x0C,0x00,0x00,0xB8,0x67,0x4A,0x74,0x04,\
+                                                0x0C,0x00,0x00,0x5D,0x67,0x42,0x74,0x01,\
+                                                0xE3,0x99,0x0C,0x00,0x00,0xA7,0x67,0x38,\
+                                                0x0C,0x00,0x00,0xB4,0x67,0x32,0x74,0x02,\
+                                                0x0C,0x00,0x00,0x20,0x67,0x2A,0x0C,0x00,\
+                                                0x00,0xA4,0x67,0x24,0x0C,0x00,0x00,0xB5,\
+                                                0x67,0x1E,0x74,0x04,0x0C,0x00,0x00,0xD5,\
+                                                0x67,0x16,0x74,0x03,0xE3,0x99,0x0C,0x00,\
+                                                0x00,0x23,0x67,0x0C,0xE3,0x99,0x0C,0x00,\
+                                                0x00,0x81,0x67,0x04,0x72,0x00,0x74,0x00,\
+                                                0x47,0xFA,0xFF,0x6A,0x26,0x81,0x47,0xFA,\
+                                                0xFF,0x68,0x16,0x82,0x4E,0x75,\
+                                                0x45,0x72,0x61,0x73,0x69,0x6E,0x67,0x20,\
+                                                0x46,0x4C,0x41,0x53,0x48,0x20,0x63,0x68,\
+                                                0x69,0x70,0x73,0x0D,0x0A,0x00,0x41,0xFA,\
+                                                0xFF,0xE8,0x70,0x01,0x12,0x3A,0xFF,0x44,\
+                                                0x53,0x01,0x67,0x16,0x53,0x01,0x67,0x00,\
+                                                0x00,0xB8,0x53,0x01,0x67,0x00,0x01,0x0A,\
+                                                0x53,0x01,0x67,0x00,0x01,0x3A,0x60,0x00,\
+                                                0x01,0x3A,0x4B,0xF8,0x00,0x00,0x24,0x3A,\
+                                                0xFF,0x1E,0x26,0x02,0x3A,0xBC,0xFF,0xFF,\
+                                                0x3A,0xBC,0xFF,0xFF,0x42,0x55,0x4A,0x35,\
+                                                0x28,0xFF,0x67,0x28,0x7A,0x19,0x1B,0xBC,\
+                                                0x00,0x40,0x28,0xFF,0x42,0x35,0x28,0xFF,\
+                                                0x72,0x15,0x4E,0x71,0x51,0xC9,0xFF,0xFC,\
+                                                0x1B,0xBC,0x00,0xC0,0x28,0xFF,0x72,0x0C,\
+                                                0x4E,0x71,0x51,0xC9,0xFF,0xFC,0x4A,0x35,\
+                                                0x28,0xFF,0x66,0x06,0x53,0x82,0x66,0xCC,\
+                                                0x60,0x04,0x53,0x45,0x66,0xD0,0x42,0x55,\
+                                                0x4A,0x55,0x4A,0x05,0x67,0x00,0x00,0xE4,\
+                                                0x24,0x03,0x50,0xC4,0x2A,0x3C,0x03,0xE8,\
+                                                0x03,0xE8,0x72,0x20,0x1B,0x81,0x28,0xFF,\
+                                                0x1B,0x81,0x28,0xFF,0x32,0x3C,0x55,0xF0,\
+                                                0x4E,0x71,0x51,0xC9,0xFF,0xFC,0x4E,0xBA,\
+                                                0xFE,0x22,0x1B,0xBC,0x00,0xA0,0x28,0xFF,\
+                                                0x72,0x0C,0x4E,0x71,0x51,0xC9,0xFF,0xFC,\
+                                                0xB8,0x35,0x28,0xFF,0x66,0x08,0x48,0x45,\
+                                                0x53,0x82,0x66,0xE6,0x60,0x04,0x53,0x45,\
+                                                0x66,0xC8,0x42,0x55,0x4A,0x55,0x4A,0x45,\
+                                                0x67,0x00,0x00,0x98,0x60,0x00,0x00,0x90,\
+                                                0x70,0x01,0x42,0x83,0x1D,0x87,0x08,0x00,\
+                                                0x1B,0x86,0x08,0x00,0x1D,0xBC,0x00,0x80,\
+                                                0x08,0x00,0x1D,0x87,0x08,0x00,0x1B,0x86,\
+                                                0x08,0x00,0x1D,0xBC,0x00,0x10,0x08,0x00,\
+                                                0x2A,0x00,0x4E,0xBA,0xFD,0xCE,0x20,0x05,\
+                                                0x1A,0x30,0x09,0x90,0x08,0x05,0x00,0x07,\
+                                                0x66,0x20,0x08,0x05,0x00,0x05,0x67,0xE8,\
+                                                0x1A,0x30,0x09,0x90,0x08,0x05,0x00,0x07,\
+                                                0x66,0x10,0x1D,0x87,0x08,0x00,0x1B,0x86,\
+                                                0x08,0x00,0x1D,0xBC,0x00,0xF0,0x08,0x00,\
+                                                0x60,0x40,0x53,0x80,0x67,0xAE,0x60,0x36,\
+                                                0x42,0x83,0x3C,0x87,0x3A,0x86,0x3C,0xBC,\
+                                                0x00,0x80,0x3C,0x87,0x3A,0x86,0x3C,0xBC,\
+                                                0x00,0x10,0x4E,0xBA,0xFD,0x86,0x3A,0x15,\
+                                                0x08,0x05,0x00,0x07,0x66,0x18,0x08,0x05,\
+                                                0x00,0x05,0x67,0xEE,0x3A,0x15,0x08,0x05,\
+                                                0x00,0x07,0x66,0x0A,0x3C,0x87,0x3A,0x86,\
+                                                0x3C,0xBC,0x00,0xF0,0x60,0x04,0x42,0x80,\
+                                                0x60,0x02,0x70,0x01,0x4E,0x75,\
+                                                0x47,0xFB,0x01,0x70,0x00,0x00,0x04,0x4E,\
+                                                0x28,0x49,0x24,0x3C,0x00,0x00,0x01,0x00,\
+                                                0x12,0x3A,0xFD,0xDA,0x53,0x01,0x67,0x14,\
+                                                0x53,0x01,0x67,0x5A,0x53,0x01,0x67,0x00,\
+                                                0x00,0xBC,0x53,0x01,0x67,0x00,0x01,0x00,\
+                                                0x60,0x00,0x01,0x2E,0x10,0x33,0x28,0xFF,\
+                                                0x0C,0x00,0x00,0xFF,0x67,0x28,0x7A,0x19,\
+                                                0x19,0xBC,0x00,0x40,0x28,0xFF,0x19,0x80,\
+                                                0x28,0xFF,0x72,0x15,0x4E,0x71,0x51,0xC9,\
+                                                0xFF,0xFC,0x19,0xBC,0x00,0xC0,0x28,0xFF,\
+                                                0x72,0x0C,0x4E,0x71,0x51,0xC9,0xFF,0xFC,\
+                                                0xB0,0x34,0x28,0xFF,0x66,0x06,0x53,0x82,\
+                                                0x66,0xCA,0x60,0x04,0x53,0x05,0x66,0xD0,\
+                                                0x42,0x55,0x4A,0x55,0x4A,0x05,0x67,0x00,\
+                                                0x00,0xE8,0x60,0x00,0x00,0xE0,0x20,0x0C,\
+                                                0xD0,0x82,0xC0,0xBC,0x00,0x00,0x00,0x01,\
+                                                0x08,0x40,0x00,0x00,0x16,0x33,0x28,0xFF,\
+                                                0x0C,0x03,0x00,0xFF,0x67,0x48,0x1D,0x87,\
+                                                0x08,0x00,0x1B,0x86,0x08,0x00,0x1D,0xBC,\
+                                                0x00,0xA0,0x08,0x00,0x19,0x83,0x28,0xFF,\
+                                                0xC6,0x3C,0x00,0x80,0x18,0x34,0x28,0xFF,\
+                                                0x1A,0x04,0xC8,0x3C,0x00,0x80,0xB8,0x03,\
+                                                0x67,0x24,0x08,0x05,0x00,0x05,0x67,0xEC,\
+                                                0x18,0x34,0x28,0xFF,0xC8,0x3C,0x00,0x80,\
+                                                0xB8,0x03,0x67,0x12,0x1D,0x87,0x08,0x00,\
+                                                0x1B,0x86,0x08,0x00,0x1D,0xBC,0x00,0xF0,\
+                                                0x08,0x00,0x60,0x00,0x00,0x84,0x53,0x82,\
+                                                0x66,0xA6,0x60,0x78,0x36,0x33,0x28,0xFE,\
+                                                0x0C,0x43,0xFF,0xFF,0x67,0x3A,0x3C,0x87,\
+                                                0x3A,0x86,0x3C,0xBC,0x00,0xA0,0x39,0x83,\
+                                                0x28,0xFE,0xC6,0x7C,0x00,0x80,0x38,0x34,\
+                                                0x28,0xFE,0x3A,0x04,0xC8,0x7C,0x00,0x80,\
+                                                0xB8,0x43,0x67,0x1C,0x08,0x05,0x00,0x05,\
+                                                0x67,0xEC,0x38,0x34,0x28,0xFE,0xC8,0x7C,\
+                                                0x00,0x80,0xB8,0x43,0x67,0x0A,0x3C,0x87,\
+                                                0x3A,0x86,0x3C,0xBC,0x00,0xF0,0x60,0x38,\
+                                                0x55,0x82,0x66,0xB8,0x60,0x2E,0x3C,0x87,\
+                                                0x3A,0x86,0x3C,0xBC,0xA0,0xA0,0x39,0xB3,\
+                                                0x28,0xFE,0x28,0xFE,0x55,0x82,0x66,0xF6,\
+                                                0x32,0x3C,0x55,0xF0,0x4E,0x71,0x51,0xC9,\
+                                                0xFF,0xFC,0x34,0x3C,0x01,0x00,0x36,0x33,\
+                                                0x28,0xFE,0xB6,0x74,0x28,0xFE,0x66,0x08,\
+                                                0x55,0x82,0x66,0xF2,0x42,0x80,0x60,0x02,\
+                                                0x70,0x01,0x4E,0x75,\
+                                                0x4F,0xFB,0x01,0x70,0x00,0x00,0x02,0xF2,\
+                                                0x4E,0xBA,0xFC,0x0A,0x4E,0xBA,0xFC,0x84,\
+                                                0x4E,0xBA,0xFD,0x32,0x4A,0xFA,0x42,0x80,\
+                                                0x22,0x40,0x4E,0xBA,0xFE,0x88,0x4A,0xFA,\
+                                                0xD2,0xFC,0x01,0x00,0x60,0xF4,0x00,0x00
+                                                };
+            */
+            uint8_t flashDriver[] = {\
+                                     0x60,0x00,0x04,0x0C,\
+                                     0x7C,0x2F,0x2D,0x5C,0x2A,0x0D,0x00,0x00,\
+                                     0x02,0x03,0x00,0x03,0x41,0xFA,0xFF,0xF6,\
+                                     0x10,0xBB,0x30,0xEE,0x70,0x01,0x4A,0xFA,\
+                                     0x52,0x43,0x4E,0x75,\
+                                     0x20,0x7C,0x00,0xFF,0xFA,0x00,0x08,0x10,\
+                                     0x00,0x04,0x66,0x4E,0xD0,0xFC,0x00,0x04,\
+                                     0x10,0xFC,0x00,0x7F,0x08,0x10,0x00,0x03,\
+                                     0x67,0xFA,0xD0,0xFC,0x00,0x1C,0x42,0x10,\
+                                     0xD0,0xFC,0x00,0x23,0x30,0xBC,0x3F,0xFF,\
+                                     0xD0,0xFC,0x00,0x04,0x70,0x07,0x30,0xC0,\
+                                     0x30,0xBC,0x68,0x70,0xD0,0xFC,0x00,0x06,\
+                                     0x30,0xC0,0x30,0xFC,0x30,0x30,0x30,0xC0,\
+                                     0x30,0xBC,0x50,0x30,0xD0,0xFC,0x01,0xBE,\
+                                     0x70,0x40,0x30,0xC0,0x30,0x80,0x30,0x3C,\
+                                     0x55,0xF0,0x4E,0x71,0x51,0xC8,0xFF,0xFC,\
+                                     0x60,0x18,0xD0,0xFC,0x00,0x08,0x30,0xFC,\
+                                     0x69,0x08,0x08,0x10,0x00,0x09,0x67,0xFA,\
+                                     0x31,0x3C,0x68,0x08,0xD0,0xFC,0x00,0x48,\
+                                     0x42,0x50,0x4E,0x75,\
+                                     0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
+                                     0x00,0x00,0x2C,0x3C,0x00,0x00,0x55,0x55,\
+                                     0x2E,0x3C,0x00,0x00,0xAA,0xAA,0x2A,0x46,\
+                                     0x53,0x8D,0x2C,0x47,0x45,0xF8,0x00,0x00,\
+                                     0x47,0xFA,0xFF,0xDE,0x3C,0x87,0x3A,0x86,\
+                                     0x3C,0xBC,0x90,0x90,0x36,0xDA,0x36,0x92,\
+                                     0x3C,0x87,0x3A,0x86,0x3C,0xBC,0xF0,0xF0,\
+                                     0x20,0x3A,0xFF,0xC6,0x72,0x02,0x48,0x41,\
+                                     0x74,0x01,0x0C,0x00,0x00,0x25,0x67,0x50,\
+                                     0x0C,0x00,0x00,0xB8,0x67,0x4A,0x74,0x04,\
+                                     0x0C,0x00,0x00,0x5D,0x67,0x42,0x74,0x01,\
+                                     0xE3,0x99,0x0C,0x00,0x00,0xA7,0x67,0x38,\
+                                     0x0C,0x00,0x00,0xB4,0x67,0x32,0x74,0x02,\
+                                     0x0C,0x00,0x00,0x20,0x67,0x2A,0x0C,0x00,\
+                                     0x00,0xA4,0x67,0x24,0x0C,0x00,0x00,0xB5,\
+                                     0x67,0x1E,0x74,0x04,0x0C,0x00,0x00,0xD5,\
+                                     0x67,0x16,0x74,0x03,0xE3,0x99,0x0C,0x00,\
+                                     0x00,0x23,0x67,0x0C,0xE3,0x99,0x0C,0x00,\
+                                     0x00,0x81,0x67,0x04,0x72,0x00,0x74,0x00,\
+                                     0x47,0xFA,0xFF,0x6A,0x26,0x81,0x47,0xFA,\
+                                     0xFF,0x68,0x16,0x82,0x4E,0x75,\
+                                     0x45,0x72,0x61,0x73,0x69,0x6E,0x67,0x20,\
+                                     0x46,0x4C,0x41,0x53,0x48,0x20,0x63,0x68,\
+                                     0x69,0x70,0x73,0x0D,0x0A,0x00,0x41,0xFA,\
+                                     0xFF,0xE8,0x70,0x01,0x4A,0xFA,0x12,0x3A,\
+                                     0xFF,0x42,0x53,0x01,0x67,0x16,0x53,0x01,\
+                                     0x67,0x00,0x00,0xB8,0x53,0x01,0x67,0x00,\
+                                     0x01,0x0A,0x53,0x01,0x67,0x00,0x01,0x3A,\
+                                     0x60,0x00,0x01,0x3A,0x4B,0xF8,0x00,0x00,\
+                                     0x24,0x3A,0xFF,0x1C,0x26,0x02,0x3A,0xBC,\
+                                     0xFF,0xFF,0x3A,0xBC,0xFF,0xFF,0x42,0x55,\
+                                     0x4A,0x35,0x28,0xFF,0x67,0x28,0x7A,0x19,\
+                                     0x1B,0xBC,0x00,0x40,0x28,0xFF,0x42,0x35,\
+                                     0x28,0xFF,0x72,0x15,0x4E,0x71,0x51,0xC9,\
+                                     0xFF,0xFC,0x1B,0xBC,0x00,0xC0,0x28,0xFF,\
+                                     0x72,0x0C,0x4E,0x71,0x51,0xC9,0xFF,0xFC,\
+                                     0x4A,0x35,0x28,0xFF,0x66,0x06,0x53,0x82,\
+                                     0x66,0xCC,0x60,0x04,0x53,0x45,0x66,0xD0,\
+                                     0x42,0x55,0x4A,0x55,0x4A,0x05,0x67,0x00,\
+                                     0x00,0xE4,0x24,0x03,0x50,0xC4,0x2A,0x3C,\
+                                     0x03,0xE8,0x03,0xE8,0x72,0x20,0x1B,0x81,\
+                                     0x28,0xFF,0x1B,0x81,0x28,0xFF,0x32,0x3C,\
+                                     0x55,0xF0,0x4E,0x71,0x51,0xC9,0xFF,0xFC,\
+                                     0x4E,0xBA,0xFE,0x20,0x1B,0xBC,0x00,0xA0,\
+                                     0x28,0xFF,0x72,0x0C,0x4E,0x71,0x51,0xC9,\
+                                     0xFF,0xFC,0xB8,0x35,0x28,0xFF,0x66,0x08,\
+                                     0x48,0x45,0x53,0x82,0x66,0xE6,0x60,0x04,\
+                                     0x53,0x45,0x66,0xC8,0x42,0x55,0x4A,0x55,\
+                                     0x4A,0x45,0x67,0x00,0x00,0x98,0x60,0x00,\
+                                     0x00,0x90,0x70,0x01,0x42,0x83,0x1D,0x87,\
+                                     0x08,0x00,0x1B,0x86,0x08,0x00,0x1D,0xBC,\
+                                     0x00,0x80,0x08,0x00,0x1D,0x87,0x08,0x00,\
+                                     0x1B,0x86,0x08,0x00,0x1D,0xBC,0x00,0x10,\
+                                     0x08,0x00,0x2A,0x00,0x4E,0xBA,0xFD,0xCC,\
+                                     0x20,0x05,0x1A,0x30,0x09,0x90,0x08,0x05,\
+                                     0x00,0x07,0x66,0x20,0x08,0x05,0x00,0x05,\
+                                     0x67,0xE8,0x1A,0x30,0x09,0x90,0x08,0x05,\
+                                     0x00,0x07,0x66,0x10,0x1D,0x87,0x08,0x00,\
+                                     0x1B,0x86,0x08,0x00,0x1D,0xBC,0x00,0xF0,\
+                                     0x08,0x00,0x60,0x40,0x53,0x80,0x67,0xAE,\
+                                     0x60,0x36,0x42,0x83,0x3C,0x87,0x3A,0x86,\
+                                     0x3C,0xBC,0x00,0x80,0x3C,0x87,0x3A,0x86,\
+                                     0x3C,0xBC,0x00,0x10,0x4E,0xBA,0xFD,0x84,\
+                                     0x3A,0x15,0x08,0x05,0x00,0x07,0x66,0x18,\
+                                     0x08,0x05,0x00,0x05,0x67,0xEE,0x3A,0x15,\
+                                     0x08,0x05,0x00,0x07,0x66,0x0A,0x3C,0x87,\
+                                     0x3A,0x86,0x3C,0xBC,0x00,0xF0,0x60,0x04,\
+                                     0x42,0x80,0x60,0x02,0x70,0x01,0x4E,0x75,\
+                                     0x47,0xFB,0x01,0x70,0x00,0x00,0x04,0x4C,\
+                                     0x28,0x49,0x24,0x3C,0x00,0x00,0x01,0x00,\
+                                     0x12,0x3A,0xFD,0xD8,0x53,0x01,0x67,0x14,\
+                                     0x53,0x01,0x67,0x5A,0x53,0x01,0x67,0x00,\
+                                     0x00,0xBC,0x53,0x01,0x67,0x00,0x01,0x00,\
+                                     0x60,0x00,0x01,0x2E,0x10,0x33,0x28,0xFF,\
+                                     0x0C,0x00,0x00,0xFF,0x67,0x28,0x7A,0x19,\
+                                     0x19,0xBC,0x00,0x40,0x28,0xFF,0x19,0x80,\
+                                     0x28,0xFF,0x72,0x15,0x4E,0x71,0x51,0xC9,\
+                                     0xFF,0xFC,0x19,0xBC,0x00,0xC0,0x28,0xFF,\
+                                     0x72,0x0C,0x4E,0x71,0x51,0xC9,0xFF,0xFC,\
+                                     0xB0,0x34,0x28,0xFF,0x66,0x06,0x53,0x82,\
+                                     0x66,0xCA,0x60,0x04,0x53,0x05,0x66,0xD0,\
+                                     0x42,0x55,0x4A,0x55,0x4A,0x05,0x67,0x00,\
+                                     0x00,0xE8,0x60,0x00,0x00,0xE0,0x20,0x0C,\
+                                     0xD0,0x82,0xC0,0xBC,0x00,0x00,0x00,0x01,\
+                                     0x08,0x40,0x00,0x00,0x16,0x33,0x28,0xFF,\
+                                     0x0C,0x03,0x00,0xFF,0x67,0x48,0x1D,0x87,\
+                                     0x08,0x00,0x1B,0x86,0x08,0x00,0x1D,0xBC,\
+                                     0x00,0xA0,0x08,0x00,0x19,0x83,0x28,0xFF,\
+                                     0xC6,0x3C,0x00,0x80,0x18,0x34,0x28,0xFF,\
+                                     0x1A,0x04,0xC8,0x3C,0x00,0x80,0xB8,0x03,\
+                                     0x67,0x24,0x08,0x05,0x00,0x05,0x67,0xEC,\
+                                     0x18,0x34,0x28,0xFF,0xC8,0x3C,0x00,0x80,\
+                                     0xB8,0x03,0x67,0x12,0x1D,0x87,0x08,0x00,\
+                                     0x1B,0x86,0x08,0x00,0x1D,0xBC,0x00,0xF0,\
+                                     0x08,0x00,0x60,0x00,0x00,0x84,0x53,0x82,\
+                                     0x66,0xA6,0x60,0x78,0x36,0x33,0x28,0xFE,\
+                                     0x0C,0x43,0xFF,0xFF,0x67,0x3A,0x3C,0x87,\
+                                     0x3A,0x86,0x3C,0xBC,0x00,0xA0,0x39,0x83,\
+                                     0x28,0xFE,0xC6,0x7C,0x00,0x80,0x38,0x34,\
+                                     0x28,0xFE,0x3A,0x04,0xC8,0x7C,0x00,0x80,\
+                                     0xB8,0x43,0x67,0x1C,0x08,0x05,0x00,0x05,\
+                                     0x67,0xEC,0x38,0x34,0x28,0xFE,0xC8,0x7C,\
+                                     0x00,0x80,0xB8,0x43,0x67,0x0A,0x3C,0x87,\
+                                     0x3A,0x86,0x3C,0xBC,0x00,0xF0,0x60,0x38,\
+                                     0x55,0x82,0x66,0xB8,0x60,0x2E,0x3C,0x87,\
+                                     0x3A,0x86,0x3C,0xBC,0xA0,0xA0,0x39,0xB3,\
+                                     0x28,0xFE,0x28,0xFE,0x55,0x82,0x66,0xF6,\
+                                     0x32,0x3C,0x55,0xF0,0x4E,0x71,0x51,0xC9,\
+                                     0xFF,0xFC,0x34,0x3C,0x01,0x00,0x36,0x33,\
+                                     0x28,0xFE,0xB6,0x74,0x28,0xFE,0x66,0x08,\
+                                     0x55,0x82,0x66,0xF2,0x42,0x80,0x60,0x02,\
+                                     0x70,0x01,0x4E,0x75,\
+                                     0x4F,0xFB,0x01,0x70,0x00,0x00,0x02,0xF0,\
+                                     0x4E,0xBA,0xFC,0x08,0x4E,0xBA,0xFC,0x82,\
+                                     0x4E,0xBA,0xFD,0x30,0x4A,0xFA,0x42,0x80,\
+                                     0x22,0x40,0x4E,0xBA,0xFE,0x88,0x4A,0xFA,\
+                                     0xD2,0xFC,0x01,0x00,0x60,0xF4
+                                    };
 
-    timer.reset();
-    timer.start();
+            /*
+            uint8_t flashDriver8[] = {\
+            0x60,0x00,0x05,0xC2,0x54,0x72,0x69,0x6F,\
+            0x6E,0x69,0x63,0x20,0x45,0x43,0x55,0x20,\
+            0x46,0x4C,0x41,0x53,0x48,0x20,0x73,0x63,\
+            0x72,0x69,0x70,0x74,0x0D,0x0A,0x00,0x50,\
+            0x72,0x6F,0x67,0x72,0x61,0x6D,0x6D,0x69,\
+            0x6E,0x67,0x20,0x46,0x4C,0x41,0x53,0x48,\
+            0x20,0x63,0x68,0x69,0x70,0x20,0x61,0x64,\
+            0x64,0x72,0x65,0x73,0x73,0x65,0x73,0x3A,\
+            0x0D,0x0A,0x00,0x54,0x72,0x69,0x6F,0x6E,\
+            0x69,0x63,0x20,0x45,0x43,0x55,0x20,0x46,\
+            0x4C,0x41,0x53,0x48,0x20,0x63,0x68,0x69,\
+            0x70,0x73,0x20,0x75,0x70,0x64,0x61,0x74,\
+            0x65,0x64,0x20,0x2D,0x20,0x65,0x6E,0x6A,\
+            0x6F,0x79,0x20,0x3A,0x2D,0x29,0x0D,0x0A,\
+            0x00,0x46,0x4C,0x41,0x53,0x48,0x20,0x73,\
+            0x69,0x7A,0x65,0x3A,0x20,0x30,0x78,0x30,\
+            0x46,0x61,0x64,0x65,0x30,0x20,0x42,0x79,\
+            0x74,0x65,0x73,0x0D,0x0A,0x00,0x30,0x78,\
+            0x30,0x43,0x61,0x66,0x65,0x30,0x2D,0x30,\
+            0x42,0x61,0x62,0x65,0x30,0x0D,0x00,0x72,\
+            0x62,0x00,\
+            0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,\
+            0x38,0x39,0x41,0x42,0x43,0x44,0x45,0x46,\
+            0xE1,0x9A,0x76,0x05,0x42,0x84,0xE9,0x9A,\
+            0x18,0x02,0x02,0x04,0x00,0x0F,0x10,0xFB,\
+            0x40,0xE0,0x51,0xCB,0xFF,0xF2,0x4E,0x75,\
+            0x7C,0x2F,0x2D,0x5C,0x2A,0x0D,0x00,0x00,\
+            0x02,0x03,0x00,0x03,0x41,0xFA,0xFF,0xF6,\
+            0x10,0xBB,0x30,0xEE,0x70,0x01,0x4A,0xFA,\
+            0x52,0x43,0x4E,0x75,\
+            0x20,0x7C,0x00,0xFF,0xFA,0x00,0x08,0x10,\
+            0x00,0x04,0x66,0x4E,0xD0,0xFC,0x00,0x04,\
+            0x10,0xFC,0x00,0x7F,0x08,0x10,0x00,0x03,\
+            0x67,0xFA,0xD0,0xFC,0x00,0x1C,0x42,0x10,\
+            0xD0,0xFC,0x00,0x23,0x30,0xBC,0x3F,0xFF,\
+            0xD0,0xFC,0x00,0x04,0x70,0x07,0x30,0xC0,\
+            0x30,0xBC,0x68,0x70,0xD0,0xFC,0x00,0x06,\
+            0x30,0xC0,0x30,0xFC,0x30,0x30,0x30,0xC0,\
+            0x30,0xBC,0x50,0x30,0xD0,0xFC,0x01,0xBE,\
+            0x70,0x40,0x30,0xC0,0x30,0x80,0x30,0x3C,\
+            0x55,0xF0,0x4E,0x71,0x51,0xC8,0xFF,0xFC,\
+            0x60,0x18,0xD0,0xFC,0x00,0x08,0x30,0xFC,\
+            0x69,0x08,0x08,0x10,0x00,0x09,0x67,0xFA,\
+            0x31,0x3C,0x68,0x08,0xD0,0xFC,0x00,0x48,\
+            0x42,0x50,0x4E,0x75,\
+            0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
+            0x00,0x00,0x2C,0x3C,0x00,0x00,0x55,0x55,\
+            0x2E,0x3C,0x00,0x00,0xAA,0xAA,0x2A,0x46,\
+            0x53,0x8D,0x2C,0x47,0x45,0xF8,0x00,0x00,\
+            0x47,0xFA,0xFF,0xDE,0x3C,0x87,0x3A,0x86,\
+            0x3C,0xBC,0x90,0x90,0x36,0xDA,0x36,0x92,\
+            0x3C,0x87,0x3A,0x86,0x3C,0xBC,0xF0,0xF0,\
+            0x20,0x3A,0xFF,0xC6,0x72,0x02,0x48,0x41,\
+            0x74,0x01,0x0C,0x00,0x00,0x25,0x67,0x50,\
+            0x0C,0x00,0x00,0xB8,0x67,0x4A,0x74,0x04,\
+            0x0C,0x00,0x00,0x5D,0x67,0x42,0x74,0x01,\
+            0xE3,0x99,0x0C,0x00,0x00,0xA7,0x67,0x38,\
+            0x0C,0x00,0x00,0xB4,0x67,0x32,0x74,0x02,\
+            0x0C,0x00,0x00,0x20,0x67,0x2A,0x0C,0x00,\
+            0x00,0xA4,0x67,0x24,0x0C,0x00,0x00,0xB5,\
+            0x67,0x1E,0x74,0x04,0x0C,0x00,0x00,0xD5,\
+            0x67,0x16,0x74,0x03,0xE3,0x99,0x0C,0x00,\
+            0x00,0x23,0x67,0x0C,0xE3,0x99,0x0C,0x00,\
+            0x00,0x81,0x67,0x04,0x72,0x00,0x74,0x00,\
+            0x47,0xFA,0xFF,0x6A,0x26,0x81,0x47,0xFA,\
+            0xFF,0x68,0x16,0x82,0x4E,0x75,\
+            0x46,0x6F,0x75,0x6E,0x64,0x20,0x61,0x20,\
+            0x54,0x20,0x20,0x20,0x0D,0x0A,0x00,0x00,\
+            0x20,0x3A,0xFF,0x4C,0x48,0x40,0x41,0xFA,\
+            0xFF,0xF1,0x72,0x38,0xE9,0x18,0x65,0x16,\
+            0x72,0x37,0xE3,0x18,0x65,0x10,0x72,0x35,\
+            0x10,0xC1,0x72,0x2E,0x10,0xC1,0x72,0x35,\
+            0xE3,0x18,0x65,0x02,0x72,0x32,0x10,0x81,\
+            0x41,0xFA,0xFF,0xC6,0x70,0x01,0x4A,0xFA,\
+            0x4E,0x75,\
+            0x46,0x49,0x4C,0x45,0x4E,0x41,0x4D,0x45,\
+            0x2E,0x42,0x49,0x4E,0x00,0x45,0x6E,0x74,\
+            0x65,0x72,0x20,0x61,0x20,0x66,0x69,0x6C,\
+            0x65,0x6E,0x61,0x6D,0x65,0x20,0x28,0x75,\
+            0x70,0x20,0x74,0x6F,0x20,0x38,0x20,0x63,\
+            0x68,0x61,0x72,0x61,0x63,0x74,0x65,0x72,\
+            0x73,0x29,0x3A,0x20,0x00,0x00,0x41,0xFA,\
+            0xFF,0xD5,0x70,0x01,0x4A,0xFA,0x41,0xFA,\
+            0xFF,0xC0,0x78,0x08,0x70,0x04,0x4A,0xFA,\
+            0x0C,0x00,0x00,0x0D,0x67,0x26,0x0C,0x00,\
+            0x00,0x2E,0x67,0x20,0x0C,0x00,0x00,0x08,\
+            0x66,0x0A,0xB8,0x00,0x67,0xE6,0x53,0x48,\
+            0x54,0x44,0x60,0x06,0x4A,0x04,0x67,0x0C,\
+            0x10,0xC0,0x12,0x00,0x70,0x02,0x4A,0xFA,\
+            0x51,0xCC,0xFF,0xD2,0x10,0xFC,0x00,0x2E,\
+            0x10,0xFC,0x00,0x42,0x10,0xFC,0x00,0x49,\
+            0x10,0xFC,0x00,0x4E,0x10,0xBC,0x00,0x00,\
+            0x59,0x88,0x70,0x01,0x4A,0xFA,0x41,0xFA,\
+            0xFD,0xB5,0x70,0x01,0x4A,0xFA,0x41,0xFA,\
+            0xFF,0x68,0x43,0xFA,0xFD,0xBD,0x70,0x06,\
+            0x4A,0xFA,0x41,0xFA,0xFF,0x58,0x20,0x80,\
+            0x4E,0x75,\
+            0x45,0x72,0x61,0x73,0x69,0x6E,0x67,0x20,\
+            0x46,0x4C,0x41,0x53,0x48,0x20,0x63,0x68,\
+            0x69,0x70,0x73,0x0D,0x0A,0x00,0x41,0xFA,\
+            0xFF,0xE8,0x70,0x01,0x4A,0xFA,0x12,0x3A,\
+            0xFE,0x52,0x53,0x01,0x67,0x16,0x53,0x01,\
+            0x67,0x00,0x00,0xB8,0x53,0x01,0x67,0x00,\
+            0x01,0x0A,0x53,0x01,0x67,0x00,0x01,0x3A,\
+            0x60,0x00,0x01,0x3A,0x4B,0xF8,0x00,0x00,\
+            0x24,0x3A,0xFE,0x2C,0x26,0x02,0x3A,0xBC,\
+            0xFF,0xFF,0x3A,0xBC,0xFF,0xFF,0x42,0x55,\
+            0x4A,0x35,0x28,0xFF,0x67,0x28,0x7A,0x19,\
+            0x1B,0xBC,0x00,0x40,0x28,0xFF,0x42,0x35,\
+            0x28,0xFF,0x72,0x15,0x4E,0x71,0x51,0xC9,\
+            0xFF,0xFC,0x1B,0xBC,0x00,0xC0,0x28,0xFF,\
+            0x72,0x0C,0x4E,0x71,0x51,0xC9,0xFF,0xFC,\
+            0x4A,0x35,0x28,0xFF,0x66,0x06,0x53,0x82,\
+            0x66,0xCC,0x60,0x04,0x53,0x45,0x66,0xD0,\
+            0x42,0x55,0x4A,0x55,0x4A,0x05,0x67,0x00,\
+            0x00,0xE4,0x24,0x03,0x50,0xC4,0x2A,0x3C,\
+            0x03,0xE8,0x03,0xE8,0x72,0x20,0x1B,0x81,\
+            0x28,0xFF,0x1B,0x81,0x28,0xFF,0x32,0x3C,\
+            0x55,0xF0,0x4E,0x71,0x51,0xC9,0xFF,0xFC,\
+            0x4E,0xBA,0xFD,0x30,0x1B,0xBC,0x00,0xA0,\
+            0x28,0xFF,0x72,0x0C,0x4E,0x71,0x51,0xC9,\
+            0xFF,0xFC,0xB8,0x35,0x28,0xFF,0x66,0x08,\
+            0x48,0x45,0x53,0x82,0x66,0xE6,0x60,0x04,\
+            0x53,0x45,0x66,0xC8,0x42,0x55,0x4A,0x55,\
+            0x4A,0x45,0x67,0x00,0x00,0x98,0x60,0x00,\
+            0x00,0x90,0x70,0x01,0x42,0x83,0x1D,0x87,\
+            0x08,0x00,0x1B,0x86,0x08,0x00,0x1D,0xBC,\
+            0x00,0x80,0x08,0x00,0x1D,0x87,0x08,0x00,\
+            0x1B,0x86,0x08,0x00,0x1D,0xBC,0x00,0x10,\
+            0x08,0x00,0x2A,0x00,0x4E,0xBA,0xFC,0xDC,\
+            0x20,0x05,0x1A,0x30,0x09,0x90,0x08,0x05,\
+            0x00,0x07,0x66,0x20,0x08,0x05,0x00,0x05,\
+            0x67,0xE8,0x1A,0x30,0x09,0x90,0x08,0x05,\
+            0x00,0x07,0x66,0x10,0x1D,0x87,0x08,0x00,\
+            0x1B,0x86,0x08,0x00,0x1D,0xBC,0x00,0xF0,\
+            0x08,0x00,0x60,0x40,0x53,0x80,0x67,0xAE,\
+            0x60,0x36,0x42,0x83,0x3C,0x87,0x3A,0x86,\
+            0x3C,0xBC,0x00,0x80,0x3C,0x87,0x3A,0x86,\
+            0x3C,0xBC,0x00,0x10,0x4E,0xBA,0xFC,0x94,\
+            0x3A,0x15,0x08,0x05,0x00,0x07,0x66,0x18,\
+            0x08,0x05,0x00,0x05,0x67,0xEE,0x3A,0x15,\
+            0x08,0x05,0x00,0x07,0x66,0x0A,0x3C,0x87,\
+            0x3A,0x86,0x3C,0xBC,0x00,0xF0,0x60,0x04,\
+            0x42,0x80,0x60,0x02,0x70,0x01,0x4E,0x75,\
+            0x47,0xFB,0x01,0x70,0x00,0x00,0x02,0x96,\
+            0x28,0x49,0x24,0x3C,0x00,0x00,0x01,0x00,\
+            0x12,0x3A,0xFC,0xE8,0x53,0x01,0x67,0x14,\
+            0x53,0x01,0x67,0x5A,0x53,0x01,0x67,0x00,\
+            0x00,0xBC,0x53,0x01,0x67,0x00,0x01,0x00,\
+            0x60,0x00,0x01,0x2E,0x10,0x33,0x28,0xFF,\
+            0x0C,0x00,0x00,0xFF,0x67,0x28,0x7A,0x19,\
+            0x19,0xBC,0x00,0x40,0x28,0xFF,0x19,0x80,\
+            0x28,0xFF,0x72,0x15,0x4E,0x71,0x51,0xC9,\
+            0xFF,0xFC,0x19,0xBC,0x00,0xC0,0x28,0xFF,\
+            0x72,0x0C,0x4E,0x71,0x51,0xC9,0xFF,0xFC,\
+            0xB0,0x34,0x28,0xFF,0x66,0x06,0x53,0x82,\
+            0x66,0xCA,0x60,0x04,0x53,0x05,0x66,0xD0,\
+            0x42,0x55,0x4A,0x55,0x4A,0x05,0x67,0x00,\
+            0x00,0xE8,0x60,0x00,0x00,0xE0,0x20,0x0C,\
+            0xD0,0x82,0xC0,0xBC,0x00,0x00,0x00,0x01,\
+            0x08,0x40,0x00,0x00,0x16,0x33,0x28,0xFF,\
+            0x0C,0x03,0x00,0xFF,0x67,0x48,0x1D,0x87,\
+            0x08,0x00,0x1B,0x86,0x08,0x00,0x1D,0xBC,\
+            0x00,0xA0,0x08,0x00,0x19,0x83,0x28,0xFF,\
+            0xC6,0x3C,0x00,0x80,0x18,0x34,0x28,0xFF,\
+            0x1A,0x04,0xC8,0x3C,0x00,0x80,0xB8,0x03,\
+            0x67,0x24,0x08,0x05,0x00,0x05,0x67,0xEC,\
+            0x18,0x34,0x28,0xFF,0xC8,0x3C,0x00,0x80,\
+            0xB8,0x03,0x67,0x12,0x1D,0x87,0x08,0x00,\
+            0x1B,0x86,0x08,0x00,0x1D,0xBC,0x00,0xF0,\
+            0x08,0x00,0x60,0x00,0x00,0x84,0x53,0x82,\
+            0x66,0xA6,0x60,0x78,0x36,0x33,0x28,0xFE,\
+            0x0C,0x43,0xFF,0xFF,0x67,0x3A,0x3C,0x87,\
+            0x3A,0x86,0x3C,0xBC,0x00,0xA0,0x39,0x83,\
+            0x28,0xFE,0xC6,0x7C,0x00,0x80,0x38,0x34,\
+            0x28,0xFE,0x3A,0x04,0xC8,0x7C,0x00,0x80,\
+            0xB8,0x43,0x67,0x1C,0x08,0x05,0x00,0x05,\
+            0x67,0xEC,0x38,0x34,0x28,0xFE,0xC8,0x7C,\
+            0x00,0x80,0xB8,0x43,0x67,0x0A,0x3C,0x87,\
+            0x3A,0x86,0x3C,0xBC,0x00,0xF0,0x60,0x38,\
+            0x55,0x82,0x66,0xB8,0x60,0x2E,0x3C,0x87,\
+            0x3A,0x86,0x3C,0xBC,0xA0,0xA0,0x39,0xB3,\
+            0x28,0xFE,0x28,0xFE,0x55,0x82,0x66,0xF6,\
+            0x32,0x3C,0x55,0xF0,0x4E,0x71,0x51,0xC9,\
+            0xFF,0xFC,0x34,0x3C,0x01,0x00,0x36,0x33,\
+            0x28,0xFE,0xB6,0x74,0x28,0xFE,0x66,0x08,\
+            0x55,0x82,0x66,0xF2,0x42,0x80,0x60,0x02,\
+            0x70,0x01,0x4E,0x75,\
+            0x4F,0xFB,0x01,0x70,0x00,0x00,0x01,0x3A,\
+            0x41,0xFA,0xFA,0x36,0x70,0x01,0x4A,0xFA,\
+            0x4E,0xBA,0xFB,0x10,0x4E,0xBA,0xFB,0x8A,\
+            0x4A,0x42,0x66,0x06,0x74,0x01,0x60,0x00,\
+            0x00,0x42,0x4E,0xBA,0xFC,0x28,0x41,0xFA,\
+            0xFA,0x93,0x24,0x3A,0xFB,0x6E,0x4E,0xBA,\
+            0xFA,0xBE,0x41,0xFA,0xFA,0x79,0x70,0x01,\
+            0x4A,0xFA,0x4E,0xBA,0xFD,0x06,0x4A,0x00,\
+            0x67,0x06,0x74,0x05,0x60,0x00,0x00,0x1C,\
+            0x4A,0xFA,0x41,0xFA,0xFA,0x0F,0x70,0x01,\
+            0x4A,0xFA,0x42,0x80,0x22,0x40,0x4E,0xBA,\
+            0xFE,0x4C,0x4A,0xFA,0xD2,0xFC,0x01,0x00,\
+            0x60,0xF4,0x20,0x7C,0x00,0xFF,0xFA,0x00,\
+            0x08,0x10,0x00,0x04,0x66,0x08,0x02,0x79,\
+            0xFF,0xBF,0x00,0xFF,0xFC,0x14,0x22,0x02,\
+            0x70,0x00,0x4A,0xFA
+            };
+            */
 
-    uint16_t word_value = 0;
-    uint8_t byte_value = 0;
-//    bool ret = true;
+
+            //if (prep_t5_do() != TERM_OK) return TERM_ERR;
+            // Set Program counter to start of BDM driver code
+            uint32_t driverAddress = 0x100000;
+            if (sysreg_write(0x0, &driverAddress) != TERM_OK) break;
+            for (uint32_t i = 0; i < sizeof(flashDriver); i++) {
+                if(memwrite_byte(&driverAddress, flashDriver[i]) != TERM_OK) return false;
+                driverAddress++;
+            }
+//            if (!bdmLoadMemory(flashDriver, driverAddress, sizeof(flashDriver))) break;
+
+            timer.reset();
+            timer.start();
+            printf("Erasing FLASH chips...\r\n");
+            printf("This can take up to a minute for a T8,\r\n");
+            printf("30s for a T7 or 15s for a T5 ECU.\r\n");
+            // execute the erase algorithm in the BDM driver
+            // write the buffer - should complete within 200 milliseconds
+            // Typical and Maximum Chip Programming times are 9 and 27 seconds for Am29BL802C
+            // Typical Chip erase time for Am29BL802C is 45 secinds, not including 0x00 programming prior to erasure.
+            // Allow for at least worst case 27 seconds programming to 0x00 + 3(?) * 45 typical erase time (162 seconds)
+            // Allow at least 200 seconds erase time 2,000 * (100ms + BDM memread time)
+            // NOTE: 29/39F010 and 29F400 erase times are considerably lower
+
+//            if (sysreg_write(0x0, &driverAddress) != TERM_OK) return TERM_ERR;
+//            break;
+            do {
+                if (!bdmRunDriver(0x0, 20000)) {
+                    printf("WARNING: An error occured when I tried to erase the FLASH chips :-(\r\n");
+                    return TERM_ERR;
+                }
+            } while (bdmProcessSyscall() == CONTINUE);
+
+//            if (!run_bdm_driver(0x0, 200000)) {
+//                printf("WARNING: An error occured when I tried to erase the FLASH chips :-(\r\n");
+//               return TERM_ERR;
+//            }
+            printf("Erasing took %#.1f seconds.\r\n",timer.read());
+
+            printf("Programming the FLASH chips...\r\n");
 
 // ready to receive data
-    printf("  0.00 %% complete.\r");
-    while (curr_addr < flash_size) {
-        // receive bytes from BIN file
-        //Get a byte - break if no more bytes to get
-        if (!fread(&byte_value,1,1,fp)) {
-            fclose(fp);
-            printf("Error reading the BIN file MODIFIED.HEX");
-            break;
-        }
-        word_value = (byte_value << 8);
-        if (!fread(&byte_value,1,1,fp)) {
-            fclose(fp);
-            printf("Error reading the BIN file MODIFIED.HEX");
+            printf("  0.00 %% complete.\r");
+            while (curr_addr < flash_size) {
+                // receive bytes from BIN file - break if no more bytes to get
+                if (!fread(file_buffer,1,0x100,fp)) {
+                    fclose(fp);
+                    printf("Error reading the BIN file MODIFIED.BIN");
+                    break;
+                }
+                if (!bdmLoadMemory((uint8_t*)file_buffer, 0x100700, 0x100)) break;
+                // write the buffer - should complete within 200 milliseconds
+                if (!bdmRunDriver(0x0, 200)) break;
+//                if (!run_bdm_driver(0x0, 200)) break;
+
+                printf("%6.2f\r", 100*(float)curr_addr/(float)flash_size );
+                // make the activity LED twinkle
+                ACTIVITYLEDON;
+                curr_addr += 0x100;
+            }
             break;
         }
-        word_value |= byte_value;
+        // johnc's original method
+        case AMD29F400B:        /// a sort of dummy 'placeholder' as the 'B' chip isn't ever fitted to T7 ECUS
+        default: {
+            timer.reset();
+            timer.start();
+
+            // reset the FLASH chips
+            printf("Reset the FLASH chip(s) to prepare them for Erasing\r\n");
+            if (!reset_func()) return TERM_ERR;
 
-        // write the word if it is not 0xffff
-        if (word_value != 0xffff) {
-            if (!flash_func(&curr_addr, word_value)) break;
+            switch (type) {
+                    // AM29Fxxx chips (retrofitted to Trionic 5.x; original to T7)
+                case AMD29BL802C:
+                case AMD29F400B:
+                case AMD29F400T:
+                case AMD29F010:
+                case SST39SF010:
+                case AMICA29010L:
+                    printf("Erasing 29BL802/F400/010 type FLASH chips...\r\n");
+                    if (!erase_am29()) {
+                        printf("WARNING: An error occured when I tried to erase the FLASH chips :-(\r\n");
+                        return TERM_ERR;
+                    }
+                    break;
+                    // AM28F010 chip (Trionic 5.x original)
+                case AMD28F010:
+                case INTEL28F010:
+                case AMD28F512:
+                case INTEL28F512:
+                    printf("Erasing 28F010/512 type FLASH chips...\r\n");
+                    if (!erase_am28(&curr_addr, &flash_size)) {
+                        printf("WARNING: An error occured when I tried to erase the FLASH chips :-(\r\n");
+                        return TERM_ERR;
+                    }
+                    break;
+                case ATMEL29C010:
+                case ATMEL29C512:
+                    printf("Atmel FLASH chips do not require ERASEing :-)\r\n");
+                    break;
+                default:
+                    // unknown flash type - shouldn't get here hence "Strange!"
+                    printf("Strange! I couldn't work out how to erase the FLASH chips in the TRIONIC ECU that I am connected to :-(\r\n");
+                    return TERM_ERR;
+            }
+
+            timer.stop();
+            printf("Erasing took %#.1f seconds.\r\n",timer.read());
+
+            printf("Programming the FLASH chips...\r\n");
+
+            timer.reset();
+            timer.start();
+
+            uint16_t word_value = 0;
+
+// ready to receive data
+            printf("  0.00 %% complete.\r");
+            while (curr_addr < flash_size) {
+                // receive bytes from BIN file
+                //Get a byte - break if no more bytes to get
+                if (!fread(&file_buffer[0],1,0x2,fp)) {
+                    fclose(fp);
+                    printf("Error reading the BIN file MODIFIED.BIN");
+                    break;
+                }
+                for(uint32_t i=0; i<2; i++) {
+                    (word_value <<= 8) |= file_buffer[i];
+                }
+
+                // write the word if it is not 0xffff
+                if (word_value != 0xffff) {
+                    if (!flash_func(&curr_addr, word_value)) break;
+                }
+
+                if (!(curr_addr % 0x80)) {
+                    printf("%6.2f\r", 100*(float)curr_addr/(float)flash_size );
+                    // make the activity LED twinkle
+                    ACTIVITYLEDON;
+                }
+                curr_addr += 2;
+            }
         }
-        curr_addr += 2;
-
-        // make the activity LED twinkle
-        ACTIVITYLEDON;
-        if (!(curr_addr % 0x80))
-            printf("%6.2f\r", 100*(float)curr_addr/(float)flash_size );
     }
-    printf("\n");
     timer.stop();
     fclose(fp);
 
     if (curr_addr == flash_size) {
+        printf("100.00\r\n");
         printf("Programming took %#.1f seconds.\r\n",timer.read());
 
         // "Just4pleisure;)" 'tag' in the empty space at the end of the FLASH chip
@@ -577,8 +1314,11 @@
         //            flash_func(&flash_tag[i].addr, (flash_tag[i].val & word_value));
         //        }
 
-    } else
-        printf("WARNING: Oh dear, I couldn't program the FLASH at address 0x%8x.\r\n", curr_addr);
+    } else {
+        printf("\r\n");
+        printf("Programming took %#.1f seconds.\r\n",timer.read());
+        printf("WARNING: Oh dear, I couldn't program the FLASH at address 0x%08x.\r\n", curr_addr);
+    }
 
     // reset flash
     return (reset_func() && (curr_addr == flash_size)) ? TERM_OK : TERM_ERR;
@@ -632,13 +1372,15 @@
     uint32_t addr = 0x0;
     uint16_t verify_value;
 
-    printf(" 0.0 seconds.\r");
-    uint8_t err_cnt = ERR_COUNT;
-    while (--err_cnt) {
-        // typical erase time = 1s
-        // Allow up to 25.5 seconds erase time
-        wait_ms(100);
-        wait_ms(100);
+    printf("  0.0 seconds.\r");
+    timeout.reset();
+    timeout.start();
+    while (timeout.read() < 200.0) {
+        // Typical and Maximum Chip Programming times are 9 and 27 seconds for Am29BL802C
+        // Typical Chip erase time for Am29BL802C is 45 secinds, not including 0x00 programming prior to erasure.
+        // Allow for at least worst case 27 seconds programming to 0x00 + 3(?) * 45 typical erase time (162 seconds)
+        // Allow at least 200 seconds erase time 2,000 * (100ms + BDM memread time)
+        // NOTE: 29/39F010 and 29F400 erase times are considerably lower
         if (memread_word(&verify_value, &addr) == TERM_OK && verify_value == 0xffff) {
             // erase completed normally
             reset_am29();
@@ -647,11 +1389,10 @@
         }
         // make the activity LED twinkle
         ACTIVITYLEDON;
-        printf("%4.1f\r", (float)ERR_COUNT/5 - (float)err_cnt/5 );
+        printf("%5.1f\r", timeout.read());
     }
+    // erase failed
     printf("\n");
-
-    // erase failed
     reset_am29();
     return false;
 }
@@ -682,11 +1423,12 @@
         return false;
     }
     // verify the result
-    uint8_t err_cnt = ERR_COUNT;
-    while (--err_cnt) {
-        // Allow up to approx 2.55 milliseconds program time (255 * ~10us BDM memread time)
-        //        wait_ms(10);
-        wait_us(100);
+    timeout.reset();
+    timeout.start();
+    while (timeout.read_us() < 500) {
+        // Typical and Maximum Word Programming times are 9us and 360us for Am29BL802C
+        // Allow at least 500 microseconds program time 500 * (1us + BDM memread time)
+        // NOTE: 29/39F010 and 29F400 programming times are considerably lower
         uint16_t verify_value;
         if ((memread_word(&verify_value, addr) == TERM_OK) &&
                 (verify_value == value)) {
@@ -699,6 +1441,56 @@
     return false;
 }
 
+
+//-----------------------------------------------------------------------------
+/**
+Writes a word to a FLASH memory chip and checks the result
+MCU must be in background mode.
+
+@param        addr        BDM driver address (0 to continue)
+@param        maxtime     how long to allow driver to execute (milliseconds)
+
+@return                    succ / fail
+*/
+bool run_bdm_driver(uint32_t addr, uint32_t maxtime)
+{
+    // Start BDM driver and allow it up to 200 milliseconds to update 256 Bytes
+    // Upto 25 pulses per byte, 16us per pulse, 256 Bytes
+    // 25 * 16 * 256 = 102,400us plus overhead for driver code execution time
+    // Allowing up to 200 milliseconds seems like a good allowance.
+    uint32_t driverAddress = addr;
+    if (run_chip(&driverAddress) != TERM_OK) {
+        printf("Failed to start BDM driver.\r\n");
+        return false;
+    }
+    timeout.reset();
+    timeout.start();
+    // T5 ECUs' BDM interface seem to have problems when the running the CPU and
+    // sometimes shows the CPU briefly switching between showing BDM mode or that
+    // the CPU is running.
+    // I 'debounce' the interface state to workaround this erratic bahaviour
+    for (uint32_t debounce = 0; debounce < 5; debounce++) {
+        while (IS_RUNNING) {
+            debounce = 0;
+            if (timeout.read_ms() > maxtime) {
+                printf("Driver did not return to BDM mode.\r\n");
+                timeout.stop();
+                return false;
+            }
+        }
+        wait_us(1);
+    }
+    timeout.stop();
+    // Check return code in D0 register (0 - OK, 1 - FAILED)
+    uint32_t result = 1;
+    if (adreg_read(&result, 0x0) != TERM_OK) {
+        printf("Failed to read BDM register.\r\n");
+        return false;
+    }
+    return (result == 1) ? false : true;
+}
+
+
 //-----------------------------------------------------------------------------
 /**
 Resets a AM28Fxxx flash memory chip. MCU must be in background mode.
@@ -742,10 +1534,11 @@
         addr += 2;
         //        // feedback to host computer
         //        pc.putc(TERM_OK);
-        // make the activity LED twinkle
-        ACTIVITYLEDON;
-        if (!(addr % 0x80))
+        if (!(addr % 0x80)) {
+            // make the activity LED twinkle
+            ACTIVITYLEDON;
             printf("%6.2f\r", 100*(float)addr/(float)*end_addr );
+        }
     }
     printf("\n");
 
@@ -777,8 +1570,11 @@
             addr++;
             // make the activity LED twinkle
             ACTIVITYLEDON;
-            if (!(addr % 0x80))
+            if (!(addr % 0x80)) {
+                // make the activity LED twinkle
+                ACTIVITYLEDON;
                 printf("%6.2f\r", 100*(float)addr/(float)*end_addr );
+            }
         }
     }
     printf("\n");
@@ -918,7 +1714,8 @@
 
 uint8_t prep_t5_do(void)
 {
-
+    // Make sure that BDM clock is SLOW
+    bdm_clk_mode(SLOW);
     // reset and freeze the MC68332/377 chip
     if (restart_chip() != TERM_OK) return TERM_ERR;
 
@@ -940,7 +1737,10 @@
     // MC68377 MCR = x111111x01001111 binary after a reset
     if ((verify_value & 0x7E4F) == 0x7E4F) {
         printf ("I have found a Trionic 8 ECU.\r\n");
-// Set MC68377 to double it's default speed (16 MHz?) (SYNCR)
+        // Stop system protection (MDR bit 0 STOP-SYS-PROT)
+        long_value = 0x00fffa04;
+        if (memwrite_byte(&long_value, 0x01) != TERM_OK) return TERM_ERR;
+        // Set MC68377 to double it's default speed (16 MHz?) (SYNCR)
         long_value = 0x00fffa08;
         // First set the MFD part (change 4x to 8x)
         if (memwrite_word(&long_value, 0x6908) != TERM_OK) return TERM_ERR;
@@ -951,7 +1751,11 @@
         // Disable watchdog and monitors (SYPCR)
         long_value = 0x00fffa50;
         if (memwrite_word(&long_value, 0x0000) != TERM_OK) return TERM_ERR;
-        return TERM_OK;
+        // Enable internal 6kByte RAM of 68377 at address 0x00100000 (DPTRAM)
+        long_value = 0x00fff684;
+        if (memwrite_word(&long_value, 0x1000) != TERM_OK) return TERM_ERR;
+        // can use fast or turbo or nitrous BDM clock mode once ECU has been prepped and CPU clock is ??MHz
+//        bdm_clk_mode(NITROUS);
     }
 // MC68332 SIMCR = 0000x00011001111 binary after a reset
     //if ((verify_value & 0x00CF) == 0x00CF) {
@@ -985,12 +1789,13 @@
         // wait for programming voltage to be ready
         wait_ms(10);
         // Enable internal 2kByte RAM of 68332 at address 0x00100000 (TRAMBAR)
-        //long_value = 0x00fffb04;
-        //if (memwrite_word(&long_value, 0x1000) != TERM_OK) return TERM_ERR;
-        return TERM_OK;
+        long_value = 0x00fffb04;
+        if (memwrite_word(&long_value, 0x1000) != TERM_OK) return TERM_ERR;
+        // can use fast or turbo BDM clock mode once ECU has been prepped and CPU clock is 16MHz
+//        bdm_clk_mode(TURBO);
+//        bdm_clk_mode(FAST);
     }
-// Unknown MC683xx chip if code reaches this point
-    return TERM_ERR;
+    return TERM_OK;
 }
 
 
--- a/bdmtrionic.h	Wed Sep 11 11:55:51 2013 +0000
+++ b/bdmtrionic.h	Sat Apr 25 17:07:08 2015 +0000
@@ -25,6 +25,7 @@
 
 #include "common.h"
 #include "bdmcpu32.h"
+#include "bdmdriver.h"
 
 // global variables
 static bool verify_flash = 1;
--- a/canutils.cpp	Wed Sep 11 11:55:51 2013 +0000
+++ b/canutils.cpp	Sat Apr 25 17:07:08 2015 +0000
@@ -26,17 +26,20 @@
 //LPC_CANx->MOD |= (1 << 1);   // Put into listen only mode
 //LPC_CANx->MOD &= ~(1);       // Re-enable CAN controller
 
-void can_disable(uint8_t chan) {
+void can_disable(uint8_t chan)
+{
     // Put a CAN controller into disabled condition
     chan == 1 ? LPC_CAN1->MOD |= 1 : LPC_CAN2->MOD |= 1;
 }
 
-void can_enable(uint8_t chan) {
+void can_enable(uint8_t chan)
+{
     // Put a CAN controller in operating mode
     chan == 1 ? LPC_CAN1->MOD &= ~(1) : LPC_CAN2->MOD &= ~(1);
 }
 
-void can_configure(uint8_t chan, uint32_t baud, bool listen) {
+void can_configure(uint8_t chan, uint32_t baud, bool listen)
+{
 
     LPC_CAN_TypeDef *pCANx = (chan == 1) ? LPC_CAN1 : LPC_CAN2;
 
@@ -92,7 +95,8 @@
 }
 
 
-void can_reset_filters() {
+void can_reset_filters()
+{
     // Initialise the Acceptance Filters
     LPC_CANAF->AFMR = 0x01;                             // Put Acceptance Filter into reset/configuration mode
     for (uint16_t i = 0; i < 512; i++)
@@ -105,7 +109,8 @@
     LPC_CANAF->AFMR = 0x00;                             // Enable Acceptance Filter all messages should be rejected
 }
 
-void can_use_filters(bool active) {
+void can_use_filters(bool active)
+{
     active ? LPC_CANAF->AFMR = 0 : LPC_CANAF->AFMR = 2;
 }
 
@@ -114,7 +119,8 @@
   original http://www.dragonwake.com/download/LPC1768/Example/CAN/CAN.c
   simplified for CAN2 interface and std id (11 bit) only
  *--------------------------------------------*/
-void can_add_filter(uint8_t chan, uint32_t id)  {
+void can_add_filter(uint8_t chan, uint32_t id)
+{
 
     static int CAN_std_cnt = 0;
     uint32_t buf0, buf1;
@@ -197,29 +203,34 @@
 } // CAN2_wrFilter
 
 
-void can_open() {
+void can_open()
+{
     // activate external can transceiver
     can.reset();
     can_rs_pin = 0;
 }
 
-void can_close() {
+void can_close()
+{
     // disable external can transceiver
     can_rs_pin = 1;
     can.reset();
 }
 
-void can_monitor() {
+void can_monitor()
+{
     // Put CAN into silent monitoring mode
     can.monitor(1);
 }
 
-void can_active() {
+void can_active()
+{
     // Take CAN out of silent monitoring mode
     can.monitor(0);
 }
 
-uint8_t can_set_speed(uint32_t speed) {
+uint8_t can_set_speed(uint32_t speed)
+{
     // 600kbit/s first - basically sets up CAN interface, but to wrong speed - not sure what else it does
 //    can.frequency(600000);
     // 615kbit/s direct write of 615 kbit/s speed setting
@@ -235,7 +246,8 @@
 // inputs:    none
 // return:    bool TRUE if there was a message, FALSE if no message.
 //
-extern void show_can_message() {
+extern void show_can_message()
+{
     CANMessage can_MsgRx;
     if (can.read(can_MsgRx)) {
         CANRXLEDON;
@@ -256,7 +268,8 @@
 // inputs:    none
 // return:    bool TRUE if there was a message, FALSE if no message.
 //
-extern void show_T5can_message() {
+extern void show_T5can_message()
+{
     CANMessage can_MsgRx;
     if (can.read(can_MsgRx)) {
         CANRXLEDON;
@@ -282,7 +295,8 @@
 // inputs:    none
 // return:    bool TRUE if there was a message, FALSE if no message.
 //
-extern void show_T7can_message() {
+extern void show_T7can_message()
+{
     CANMessage can_MsgRx;
     if (can.read(can_MsgRx)) {
         CANRXLEDON;
@@ -324,7 +338,8 @@
 // inputs:    none
 // return:    bool TRUE if there was a message, FALSE if no message.
 //
-extern void show_T8can_message() {
+extern void show_T8can_message()
+{
     CANMessage can_MsgRx;
     if (can.read(can_MsgRx)) {
         CANRXLEDON;
@@ -354,7 +369,8 @@
 // inputs:    none
 // return:    bool TRUE if there was a message, FALSE if no message.
 //
-extern void silent_can_message() {
+extern void silent_can_message()
+{
     CANMessage can_MsgRx;
     if (can.read(can_MsgRx)) {
         CANRXLEDON;
@@ -369,9 +385,17 @@
 // return:     TRUE if the CAN message was sent before the 'timeout' expires
 //          FALSE if 'timeout' expires or the message length is wrong
 //
-extern bool can_send_timeout (uint32_t id, char *frame, uint8_t len, uint16_t timeout) {
+extern bool can_send_timeout (uint32_t id, char *frame, uint8_t len, uint16_t timeout)
+{
     CANTimer.reset();
     CANTimer.start();
+#ifdef DEBUG
+    printf("ID:%03x Len:%03x", id, len);
+    for (char i=0; i<len; i++) {
+        printf(" %02x", frame[i]);
+    }
+    printf("\n\r");
+#endif
     while (CANTimer.read_ms() < timeout) {
         if (can.write(CANMessage(id, frame, len))) {
             CANTimer.stop();
@@ -396,24 +420,25 @@
 // return:    TRUE if a qualifying message was received
 //          FALSE if 'timeout' expires or the message length is wrong
 //
-extern bool can_wait_timeout (uint32_t id, char *frame, uint8_t len, uint16_t timeout) {
+extern bool can_wait_timeout (uint32_t id, char *frame, uint8_t len, uint16_t timeout)
+{
     CANMessage CANMsgRx;
     CANTimer.reset();
     CANTimer.start();
     while (CANTimer.read_ms() < timeout) {
         if (can.read(CANMsgRx)) {
-            /*
-                        printf("w%03x8", CANMsgRx.id);
-                        for (char i=0; i<len; i++) {
-                            printf("%02x", CANMsgRx.data[i]);
-                        }
-                        printf("\n\r");
-            //            */
+#ifdef DEBUG
+            printf("ID:%03x Len:%03x", CANMsgRx.id, CANMsgRx.len);
+            for (char i=0; i<len; i++) {
+                printf(" %02x", CANMsgRx.data[i]);
+            }
+            printf("\n\r");
+#endif
             CANRXLEDON;
 //            led2 = 1;
             if (CANMsgRx.id == id || id ==0) {
                 CANTimer.stop();
-//                if (T5MsgRx.len != len)
+//                if (CANMsgRx.len != len)
 //                    return FALSE;
                 for (int i=0; i<len; i++)
                     frame[i] = CANMsgRx.data[i];
--- a/common.h	Wed Sep 11 11:55:51 2013 +0000
+++ b/common.h	Sat Apr 25 17:07:08 2015 +0000
@@ -29,6 +29,8 @@
 #include "sizedefs.h"
 #include "strings.h"
 #include "interfaces.h"
+#include "t8bootloaders.h"
+#include "t5bootloaders.h"
 
 // build configuration
 //#define IGNORE_VCC_PIN            ///< uncomment to ignore the VCC pin
@@ -60,19 +62,33 @@
 #define FILE_BUF_LENGTH      0x1000              ///< file buffer size
 static char file_buffer[FILE_BUF_LENGTH];     ///< file buffer
 
+static const uint8_t T8BootloaderRead[] = T8_BOOTLOADER_DUMP;
+static const uint8_t T8BootLoaderWrite[] = T8_BOOTLOADER_PROG;
+
+static const uint8_t T5BootLoader[] = MYBOOTY;
+
 // FLASH chip manufacturer id values
 #define AMD                 0x01
 #define CSI                 0x31
 #define INTEL               0x89
+#define ATMEL               0x1F
+#define SST                 0xBF
+#define ST                  0x20
+#define AMIC                0x37
 
 // FLASH chip type values
 #define INTEL28F512         0xB8
 #define AMD28F512           0x25
-#define INTEL28F010         0xB4
+#define INTEL28F010         0xB4        // and CSI
 #define AMD28F010           0xA7
-#define AMD29F010           0x20
+#define AMD29F010           0x20        // and ST
+#define ATMEL29C512         0x5D
+#define ATMEL29C010         0xD5
+#define SST39SF010          0xB5
+#define ST29F010            0x20
+#define AMICA29010L         0xA4
 #define AMD29F400T          0x23
-#define AMD29F400B          0xAB
+#define AMD29F400B          0xAB        // !!! NOT USED IN T7 !!!
 //#define 29F400T             0x2223
 //#define 29F400B             0x22AB
 #define AMD29BL802C         0x81
--- a/gmlan.cpp	Wed Sep 11 11:55:51 2013 +0000
+++ b/gmlan.cpp	Sat Apr 25 17:07:08 2015 +0000
@@ -1,5 +1,8 @@
 #include "gmlan.h"
 
+Timer   GMLANtimer;
+
+
 void GMLANTesterPresentAll()
 {
     char GMLANMsg[] = GMLANTesterPresentFunctional;
@@ -7,58 +10,61 @@
     ACTIVITYLEDON;
 }
 
-void GMLANTesterPresentT8()
+void GMLANTesterPresent(uint32_t ReqID, uint32_t RespID)
 {
     char GMLANMsg[] = GMLANTesterPresentPhysical;
-    can_send_timeout(T8RequestId, GMLANMsg, 8, GMLANPTCT);
-    can_wait_timeout(T8ResponseId, GMLANMsg, 8, GMLANPTCT);
+    can_send_timeout(ReqID, GMLANMsg, 2, GMLANPTCT);
+    can_wait_timeout(RespID, GMLANMsg, 2, GMLANPTCT);
     ACTIVITYLEDON;
 }
 
 // All steps needed in preparation for using a bootloader ('Utility File' in GMLAN parlance)
-bool GMLANprogrammingSetupProcess()
+bool GMLANprogrammingSetupProcess(uint32_t ReqID, uint32_t RespID)
 {
+    GMLANTesterPresent(ReqID, RespID);
     printf("Starting Diagnostic session\r\n");
-    if (!GMLANinitiateDiagnostic(GMLANdisableAllDTCs)) {
+    if (!GMLANinitiateDiagnostic(ReqID, RespID, GMLANdisableAllDTCs)) {
         printf("Unable to start Diagnostic session\r\n");
         return FALSE;
     }
     printf("Disabling Normal Communincation Messages\r\n");
-    if (!GMLANdisableNormalCommunication()) {
+    if (!GMLANdisableNormalCommunication(ReqID, RespID)) {
         printf("Unable to tell T8 to disable normal communication messages\r\n");
         return FALSE;
     }
     printf("Report Programmed State\r\n");
-    if (!GMLANReportProgrammedState()) {
+    if (!GMLANReportProgrammedState(ReqID, RespID)) {
         printf("Unable to determine ECU programmed state\r\n");
-        return FALSE;
     }
     printf("Requesting program mode\r\n");
-    if (!GMLANProgrammingMode(GMLANRequestProgrammingNormal)) {
+    if (!GMLANProgrammingMode(ReqID, RespID, GMLANRequestProgrammingNormal)) {
         printf("Unable to request programming mode\r\n");
         return FALSE;
     }
     printf("Starting program session\r\n");
-    if (!GMLANProgrammingMode(GMLANEnableProgrammingMode)) {
+    if (!GMLANProgrammingMode(ReqID, RespID, GMLANEnableProgrammingMode)) {
         printf("Unable to start program session\r\n");
         return FALSE;
     }
+    wait_ms(500);   // was 5
     return TRUE;
 }
 
 
 // All steps needed to transfer and start a bootloader ('Utility File' in GMLAN parlance)
-bool GMLANprogrammingUtilityFileProcess(char UtilityFile[])
+bool GMLANprogrammingUtilityFileProcess(uint32_t ReqID, uint32_t RespID, const uint8_t 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;
 //
+    GMLANTesterPresent(ReqID, RespID);
+    GMLANtimer.start();
     printf("Waiting for Permission to send bootloader\r\n");
-    if (!GMLANRequestDownload(GMLANRequestDownloadModeNormal)) {
+    wait_ms(500);
+    if (!GMLANRequestDownload(ReqID, RespID, GMLANRequestDownloadModeNormal)) {
         printf("Unable to request Bootloader Upload\r\n");
         return FALSE;
     }
@@ -66,7 +72,7 @@
     printf("  0.00 %% complete.\r");
 //
     for (i=0; i<0x46; i++) {
-        if (!GMLANDataTransferFirstFrame(0xF0, GMLANDOWNLOAD, StartAddress)) {
+        if (!GMLANDataTransferFirstFrame(ReqID, RespID, 0xF0, GMLANDOWNLOAD, StartAddress)) {
             printf("Unable to start Bootloader Upload\r\n");
             return FALSE;
         }
@@ -75,48 +81,24 @@
             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)) {
+            if (!can_send_timeout(ReqID, 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;
-            }
+            wait_ms(2);     // was 2
         }
-#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]);
+        if (!GMLANDataTransferBlockAcknowledge(RespID))
             return FALSE;
+        if (GMLANtimer.read_ms() > 2000) {
+            GMLANTesterPresent(ReqID, RespID);
+            GMLANtimer.reset();
         }
-        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)) {
+    if (!GMLANDataTransferFirstFrame(ReqID, RespID, 0x0A, GMLANDOWNLOAD, StartAddress)) {
         printf("Unable to finish Bootloader Upload\r\n");
         return FALSE;
     }
@@ -125,195 +107,147 @@
     for (k=0; k<7; k++) {
         GMLANMsg[k+1] = UtilityFile[txpnt++];
     }
-    if (!can_send_timeout(T8RequestId, GMLANMsg, 8, GMLANPTCT)) {
+    if (!can_send_timeout(ReqID, GMLANMsg, 8, GMLANPTCT)) {
         printf("Unable to finish sending Bootloader\r\n");
         return FALSE;
     }
-    if (!can_wait_timeout(T8ResponseId, GMLANMsg, 8, GMLANPTCT))
+    if (!can_wait_timeout(RespID, 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)) {
+    if (!GMLANDataTransfer(ReqID, RespID, 0x06, GMLANEXECUTE, 0x00102460)) {
         printf("Unable to start the Bootloader\r\n");
         return FALSE;
     }
-    wait_ms(500);
+    wait_ms(500);   // was 100
     return TRUE;
 }
 
-bool GMLANinitiateDiagnostic(char level)
+bool GMLANinitiateDiagnostic(uint32_t ReqID, uint32_t RespID, char level)
 {
     char GMLANMsg[] = GMLANinitiateDiagnosticOperation;
     GMLANMsg[2] = level;
-    if (!can_send_timeout(T8RequestId, GMLANMsg, 3, GMLANPTCT))
+    if (!can_send_timeout(ReqID, GMLANMsg, 3, GMLANPTCT))
         return FALSE;
-    if (!can_wait_timeout(T8ResponseId, GMLANMsg, 8, GMLANPTCT))
+    if (ReqID == T8USDTREQID) return TRUE;
+    if (!can_wait_timeout(RespID, 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))
+        if (!can_wait_timeout(RespID, 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()
+bool GMLANdisableNormalCommunication(uint32_t ReqID, uint32_t RespID)
 {
     char GMLANMsg[] = GMLANdisableCommunication;
-    if (!can_send_timeout(T8RequestId, GMLANMsg, 2, GMLANPTCT))
-        return FALSE;
-    if (!can_wait_timeout(T8ResponseId, GMLANMsg, 8, GMLANPTCT))
+    if (!can_send_timeout(ReqID, GMLANMsg, 2, GMLANPTCT))
         return FALSE;
-    while (GMLANMsg[0] == 0x7F && GMLANMsg[2] == 0x78)
-        if (!can_wait_timeout(T8ResponseId, GMLANMsg, 8, GMLANPTCTENHANCED))
+    if (ReqID == T8USDTREQID) return TRUE;
+    if (!can_wait_timeout(RespID, GMLANMsg, 8, GMLANPTCT))
+        return FALSE;
+    while (GMLANMsg[0] == 0x03 && GMLANMsg[1] == 0x7F && GMLANMsg[2] == 0x28 && GMLANMsg[3] == 0x78)
+        if (!can_wait_timeout(RespID, 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()
+bool GMLANReportProgrammedState(uint32_t ReqID, uint32_t RespID)
 {
     char GMLANMsg[] = GMLANReportProgrammed;
-    if (!can_send_timeout(T8RequestId, GMLANMsg, 2, GMLANPTCT))
+    if (!can_send_timeout(ReqID, GMLANMsg, 2, GMLANPTCT))
         return FALSE;
-    if (!can_wait_timeout(T8ResponseId, GMLANMsg, 8, GMLANPTCT))
+    if (!can_wait_timeout(RespID, GMLANMsg, 8, GMLANPTCT))
         return FALSE;
-    while (GMLANMsg[0] == 0x7F && GMLANMsg[2] == 0x78)
-        if (!can_wait_timeout(T8ResponseId, GMLANMsg, 8, GMLANPTCTENHANCED))
+    while (GMLANMsg[0] == 0x03 && GMLANMsg[1] == 0x7F && GMLANMsg[2] == 0xA2 && GMLANMsg[3] == 0x78)
+        if (!can_wait_timeout(RespID, 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)
+bool GMLANProgrammingMode(uint32_t ReqID, uint32_t RespID, 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))
+    if (!can_send_timeout(ReqID, 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))
+    if (!can_wait_timeout(RespID, GMLANMsg, 8, GMLANPTCT))
         return FALSE;
-    while (GMLANMsg[0] == 0x7F && GMLANMsg[2] == 0x78)
-        if (!can_wait_timeout(T8ResponseId, GMLANMsg, 8, GMLANPTCTENHANCED))
+    while (GMLANMsg[0] == 0x03 && GMLANMsg[1] == 0x7F && GMLANMsg[2] == 0xA5 && GMLANMsg[3] == 0x78)
+        if (!can_wait_timeout(RespID, 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)
+bool GMLANSecurityAccessRequest(uint32_t ReqID, uint32_t RespID, 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))
+    if (!can_send_timeout(ReqID, GMLANMsg, 3, GMLANPTCT))
         return FALSE;
-    if (!can_wait_timeout(T8ResponseId, GMLANMsg, 8, GMLANPTCT))
+    if (!can_wait_timeout(RespID, GMLANMsg, 8, GMLANPTCT))
         return FALSE;
-    while (GMLANMsg[0] == 0x7F && GMLANMsg[2] == 0x78)
-        if (!can_wait_timeout(T8ResponseId, GMLANMsg, 8, GMLANPTCTENHANCED))
+    while (GMLANMsg[0] == 0x03 && GMLANMsg[1] == 0x7F && GMLANMsg[2] == 0x27 && GMLANMsg[3] == 0x78)
+        if (!can_wait_timeout(RespID, 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)
+bool GMLANSecurityAccessSendKey(uint32_t ReqID, uint32_t RespID, 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))
+    if (!can_send_timeout(ReqID, GMLANMsg, 5, GMLANPTCT))
         return FALSE;
-    if (!can_wait_timeout(T8ResponseId, GMLANMsg, 8, GMLANPTCT))
+    if (!can_wait_timeout(RespID, GMLANMsg, 8, GMLANPTCT))
         return FALSE;
-    while (GMLANMsg[0] == 0x7F && GMLANMsg[2] == 0x78)
-        if (!can_wait_timeout(T8ResponseId, GMLANMsg, 8, GMLANPTCTENHANCED))
+    while (GMLANMsg[0] == 0x03 && GMLANMsg[1] == 0x7F && GMLANMsg[2] == 0x27 && GMLANMsg[3] == 0x78)
+        if (!can_wait_timeout(RespID, 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)
+bool GMLANRequestDownload(uint32_t ReqID, uint32_t RespID, 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))
+    if (!can_send_timeout(ReqID, GMLANMsg, 7, GMLANPTCT))
+        return FALSE;
+    if (!can_wait_timeout(RespID, GMLANMsg, 8, 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))
+        printf("Waiting\r\n");
+        GMLANTesterPresent(T8REQID, T8RESPID);
+        if (!can_wait_timeout(RespID, 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)
+bool GMLANDataTransfer(uint32_t ReqID, uint32_t RespID, char length, char function, uint32_t address)
 {
     char GMLANMsg[8];
     GMLANMsg[0] = length;
@@ -324,28 +258,20 @@
     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))
+    if (!can_send_timeout(ReqID, GMLANMsg, 8, GMLANPTCT))
         return FALSE;
-    if (!can_wait_timeout(T8ResponseId, GMLANMsg, 8, GMLANPTCT))
+    if (!can_wait_timeout(RespID, GMLANMsg, 8, GMLANPTCT))
         return FALSE;
-    while (GMLANMsg[0] == 0x7F && GMLANMsg[2] == 0x78)
-        if (!can_wait_timeout(T8ResponseId, GMLANMsg, 8, GMLANPTCTENHANCED))
+    while (GMLANMsg[0] == 0x03 && GMLANMsg[1] == 0x7F && GMLANMsg[2] == 0x36 && GMLANMsg[3] == 0x78)
+        if (!can_wait_timeout(RespID, 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)
+bool GMLANDataTransferFirstFrame(uint32_t ReqID, uint32_t RespID, char length, char function, uint32_t address)
 {
     char GMLANMsg[8];
     GMLANMsg[0] = 0x10;
@@ -356,55 +282,66 @@
     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))
+    if (!can_send_timeout(ReqID, GMLANMsg, 8, GMLANPTCT))
         return FALSE;
-    if (!can_wait_timeout(T8ResponseId, GMLANMsg, 8, GMLANPTCT))
+    if (!can_wait_timeout(RespID, GMLANMsg, 8, GMLANPTCT))
         return FALSE;
-    while (GMLANMsg[0] == 0x7F && GMLANMsg[2] == 0x78)
-        if (!can_wait_timeout(T8ResponseId, GMLANMsg, 8, GMLANPTCTENHANCED))
+    while (GMLANMsg[0] == 0x03 && GMLANMsg[1] == 0x7F && GMLANMsg[2] == 0x36 && GMLANMsg[3] == 0x78)
+        if (!can_wait_timeout(RespID, 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])
+bool GMLANDataTransferConsecutiveFrame(uint32_t ReqID, char framenumber, char data[8])
 {
     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;
+    return (can_send_timeout(ReqID, GMLANMsg, 8, GMLANPTCT)) ? TRUE : FALSE;
 }
 
-bool GMLANReturnToNormalMode()
+bool GMLANDataTransferBlockAcknowledge(uint32_t RespID)
 {
-    char GMLANMsg[] = GMLANRetrunToNormalModeMessage;
-    if (!can_send_timeout(T8RequestId, GMLANMsg, 2, GMLANPTCT))
-        return FALSE;
-    if (!can_wait_timeout(T8ResponseId, GMLANMsg, 8, GMLANPTCT))
+    char GMLANMsg[8];
+    if (!can_wait_timeout(RespID, GMLANMsg, 8, GMLANPTCT)) {
+        printf("\r\nI did not receive a block acknowledge message\r\n");
         return FALSE;
-    while (GMLANMsg[0] == 0x7F && GMLANMsg[2] == 0x78)
-        if (!can_wait_timeout(T8ResponseId, GMLANMsg, 8, GMLANPTCTENHANCED))
+    }
+    if (GMLANMsg[0] != 0x01 && GMLANMsg[1] != 0x76) {
+        while (GMLANMsg[0] == 0x03 && GMLANMsg[1] == 0x7F && GMLANMsg[2] == 0x36 && GMLANMsg[3] == 0x78) {
+            printf("\r\nI'm waiting for a block acknowledge message\r\n");
+            if (!can_wait_timeout(RespID, GMLANMsg, 8, GMLANPTCTENHANCED)) {
+                printf("I did not receive a block acknowledge message after enhanced timeout\r\n");
+                return FALSE;
+            }
+        }
+        if ( GMLANMsg[0] == 0x03 && GMLANMsg[1] == 0x7F && GMLANMsg[2] == 0x36 ) {
+            GMLANShowReturnCode(GMLANMsg[3]);
+            return FALSE;
+        }
+        if (GMLANMsg[0] != 0x01 && GMLANMsg[1] != 0x76) {
+            printf("\r\nEXITING due to an unexpected CAN message\r\n");
             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 )
+        }
+    }
+    return TRUE;
+}
+
+bool GMLANReturnToNormalMode(uint32_t ReqID, uint32_t RespID)
+{
+    char GMLANMsg[] = GMLANReturnToNormalModeMessage;
+    if (!can_send_timeout(ReqID, GMLANMsg, 2, GMLANPTCT))
+        return FALSE;
+    if (!can_wait_timeout(RespID, GMLANMsg, 8, GMLANPTCT))
+        return FALSE;
+    while (GMLANMsg[0] == 0x03 && GMLANMsg[1] == 0x7F && GMLANMsg[2] == 0x20 && GMLANMsg[3] == 0x78)
+        if (!can_wait_timeout(RespID, GMLANMsg, 8, GMLANPTCTENHANCED))
+            return FALSE;
+    if ( GMLANMsg[0] == 0x03 && GMLANMsg[1] == 0x7F && GMLANMsg[2] == 0x20 )
         GMLANShowReturnCode(GMLANMsg[3]);
     return (GMLANMsg[0] == 0x01 && GMLANMsg[1] == 0x60) ? TRUE : FALSE;
 }
--- a/gmlan.h	Wed Sep 11 11:55:51 2013 +0000
+++ b/gmlan.h	Sat Apr 25 17:07:08 2015 +0000
@@ -11,8 +11,13 @@
 #include "common.h"
 #include "canutils.h"
 
-#define T8RequestId 0x7E0
-#define T8ResponseId 0x7E8
+#define T8REQID 0x7E0
+#define T8RESPID 0x7E8
+
+#define T8USDTREQID 0x011
+#define T8UUDTRESPID 0x311
+#define T8USDTRESPID 0x411
+
 #define GMLANALLNODES 0x101
 
 #define GMLANMESSAGETIMEOUT 50             // 50 milliseconds (0.05 of a second) - Seems to be plenty of time to wait for messages on the CAN bus
@@ -24,42 +29,42 @@
 #define GMLANTesterPresentPhysical    {0x01,0x3E,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa}
 #define GMLANTesterPresentFunctional  {0xFE,0x01,0x3E,0xaa,0xaa,0xaa,0xaa,0xaa}
 extern void GMLANTesterPresentAll();
-extern void GMLANTesterPresentT8();
+extern void GMLANTesterPresent(uint32_t ReqID, uint32_t RespID);
 
 // All steps needed in preparation for using a bootloader ('Utility File' in GMLAN parlance)
-bool GMLANprogrammingSetupProcess();
+bool GMLANprogrammingSetupProcess(uint32_t ReqID, uint32_t RespID);
 
 // All steps needed to transfer and start a bootloader ('Utility File' in GMLAN parlance)
-bool GMLANprogrammingUtilityFileProcess(char UtilityFile[]);
+bool GMLANprogrammingUtilityFileProcess(uint32_t ReqID, uint32_t RespID, const uint8_t UtilityFile[]);
 
 
 // Start a Diagnostic Session
 #define GMLANinitiateDiagnosticOperation {0x02,0x10,0x02,0xaa,0xaa,0xaa,0xaa,0xaa}
 #define GMLANdisableAllDTCs 0x02
-bool GMLANinitiateDiagnostic(char level);
+bool GMLANinitiateDiagnostic(uint32_t ReqID, uint32_t RespID, char level);
 
 
 // Tell T8 To disable normal communication messages
 #define GMLANdisableCommunication {0x01,0x28,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa}
-bool GMLANdisableNormalCommunication();
+bool GMLANdisableNormalCommunication(uint32_t ReqID, uint32_t RespID);
 
 
 // Tell T8 To report programmed state
 #define GMLANReportProgrammed    {0x01,0xA2,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa}
-bool GMLANReportProgrammedState();
+bool GMLANReportProgrammedState(uint32_t ReqID, uint32_t RespID);
 
 // Tell T8 To request or initiate programming
 #define GMLANProgramming    {0x02,0xA5,0x00,0xaa,0xaa,0xaa,0xaa,0xaa}
 #define GMLANRequestProgrammingNormal 0x01  // I or P-Bus speed
 #define GMLANRequestProgrammingFast 0x02    // 83.333 kbps for single-wire CAN
 #define GMLANEnableProgrammingMode 0x03     // Tell T8 To initiate programming
-bool GMLANProgrammingMode(char mode);
+bool GMLANProgrammingMode(uint32_t ReqID, uint32_t RespID, char mode);
 
 // authenticate with T8
 #define GMLANSecurityAccessSeed     {0x02,0x27,0x01,0xaa,0xaa,0xaa,0xaa,0xaa}
-bool GMLANSecurityAccessRequest(char level, uint16_t& seed);
+bool GMLANSecurityAccessRequest(uint32_t ReqID, uint32_t RespID, char level, uint16_t& seed);
 #define GMLANSecurityAccessKey      {0x04,0x27,0x02,0xCA,0xFE,0xaa,0xaa,0xaa}
-bool GMLANSecurityAccessSendKey(char level, uint16_t key);
+bool GMLANSecurityAccessSendKey(uint32_t ReqID, uint32_t RespID, char level, uint16_t key);
 
 // Tell T8 We are Requesting a download session
 #define GMLANRequestDownloadMessage {0x06,0x34,0x00,0x00,0x00,0x00,0x00,0xaa}
@@ -67,19 +72,20 @@
 #define GMLANRequestDownloadModeEncrypted 0x01
 #define GMLANRequestDownloadModeCompressed 0x10
 #define GMLANRequestDownloadModeCompressedEncrypted 0x11
-bool GMLANRequestDownload(char dataFormatIdentifier);
+bool GMLANRequestDownload(uint32_t ReqID, uint32_t RespID, char dataFormatIdentifier);
 
 // Data blocks are sent using this message type
 #define GMLANDataTransferMessage    {0x10,0xF0,0x36,0x00,0xCA,0xFE,0xBA,0xBE}
 #define GMLANDOWNLOAD 0x00
 #define GMLANEXECUTE  0x80
-bool GMLANDataTransfer(char length, char function, uint32_t address);
-bool GMLANDataTransferFirstFrame(char length, char function, uint32_t address);
-bool GMLANDataTransferConsecutiveFrame(char framenumber, char data[7]);
+bool GMLANDataTransfer(uint32_t ReqID, uint32_t RespID, char length, char function, uint32_t address);
+bool GMLANDataTransferFirstFrame(uint32_t ReqID, uint32_t RespID, char length, char function, uint32_t address);
+bool GMLANDataTransferConsecutiveFrame(uint32_t ReqID, char framenumber, char data[7]);
+bool GMLANDataTransferBlockAcknowledge(uint32_t RespID);
 
 // Tell T8 ECU to return to normal mode after FLASHing
-#define GMLANRetrunToNormalModeMessage    {0x01,0x20,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa}
-bool GMLANReturnToNormalMode();
+#define GMLANReturnToNormalModeMessage    {0x01,0x20,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa}
+bool GMLANReturnToNormalMode(uint32_t ReqID, uint32_t RespID);
 
 
 // Show a description of GMLAN Return Codes when an error occurs
--- a/interfaces.cpp	Wed Sep 11 11:55:51 2013 +0000
+++ b/interfaces.cpp	Sat Apr 25 17:07:08 2015 +0000
@@ -18,6 +18,8 @@
 
 // A timer for timing how long things take to happen
 Timer timer;
+// A timer for checking that timeout periods aren't exceeded
+Timer timeout;
 
 // We use CAN on mbed pins 29(CAN_TXD) and 30(CAN_RXD).
 CAN can(p30, p29);
--- a/interfaces.h	Wed Sep 11 11:55:51 2013 +0000
+++ b/interfaces.h	Sat Apr 25 17:07:08 2015 +0000
@@ -24,6 +24,7 @@
 extern LocalFileSystem  local;                  //Serial pc(USBTX, USBRX); // tx, rx
 
 extern Timer            timer;
+extern Timer            timeout;
 
 extern DigitalIn        PIN_PWR;                // power supply
 extern DigitalIn        PIN_NC;                 // connection signal
--- a/main.cpp	Wed Sep 11 11:55:51 2013 +0000
+++ b/main.cpp	Sat Apr 25 17:07:08 2015 +0000
@@ -28,9 +28,34 @@
 
 ********************************************************************************
 
+Version 1.5 (04/2015)
+
+Added since Version 1.4
+    T8 CAN functions: DUMP, FLASH and RECOVERY
+        Using modified T8Bootloaders that are slightly faster :-)
+    Algorithms for different types of 5 volt replacement FLASH Chips in T5 ECUs
+        AMD, ST and AMIC 29F010 types
+        SST 39F010
+        ATMEL 29C512 and 29C010
+        
+Changes since Version 1.4
+    BDM FLASHing uses BD32 like Target Resident Drivers.
+        Based on my 'universal scripts'
+        BDM FLASHing much faster now
+    Always use slow BDM clock function (bdm_clk_slow) for reliability
+        Even when using the slow method it only takes 8 seconds
+        longer to FLASH a T8 ECU.
+        mbed library and compiler changes make it difficult to
+        maintain the faster bdm functions that rely on software
+        delay loops for timing.
+    The file extension of the file to be FLASHed is now the more usual 'BIN'.
+        i.e. 'modified.bin' instead of 'modified.hex'
+
+********************************************************************************
+
 Version 1.4 (07/2013)
 
-Changes since Verion 1.3
+Added since Verion 1.3
     Progress indication shown as a percentage, slightly slower but more informative
     T8 BDM Functionality
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Sat Apr 25 17:07:08 2015 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/433970e64889
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/t5bootloaders.h	Sat Apr 25 17:07:08 2015 +0000
@@ -0,0 +1,90 @@
+/*******************************************************************************
+
+t5bootloaders.h - definitions for the MyBooty bootloader for T5 ECU's
+(c) 2010,2011,2012,2013,2014,2015 by Sophie Dexter
+
+********************************************************************************
+
+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.
+
+*******************************************************************************/
+#ifndef __T5BOOTLOADERS_H__
+#define __T5BOOTLOADERS_H__
+
+// MyBooty bootloader
+//
+// This is version 2.1
+//
+// Start address is 0x5000
+#define MYBOOTY_START 0x5000
+// Send MyBooty in chunks of 0x20 bytes
+#define MYBOOTY_CHUNK 0x20
+// The size of the array must be 'padded' out with 0x00's to be a multiple of 0x20 bytes because 't5_can_send_boot_loader' is coded with magic numbers!
+#define MYBOOTY {\
+0x4E,0xB8,0x50,0x0C,0x4E,0xB8,0x50,0xAC,0x4E,0xED,0x00,0x04,0x20,0x7C,0x00,0xFF,0xFA,0x04,0x10,0xFC,0x00,0x7F,0x08,0x10,0x00,0x03,0x67,0xFA,0x33,0xFC,0x04,0x05,\
+0x00,0xFF,0xFA,0x48,0x33,0xFC,0x04,0x05,0x00,0xFF,0xFA,0x50,0x33,0xFC,0x04,0x05,0x00,0xFF,0xFA,0x54,0x33,0xFC,0x30,0x30,0x00,0xFF,0xFA,0x52,0x33,0xFC,0x50,0x30,\
+0x00,0xFF,0xFA,0x56,0x02,0x79,0xFF,0xBF,0x00,0xFF,0xFC,0x14,0x00,0x79,0x00,0x10,0x00,0xFF,0xFC,0x14,0x02,0x79,0x8F,0xDF,0x00,0xFF,0xFC,0x16,0x00,0x79,0x00,0x50,\
+0x00,0xFF,0xFC,0x16,0x2A,0x7C,0x00,0x04,0x00,0x00,0x2C,0x7C,0x00,0xFF,0xFA,0x26,0x3C,0x3C,0x55,0x55,0x3E,0x3C,0xAA,0xAA,0x24,0x7C,0x00,0xF0,0x07,0xFF,0x26,0x7C,\
+0x00,0xF0,0x08,0x00,0x40,0xC1,0x00,0x7C,0x07,0x00,0x42,0x12,0x00,0x13,0x00,0x01,0x14,0xBC,0x00,0x01,0x08,0x13,0x00,0x00,0x67,0xFA,0x14,0xBC,0x00,0x04,0x16,0xBC,\
+0x00,0x01,0x42,0x12,0x02,0x13,0x00,0xFE,0x46,0xC1,0x4E,0x75,0x4E,0xB8,0x51,0xE4,0x20,0x7C,0x00,0x00,0x57,0x90,0x22,0x7C,0x00,0x00,0x57,0x98,0x10,0x10,0x12,0xC0,\
+0x12,0xFC,0x00,0x09,0x22,0xFC,0x08,0x08,0x08,0x08,0x32,0xBC,0x08,0x08,0x5B,0x89,0x0C,0x00,0x00,0xC7,0x67,0x00,0x00,0xD8,0x0C,0x00,0x00,0x7F,0x63,0x00,0x00,0x5E,\
+0x0C,0x00,0x00,0xA5,0x67,0x00,0x00,0x42,0x0C,0x00,0x00,0xC0,0x67,0x00,0x00,0x8A,0x0C,0x00,0x00,0xC2,0x67,0x00,0x00,0x9E,0x0C,0x00,0x00,0xC3,0x67,0x00,0x00,0xA4,\
+0x0C,0x00,0x00,0xC8,0x67,0x00,0x00,0xC2,0x0C,0x00,0x00,0xC9,0x67,0x00,0x00,0xC2,0x4E,0xB8,0x52,0x4C,0x0C,0x38,0x00,0xC2,0x57,0x98,0x66,0x90,0x14,0xBC,0x00,0x08,\
+0x08,0x13,0x00,0x06,0x67,0xFA,0x4E,0x75,0x20,0x18,0xE1,0x88,0x80,0x18,0x21,0xC0,0x57,0xA2,0x11,0xD0,0x57,0xA6,0x42,0x11,0x60,0x00,0xFF,0xD6,0x24,0x7C,0x00,0x00,\
+0x57,0xA7,0x70,0x06,0x42,0x81,0x12,0x18,0xD5,0xC1,0x14,0x38,0x57,0xA6,0x14,0xD8,0x52,0x01,0xB2,0x02,0x67,0x0A,0x51,0xC8,0xFF,0xF6,0x42,0x11,0x60,0x00,0xFF,0xB2,\
+0x4E,0xB8,0x54,0xE4,0x12,0xC0,0x67,0x00,0xFF,0xA8,0x22,0x84,0x02,0x79,0xFF,0xBF,0x00,0xFF,0xFC,0x14,0x60,0x00,0xFF,0x9A,0x4E,0xB8,0x56,0xFA,0x4E,0xB8,0x52,0x9C,\
+0x12,0xC0,0x67,0x00,0xFF,0x8C,0x22,0x82,0x02,0x79,0xFF,0xBF,0x00,0xFF,0xFC,0x14,0x60,0x00,0xFF,0x7E,0x02,0x79,0xFF,0xBF,0x00,0xFF,0xFC,0x14,0x42,0x11,0x60,0x00,\
+0xFF,0x70,0x42,0x19,0x22,0xBC,0x00,0x07,0xFF,0xFF,0x60,0x00,0xFF,0x64,0x20,0x18,0xE1,0x88,0x80,0x10,0x24,0x40,0x42,0x19,0x12,0xD2,0x12,0xE2,0x12,0xE2,0x12,0xE2,\
+0x12,0xE2,0x12,0xA2,0x60,0x00,0xFF,0x4A,0x4E,0xB8,0x56,0x70,0x60,0x00,0xFF,0x42,0x4E,0xB8,0x56,0xFA,0x42,0x19,0x22,0xCD,0x12,0xF8,0x57,0xA0,0x12,0xB8,0x57,0xA1,\
+0x60,0x00,0xFF,0x2E,0x20,0x7C,0x00,0x00,0x57,0x90,0x24,0x7C,0x00,0xF0,0x07,0xFF,0x26,0x7C,0x00,0xF0,0x08,0x00,0x40,0xC1,0x00,0x7C,0x07,0x00,0x14,0xBC,0x00,0x02,\
+0x4A,0x13,0x14,0xBC,0x00,0x12,0x08,0x13,0x00,0x00,0x67,0xFA,0x14,0xBC,0x00,0x13,0x08,0x13,0x00,0x06,0x66,0x08,0x46,0xC1,0x3C,0x86,0x3C,0x87,0x60,0xD8,0x14,0xBC,\
+0x00,0x13,0x16,0xBC,0x00,0x08,0x70,0x14,0x74,0x1B,0x14,0x80,0x52,0x00,0x10,0xD3,0xB0,0x02,0x63,0xF6,0x14,0xBC,0x00,0x12,0x08,0x13,0x00,0x00,0x67,0xFA,0x14,0xBC,\
+0x00,0x13,0x08,0x13,0x00,0x06,0x66,0xD6,0x46,0xC1,0x4E,0x75,0x22,0x7C,0x00,0x00,0x57,0x98,0x24,0x7C,0x00,0xF0,0x07,0xFF,0x26,0x7C,0x00,0xF0,0x08,0x00,0x40,0xC1,\
+0x00,0x7C,0x07,0x00,0x14,0xBC,0x00,0x02,0x4A,0x13,0x14,0xBC,0x00,0x06,0x42,0x13,0x14,0xBC,0x00,0x07,0x08,0x13,0x00,0x00,0x67,0xFA,0x70,0x09,0x74,0x10,0x14,0x80,\
+0x52,0x00,0x16,0x99,0xB0,0x02,0x63,0xF6,0x14,0xBC,0x00,0x08,0x16,0xBC,0x00,0x88,0x14,0xBC,0x00,0x06,0x16,0xBC,0x00,0x80,0x46,0xC1,0x4E,0x75,0x10,0x38,0x57,0xA0,\
+0x12,0x38,0x57,0xA1,0x0C,0x00,0x00,0x89,0x66,0x16,0x0C,0x01,0x00,0xB8,0x67,0x00,0x01,0x04,0x0C,0x01,0x00,0xB4,0x67,0x00,0x00,0xF4,0x70,0x04,0x60,0x00,0x02,0x24,\
+0x0C,0x00,0x00,0x01,0x66,0x1E,0x0C,0x01,0x00,0x25,0x67,0x00,0x00,0xE8,0x0C,0x01,0x00,0xA7,0x67,0x00,0x00,0xD8,0x0C,0x01,0x00,0x20,0x67,0x00,0x01,0x8C,0x70,0x05,\
+0x60,0x00,0x02,0x00,0x0C,0x00,0x00,0x31,0x66,0x0E,0x0C,0x01,0x00,0xB4,0x67,0x00,0x00,0xBC,0x70,0x06,0x60,0x00,0x01,0xEC,0x0C,0x00,0x00,0x1F,0x66,0x12,0x0C,0x01,\
+0x00,0xD5,0x67,0x4E,0x0C,0x01,0x00,0x5D,0x67,0x50,0x70,0x07,0x60,0x00,0x01,0xD4,0x0C,0x00,0x00,0xBF,0x66,0x0E,0x0C,0x01,0x00,0xB5,0x67,0x00,0x01,0x4C,0x70,0x08,\
+0x60,0x00,0x01,0xC0,0x0C,0x00,0x00,0x20,0x66,0x0E,0x0C,0x01,0x00,0x20,0x67,0x00,0x01,0x38,0x70,0x09,0x60,0x00,0x01,0xAC,0x0C,0x00,0x00,0x37,0x66,0x0E,0x0C,0x01,\
+0x00,0xA4,0x67,0x00,0x01,0x24,0x70,0x0A,0x60,0x00,0x01,0x98,0x70,0x03,0x60,0x00,0x01,0x92,0x24,0x3C,0x00,0x04,0x00,0x00,0x60,0x06,0x24,0x3C,0x00,0x02,0x00,0x00,\
+0x3B,0x87,0x01,0x70,0x00,0x00,0xAA,0xAA,0x3B,0x46,0x55,0x54,0x3B,0xBC,0x80,0x80,0x01,0x70,0x00,0x00,0xAA,0xAA,0x3B,0x87,0x01,0x70,0x00,0x00,0xAA,0xAA,0x3B,0x46,\
+0x55,0x54,0x3B,0xBC,0x10,0x10,0x01,0x70,0x00,0x00,0xAA,0xAA,0x32,0x3C,0xAB,0xE0,0x4E,0x71,0x51,0xC9,0xFF,0xFC,0x50,0xC0,0x3C,0x86,0x3C,0x87,0xB0,0x35,0x28,0xFF,\
+0x66,0x00,0x01,0x3E,0x53,0x82,0x66,0xF0,0x60,0x00,0x01,0x32,0x24,0x3C,0x00,0x04,0x00,0x00,0x60,0x06,0x24,0x3C,0x00,0x02,0x00,0x00,0x20,0x02,0x16,0x3C,0x00,0x40,\
+0x18,0x3C,0x00,0xC0,0x3A,0xBC,0xFF,0xFF,0x3A,0xBC,0xFF,0xFF,0x42,0x55,0x4A,0x35,0x28,0xFF,0x67,0x24,0x7A,0x19,0x1B,0x83,0x28,0xFF,0x42,0x35,0x28,0xFF,0x72,0x15,\
+0x4E,0x71,0x51,0xC9,0xFF,0xFC,0x1B,0x84,0x28,0xFF,0x72,0x0C,0x4E,0x71,0x51,0xC9,0xFF,0xFC,0x4A,0x35,0x28,0xFF,0x66,0x0A,0x3C,0x86,0x3C,0x87,0x53,0x82,0x66,0xCC,\
+0x60,0x04,0x53,0x45,0x66,0xD0,0x42,0x55,0x4A,0x55,0x4A,0x05,0x66,0x06,0x70,0x02,0x60,0x00,0x00,0xD0,0x24,0x00,0x50,0xC0,0x16,0x3C,0x00,0x20,0x18,0x3C,0x00,0xA0,\
+0x2A,0x3C,0x03,0xE8,0x03,0xE8,0x1B,0x83,0x28,0xFF,0x1B,0x83,0x28,0xFF,0x32,0x3C,0x55,0xF0,0x4E,0x71,0x51,0xC9,0xFF,0xFC,0x1B,0x84,0x28,0xFF,0x72,0x0C,0x4E,0x71,\
+0x51,0xC9,0xFF,0xFC,0x3C,0x86,0x3C,0x87,0xB0,0x35,0x28,0xFF,0x66,0x08,0x48,0x45,0x53,0x82,0x66,0xE4,0x60,0x04,0x53,0x45,0x66,0xCC,0x42,0x55,0x4A,0x55,0x4A,0x45,\
+0x67,0x00,0x00,0x7E,0x60,0x00,0x00,0x76,0x70,0x01,0x1B,0x87,0x09,0x30,0x00,0x00,0xAA,0xAA,0x1B,0x86,0x09,0x20,0x55,0x54,0x1B,0xBC,0x00,0x80,0x09,0x30,0x00,0x00,\
+0xAA,0xAA,0x1B,0x87,0x09,0x30,0x00,0x00,0xAA,0xAA,0x1B,0x86,0x09,0x20,0x55,0x54,0x1B,0xBC,0x00,0x10,0x09,0x30,0x00,0x00,0xAA,0xAA,0x3C,0x86,0x3C,0x87,0x1A,0x35,\
+0x08,0x00,0x08,0x05,0x00,0x07,0x66,0x2A,0x08,0x05,0x00,0x05,0x67,0xEC,0x1A,0x35,0x08,0x00,0x08,0x05,0x00,0x07,0x66,0x1A,0x1B,0x87,0x09,0x30,0x00,0x00,0xAA,0xAA,\
+0x1B,0x86,0x09,0x20,0x55,0x54,0x1B,0xBC,0x00,0xF0,0x09,0x30,0x00,0x00,0xAA,0xAA,0x60,0x0E,0x53,0x80,0x67,0x00,0xFF,0x94,0x60,0x00,0x00,0x02,0x42,0x80,0x60,0x02,\
+0x70,0x01,0x4E,0x75,0x26,0x7C,0x00,0x00,0x57,0xA2,0x28,0x53,0xBB,0xCC,0x62,0x00,0x01,0x7C,0x42,0x82,0x14,0x2B,0x00,0x04,0x12,0x38,0x57,0xA1,0x0C,0x01,0x00,0x20,\
+0x67,0x00,0x00,0xEE,0x0C,0x01,0x00,0xD5,0x67,0x22,0x0C,0x01,0x00,0x5D,0x67,0x1C,0x0C,0x01,0x00,0xB5,0x67,0x00,0x00,0xDA,0x0C,0x01,0x00,0x20,0x67,0x00,0x00,0xD2,\
+0x0C,0x01,0x00,0xA4,0x67,0x00,0x00,0xCA,0x60,0x00,0x00,0x78,0x20,0x0C,0x02,0x80,0x00,0x00,0x00,0xFF,0x99,0xC0,0x24,0x7C,0x00,0x00,0x58,0x28,0x22,0x3C,0x00,0x00,\
+0x01,0x00,0x35,0xB4,0x18,0xFE,0x18,0xFE,0x55,0x81,0x66,0xF6,0xD5,0xC0,0x22,0x02,0x15,0xB3,0x18,0x04,0x18,0xFF,0x53,0x81,0x66,0xF6,0x95,0xC0,0x3B,0x87,0x01,0x70,\
+0x00,0x00,0xAA,0xAA,0x3B,0x46,0x55,0x54,0x3B,0xBC,0xA0,0xA0,0x01,0x70,0x00,0x00,0xAA,0xAA,0x32,0x3C,0x01,0x00,0x39,0xB2,0x18,0xFE,0x18,0xFE,0x55,0x81,0x66,0xF6,\
+0x32,0x3C,0x55,0xF0,0x4E,0x71,0x51,0xC9,0xFF,0xFC,0x32,0x3C,0x01,0x00,0x36,0x32,0x18,0xFE,0xB6,0x74,0x18,0xFE,0x66,0x00,0x00,0xD4,0x55,0x81,0x66,0xF0,0x60,0x00,\
+0x00,0xC8,0x16,0x3C,0x00,0x40,0x18,0x3C,0x00,0xC0,0x10,0x33,0x28,0x04,0x0C,0x00,0x00,0xFF,0x67,0x24,0x7A,0x19,0x19,0x83,0x28,0xFF,0x19,0x80,0x28,0xFF,0x72,0x15,\
+0x4E,0x71,0x51,0xC9,0xFF,0xFC,0x19,0x84,0x28,0xFF,0x72,0x0C,0x4E,0x71,0x51,0xC9,0xFF,0xFC,0xB0,0x34,0x28,0xFF,0x66,0x06,0x53,0x82,0x66,0xCE,0x60,0x04,0x53,0x05,\
+0x66,0xD4,0x42,0x55,0x4A,0x55,0x4A,0x05,0x67,0x00,0x00,0x82,0x60,0x00,0x00,0x7A,0x12,0x3C,0x00,0xA0,0x20,0x0C,0xD0,0x82,0xC0,0xBC,0x00,0x00,0x00,0x01,0x08,0x40,\
+0x00,0x00,0x16,0x33,0x28,0x04,0x0C,0x03,0x00,0xFF,0x67,0x58,0x1B,0x87,0x09,0x30,0x00,0x00,0xAA,0xAA,0x1B,0x86,0x09,0x20,0x55,0x54,0x1B,0x81,0x09,0x30,0x00,0x00,\
+0xAA,0xAA,0x19,0x83,0x28,0xFF,0xC6,0x3C,0x00,0x80,0x18,0x34,0x28,0xFF,0x1A,0x04,0xC8,0x3C,0x00,0x80,0xB8,0x03,0x67,0x2C,0x08,0x05,0x00,0x05,0x67,0xEC,0x18,0x34,\
+0x28,0xFF,0xC8,0x3C,0x00,0x80,0xB8,0x03,0x67,0x1A,0x1B,0x87,0x09,0x30,0x00,0x00,0xAA,0xAA,0x1B,0x86,0x09,0x20,0x55,0x54,0x1B,0xBC,0x00,0xF0,0x09,0x30,0x00,0x00,\
+0xAA,0xAA,0x60,0x08,0x53,0x82,0x66,0x96,0x42,0x40,0x60,0x02,0x70,0x01,0x4E,0x75,0x24,0x7C,0x00,0x07,0xFF,0xFB,0x42,0x80,0x42,0x81,0x42,0x82,0x42,0x83,0x42,0x84,\
+0x18,0x3C,0x00,0xFD,0x12,0x12,0x67,0x00,0x00,0x6C,0x0C,0x01,0x00,0xFF,0x67,0x00,0x00,0x64,0x10,0x2A,0xFF,0xFF,0x95,0xC1,0x55,0x8A,0xB0,0x04,0x66,0xE6,0x10,0x32,\
+0x18,0x00,0x04,0x00,0x00,0x30,0x0C,0x40,0x00,0x0A,0x65,0x02,0x5F,0x00,0xE9,0x8A,0x84,0x00,0x53,0x01,0x66,0xE8,0xC5,0x43,0x0C,0x04,0x00,0xFE,0x67,0x04,0x52,0x04,\
+0x60,0xC2,0xB6,0x82,0x63,0x2E,0x0C,0x83,0x00,0x07,0xFF,0xFF,0x64,0x26,0x52,0x83,0x24,0x42,0x42,0x80,0x42,0x81,0x3C,0x86,0x3C,0x87,0x12,0x1A,0xD0,0x81,0x12,0x1A,\
+0xD0,0x81,0xB5,0xC3,0x66,0xF0,0xB0,0xB9,0x00,0x07,0xFF,0xFC,0x66,0x06,0x42,0x19,0x22,0x80,0x60,0x04,0x12,0xBC,0x00,0x01,0x4E,0x75,0x24,0x7C,0x00,0x00,0x57,0xA0,\
+0x00,0x79,0x00,0x40,0x00,0xFF,0xFC,0x14,0x32,0x3C,0x55,0xF0,0x4E,0x71,0x51,0xC9,0xFF,0xFC,0x50,0xD5,0x50,0xD5,0x1A,0xBC,0x00,0x90,0x14,0xD5,0x14,0xAD,0x00,0x02,\
+0x50,0xD5,0x50,0xD5,0x0C,0x22,0x00,0x89,0x67,0x64,0x0C,0x12,0x00,0x01,0x67,0x5E,0x0C,0x12,0x00,0x31,0x67,0x58,0x02,0x79,0xFF,0xBF,0x00,0xFF,0xFC,0x14,0x32,0x3C,\
+0xAB,0xE0,0x4E,0x71,0x51,0xC9,0xFF,0xFC,0x1B,0x87,0x01,0x70,0x00,0x00,0xAA,0xAA,0x1B,0x46,0x55,0x54,0x1B,0xBC,0x00,0x90,0x01,0x70,0x00,0x00,0xAA,0xAA,0x32,0x3C,\
+0x55,0xF0,0x4E,0x71,0x51,0xC9,0xFF,0xFC,0x14,0xD5,0x14,0xAD,0x00,0x02,0x1B,0x87,0x01,0x70,0x00,0x00,0xAA,0xAA,0x1B,0x46,0x55,0x54,0x1B,0xBC,0x00,0xF0,0x01,0x70,\
+0x00,0x00,0xAA,0xAA,0x32,0x3C,0x55,0xF0,0x4E,0x71,0x51,0xC9,0xFF,0xFC,0x4E,0x75,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,\
+0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}
+
+
+#endif
\ No newline at end of file
--- a/t5can.cpp	Wed Sep 11 11:55:51 2013 +0000
+++ b/t5can.cpp	Sat Apr 25 17:07:08 2015 +0000
@@ -42,7 +42,8 @@
 void t5_can_show_help();
 void t5_can_show_full_help();
 
-void t5_can() {
+void t5_can()
+{
     // Start the CAN bus system
     // Note that at the moment this is only for T5 ECUs at 615 kbits
     can_open();
@@ -103,7 +104,8 @@
 
     @return                    command flag (success / failure)
 */
-uint8_t execute_t5_cmd() {
+uint8_t execute_t5_cmd()
+{
 
 
 //    uint8_t cmd_length = strlen(cmd_buffer);
@@ -151,9 +153,10 @@
 
             // Send a Bootloader file to the T5 ECU
         case 'b':
+            return (t5_can_send_boot_loader() && can_set_speed(1000000))
+                   ? TERM_OK : TERM_ERR;
         case 'B':
-            return (t5_can_send_boot_loader() && can_set_speed(1000000))
-//            return (t5_can_send_boot_loader() && can_set_speed(615000))
+            return (t5_can_send_boot_loader_S19() && can_set_speed(1000000))
                    ? TERM_OK : TERM_ERR;
 
             // Get Checksum from ECU (Bootloader must be uploaded first)
@@ -186,8 +189,7 @@
             return t5_can_dump_flash(T55FLASHSTART)
                    ? TERM_OK : TERM_ERR;
         case 'D':
-            if (!t5_can_get_adaption_data())
-                return TERM_ERR;
+//            if (!t5_can_send_boot_loader_S19())
             if (!t5_can_send_boot_loader())
                 return TERM_ERR;
             can_set_speed(1000000);
@@ -201,10 +203,12 @@
 
             // Send a FLASH update file to the T5 ECU
         case 'f':
-            // NOTE 'f' command Just4TESTING! only FLASHes T5.5 ECU (with S19 type file) 
-            return t5_can_send_flash_s19_update(T55FLASHSTART)
+            // NOTE 'f' command Just4TESTING! only FLASHes T5.5 ECU (with S19 type file)
+            //return t5_can_send_flash_s19_update(T55FLASHSTART)
+            return t5_can_send_flash_bin_update(T55FLASHSTART)
                    ? TERM_OK : TERM_ERR;
         case 'F':
+//            if (!t5_can_send_boot_loader_S19())
             if (!t5_can_send_boot_loader())
                 return TERM_ERR;
             can_set_speed(1000000);
@@ -251,11 +255,12 @@
 // inputs:    none
 // return:    none
 //
-void t5_can_show_help() {
+void t5_can_show_help()
+{
     printf("Trionic 5 Command Menu\r\n");
     printf("======================\r\n");
-    printf("D - Read SRAM adaption and DUMP T5 FLASH BIN file\r\n");
-    printf("F - FLASH the update file to the T5 (and write SRAM - not done!)\r\n");
+    printf("D - DUMP the T5.x ECU FLASH to a file 'ORIGINAL.BIN'\r\n");
+    printf("F - FLASH the update file 'MODIFIED.BIN' to the T5.x\r\n");
     printf("\r\n");
     printf("r - read SRAM and write it to ADAPTION.RAM file\r\n");
     printf("s - read Symbol Table and write it to SYMBOLS.TXT\r\n");
@@ -275,17 +280,18 @@
 // inputs:    none
 // return:    none
 //
-void t5_can_show_full_help() {
+void t5_can_show_full_help()
+{
     printf("Trionic 5 Command Menu\r\n");
     printf("======================\r\n");
-    printf("D - Read SRAM adaption and DUMP T5 FLASH BIN file\r\n");
-    printf("F - FLASH the update file to the T5 (and write SRAM - not done!)\r\n");
+    printf("D - DUMP the T5.x ECU FLASH to a file 'ORIGINAL.BIN'\r\n");
+    printf("F - FLASH the update file 'MODIFIED.BIN' to the T5.x\r\n");
     printf("\r\n");
     printf("b - upload and start MyBooty.S19 bootloader\r\n");
     printf("c - get T5 ECU FLASH checksum (need to upload BOOTY.S19 before using this command)\r\n");
     printf("d - dump the T5 FLASH BIN file and write it to ORIGINAL.BIN\r\n");
     printf("e - erase the FLASH chips in the T5 ECU\r\n");
-    printf("f - FLASH the update file MODIFIED.S19 to the T5 ECU\r\n");
+    printf("f - FLASH the update file MODIFIED.BIN to the T5 ECU\r\n");
     printf("r - read SRAM and write it to ADAPTION.RAM file\r\n");
     printf("s - read Symbol Table, display it and write it to SYMBOLS.TXT\r\n");
     printf("v - read T5 ECU software version, display it and write it to VERSION.TXT\r\n");
@@ -313,7 +319,8 @@
 // inputs:    none
 // return:    bool TRUE if there was a message, FALSE if no message.
 //
-bool t5_can_show_can_message() {
+bool t5_can_show_can_message()
+{
     CANMessage can_MsgRx;
     if (can.read(can_MsgRx)) {
         printf("w%03x%d", can_MsgRx.id, can_MsgRx.len);
@@ -336,7 +343,8 @@
 // inputs:    none
 // return:    bool TRUE if there all went OK, FALSE if there was an error
 //
-bool t5_can_get_symbol_table() {
+bool t5_can_get_symbol_table()
+{
     printf("Saving the symbol table file\r\n");
     FILE *fp = fopen("/local/symbols.txt", "w");  // Open "symbols.txt" on the local file system for writing
     if (!fp) {
@@ -376,7 +384,8 @@
 // inputs:    none
 // return:    bool TRUE if there all went OK, FALSE if there was an error
 //
-bool t5_can_get_version() {
+bool t5_can_get_version()
+{
     FILE *fp = fopen("/local/version.txt", "w");  // Open "version.txt" on the local file system for writing
     if (!fp) {
         perror ("The following error occured");
@@ -416,7 +425,8 @@
 // inputs:    none
 // return:    bool TRUE if all went OK, FALSE if there was an error.
 //
-bool t5_can_get_adaption_data() {
+bool t5_can_get_adaption_data()
+{
     printf("Saving the SRAM adaption data.\r\n");
     FILE *fp = fopen("/local/adaption.RAM", "w");    // Open "adaption.RAM" on the local file system for writing
     if (!fp) {
@@ -468,7 +478,59 @@
 // return:    bool TRUE if all went OK,
 //                 FALSE if the 'bootloader' wasn't sent for some reason.
 //
-bool t5_can_send_boot_loader() {
+bool t5_can_send_boot_loader()
+{
+    uint32_t BootloaderSize = sizeof(T5BootLoader);
+    uint32_t address = MYBOOTY_START; // Start and execute from address of T5Bootloader
+    uint32_t count = 0; // progress count of bootloader bytes transferred
+    char msg[8]; // Construct the bootloader frame for uploading
+
+    printf("Starting the bootloader.\r\n");
+    while (count < BootloaderSize) {
+// send a bootloader address message
+        if (!t5_can_send_boot_address((address+count), MYBOOTY_CHUNK)) return FALSE;
+// send bootloader frames
+// NOTE the last frame sent may have less than 7 real data bytes but 7 bytes are always sent. In this case the unnecessary bytes
+// are repeated from the previous frame. This is OK because the T5 ECU knows how many bytes to expect (because the count of bytes
+// is sent with the upload address) and ignores any extra bytes in the last frame.
+        for (uint8_t i=0; i<MYBOOTY_CHUNK; i++) {
+            msg[1+(i%7)] = T5BootLoader[count+i];
+            if (i%7 == 0) msg[0]=i;     // set the index number
+            if ((i%7 == 6) || (i == MYBOOTY_CHUNK-1 )) {
+                if (!t5_can_send_boot_frame(msg)) return FALSE;
+            }
+        }
+        count += MYBOOTY_CHUNK;
+    }
+// These two lines really shouldn't be necessary but for some reason the first start
+// command is ignored and a short delay is required before repeating. Using only a
+// delay, even a very long one, doesn't work.
+//
+// NOTE: This measure isn't required when uploading an external S19 bootloader file!
+//
+    T5StartBootLoader(address);
+    wait_ms(1);
+//
+    return T5StartBootLoader(address);
+}
+
+
+//
+// t5_can_send_boot_loader_S19
+//
+// Sends a 'bootloader' file, booty.s19 to the T5 ECU.
+// The 'bootloader' is stored on the mbed 'local' file system 'disk' and must be in S19 format.
+//
+// The 'bootloader' is then able to dump or reFLASH the T5 ECU FLASH chips - this is the whole point of the exercise :-)
+//
+// Sending the 'bootloader' to the T5 ECU takes just over 1 second.
+//
+// inputs:    none
+// return:    bool TRUE if all went OK,
+//                 FALSE if the 'bootloader' wasn't sent for some reason.
+//
+bool t5_can_send_boot_loader_S19()
+{
     printf("Starting the bootloader.\r\n");
     FILE *fp = fopen("/local/MyBooty.S19", "r");    // Open "booty.s19" on the local file system for reading
     if (!fp) {
@@ -514,6 +576,7 @@
                     count--;
                 }
 // send a bootloader address message
+////                printf("address %x count %x\r\n",address ,count-1 );
                 if (!t5_can_send_boot_address(address, (count-1))) return FALSE;
 // get and send the bootloader frames for this S-record
 // NOTE the last frame sent may have less than 7 real data bytes but 7 bytes are always sent. In this case the unnecessary bytes
@@ -524,11 +587,13 @@
                     checksum += c;
                     msg[1+(i%7)] = c;
                     if (i%7 == 0) msg[0]=i;     // set the index number
-                    if ((i%7 == 6) || (i == count - 2))
+                    if ((i%7 == 6) || (i == count - 2)) {
+////                        printf("Sending %2x %2x %2x %2x %2x %2x %2x %2x \r\n", msg[0], msg[1], msg[2], msg[3], msg[4], msg[5], msg[6], msg[7] );
                         if (!t5_can_send_boot_frame(msg)) {
                             fclose(fp);
                             return FALSE;
                         }
+                    }
                 }
 // get the checksum
                 if ((checksum += SRecGetByte(fp)) != 0xFF) {
@@ -545,6 +610,7 @@
             case '8':
             case '9':
                 asize = 11 - (c - '0');  // 2, 3 or 4 bytes for address
+                address = 0;
 // get the number of bytes (in ascii format) in this S-record line there must be just the address and the checksum
 // so return with an error if other than this!
                 if ((c = SRecGetByte(fp)) != (asize + 1)) break;
@@ -604,7 +670,8 @@
 // inputs:    none
 // return:    bool TRUE if all went OK,
 //
-bool t5_can_get_checksum() {
+bool t5_can_get_checksum()
+{
     uint32_t checksum = 0;
     if (!t5_boot_checksum_command(&checksum)) {
         printf("Error The ECU's checksum is wrong!\r\n");
@@ -622,7 +689,8 @@
 // inputs:    none
 // outputs:    bool TRUE if all went OK.
 //
-bool t5_can_bootloader_reset() {
+bool t5_can_bootloader_reset()
+{
     printf("Exiting the bootloader and restarting the T5 ECU.\r\n");
     if (!t5_boot_reset_command()) {
         printf("Error trying to reset the T5 ECU!\r\n");
@@ -670,7 +738,8 @@
 // inputs:    start     T5 ecu start address
 // return:    bool      TRUE if all went OK.
 //
-bool t5_can_get_start_and_chip_types(uint32_t* start) {
+bool t5_can_get_start_and_chip_types(uint32_t* start)
+{
     *start = 0;
     uint8_t make = 0;
     uint8_t type = 0;
@@ -689,23 +758,44 @@
         case INTEL:
             printf("INTEL ");
             break;
+        case ATMEL:
+            printf("ATMEL ");
+            break;
+        case SST:
+            printf("SST ");
+            break;
+        case ST:
+            printf("ST ");
+            break;
+        case AMIC:
+            printf("AMIC ");
+            break;
         default:
-            printf("UNKNOWN FLASH chips - check pin65 has enough volts!\r\n");
+            printf("\r\nUNKNOWN Manufacturer Id: %02x - Also check pin65 has enough volts!\r\n", make);
     }
     switch (type) {
         case AMD28F512:
         case INTEL28F512:
             printf("28F512 FLASH chips.\r\n");
             break;
+        case ATMEL29C512:
+            printf("29C512 FLASH chips.\r\n");
+            break;
+        case ATMEL29C010:
+            printf("29C010 FLASH chips.\r\n");
+            break;
         case AMD28F010:
         case INTEL28F010:
             printf("28F010 FLASH chips.\r\n");
             break;
         case AMD29F010:
+        case SST39SF010:
+//        case ST29F010:      // Same as AMD29F010
+        case AMICA29010L:
             printf("29F010 FLASH chips.\r\n");
             break;
         default:
-            printf("UNKNOWN - check pin65 has enough volts!\r\n");
+            printf("UNKNOWN Device Id: %02x - Also check pin65 has enough volts!\r\n", type);
             return FALSE;
     }
     return TRUE;
@@ -739,7 +829,8 @@
 // inputs:    none
 // return:    bool TRUE if all went OK.
 //
-bool t5_can_erase_flash() {
+bool t5_can_erase_flash()
+{
     printf("Erasing the FLASH chips.\r\n");
     if (!t5_boot_erase_command()) {
         printf("Error The ECU's FLASH has not been erased!\r\n");
@@ -762,7 +853,8 @@
 
 // return:    bool TRUE if all went OK, FALSE if there was an error.
 //
-bool t5_can_dump_flash(uint32_t start) {
+bool t5_can_dump_flash(uint32_t start)
+{
     printf("Saving the original FLASH BIN file.\r\n");
     FILE *fp = fopen("/local/original.bin", "w");    // Open "original.bin" on the local file system for writing
     if (!fp) {
@@ -771,6 +863,7 @@
     }
     uint32_t address = start + 5;                  // Mysterious reason for starting at 5 !!!
     char FLASHdata[6];
+    printf("  0.00 %% complete.\r");
     while (address < TRIONICLASTADDR) {
         if (!t5_can_read_data(FLASHdata, address)) {
             fclose (fp);
@@ -783,6 +876,7 @@
             printf ("Error writing to the FLASH BIN file.\r\n");
             return FALSE;
         }
+        printf("%6.2f\r", 100*(float)(address-start)/(float)(TRIONICLASTADDR - start) );
     }
     // There are a few more bytes to get because because the bin file is not an exact multiple of 6 bytes!
     // the % (modulo) mathematics function tells us how many bytes there are still to get
@@ -796,6 +890,7 @@
         printf ("Error writing to the FLASH BIN file.\r\n");
         return FALSE;
     }
+    printf("100.00 %% complete.\r\n");
     fclose(fp);
     return TRUE;
 }
@@ -804,7 +899,7 @@
 //
 // t5_can_send_flash_bin_update
 //
-// Sends a FLASH update file, modified.hex to the T5 ECU.
+// Sends a FLASH update file, modified.bin to the T5 ECU.
 // The FLASH update file is stored on the local file system and must be in hex format.
 //
 // FLASHing a T5.5 ECU takes around 40 seconds. FLASHing T5.2 ECUs should take about half of this time
@@ -814,11 +909,12 @@
 // return:    bool      TRUE if all went OK,
 //                      FALSE if the FLASH update failed for some reason.
 //
-bool t5_can_send_flash_bin_update(uint32_t start) {
+bool t5_can_send_flash_bin_update(uint32_t start)
+{
     printf("Programming the FLASH chips.\r\n");
-    FILE *fp = fopen("/local/modified.hex", "r");    // Open "modified.s19" on the local file system for reading
+    FILE *fp = fopen("/local/modified.bin", "r");    // Open "modified.bin" on the local file system for reading
     if (!fp) {
-        printf("Error: I could not find the BIN file MODIFIED.HEX\r\n");
+        printf("Error: I could not find the BIN file MODIFIED.BIN\r\n");
         return FALSE;
     }
 
@@ -857,15 +953,15 @@
     uint32_t curr_addr = start; // address to put FLASH data
     uint8_t byte_value = 0;
 
+    printf("  0.00 %% complete.\r");
     while (curr_addr <= TRIONICLASTADDR) {
 
 // send a bootloader address message
         if (!t5_can_send_boot_address(curr_addr, 0x80)) {
             fclose(fp);
-            printf("Error sending CAN message");
+            printf("\r\nError sending Block Start message. Address: %08x\r\n",curr_addr);
             return FALSE;
         }
-        curr_addr += 0x80;
 // Construct and send the bootloader frames
 // NOTE the last frame sent may have less than 7 real data bytes but 7 bytes are always sent. In this case the unnecessary bytes
 // are repeated from the previous frame. This is OK because the T5 ECU knows how many bytes to expect (because the count of bytes
@@ -873,7 +969,7 @@
         for (uint8_t i=0; i<0x80; i++) {
             if (!fread(&byte_value,1,1,fp)) {
                 fclose(fp);
-                printf("Error reading the BIN file MODIFIED.HEX");
+                printf("\r\nError reading the BIN file MODIFIED.BIN\r\n");
                 return FALSE;
             }
             msg[1+(i%7)] = byte_value;
@@ -881,11 +977,15 @@
             if ((i%7 == 6) || (i == 0x80 - 1))
                 if (!t5_can_send_boot_frame(msg)) {
                     fclose(fp);
-                    printf("Error sending CAN message");
+                    printf("\r\nError sending a Block data message. Address: %08x, Index: %02x\r\n",curr_addr, i);
                     return FALSE;
                 }
+
         }
+        curr_addr += 0x80;
+        printf("%6.2f\r", 100*(float)(curr_addr - start)/(float)(TRIONICLASTADDR - start) );
     }
+    printf("100.00 %% complete.\r\n");
     fclose(fp);
     return TRUE;
 }
@@ -903,7 +1003,8 @@
 // return:    bool TRUE if all went OK,
 //                 FALSE if the FLASH update failed for some reason.
 //
-bool t5_can_send_flash_s19_update(uint32_t start) {
+bool t5_can_send_flash_s19_update(uint32_t start)
+{
     printf("Programming the FLASH chips.\r\n");
     FILE *fp = fopen("/local/modified.s19", "r");    // Open "modified.s19" on the local file system for reading
     if (!fp) {
@@ -1014,7 +1115,8 @@
 // inputs:    none
 // return:    bool TRUE if all went OK,
 //
-bool t5_can_get_last_address() {
+bool t5_can_get_last_address()
+{
     uint32_t last_address = 0;
     uint16_t mode = 0;
     if (!t5_boot_c3_command(&last_address, &mode)) {
--- a/t5can.h	Wed Sep 11 11:55:51 2013 +0000
+++ b/t5can.h	Sat Apr 25 17:07:08 2015 +0000
@@ -33,6 +33,7 @@
 bool t5_can_get_symbol_table();
 bool t5_can_get_version();
 bool t5_can_get_adaption_data();
+bool t5_can_send_boot_loader_S19();
 bool t5_can_send_boot_loader();
 bool t5_can_get_checksum();
 bool t5_can_bootloader_reset();
--- a/t7can.cpp	Wed Sep 11 11:55:51 2013 +0000
+++ b/t7can.cpp	Sat Apr 25 17:07:08 2015 +0000
@@ -282,7 +282,7 @@
     printf("Trionic 7 Command Menu\r\n");
     printf("======================\r\n");
     printf("D - DUMP the T7 ECU FLASH to a file 'ORIGINAL.BIN'\r\n");
-    printf("F - FLASH the update file 'MODIFIED.HEX' to the T7\r\n");
+    printf("F - FLASH the update file 'MODIFIED.BIN' to the T7\r\n");
     printf("\r\n");
     printf("I - Try to open CAN I-Bus (47619 Bit/s)\r\n");
     printf("P - Try to open CAN P-Bus (500 kBit/s)\r\n");
@@ -305,7 +305,7 @@
     printf("Trionic 7 Command Menu\r\n");
     printf("======================\r\n");
     printf("D - DUMP the T7 ECU FLASH to a file 'ORIGINAL.BIN'\r\n");
-    printf("F - FLASH the update file 'MODIFIED.HEX' to the T7\r\n");
+    printf("F - FLASH the update file 'MODIFIED.BIN' to the T7\r\n");
     printf("\r\n");
     printf("I - Try to open CAN I-Bus (47619 Bit/s)\r\n");
     printf("P - Try to open CAN P-Bus (500 kBit/s)\r\n");
--- a/t7utils.cpp	Wed Sep 11 11:55:51 2013 +0000
+++ b/t7utils.cpp	Sat Apr 25 17:07:08 2015 +0000
@@ -380,12 +380,12 @@
     char data[8];
     int i, k;
 
-    // fopen modified.hex here?
+    // fopen modified.bin here?
     // need lots of fcloses though
     printf("Checking the FLASH BIN file...\r\n");
-    FILE *fp = fopen("/local/modified.hex", "r");    // Open "modified.hex" on the local file system for reading
+    FILE *fp = fopen("/local/modified.bin", "r");    // Open "modified.bin" on the local file system for reading
     if (!fp) {
-        printf("Error: I could not find the BIN file MODIFIED.HEX\r\n");;
+        printf("Error: I could not find the BIN file MODIFIED.BIN\r\n");;
         return TERM_ERR;
     }
     // obtain file size - it should match the size of the FLASH chips:
@@ -462,7 +462,7 @@
             //data[k] = *(bin + bin_count++);
             if (!fread(&data[k],1,1,fp)) {
                 fclose(fp);
-                printf("Error reading the BIN file MODIFIED.HEX\r\n");
+                printf("Error reading the BIN file MODIFIED.BIN\r\n");
                 return FALSE;
             }
 //      /* DEBUG info...
@@ -484,7 +484,7 @@
                         //data[k] = *(bin + bin_count++);
                         if (!fread(&data[k],1,1,fp)) {
                             fclose(fp);
-                            printf("Error reading the BIN file MODIFIED.HEX\r\n");
+                            printf("Error reading the BIN file MODIFIED.BIN\r\n");
                             return FALSE;
                         }
         //            /* DEBUG info...
@@ -592,12 +592,12 @@
     char data[8];
     int i, k;
 
-    // fopen modified.hex here?
+    // fopen modified.bin here?
     // need lots of fcloses though
     printf("Checking the FLASH BIN file...\r\n");
-    FILE *fp = fopen("/local/modified.hex", "r");    // Open "modified.hex" on the local file system for reading
+    FILE *fp = fopen("/local/modified.bin", "r");    // Open "modified.bin" on the local file system for reading
     if (!fp) {
-        printf("Error: I could not find the BIN file MODIFIED.HEX\r\n");;
+        printf("Error: I could not find the BIN file MODIFIED.BIN\r\n");;
         return TERM_ERR;
     }
     // obtain file size - it should match the size of the FLASH chips:
@@ -669,7 +669,7 @@
         for ( k = 4; k < 8; k++ )
             if (!fread(&data[k],1,1,fp)) {
                 fclose(fp);
-                printf("Error reading the BIN file MODIFIED.HEX\r\n");
+                printf("Error reading the BIN file MODIFIED.BIN\r\n");
                 return FALSE;
             }
         if (!can_send_timeout (T7SEC_ID, data, 8, T7MESSAGETIMEOUT)) {
@@ -740,7 +740,7 @@
         for ( k = 4; k < 8; k++ )
             if (!fread(&data[k],1,1,fp)) {
                 fclose(fp);
-                printf("Error reading the BIN file MODIFIED.HEX\r\n");
+                printf("Error reading the BIN file MODIFIED.BIN\r\n");
                 return FALSE;
             }
         if (!can_send_timeout (T7SEC_ID, data, 8, T7MESSAGETIMEOUT)) {
--- a/t8bootloaders.h	Wed Sep 11 11:55:51 2013 +0000
+++ b/t8bootloaders.h	Sat Apr 25 17:07:08 2015 +0000
@@ -1,8 +1,17 @@
 #ifndef __T8BOOTLOADERS_H__
 #define __T8BOOTLOADERS_H__
 
-
-#define T8BootloaderProg {\
+//0x77ED eor 0x4739 = 0x30D4 12,500 4.5454 ms with 5.5 MHz Clock
+//    0x11,0x77,0xED,0x39,0x32,0x66,0x11,
+//0x6029 eor 0x4739 = 0x2710 10,000 4.5454 ms with 5.5 MHz Clock
+//    0x11,0x60,0x29,0x39,0x32,0x66,0x11,
+//0x5A75 eor 0x4739 = 0x1D4C 7,500 4.5454 ms with 5.5 MHz Clock
+//    0x11,0x5A,0x75,0x39,0x32,0x66,0x11,
+//0x54B1 eor 0x4739 = 0x1388 5,000 4.5454 ms with 5.5 MHz Clock
+//    0x11,0x54,0xB1,0x39,0x32,0x66,0x11,
+//0x4EFD eor 0x4739 = 0x09C4 2,500 0.909 ms with 5.5 MHz Clock
+//    0x11,0x4E,0xFD,0x39,0x32,0x66,0x11,
+#define T8_BOOTLOADER_PROG {\
     0x77,0xD1,0x77,0x7D,0x1B,0x09,0x77,\
     0xD1,0x77,0x7D,0x1B,0x7D,0x77,0x1D,\
     0x39,0x1C,0x05,0x00,0x39,0x78,0x0B,\
@@ -1990,7 +1999,7 @@
     0x39,0x97,0x8D,0x6D,0x05,0x51,0x39,\
     0x32,0x75,0x45,0x47,0xC1,0x39,0x3A,\
     0x77,0x45,0x47,0x38,0x39,0x3A,0x46,\
-    0x11,0x77,0xED,0x39,0x32,0x66,0x11,\
+    0x11,0x60,0x29,0x39,0x32,0x66,0x11,\
     0x47,0x79,0x39,0x3B,0x77,0x05,0x46,\
     0x29,0x39,0x38,0x59,0x51,0x47,0x29,\
     0x65,0x38,0x39,0x16,0x3F,0x38,0x3B,\
@@ -2385,7 +2394,17 @@
     0x6D,0x43,0x4D,0x00,0x36,0x43,0x36,\
     0x44,0x54,0x45,0x43,0x00,0x49,0x00} //16384
 
-#define T8Bootloader {\
+//0x77ED eor 0x4739 = 0x30D4 12,500 4.5454 ms with 5.5 MHz Clock
+//    0x11,0x77,0xED,0x39,0x32,0x66,0x11,
+//0x6029 eor 0x4739 = 0x2710 10,000 4.5454 ms with 5.5 MHz Clock
+//    0x11,0x60,0x29,0x39,0x32,0x66,0x11,
+//0x5A75 eor 0x4739 = 0x1D4C 7,500 4.5454 ms with 5.5 MHz Clock
+//    0x11,0x5A,0x75,0x39,0x32,0x66,0x11,
+//0x54B1 eor 0x4739 = 0x1388 5,000 4.5454 ms with 5.5 MHz Clock
+//    0x11,0x54,0xB1,0x39,0x32,0x66,0x11,
+//0x4EFD eor 0x4739 = 0x09C4 2,500 0.909 ms with 5.5 MHz Clock
+//    0x11,0x4E,0xFD,0x39,0x32,0x66,0x11,
+#define T8_BOOTLOADER_DUMP {\
     0x77,0xD1,0x77,0x7D,0x1B,0x09,0x77,\
     0xD1,0x77,0x7D,0x1B,0x7D,0x77,0x1D,\
     0x39,0x1C,0x05,0x00,0x39,0x78,0x0B,\
@@ -4373,7 +4392,7 @@
     0x39,0x97,0x8D,0x6D,0x05,0x51,0x39,\
     0x32,0x75,0x45,0x47,0xC1,0x39,0x3A,\
     0x77,0x45,0x47,0x38,0x39,0x3A,0x46,\
-    0x11,0x77,0xED,0x39,0x32,0x66,0x11,\
+    0x11,0x60,0x29,0x39,0x32,0x66,0x11,\
     0x47,0x79,0x39,0x3B,0x77,0x05,0x46,\
     0x29,0x39,0x38,0x59,0x51,0x47,0x29,\
     0x65,0x38,0x39,0x16,0x3F,0x38,0x3B,\
--- a/t8can.cpp	Wed Sep 11 11:55:51 2013 +0000
+++ b/t8can.cpp	Sat Apr 25 17:07:08 2015 +0000
@@ -64,6 +64,15 @@
         }
     }
 
+    can_reset_filters();
+    can_add_filter(2, 0x645);         //645h - CIM
+    can_add_filter(2, 0x7E0);         //7E0h -
+    can_add_filter(2, 0x7E8);         //7E8h -
+    can_add_filter(2, 0x311);         //311h -
+    can_add_filter(2, 0x5E8);         //5E8h -
+    //can_add_filter(2, 0x101);         //101h -
+
+
 // main loop
     *cmd_buffer = '\0';
     char ret;
@@ -139,7 +148,7 @@
 //                   ? TERM_OK : TERM_ERR;
         case 'a' :
         case 'A' :
-            if (t8_authenticate(0x01)) {
+            if (t8_authenticate(T8REQID, T8RESPID, 0x01)) {
                 printf("Security Key Accepted\r\n");
                 return TERM_OK;
             } else {
@@ -149,45 +158,21 @@
 //            return t7_authenticate()
 //                   ? TERM_OK : TERM_ERR;
 
-// Erase the FLASH chips
-        case 'e':
-        case 'E':
-            return t8_erase()
-                   ? TERM_OK : TERM_ERR;
 // DUMP the T8 ECU BIN file stored in the FLASH chips
         case 'D':
-            if (!t8_authenticate(0x00)) {
-                if (!t8_initialise()) {
-                    printf("Trionic 7 Connection Failed\r\n");
-                    return TERM_ERR;
-                }
-                if (!t8_authenticate(0x00)) {
-                    printf("Security Key Failed\r\n");
-                    return TERM_ERR;
-                }
-            }
         case 'd':
             return t8_dump()
                    ? TERM_OK : TERM_ERR;
 // Send a FLASH update file to the T8 ECU
         case 'F':
-            if (!t8_authenticate(0x00)) {
-                if (!t8_initialise()) {
-                    printf("Trionic 7 Connection Failed\r\n");
-                    return TERM_ERR;
-                }
-                if (!t8_authenticate(0x00)) {
-                    printf("Security Key Failed\r\n");
-                    return TERM_ERR;
-                }
-            }
-            if (!t8_erase()) {
-                printf("Could not Erase FLASH!\r\n");
-                return TERM_ERR;
-            }
         case 'f':
             return t8_flash()
                    ? TERM_OK : TERM_ERR;
+// Erase the FLASH chips
+        case 'r':
+        case 'R':
+            return t8_recover()
+                   ? TERM_OK : TERM_ERR;
 // Try to connect to CAN I-BUS
         case 'I' :
             printf("Trying to open CAN I-Bus (47619 Bit/s)...\r\n");
@@ -255,7 +240,8 @@
     printf("Trionic 8 Command Menu\r\n");
     printf("======================\r\n");
     printf("D - DUMP the T8 ECU FLASH to a file 'ORIGINAL.BIN'\r\n");
-    printf("F - FLASH the update file 'MODIFIED.HEX' to the T8\r\n");
+    printf("F - FLASH the update file 'MODIFIED.BIN' to the T8\r\n");
+    printf("R - Recover your T8 ECU FLASH with 'MODIFIED.BIN' file\r\n");
     printf("\r\n");
     printf("I - Try to open CAN I-Bus (47619 Bit/s)\r\n");
     printf("P - Try to open CAN P-Bus (500 kBit/s)\r\n");
@@ -279,7 +265,8 @@
     printf("Trionic 8 Command Menu\r\n");
     printf("======================\r\n");
     printf("D - DUMP the T8 ECU FLASH to a file 'ORIGINAL.BIN'\r\n");
-    printf("F - FLASH the update file 'MODIFIED.HEX' to the T8\r\n");
+    printf("F - FLASH the update file 'MODIFIED.BIN' to the T8\r\n");
+    printf("R - Recover your T8 ECU FLASH with 'MODIFIED.BIN' file\r\n");
     printf("\r\n");
     printf("I - Try to open CAN I-Bus (47619 Bit/s)\r\n");
     printf("P - Try to open CAN P-Bus (500 kBit/s)\r\n");
--- a/t8utils.cpp	Wed Sep 11 11:55:51 2013 +0000
+++ b/t8utils.cpp	Sat Apr 25 17:07:08 2015 +0000
@@ -38,7 +38,7 @@
 
 bool t8_show_VIN()
 {
-    uint16_t i;
+    uint32_t i;
     char T8TxFlo[] = T8FLOCTL;
     char T8TxMsg[] = T8REQVIN;
     char T8RxMsg[8];
@@ -87,7 +87,7 @@
     char T8RxMsg[8];
     char k = 0;
 
-//    GMLANTesterPresentT8();
+//    GMLANTesterPresent(T8REQID, T8RESPID);
 //    wait_ms(2000);
 //
 //    printf("Requesting Security Access\r\n");
@@ -97,10 +97,10 @@
 //    }
 //    printf("Security Access Granted\r\n");
 //
-//    GMLANTesterPresentT8();
+//    GMLANTesterPresent(T8REQID, T8RESPID);
 //    wait_ms(2000);
 //
-//    GMLANTesterPresentT8();
+//    GMLANTesterPresent(T8REQID, T8RESPID);
 //    wait_ms(2000);
 //
     if (!can_send_timeout (T8TSTRID, SetVin10, 8, T8MESSAGETIMEOUT)) {
@@ -132,7 +132,7 @@
     for (k = 0; k < 8; k++ ) printf("0x%02X ", T8RxMsg[k] );
     printf("\r\n");
     return TRUE;
-//    GMLANTesterPresentT8();
+//    GMLANTesterPresent(T8REQID, T8RESPID);
 //    wait_ms(2000);
 //
 }
@@ -147,13 +147,25 @@
 // return:    bool TRUE if there was a message, FALSE if no message.
 //
 
-bool t8_authenticate(char level)
+bool t8_authenticate(uint32_t ReqID, uint32_t RespID, char level)
 {
-    uint16_t seed, key;
-    if (!GMLANSecurityAccessRequest(level, seed)) {
+    uint16_t i, seed, key;
+//    if (!GMLANSecurityAccessRequest(ReqID, RespID, level, seed)) {
+//        printf("Unable to request SEED value for security access\r\n");
+//        return FALSE;
+//    }
+
+    for (i=0; i < 20; i++) {
+        if (GMLANSecurityAccessRequest(ReqID, RespID, level, seed))
+            break;
+        wait(1);
+        GMLANTesterPresent(ReqID, RespID);
+    }
+    if (i == 20) {
         printf("Unable to request SEED value for security access\r\n");
         return FALSE;
     }
+
     if ( seed == 0x0000 ) {
         printf("T8 ECU is already unlocked\r\n");
         return TRUE;
@@ -175,16 +187,17 @@
         key = (key >> 8) | (key << 8);
         key -= 0x3FC7;
     */
-    if (!GMLANSecurityAccessSendKey(level, key)) {
+    wait_ms(1);
+    if (!GMLANSecurityAccessSendKey(ReqID, RespID, level, key)) {
         printf("Unable to send KEY value for security access\r\n");
         return FALSE;
     }
     printf("Key Accepted\r\n");
+    wait_ms(500);       // was 5
     return TRUE;
 }
 
 
-
 //
 // t8_dump
 //
@@ -197,7 +210,7 @@
 
 bool t8_dump()
 {
-    uint16_t i = 0, k = 0;
+    uint32_t i = 0, k = 0;
     char T8TxMsg[8];
     char T8RxMsg[8];
 
@@ -206,28 +219,19 @@
     printf("Creating FLASH dump file...\r\n");
 
 //
-    GMLANTesterPresentT8();
-//
-    if (!GMLANprogrammingSetupProcess())
+    if (!GMLANprogrammingSetupProcess(T8REQID, T8RESPID))
         return FALSE;
 //
-    wait_ms(500);
     printf("Requesting Security Access\r\n");
-    if (!t8_authenticate(0x01)) {
+    if (!t8_authenticate(T8REQID, T8RESPID, 0x01)) {
         printf("Unable to get Security Access\r\n");
         return FALSE;
     }
     printf("Security Access Granted\r\n");
-    wait_ms(500);
-    GMLANTesterPresentT8();
 //
-    char BootLoader[] = T8Bootloader;
-    if(!GMLANprogrammingUtilityFileProcess(BootLoader))
+    if(!GMLANprogrammingUtilityFileProcess(T8REQID, T8RESPID, T8BootloaderRead))
         return FALSE;
 //
-    uint32_t StartAddress = 0x0;
-    uint16_t txpnt = 0;
-    char iFrameNumber = 0x21;
 //
     printf("Downloading FLASH BIN file...\r\n");
     printf("Creating FLASH dump file...\r\n");
@@ -238,7 +242,34 @@
     }
     printf("  0.00 %% complete.\r");
     TesterPresent.start();
-    while (StartAddress < 0x100000) {     // 0x100000
+
+// It is possible to save some time by only reading the program code and CAL data
+// This is just a rough calculation, and slight overestimate of the number of blocks of data needed to send the BIN file
+    T8TxMsg[0] = 0x06;
+    T8TxMsg[1] = 0x21;
+    T8TxMsg[2] = 0x80;  // Blocksize
+    T8TxMsg[3] = 0x00;  // This address (0x020140) points to the Header at the end of the BIN
+    T8TxMsg[4] = 0x02;
+    T8TxMsg[5] = 0x01;
+    T8TxMsg[6] = 0x40;
+    T8TxMsg[7] = 0xaa;
+    if (!can_send_timeout (T8TSTRID, T8TxMsg, 7, T8MESSAGETIMEOUT)) {
+        printf("Unable to download FLASH\r\n");
+        return FALSE;
+    }
+    if (!can_wait_timeout(T8ECU_ID, T8RxMsg, 8, T8MESSAGETIMEOUT))
+        return FALSE;
+    uint32_t EndAddress = (T8RxMsg[5] << 16) | (T8RxMsg[6] << 8) | T8RxMsg[7];
+    EndAddress += 0x200;    // Add some bytes for the Footer itself and to account for division rounded down later
+    char T8TxFlo[] = T8FLOCTL;
+    can_send_timeout (T8TSTRID, T8TxFlo, 8, T8MESSAGETIMEOUT);
+    for (i = 0; i < 0x12; i++) {
+        if (!can_wait_timeout(T8ECU_ID, T8RxMsg, 8, T8MESSAGETIMEOUT))
+            return FALSE;
+    }
+    printf("Reading your BIN file adjusted for footer = 0x%06X Bytes\r\n", EndAddress );
+
+    for ( uint32_t StartAddress = 0x0; StartAddress < EndAddress; StartAddress +=0x80 ) {     // 0x100000
         T8TxMsg[0] = 0x06;
         T8TxMsg[1] = 0x21;
         T8TxMsg[2] = 0x80;  // Blocksize
@@ -258,26 +289,22 @@
             return FALSE;
 #ifdef DEBUG
         printf("first %#.3f\r\n",timer.read());
-        for (k = 0; k < 8; k++ ) printf("0x%02X ", T8RxMsg[k] );
-        printf("\r\n");
 #endif
-        txpnt = 0;
+        uint32_t txpnt = 0;
         for (k = 4; k < 8; k++ ) file_buffer[txpnt++] = T8RxMsg[k];
 
         uint8_t DataFrames = 0x12;
-        iFrameNumber = 0x21;
+        char iFrameNumber = 0x21;
         char T8TxFlo[] = T8FLOCTL;
+        can_send_timeout (T8TSTRID, T8TxFlo, 8, T8MESSAGETIMEOUT);
 #ifdef DEBUG
         printf("flowCtrl %#.3f\r\n",timer.read());
 #endif
-        can_send_timeout (T8TSTRID, T8TxFlo, 8, T8MESSAGETIMEOUT);
         for (i = 0; i < DataFrames; i++) {
             if (!can_wait_timeout(T8ECU_ID, T8RxMsg, 8, T8MESSAGETIMEOUT))
                 return FALSE;
 #ifdef DEBUG
             printf("Consec %#.3f\r\n",timer.read());
-            for (k = 0; k < 8; k++ ) printf("0x%02X ", T8RxMsg[k] );
-            printf("\r\n");
 #endif
             iFrameNumber++;
             for (k = 1; k < 8; k++ ) file_buffer[txpnt++] = T8RxMsg[k];
@@ -288,12 +315,22 @@
             printf ("Error writing to the FLASH BIN file.\r\n");
             return TERM_ERR;
         }
-        StartAddress +=0x80;
-        printf("%6.2f\r", (100.0*(float)StartAddress)/(float)(0x100000) );
+        printf("%6.2f\r", (100.0*(float)StartAddress)/(float)(EndAddress) );
         if (TesterPresent.read_ms() > 2000) {
-            GMLANTesterPresentT8();
+            GMLANTesterPresent(T8REQID, T8RESPID);
             TesterPresent.reset();
-            ACTIVITYLEDON;
+        }
+    }
+
+    for (uint32_t i = 0; i < 0x80; i++)
+        file_buffer[i] = 0xFF;
+    while ( ftell(fp) < 0x100000 ) {
+//  for ( uint32_t StartAddress = EndAddress; StartAddress < 0x100000; StartAddress +=0x80 ) {
+        fwrite((file_buffer), 1, 0x80, fp);
+        if (ferror (fp)) {
+            fclose (fp);
+            printf ("Error writing to the FLASH BIN file.\r\n");
+            return TERM_ERR;
         }
     }
 
@@ -304,69 +341,44 @@
     return TRUE;
 }
 
-bool t8_erase()
-{
-    printf("Erasing T8 ECU FLASH...\r\n");
-    printf("SUCCESS: The FLASH has been erased.\r\n");
-    return TRUE;
-}
-
-bool t8_flash_raw()
-{
-    timer.reset();
-    timer.start();
-    printf("Checking the FLASH BIN file...\r\n");
-    timer.stop();
-    printf("SUCCESS! Programming the FLASH took %#.1f seconds.\r\n",timer.read());
-    return TRUE;
-}
-
 
 bool t8_flash()
 {
-    uint16_t i = 0, j = 0, k = 0;
+    uint32_t i = 0, j = 0, k = 0;
 
     timer.reset();
     timer.start();
     printf("FLASHing T8 BIN file...\r\n");
 
 //
-    GMLANTesterPresentT8();
-//
-    if (!GMLANprogrammingSetupProcess())
+    if (!GMLANprogrammingSetupProcess(T8REQID, T8RESPID))
         return FALSE;
 //
-    wait_ms(500);
     printf("Requesting Security Access\r\n");
-    if (!t8_authenticate(0x01)) {
+    if (!t8_authenticate(T8REQID, T8RESPID, 0x01)) {
         printf("Unable to get Security Access\r\n");
         return FALSE;
     }
     printf("Security Access Granted\r\n");
-    wait_ms(500);
-    GMLANTesterPresentT8();
 //
-    char BootLoader[] = T8BootloaderProg;
-    if(!GMLANprogrammingUtilityFileProcess(BootLoader))
+//    const uint8_t BootLoader[] = T8BootloaderProg;
+//    if(!GMLANprogrammingUtilityFileProcess(T8REQID, T8RESPID, BootLoader))
+    if(!GMLANprogrammingUtilityFileProcess(T8REQID, T8RESPID, T8BootLoaderWrite))
         return FALSE;
 //
-
-
 // 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 = 0x020000;
-    uint16_t txpnt = 0;
+    uint32_t txpnt = 0;
     char iFrameNumber = 0x21;
     char GMLANMsg[8];
     char data2Send[0xE0];
 //
-    // fopen modified.hex here, check it is OK and work out how much data I need to send
+    // fopen modified.bin here, check it is OK and work out how much data I need to send
     // need lots of fcloses though
     printf("Checking the FLASH BIN file...\r\n");
-    FILE *fp = fopen("/local/modified.hex", "r");    // Open "modified.hex" on the local file system for reading
+    FILE *fp = fopen("/local/modified.bin", "r");    // Open "modified.bin" on the local file system for reading
     if (!fp) {
-        printf("Error: I could not find the BIN file MODIFIED.HEX\r\n");;
+        printf("Error: I could not find the BIN file MODIFIED.BIN\r\n");;
         return TERM_ERR;
     }
     // obtain file size - it should match the size of the FLASH chips:
@@ -376,7 +388,10 @@
 
     // read the initial stack pointer value in the BIN file - it should match the value expected for the type of ECU
     uint32_t stack_long = 0;
-    if (!fread(&stack_long,4,1,fp)) return TERM_ERR;
+    if (!fread(&stack_long,4,1,fp)) {
+        fclose(fp);
+        return TERM_ERR;
+    }
     stack_long = (stack_long >> 24) | ((stack_long << 8) & 0x00FF0000) | ((stack_long >> 8) & 0x0000FF00) |  (stack_long << 24);
 //
     if (file_size != T8FLASHSIZE || stack_long != T8POINTER) {
@@ -389,7 +404,10 @@
 // This is just a rough calculation, and slight overestimate of the number of blocks of data needed to send the BIN file
     uint32_t blocks2Send;
     fseek(fp,0x020140,SEEK_SET);
-    if (!fread(&blocks2Send,4,1,fp)) return TERM_ERR;
+    if (!fread(&blocks2Send,4,1,fp)) {
+        fclose(fp);
+        return TERM_ERR;
+    }
     blocks2Send = (blocks2Send >> 24) | ((blocks2Send << 8) & 0x00FF0000) | ((blocks2Send >> 8) & 0x0000FF00) |  (blocks2Send << 24);
     printf("Start address of BIN file's Footer area = 0x%06X\r\n", blocks2Send );
     blocks2Send += 0x200;       // Add some bytes for the Footer itself and to account for division rounded down later
@@ -401,45 +419,31 @@
     fseek (fp , 0x020000 , SEEK_SET);
 // Erase the FLASH
     printf("Waiting for FLASH to be Erased\r\n");
-    if (!GMLANRequestDownload(GMLANRequestDownloadModeEncrypted)) {
+    if (!GMLANRequestDownload(T8REQID, T8RESPID, GMLANRequestDownloadModeEncrypted)) {
+        fclose(fp);
         printf("Unable to erase the FLASH chip!\r\n");
         return FALSE;
     }
 // Now send the BIN file
+    GMLANTesterPresent(T8REQID, T8RESPID);
     TesterPresent.start();
     printf("Sending FLASH BIN file\r\n");
     printf("  0.00 %% complete.\r");
     for (i=0; i<blocks2Send; i++) {
         // get a block of 0xE0 bytes in an array called data2Send
-        for ( j = 0; j < 0xE0; j++ ) {
-            //data[k] = *(bin + bin_count++);
-            if (!fread(&data2Send[j],1,1,fp)) {
-                fclose(fp);
-                printf("Error reading the BIN file MODIFIED.HEX\r\n");
-                return FALSE;
-            }
-            // encrypt data2Send array by XORing with 6 different in a ring (modulo function)
-            switch ( ((0xE0*i)+j) %6) {
-                case 1:
-                    data2Send[j] ^= 0x68;
-                    break;
-                case 2:
-                    data2Send[j] ^= 0x77;
-                    break;
-                case 3:
-                    data2Send[j] ^= 0x6D;
-                    break;
-                case 4:
-                    data2Send[j] ^= 0x47;
-                    break;
-                default:        // remainder 0 and 5 both XOR with 0x39
-                    data2Send[j] ^= 0x39;
-            }
+        if (!fread(data2Send,0xE0,1,fp)) {
+            fclose(fp);
+            printf("\r\nError reading the BIN file MODIFIED.BIN\r\n");
+            return FALSE;
         }
+        // encrypt data2Send array by XORing with 6 different values in a ring (modulo function)
+        char key[6] = { 0x39, 0x68, 0x77, 0x6D, 0x47, 0x39 };
+        for ( j = 0; j < 0xE0; j++ )
+            data2Send[j] ^= key[(((0xE0*i)+j) % 6)];
         // Send the block of data
-        if (!GMLANDataTransferFirstFrame(0xE6, GMLANDOWNLOAD, StartAddress)) {
+        if (!GMLANDataTransferFirstFrame(T8REQID, T8RESPID, 0xE6, GMLANDOWNLOAD, StartAddress)) {
             fclose(fp);
-            printf("Unable to start BIN File Upload\r\n");
+            printf("\r\nUnable to start BIN File Upload\r\n");
             return FALSE;
         }
         // Send 0x20 messages of 0x07 bytes each (0x20 * 0x07 = 0xE0)
@@ -449,50 +453,21 @@
             GMLANMsg[0] = iFrameNumber;
             for (k=1; k<8; k++)
                 GMLANMsg[k] = data2Send[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)) {
+            if (!can_send_timeout(T8REQID, GMLANMsg, 8, GMLANPTCT)) {
                 fclose(fp);
-                printf("Unable to send BIN File\r\n");
+                printf("\r\nUnable to send BIN File\r\n");
                 return FALSE;
             }
             ++iFrameNumber &= 0x2F;
-//            wait_ms(1);
-            wait_us(250);
-        }
-        if (!can_wait_timeout(T8ResponseId, GMLANMsg, 8, GMLANPTCT)) {
-            fclose(fp);
-            printf("I did not receive a block acknowledge message\r\n");
-            return FALSE;
+            wait_us(1000);   // can be as low as 250 for an ECU on its own, but need 1000 (1ms) to work in a car (use a longer delay to be ultrasafe??? )
         }
-        while (GMLANMsg[0] == 0x03 && GMLANMsg[1] == 0x7F && GMLANMsg[2] == 0x36 && GMLANMsg[3] == 0x78) {
-            printf("I'm waiting for a Block to be programmed into FLASH\r\n");
-            if (!can_wait_timeout(T8ResponseId, GMLANMsg, 8, GMLANPTCTENHANCED)) {
-                printf("I did not receive a block acknowledge message after enhanced timeout\r\n");
-                fclose(fp);
-                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]);
-            fclose(fp);
-            return FALSE;
-        }
-        if (GMLANMsg[0] != 0x01 && GMLANMsg[1] != 0x76) {
-            printf("EXITING due to an unexpected CAN message");
+        if (!GMLANDataTransferBlockAcknowledge(T8RESPID)) {
             fclose(fp);
             return FALSE;
         }
         if (TesterPresent.read_ms() > 2000) {
-            GMLANTesterPresentT8();
+            GMLANTesterPresent(T8REQID, T8RESPID);
             TesterPresent.reset();
-            ACTIVITYLEDON;
         }
         StartAddress += 0xE0;
         printf("%6.2f\r", (100.0*(float)i)/(float)(blocks2Send) );
@@ -500,14 +475,158 @@
 // FLASHing complete
     printf("%6.2f\r\n", (float)100 );
 // End programming session and return to normal mode
-    if (!GMLANReturnToNormalMode()) {
+    if (!GMLANReturnToNormalMode(T8REQID, T8RESPID)) {
         fclose(fp);
         printf("UH-OH! T8 ECU did not Return To Normal Mode!!\r\n");
         return FALSE;
     }
-    wait_ms(1000);
     timer.stop();
     printf("SUCCESS! FLASHing the BIN file took %#.1f seconds.\r\n",timer.read());
     fclose(fp);
     return TRUE;
 }
+
+bool t8_recover()
+{
+    uint32_t i = 0, j = 0, k = 0;
+
+    timer.reset();
+    timer.start();
+    printf("Recovering your T8 ECU ...\r\n");
+//
+    if (!GMLANprogrammingSetupProcess(T8USDTREQID, T8UUDTRESPID))
+        return FALSE;
+//
+    printf("Requesting Security Access\r\n");
+    if (!t8_authenticate(T8USDTREQID, T8UUDTRESPID, 0x01)) {
+        printf("Unable to get Security Access\r\n");
+        return FALSE;
+    }
+    printf("Security Access Granted\r\n");
+//
+//    const uint8_t BootLoader[] = T8BootloaderProg;
+//    if(!GMLANprogrammingUtilityFileProcess(T8USDTREQID, T8UUDTRESPID, BootLoader))
+    if(!GMLANprogrammingUtilityFileProcess(T8USDTREQID, T8UUDTRESPID, T8BootLoaderWrite))
+        return FALSE;
+//
+
+
+// All steps needed to transfer and start a bootloader ('Utility File' in GMLAN parlance)
+    uint32_t StartAddress = 0x020000;
+    uint32_t txpnt = 0;
+    char iFrameNumber = 0x21;
+    char GMLANMsg[8];
+    char data2Send[0xE0];
+//
+    // fopen modified.bin here, check it is OK and work out how much data I need to send
+    // need lots of fcloses though
+    printf("Checking the FLASH BIN file...\r\n");
+    FILE *fp = fopen("/local/modified.bin", "r");    // Open "modified.bin" on the local file system for reading
+    if (!fp) {
+        printf("Error: I could not find the BIN file MODIFIED.BIN\r\n");;
+        return TERM_ERR;
+    }
+    // obtain file size - it should match the size of the FLASH chips:
+    fseek (fp , 0 , SEEK_END);
+    uint32_t file_size = ftell (fp);
+    rewind (fp);
+
+    // read the initial stack pointer value in the BIN file - it should match the value expected for the type of ECU
+    uint32_t stack_long = 0;
+    if (!fread(&stack_long,4,1,fp)) {
+        fclose(fp);
+        return TERM_ERR;
+    }
+    stack_long = (stack_long >> 24) | ((stack_long << 8) & 0x00FF0000) | ((stack_long >> 8) & 0x0000FF00) |  (stack_long << 24);
+//
+    if (file_size != T8FLASHSIZE || stack_long != T8POINTER) {
+        fclose(fp);
+        printf("The BIN file does not appear to be for a T8 ECU :-(\r\n");
+        printf("BIN file size: %#010x, FLASH chip size: %#010x, Pointer: %#010x.\r\n", file_size, T7FLASHSIZE, stack_long);
+        return TERM_ERR;
+    }
+// It is possible to save some time by only sending the program code and CAL data
+// This is just a rough calculation, and slight overestimate of the number of blocks of data needed to send the BIN file
+    uint32_t blocks2Send;
+    fseek(fp,0x020140,SEEK_SET);
+    if (!fread(&blocks2Send,4,1,fp)) {
+        fclose(fp);
+        return TERM_ERR;
+    }
+    blocks2Send = (blocks2Send >> 24) | ((blocks2Send << 8) & 0x00FF0000) | ((blocks2Send >> 8) & 0x0000FF00) |  (blocks2Send << 24);
+    printf("Start address of BIN file's Footer area = 0x%06X\r\n", blocks2Send );
+    blocks2Send += 0x200;       // Add some bytes for the Footer itself and to account for division rounded down later
+    blocks2Send -= 0x020000;    // Remove 0x020000 because we don't send the bootblock and adaptation blocks
+    printf("Amount of data to send BIN file adjusted for footer = 0x%06X Bytes\r\n", blocks2Send );
+    blocks2Send /= 0xE0;
+    printf("Number of Blocks of 0xE0 Bytes needed to send BIN file = 0x%04X\r\n", blocks2Send );
+// Move BIN file pointer to start of data
+    fseek (fp , 0x020000 , SEEK_SET);
+// Erase the FLASH
+    printf("Waiting for FLASH to be Erased\r\n");
+    if (!GMLANRequestDownload(T8REQID, T8RESPID, GMLANRequestDownloadModeEncrypted)) {
+        fclose(fp);
+        printf("Unable to erase the FLASH chip!\r\n");
+        return FALSE;
+    }
+// Now send the BIN file
+    GMLANTesterPresent(T8REQID, T8RESPID);
+    TesterPresent.start();
+    printf("Sending FLASH BIN file\r\n");
+    printf("  0.00 %% complete.\r");
+    for (i=0; i<blocks2Send; i++) {
+        // get a block of 0xE0 bytes in an array called data2Send
+        if (!fread(data2Send,0xE0,1,fp)) {
+            fclose(fp);
+            printf("\r\nError reading the BIN file MODIFIED.BIN\r\n");
+            return FALSE;
+        }
+        // encrypt data2Send array by XORing with 6 different values in a ring (modulo function)
+        char key[6] = { 0x39, 0x68, 0x77, 0x6D, 0x47, 0x39 };
+        for ( j = 0; j < 0xE0; j++ )
+            data2Send[j] ^= key[(((0xE0*i)+j) % 6)];
+        // Send the block of data
+        if (!GMLANDataTransferFirstFrame(T8REQID, T8RESPID, 0xE6, GMLANDOWNLOAD, StartAddress)) {
+            fclose(fp);
+            printf("\r\nUnable to start BIN File Upload\r\n");
+            return FALSE;
+        }
+        // Send 0x20 messages of 0x07 bytes each (0x20 * 0x07 = 0xE0)
+        txpnt = 0;
+        iFrameNumber = 0x21;
+        for (j=0; j < 0x20; j++) {
+            GMLANMsg[0] = iFrameNumber;
+            for (k=1; k<8; k++)
+                GMLANMsg[k] = data2Send[txpnt++];
+            if (!can_send_timeout(T8REQID, GMLANMsg, 8, GMLANPTCT)) {
+                fclose(fp);
+                printf("\r\nUnable to send BIN File\r\n");
+                return FALSE;
+            }
+            ++iFrameNumber &= 0x2F;
+            wait_us(1000);   // was 250 use 1000 or wait_ms(1) to be ultrasafe
+        }
+        if (!GMLANDataTransferBlockAcknowledge(T8RESPID)) {
+            fclose(fp);
+            return FALSE;
+        }
+        if (TesterPresent.read_ms() > 2000) {
+            GMLANTesterPresent(T8REQID, T8RESPID);
+            TesterPresent.reset();
+        }
+        StartAddress += 0xE0;
+        printf("%6.2f\r", (100.0*(float)i)/(float)(blocks2Send) );
+    }
+// FLASHing complete
+    printf("%6.2f\r\n", (float)100 );
+// End programming session and return to normal mode
+    if (!GMLANReturnToNormalMode(T8REQID, T8RESPID)) {
+        fclose(fp);
+        printf("UH-OH! T8 ECU did not Return To Normal Mode!!\r\n");
+        return FALSE;
+    }
+    timer.stop();
+    fclose(fp);
+    printf("SUCCESS: Your T8 ECU has been recovered.\r\n");
+    return TRUE;
+}
--- a/t8utils.h	Wed Sep 11 11:55:51 2013 +0000
+++ b/t8utils.h	Sat Apr 25 17:07:08 2015 +0000
@@ -11,7 +11,7 @@
 #include "common.h"
 #include "canutils.h"
 
-#include "t8bootloaders.h"
+//#include "t8bootloaders.h"
 #include "gmlan.h"
 
 
@@ -45,11 +45,10 @@
 extern bool t8_initialise();
 extern bool t8_show_VIN();
 extern bool t8_write_VIN();
-extern bool t8_authenticate(char level);
+extern bool t8_authenticate(uint32_t ReqID, uint32_t RespID, char level);
 extern bool t8_dump();
 extern bool t8_flash();
-extern bool t8_flash_raw();
-extern bool t8_erase();
+extern bool t8_recover();
 
 
 #endif
\ No newline at end of file