Just4Trionic - CAN and BDM FLASH programmer for Saab cars

Dependencies:   mbed

Revision:
1:d5452e398b76
Child:
2:bf3a2b29259a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bdm.cpp	Tue Sep 14 21:02:04 2010 +0000
@@ -0,0 +1,567 @@
+/*******************************************************************************
+
+bdm.cpp
+(c) 2010 by Sophie Dexter
+
+BDM functions for Just4Trionic by Just4pLeisure
+
+A derivative work based on:
+//-----------------------------------------------------------------------------
+//    Firmware for USB BDM v2.0
+//    (C) johnc, 2009
+//    $id$
+//-----------------------------------------------------------------------------
+
+********************************************************************************
+
+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 "bdm.h"
+
+// constants
+#define CMD_BUF_LENGTH      32              ///< command buffer size
+
+// LED constants and macros
+#define LED_ONTIME          5               ///< LED 'on' time, ms    
+#define LED_TCNT            (255 - (unsigned char)((unsigned long)(LED_ONTIME * 1000L)  \
+                            / (1000000L / (float)((unsigned long)XTAL_CPU / 1024L))))
+
+// command characters
+#define CMDGROUP_ADAPTER    'a'             ///< adapter commands 
+#define CMD_VERSION         'v'             ///< firmware version
+#define CMD_PINSTATUS       's'             ///< momentary status of BDM pins
+#define CMD_BKPTLOW         '1'             ///< pull BKPT low
+#define CMD_BKPTHIGH        '2'             ///< pull BKPT high
+#define CMD_RESETLOW        '3'             ///< pull RESET low
+#define CMD_RESETHIGH       '4'             ///< pull RESET high
+
+#define CMDGROUP_MCU        'c'             ///< target MCU management commands
+#define CMD_STOPCHIP        'S'             ///< stop
+#define CMD_RESETCHIP       'R'             ///< reset
+#define CMD_RUNCHIP         'r'             ///< run from given address
+#define CMD_RESTART         's'             ///< restart
+#define CMD_STEP            'b'             ///< step
+
+#define CMDGROUP_FLASH      'f'
+#define CMD_GETVERIFY       'v'             ///< gets verification status
+#define CMD_SETVERIFY       'V'             ///< sets verification on/off
+#define CMD_DUMP            'd'             ///< dumps memory contents
+#define CMD_ERASE           'E'             ///< erase entire flash memory            
+#define CMD_WRITE           'w'             ///< writes to flash memory
+
+#define CMDGROUP_MEMORY     'm'             ///< target MCU memory commands
+#define CMD_READBYTE        'b'             ///< read byte from memory
+#define CMD_READWORD        'w'             ///< read word (2 bytes) from memory
+#define CMD_READLONG        'l'             ///< read long word (4 bytes) from memory
+#define CMD_DUMPBYTE        'z'             ///< dump byte from memory
+#define CMD_DUMPWORD        'x'             ///< dump word from memory
+#define CMD_DUMPLONG        'c'             ///< dump long word from memory
+#define CMD_WRITEBYTE       'B'             ///< write byte to memory
+#define CMD_WRITEWORD       'W'             ///< write word to memory
+#define CMD_WRITELONG       'L'             ///< write long word to memory
+#define CMD_FILLBYTE        'f'             ///< fill byte in memory
+#define CMD_FILLWORD        'F'             ///< fill word in memory
+#define CMD_FILLLONG        'M'             ///< fill long word in memory 
+
+#define CMDGROUP_REGISTER   'r'             ///< register commands
+#define CMD_READSYSREG      'r'             ///< read system register
+#define CMD_WRITESYSREG     'W'             ///< write system register
+#define CMD_READADREG       'a'             ///< read A/D register
+#define CMD_WRITEADREG      'A'             ///< write A/D register
+
+#define CMDGROUP_TRIONIC    'T'
+#define CMD_TRIONICDUMP     'D'             ///< dumps memory contents
+#define CMD_TRIONICWRITE    'F'             ///< writes to flash memory
+
+// static variables
+static char cmd_buffer[CMD_BUF_LENGTH];     ///< command string buffer
+static uint32_t cmd_addr;                   ///< address (optional)
+static uint32_t cmd_value;                  ///< value    (optional)
+static uint32_t cmd_result;                 ///< result
+
+// private functions
+uint8_t execute_bdm_cmd();
+
+void bdm_show_help();
+void bdm_show_full_help();
+
+// command argument macros
+#define CHECK_ARGLENGTH(len) \
+    if (cmd_length != len + 2) \
+        return TERM_ERR
+
+#define GET_NUMBER(target, offset, len)    \
+    if (!ascii2int(target, cmd_buffer + 2 + offset, len)) \
+        return TERM_ERR
+
+
+void bdm() {
+
+    bdm_show_help();
+    // set up LED pins
+//    SETBIT(LED_DIR, _BV(LED_ERR) | _BV(LED_ACT));
+    // set up USB_RD and USB_WR pins
+//    SETBIT(USB_RXTX_DIR, _BV(USB_RD) | _BV(USB_WR));
+
+    // enable interrupts
+//    sei();
+
+    // load configuration from EEPROM
+//    verify_flash = eeprom_read_byte(&ee_verify);
+
+// Set some initial values to help with checking if the BDM connector is plugged in
+    PIN_PWR.mode(PullDown);
+    PIN_NC.mode(PullUp);
+    PIN_DS.mode(PullUp);
+    PIN_FREEZE.mode(PullUp);
+    PIN_DSO.mode(PullUp);
+
+    verify_flash = true;
+
+    // main loop
+    *cmd_buffer = '\0';
+    char ret;
+    char rx_char;
+    while (true) {
+        // read chars from USB
+        if (pc.readable()) {
+            // turn Error LED off for next command
+            led4 = 0;
+            rx_char = pc.getc();
+            switch (rx_char) {
+                    // 'ESC' key to go back to mbed Just4Trionic 'home' menu
+                case '\e':
+                    reset_chip();
+                    return;
+                    // end-of-command reached
+                case TERM_OK :
+                    // execute command and return flag via USB
+                    ret = execute_bdm_cmd();
+                    pc.putc(ret);
+                    // reset command buffer
+                    *cmd_buffer = '\0';
+                    // light up LED
+//                    ret == TERM_OK ? led_on(LED_ACT) : led_on(LED_ERR);
+                    ret == TERM_OK ? led3 = 1 : led4 = 1;
+                    break;
+                    // another command char
+                default:
+                    // store in buffer if space permits
+                    if (StrLen(cmd_buffer) < CMD_BUF_LENGTH - 1) {
+                        StrAddc(cmd_buffer, rx_char);
+                    }
+                    break;
+            }
+        }
+    }
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Executes a command and returns result flag (does not transmit the flag
+    itself).
+
+    @return                    command flag (success / failure)
+*/
+uint8_t execute_bdm_cmd() {
+    uint8_t cmd_length = strlen(cmd_buffer);
+    char cmd = *(cmd_buffer + 1);
+
+    // command groups
+    switch (*cmd_buffer) {
+            // adapter commands
+        case CMDGROUP_ADAPTER:
+            CHECK_ARGLENGTH(0);
+            switch (cmd) {
+                    // get firmware version
+                case CMD_VERSION:
+                    printf("%02x", FW_VERSION_MAJOR);
+                    printf("%02x", FW_VERSION_MINOR);
+                    return TERM_OK;
+
+                    // get momentary status of BDM pins 0...5 (for debugging)
+                case CMD_PINSTATUS:
+//                    printf("%02x", (BDM_PIN & 0x3f));
+                    printf("PWR %d, ", PIN_PWR.read());
+                    printf("NC %d, ", PIN_NC.read());
+                    printf("DS %d, ", PIN_DS.read());
+                    printf("FREEZE %d, ", PIN_FREEZE.read());
+                    printf("DSO %d, ", PIN_DSO.read());
+                    return TERM_OK;
+
+                    // pull BKPT low
+                case CMD_BKPTLOW:
+                    return bkpt_low();
+
+                    // pull BKPT high
+                case CMD_BKPTHIGH:
+                    return bkpt_high();
+
+                    // pull RESET low
+                case CMD_RESETLOW:
+                    return reset_low();
+
+                    // pull RESET high
+                case CMD_RESETHIGH:
+                    return reset_high();
+            }
+            break;
+
+            // MCU management
+        case CMDGROUP_MCU:
+            switch (cmd) {
+                    // stop target MCU
+                case CMD_STOPCHIP:
+                    return stop_chip();
+
+                    // reset target MCU
+                case CMD_RESETCHIP:
+                    return reset_chip();
+
+                    // run target MCU from given address
+                case CMD_RUNCHIP:
+                    CHECK_ARGLENGTH(8);
+                    GET_NUMBER(&cmd_addr, 0, 8);
+                    return run_chip(&cmd_addr);
+
+                    // restart
+                case CMD_RESTART:
+                    return restart_chip();
+
+                    // step
+                case CMD_STEP:
+                    return step_chip();
+            }
+            break;
+
+            // Trionic dumping and flashing
+        case CMDGROUP_FLASH:
+            switch (cmd) {
+                    // get verification flag
+                case CMD_GETVERIFY:
+                    CHECK_ARGLENGTH(0);
+                    printf("%02x", (uint8_t)verify_flash);
+                    return TERM_OK;
+
+                    // set verification flag
+                case CMD_SETVERIFY:
+                    CHECK_ARGLENGTH(2);
+                    GET_NUMBER(&cmd_addr, 0, 2);
+                    verify_flash = (bool)cmd_addr;
+//                    eeprom_write_byte(&ee_verify, verify_flash);
+                    return TERM_OK;
+
+                    // dump flash contents as block
+                case CMD_DUMP:
+                    CHECK_ARGLENGTH(16);
+                    GET_NUMBER(&cmd_addr, 0, 8);
+                    GET_NUMBER(&cmd_value, 8, 8);
+                    return dump_flash(&cmd_addr, &cmd_value);
+
+                    // erase entire flash memory
+                case CMD_ERASE:
+                    CHECK_ARGLENGTH(22);
+                    GET_NUMBER(&cmd_addr, 6, 8);
+                    GET_NUMBER(&cmd_value, 14, 8);
+                    return erase_flash(cmd_buffer + 2, &cmd_addr, &cmd_value);
+
+                    // write data block to flash memory
+                case CMD_WRITE:
+                    CHECK_ARGLENGTH(14);
+                    GET_NUMBER(&cmd_addr, 6, 8);
+                    return write_flash(cmd_buffer + 2, &cmd_addr);
+            }
+            break;
+
+            // memory
+        case CMDGROUP_MEMORY:
+            if (cmd != CMD_FILLBYTE && cmd != CMD_FILLWORD &&
+                    cmd != CMD_FILLLONG && cmd != CMD_DUMPBYTE && cmd != CMD_DUMPWORD &&
+                    cmd != CMD_DUMPLONG) {
+                // get memory address
+                if (cmd_length < 10 || !ascii2int(&cmd_addr, cmd_buffer + 2, 8)) {
+                    // broken parametre
+                    return TERM_ERR;
+                }
+
+                // get optional value
+                if (cmd_length > 10 &&
+                        !ascii2int(&cmd_value, cmd_buffer + 10, cmd_length - 10)) {
+                    // broken parametre
+                    return TERM_ERR;
+                }
+            }
+
+            switch (cmd) {
+                    // read byte
+                case CMD_READBYTE:
+                    if (cmd_length != 10 ||
+                            memread_byte((uint8_t*)(&cmd_result), &cmd_addr) != TERM_OK) {
+                        return TERM_ERR;
+                    }
+                    printf("%02x", (uint8_t)cmd_result);
+                    return TERM_OK;
+
+                    // read word
+                case CMD_READWORD:
+                    if (cmd_length != 10 ||
+                            memread_word((uint16_t*)(&cmd_result), &cmd_addr) != TERM_OK) {
+                        return TERM_ERR;
+                    }
+                    printf("%04X", (uint16_t)cmd_result);
+                    return TERM_OK;
+
+                    // read long word
+                case CMD_READLONG:
+                    if (cmd_length != 10 ||
+                            memread_long(&cmd_result, &cmd_addr) != TERM_OK) {
+                        return TERM_ERR;
+                    }
+                    printf("%08X", cmd_result);
+                    return TERM_OK;
+
+                    // dump byte
+                case CMD_DUMPBYTE:
+                    if (cmd_length != 2 ||
+                            memdump_byte((uint8_t*)(&cmd_result)) != TERM_OK) {
+                        return TERM_ERR;
+                    }
+                    printf("%02x", (uint8_t)cmd_result);
+                    return TERM_OK;
+
+                    // dump word
+                case CMD_DUMPWORD:
+                    if (cmd_length != 2 ||
+                            memdump_word((uint16_t*)(&cmd_result)) != TERM_OK) {
+                        return TERM_ERR;
+                    }
+                    printf("%04X", (uint16_t)cmd_result);
+                    return TERM_OK;
+
+                    // dump long word
+                case CMD_DUMPLONG:
+                    if (cmd_length != 2 ||
+                            memdump_long(&cmd_result) != TERM_OK) {
+                        return TERM_ERR;
+                    }
+                    printf("%08X", cmd_result);
+                    return TERM_OK;
+
+                    // write byte
+                case CMD_WRITEBYTE:
+                    return (cmd_length == 12 &&
+                            memwrite_byte(&cmd_addr, cmd_value) == TERM_OK) ?
+                           TERM_OK : TERM_ERR;
+
+                    // write word
+                case CMD_WRITEWORD:
+                    return (cmd_length == 14 &&
+                            memwrite_word(&cmd_addr, cmd_value) == TERM_OK) ?
+                           TERM_OK : TERM_ERR;
+
+                    // write long word
+                case CMD_WRITELONG:
+                    return (cmd_length == 18 &&
+                            memwrite_long(&cmd_addr, &cmd_value) == TERM_OK) ?
+                           TERM_OK : TERM_ERR;
+
+                    // fill byte
+                case CMD_FILLBYTE:
+                    if (cmd_length != 4 || !ascii2int(&cmd_value, cmd_buffer + 2, 2)) {
+                        return TERM_ERR;
+                    }
+                    return (memfill_byte(cmd_value));
+
+                    // fill word
+                case CMD_FILLWORD:
+                    if (cmd_length != 6 || !ascii2int(&cmd_value, cmd_buffer + 2, 4)) {
+                        return TERM_ERR;
+                    }
+                    return (memfill_word(cmd_value));
+
+                    // fill long word
+                case CMD_FILLLONG:
+                    if (cmd_length != 10 || !ascii2int(&cmd_value, cmd_buffer + 2, 8)) {
+                        return TERM_ERR;
+                    }
+                    return (memfill_long(&cmd_value));
+            }
+            break;
+
+            // registers
+        case CMDGROUP_REGISTER:
+            // get register code
+            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) {
+                    // read system register
+                case CMD_READSYSREG:
+                    if (cmd_length != 4 ||
+                            sysreg_read(&cmd_result, (uint8_t)cmd_addr) != TERM_OK) {
+                        return TERM_ERR;
+                    }
+                    printf("%08X", cmd_result);
+                    return TERM_OK;
+
+                    // write system register
+                case CMD_WRITESYSREG:
+                    return (cmd_length == 12 &&
+                            sysreg_write((uint8_t)cmd_addr, &cmd_value) == TERM_OK) ?
+                           TERM_OK : TERM_ERR;
+
+                    // read A/D register
+                case CMD_READADREG:
+                    if (cmd_length != 4 ||
+                            adreg_read(&cmd_result, (uint8_t)cmd_addr) != TERM_OK) {
+                        return TERM_ERR;
+                    }
+                    printf("%08X", cmd_result);
+                    return TERM_OK;
+
+                    // write A/D register
+                case CMD_WRITEADREG:
+                    return (cmd_length == 12 &&
+                            adreg_write((uint8_t)cmd_addr, &cmd_value) == TERM_OK) ?
+                           TERM_OK : TERM_ERR;
+            }
+            break;
+
+            // Trionic dumping and flashing
+        case CMDGROUP_TRIONIC:
+
+            switch (cmd) {
+
+                    // dump flash contents to a bin file
+                case CMD_TRIONICDUMP:
+                    CHECK_ARGLENGTH(0);
+                    return dump_trionic();
+
+                    // write data block to flash memory
+                case CMD_TRIONICWRITE:
+                    CHECK_ARGLENGTH(0);
+                    return flash_trionic();
+            }
+
+            // show help for BDM commands
+        case 'H':
+            bdm_show_full_help();
+            return TERM_OK;
+        case 'h':
+            bdm_show_help();
+            return TERM_OK;
+        default:
+            bdm_show_help();
+    }
+
+    // unknown command
+    return TERM_ERR;
+}
+
+void bdm_show_help() {
+    printf("Just4Trionic BDM Command Menu\r\n");
+    printf("=============================\r\n");
+    printf("TD - and DUMP T5 FLASH BIN file\r\n");
+    printf("TF - FLASH the update file to the T5 (and write SRAM)\r\n");
+    printf("Tr - Read SRAM adaption (not done).\r\n");
+    printf("Tw - Write SRAM adaptation (not done).\r\n");
+    printf("\r\n");
+    printf("'ESC' - Return to Just4Trionic Main Menu\r\n");
+    printf("\r\n");
+    printf("h  - Show this help menu\r\n");
+    printf("\r\n");
+    return;
+}
+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");
+    printf("TF - FLASH the update file to the T5 (and write SRAM)\r\n");
+    printf("Tr - Read SRAM adaption (not done).\r\n");
+    printf("Tw - Write SRAM adaptation (not done).\r\n");
+    printf("\r\n");
+    printf("Adapter Commands - a\r\n");
+    printf("====================\r\n");
+    printf("av - display firmware version\r\n");
+    printf("as - display status of BDM pins\r\n");
+    printf("a1 - pull BKPT low\r\n");
+    printf("a2 - pull BKPT high\r\n");
+    printf("a3 - pull RESET low\r\n");
+    printf("a4 - pull RESET high\r\n");
+    printf("\r\n");
+    printf("MCU Management Commands - c\r\n");
+    printf("===========================\r\n");
+    printf("cS - stop MCU\r\n");
+    printf("cR - reset MCU\r\n");
+    printf("cr - run from given address\r\n");
+    printf("     e.g. crCAFEBABE run from address 0xcafebabe\r\n");
+    printf("cs - restart MCU\r\n");
+    printf("cb - step MCU\r\n");
+    printf("\r\n");
+    printf("MCU FLASH Commands - f\r\n");
+    printf("======================\r\n");
+    printf("fv - gets verification status (always verify)\r\n");
+    printf("fV - sets verification on/off (always on)\r\n");
+    printf("fd - DUMPs memory contents\r\n");
+    printf("     e.g. fdSSSSSSSSEEEEEEEE S...E... start and end addresses\r\n");
+    printf("     e.g. fd0000000000020000 to DUMP T5.2\r\n");
+    printf("     e.g. fd0000000000040000 to DUMP T5.5\r\n");
+    printf("     e.g. fd0000000000080000 to DUMP T7\r\n");
+    printf("fE - Erases entire FLASH memory\r\n");
+    printf("     e.g. fETTTTTTSSSSSSSSEEEEEEEE T...S...E type, start and end addresses\r\n");
+    printf("     e.g. fE28f0100000000000020000 erase 28F512 in T5.2\r\n");
+    printf("     e.g. fE28f0100000000000040000 erase 28F010 in T5.5\r\n");
+    printf("     e.g. fE29f0100000000000040000 erase 29F010 in T5.5 (addresses not used)\r\n");
+    printf("     e.g. fE29f4000000000000080000 erase 29F400 in T7 (addresses not used)\r\n");
+    printf("fw - writes to FLASH memory\r\n");
+    printf("     Write a batch of long words to flash from a start address\r\n");
+    printf("     followed by longwords LLLLLLLL, LLLLLLLL etc\r\n");
+    printf("     Send a break character to stop when doneg");
+    printf("     e.g. fwTTTTTTSSSSSSSS T...S... type and start address\r\n");
+    printf("     e.g. fw28f01000004000 start at address 0x004000 T5.2/5.5\r\n");
+    printf("     e.g. fw29f01000004000 start at address 0x004000 T5.5 with 29F010\r\n");
+    printf("     e.g. fw29f40000004000 start at address 0x004000 T7\r\n");
+    printf("\r\n");
+    printf("MCU Memory Commands - m\r\n");
+    printf("=======================\r\n");
+    printf("mbAAAAAAAA - read byte from memory at 0xaaaaaaaa\r\n");
+    printf("mwAAAAAAAA - read word (2 bytes) from memory\r\n");
+    printf("mlAAAAAAAA - read long word (4 bytes) from memory\r\n");
+    printf("mz - dump byte from the next memory address\r\n");
+    printf("mx - dump word from the next memory address\r\n");
+    printf("mc - dump long word from the next memory address\r\n");
+    printf("mBAAAAAAAADD - write byte 0xdd to memory 0xaaaaaaaa\r\n");
+    printf("mWAAAAAAAADDDD - write word 0xdddd to memory 0xaaaaaaaa\r\n");
+    printf("mLAAAAAAAADDDDDDD - write long word 0xdddddddd to memory 0xaaaaaaaa\r\n");
+    printf("mfDD - fill byte 0xdd to next memory address\r\n");
+    printf("mFDDDD - fill word 0xdddd to next memory address\r\n");
+    printf("mMDDDDDDDD - fill long word 0xdddddddd to next memory address\r\n");
+    printf("\r\n");
+    printf("MCU Register Commands - r\r\n");
+    printf("=========================\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");
+    printf("rWRRCAFEBABE - write 0xcafebabe system register RR\r\n");
+    printf("raAD - read A/D register 0x00-07 D0-D7, 0x08-15 A0-A7\r\n");
+    printf("rAADCAFEBABE - write 0xcafebabe to A/D register \r\n");
+    printf("\r\n");
+    printf("'ESC' - Return to Just4Trionic Main Menu\r\n");
+    printf("\r\n");
+    printf("H  - Show this help menu\r\n");
+    printf("\r\n");
+    return;
+}