Just4Trionic - CAN and BDM FLASH programmer for Saab cars

Dependencies:   mbed

Files at this revision

API Documentation at this revision

Comitter:
Just4pLeisure
Date:
Tue Sep 14 21:02:04 2010 +0000
Parent:
0:e0b964252a05
Child:
2:bf3a2b29259a
Commit message:

Changed in this revision

BDM.cpp Show diff for this revision Revisions of this file
BDM.h Show diff for this revision Revisions of this file
CAN232.cpp Show diff for this revision Revisions of this file
CAN232.h Show diff for this revision Revisions of this file
CANUtils.cpp Show diff for this revision Revisions of this file
CANUtils.h Show diff for this revision Revisions of this file
SRecUtils.cpp Show diff for this revision Revisions of this file
SRecUtils.h Show diff for this revision Revisions of this file
T5Utils.cpp Show diff for this revision Revisions of this file
T5Utils.h Show diff for this revision Revisions of this file
Trionic5.cpp Show diff for this revision Revisions of this file
Trionic5.h Show diff for this revision Revisions of this file
bdm.cpp Show annotated file Show diff for this revision Revisions of this file
bdm.h 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
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
can232.cpp Show annotated file Show diff for this revision Revisions of this file
can232.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
canutils.h 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
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
sizedefs.h Show annotated file Show diff for this revision Revisions of this file
srecutils.cpp Show annotated file Show diff for this revision Revisions of this file
srecutils.h Show annotated file Show diff for this revision Revisions of this file
strings.cpp Show annotated file Show diff for this revision Revisions of this file
strings.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
t5utils.cpp Show annotated file Show diff for this revision Revisions of this file
t5utils.h Show annotated file Show diff for this revision Revisions of this file
--- a/BDM.cpp	Wed May 19 12:39:18 2010 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,5 +0,0 @@
-
-#include "BDM.h"
-
-void BDM() {
-}
\ No newline at end of file
--- a/BDM.h	Wed May 19 12:39:18 2010 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,3 +0,0 @@
-// BDM.h
-
-extern void BDM();
\ No newline at end of file
--- a/CAN232.cpp	Wed May 19 12:39:18 2010 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,5 +0,0 @@
-
-#include "CAN232.h"
-
-void CAN232() {
-}
\ No newline at end of file
--- a/CAN232.h	Wed May 19 12:39:18 2010 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,3 +0,0 @@
-// CAN232.h
-
-extern void CAN232();
\ No newline at end of file
--- a/CANUtils.cpp	Wed May 19 12:39:18 2010 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,97 +0,0 @@
-// CANUtils.cpp - functions that work with the CAN bus directly
-// Anything to do with the CAN bus must (should anyway) be done by one of these functions.
-
-#include "CANUtils.h"
-
-// CAN_RS pin at Philips PCA82C250 can bus controller.
-// activate transceiver by pulling this pin to GND.
-// (Rise and fall slope controlled by resistor R_s)
-// (+5V result in tranceiver standby mode)
-// For further information see datasheet page 4
-DigitalOut can_Pca82c250SlopePin(p28);// second can controller on these pins. Not used here.
-// CAN can1(p9, p10);
-// We use can on mbed pins 29(CAN_TXD) and 30(CAN_RXD).
-CAN can2(p30, p29);
-// Use a timer to see if things take too long
-Timer CANTimer;
-
-// Use the LEDs to if anything is happening on the CAN bus
-// LED1 CAN send
-DigitalOut led1(LED1);
-// LED2 CAN receive
-DigitalOut led2(LED2);
-
-
-void CANOpen() {
-    // 600kbit/s first - basically sets up CAN interface, but to wrong speed - not sure what else it does
-    can2.frequency(600000);
-    // 615kbit/s direct write of 615 kbit/s speed setting
-    LPC_CAN2->BTR = 0x370002;
-    // activate external can transceiver
-    can_Pca82c250SlopePin = 0;
-}
-
-void CANClose() {
-    // disable external can transceiver
-    can_Pca82c250SlopePin = 1;
-}
-
-//
-// Sends a CAN Message, returns FALSE if the message wasn't sent in time
-//
-// inputs:  integer CAN message 'id', pointer to 'frame', integer message length and integer timeout
-// return:     TRUE if the CAN message was sent before the 'timeout' expires
-//          FALSE if 'timeout' expires or the message length is wrong
-//
-extern bool CANSendTimeout (int id, char *frame, int len, int timeout) {
-    CANTimer.reset();
-    CANTimer.start();
-    while (CANTimer.read_ms() < timeout) {
-        if (can2.write(CANMessage(id, frame, len))) {
-            CANTimer.stop();
-            led1 = !led1;
-            return TRUE;
-        }
-    }
-    CANTimer.stop();
-    return FALSE;
-}
-
-//
-// Waits for a CAN Message with the specified 'id' for a time specified by the 'timeout'
-// All other messages are ignored
-// The CAN message frame is returned using the pointer to 'frame'
-//
-// inputs:    integer CAN message 'id', pointer to 'frame' for returning the data
-//          integer expected length of message, len and integer for the waiting time 'timeout'
-//
-// return:    TRUE if a qualifying message was received
-//          FALSE if 'timeout' expires or the message length is wrong
-//
-extern bool CANWaitTimeout (int id, char *frame, int len, int timeout) {
-    CANMessage CANMsgRx;
-    CANTimer.reset();
-    CANTimer.start();
-    while (CANTimer.read_ms() < timeout) {
-        if (can2.read(CANMsgRx)) {
-/*
-            printf("w%03x8", CANMsgRx.id);
-            for (char i=0; i<len; i++) {
-                printf("%02x", CANMsgRx.data[i]);
-            }
-            printf("\n\r");
-//            */
-            led2 = !led2;
-            if (CANMsgRx.id == id) {
-                CANTimer.stop();
-//                if (T5MsgRx.len != len)
-//                    return FALSE;
-                for (int i=0; i<len; i++)
-                    frame[i] = CANMsgRx.data[i];
-                return TRUE;
-            }
-        }
-    }
-    CANTimer.stop();
-    return FALSE;
-}
--- a/CANUtils.h	Wed May 19 12:39:18 2010 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,14 +0,0 @@
-
-// CANUtils.h - information and definitions needed for the CAN bus
-
-#include "CAN.h"
-#include "mbed.h"
-
-#define TRUE 1
-#define FALSE 0
-
-extern void CANOpen();
-extern void CANClose();
-
-extern bool CANSendTimeout (int id, char *frame, int len, int timeout);
-extern bool CANWaitTimeout (int id, char *frame, int len, int timeout);
--- a/SRecUtils.cpp	Wed May 19 12:39:18 2010 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,40 +0,0 @@
-
-#include "SRecUtils.h"
-
-// SRecGetByte
-//
-// Returns an int which is a single byte made up from two ascii characters read from an S-record file
-//
-// inputs:	a file pointer for the S-record file
-// return:	an integer which is the byte in hex format
-
-int SRecGetByte(FILE *fp) {
-    int c = 0;
-    int retbyte = 0;
-
-    for(int i=0; i<2; i++) {
-        if ((c = fgetc(fp)) == EOF) return -1;
-        c -= (c > '9') ? ('A' - 10) : '0';
-        retbyte = (retbyte << 4) + c;
-    }
-    return retbyte;
-}
-
-// SRecGetAddress
-//
-// Returns an int which is the address part of the S-record line
-// The S-record type 1/2/3 or 9/8/7 determines if there are 2, 3 or 4 bytes in the address
-//
-// inputs:	an integer which is the number of bytes that make up the address; 2, 3 or 4 bytes
-//			a file pointer for the S-record file
-// return:	an integer which is the load address for the S-record
-
-int SRecGetAddress(int size, FILE *fp) {
-    int address = 0;
-    for (int i = 0; i<size; i++)
-    {
-        address <<= 8;
-        address |= SRecGetByte (fp);
-    }
-    return address;
-}
\ No newline at end of file
--- a/SRecUtils.h	Wed May 19 12:39:18 2010 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,10 +0,0 @@
-
-// SRecUtils.h - information and definitions needed for working with S-Records
-
-#include "mbed.h"
-
-#define TRUE 1
-#define FALSE 0
-
-extern int SRecGetByte(FILE *fp);
-extern int SRecGetAddress(int size, FILE *fp);
--- a/T5Utils.cpp	Wed May 19 12:39:18 2010 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,389 +0,0 @@
-/*******************************************************************************
-
-T5Utils.cpp - By Sophie Dexter, April 2010
-
-This C++ module provides functions for communicating simple messages to and from
-the T5 ECU
-
-********************************************************************************
-
-WARNING: Use at your own risk, sadly this software comes with no guarantees.
-This software is provided 'free' and in good faith, but the author does not
-accept liability for any damage arising from its use.
-
-*******************************************************************************/
-
-#include "T5Utils.h"
-
-//
-// T5Open enables the CAN chip and sets the CAN speed to 615 kbits.
-//
-// This function is a 'quick fix' for now.
-//
-// inputs:    none
-// return:    bool TRUE if all went OK, 
-//
-bool T5Open() {
-    CANOpen ();
-    return TRUE;
-}
-
-//
-// T5Close disables the CAN chip.
-//
-// This function is a 'quick fix' for now.
-//
-// inputs:    none
-// return:    bool TRUE if all went OK, 
-//
-bool T5Close() {
-    CANClose ();
-    return TRUE;
-}
-
-//
-// T5WaitResponse
-//
-// Waits for a response message with the correct message id from the T5 ECU.
-// The response is a single ascii character from the symboltable.
-//
-// Returns an error ('BELL' character) if:
-//      a response is not received before the timeout
-//      the message length is less than 8 bytes (all messages should be 8 bytes)
-//      the message type is incorrect
-//
-// inputs:    none
-// return:    a single char that is the response from the T5 ECU
-//
-char T5WaitResponse() {
-    char T5RxMsg[8];
-    if (!CANWaitTimeout(RESPID, T5RxMsg, 8, T5MESSAGETIMEOUT)) return '\a';
-    if (T5RxMsg[0] != 0xC6) return '\a';
-    return T5RxMsg[2];
-}
-
-//
-//
-// T5WaitResponsePrint
-//
-// Waits for a response message with the correct message id from the T5 ECU and displays the whole message:
-//
-// wiiildddddddddddddddd
-//  iii - is the CAN message id
-//     l - is the message length, should always be 8 for T5 messages
-//      dd,dd,dd,dd,dd,dd,dd,dd are the CAN message data bytes
-//
-// Returns an error if:
-//      a response is not received before the timeout
-//      the message length is less than 8 bytes (all messages should be 8 bytes)
-//      the message type is incorrect
-//
-// Inputs:    none
-// return:    bool TRUE if a qualifying message was received
-//                 FALSE if a message wasn't received in time, had the wrong id etc...
-//
-bool T5WaitResponsePrint() {
-    char T5RxMsg[8];
-    if (!CANWaitTimeout(RESPID, T5RxMsg, 8, T5CHECKSUMTIMEOUT)) return FALSE;
-    printf("w%03x8", RESPID);
-    for (char i=0; i<8; i++) {
-        printf("%02x", T5RxMsg[i]);
-    }
-    printf("\n\r");
-    return TRUE;
-}
-
-// T5GetSymbol
-//
-// Reads a single symbol name (in the symbol table) from the T5 ECU.
-// T5GetSymbol sends ACK messages to the T5 ECU and stores the
-// reply characters in a string until a '\n' character is received
-// when the function returns with the pointer to that string.
-//
-// inputs:    a pointer to the string used to store the symbol name.
-// return:    a pointer to the string used to store the symbol name.
-//
-char *T5GetSymbol(char *s) {
-    do {
-        if (T5Ack()) {
-        }
-        *s = T5WaitResponse();
-    } while (*s++ != '\n');
-    *s = '\0';
-    return s;
-}
-
-// T5ReadCmnd
-//
-// Sends a 'read' type command to the T5 ECU. 'read' commands are used to read something from the T5 ECU.
-//
-// inputs:    a 'char' which is the type of 'read' requested (e.g. symbol table, version etc).
-// return:    bool TRUE if the message was sent within the timeout period,
-//                 FALSE if the message couldn't be sent.
-//
-bool T5ReadCmnd(char c) {
-    char T5TxMsg[] = T5_RDCMND;
-    T5TxMsg[1] = c;
-    return (CANSendTimeout (CMNDID, T5TxMsg, 8, T5MESSAGETIMEOUT));
-}
-
-//
-// T5WriteCmnd is unfinished
-//
-bool T5WriteCmnd(unsigned int addr, char data) {
-    return FALSE;
-}
-
-// T5ReadRAM
-//
-// Reads 6 bytes of the adaption data from the SRAM in the T5 ECU.
-//
-// inputs:    a pointer to an array of 6 bytes for storing the data read from the T5 ECU.
-//            the address to read SRAM data from in the T5 ECU
-// return:    a pointer to an array of 6 bytes for storing the data read from the T5 ECU.
-//
-char *T5ReadRAM(char *data, unsigned int addr) {
-    T5RAMCmnd(addr);
-    T5WaitRAM(data);
-    return data;
-}
-
-// T5ReadFLASH
-//
-// Reads 6 bytes of the FLASH in the T5 ECU.
-//
-// inputs:    a pointer to an array of 6 bytes for storing the data read from the T5 ECU.
-//            the address to read SRAM data from in the T5 ECU
-// return:    a pointer to an array of 6 bytes for storing the data read from the T5 ECU.
-//
-char *T5ReadFLASH(char *data, unsigned int addr) {
-    T5RAMCmnd(addr);
-    T5WaitRAM(data);
-    return data;
-}
-
-//
-// T5RAMCmnd
-//
-// Sends a command to the ECU asking the T5 ECU to send some SRAM data
-//
-// inputs:    the address to read SRAM data from in the T5 ECU
-// return:    bool TRUE if the message was sent within the timeout period,
-//                 FALSE if the message couldn't be sent.
-//
-bool T5RAMCmnd(unsigned int addr) {
-    char T5TxMsg[] = T5RAMCMND;
-    T5TxMsg[1] = ((char)(addr >> 24));         // high high byte of address
-    T5TxMsg[2] = ((char)(addr >> 16));         // high low byte of address
-    T5TxMsg[3] = ((char)(addr >> 8));          // low high byte of address
-    T5TxMsg[4] = ((char)(addr));               // low low byte of address
-    return (CANSendTimeout (CMNDID, T5TxMsg, 8, T5MESSAGETIMEOUT));
-}
-
-//
-// T5WaitRAM
-//
-// Waits for the T5 ECU to send some SRAM data
-//
-// There is something back-to-front about the way this works, but it does :-)
-//
-// inputs:    a pointer to an array of 6 bytes for storing the data read from the T5 ECU.
-// return:    a pointer to an array of 6 bytes for storing the data read from the T5 ECU.
-//
-char *T5WaitRAM(char *data) {
-    char T5RxMsg[8];
-    CANWaitTimeout(RESPID, T5RxMsg, 8, T5MESSAGETIMEOUT);
-//    if (T5RxMsg[0] != 0xC6) return FALSE;
-//    if (T5RxMsg[0] != 0x0C) return FALSE;
-    for (int i=2; i<8; i++)
-        data[7-i] = T5RxMsg[i];
-    return data;
-}
-
-// T5Ack
-//
-// Sends an 'ACK' message to the T5 ECU to prompt the T5 to send the next
-// ascii character from the symboltable
-//
-// Returns an error if:
-//      the 'ACK' message cannot be sent before the timeout
-//
-// inputs:    none
-// return:    bool TRUE if message was sent OK,
-//                 FALSE if message could not be sent.
-
-bool T5Ack() {
-    char T5TxMsg[] = T5ACKCMND;
-    return (CANSendTimeout (CMNDID, T5TxMsg, 8, T5MESSAGETIMEOUT));
-}
-
-//
-// T5SendBootAddress
-//
-// Send an address where 'bootloader' or FLASH CAN messages are uploaded to.
-// The number of bytes (up to 0x7F) that will be sent in the following CAN messages is also sent.
-//
-// inputs:    an unsigned int, the address where messages should be sent.
-//            an int, the number of bytes (up to 0x7F) that will be sent in the following CAN messages.
-// return:    bool TRUE if message was sent OK,
-//                 FALSE if message could not be sent.
-//
-bool T5SendBootAddress(unsigned int addr, int len) {
-    char T5TxMsg[] = T5_BTCMND;
-    T5TxMsg[1] = ((char)(addr >> 24));         // high high byte of address
-    T5TxMsg[2] = ((char)(addr >> 16));         // high low byte of address
-    T5TxMsg[3] = ((char)(addr >> 8));          // low high byte of address
-    T5TxMsg[4] = ((char)(addr));               // low low byte of address
-    T5TxMsg[5] = ((char)(len));                // number of bytes to upload (sent in following messages)
-    return (CANSendTimeout (CMNDID, T5TxMsg, 8, T5MESSAGETIMEOUT));
-}
-
-// Upload 'bootloader' or new FLASH byts to T5 ECU in CAN messages
-//
-// The CAN messages are made up of 1 byte which is added to the address given in the T5SendBootAddress meaassge
-// followed by 7 bytes of data.
-// The first byte normally starts at 0x00 and increases by 7 in following messages until another T5SendBootAddress message is sent e.g.
-// 00,dd,dd,dd,dd,dd,dd,dd,dd 'dd' bytes are the data bytes, 7 in each CAN message except the last one which may have less.
-// 07,dd,dd,dd,dd,dd,dd,dd,dd
-// 0E,dd,dd,dd,dd,dd,dd,dd,dd (0x0E is 14)
-// 15,dd,dd,dd,dd,dd,dd,dd,dd (0x15 is 21)
-// etc.
-//
-// inputs:    a pointer to an array of 8 bytes to be sent to the T5 ECU SRAM or FLASH.
-// return:    bool TRUE if message was sent OK,
-//                 FALSE if message could not be sent.
-//
-bool T5SendBootFrame (char *frame) {
-    return (CANSendTimeout (CMNDID, frame, 8, T5MESSAGETIMEOUT));
-}
-
-//
-// T5StartBootLoader
-//
-// Send the jump to address to the T5 ECU for starting the 'bootloader'.
-// The jump address must be somewhere in RAM (addresses 0x0000 to 0x8000).
-// (The start address comes from the S7/8/9 line in the S19 file.)
-//
-// inputs:    an unsigned int, the address to jump to start of 'bootloader'.
-// return:    bool TRUE if message was sent OK,
-//                 FALSE if message could not be sent.
-//
-bool T5StartBootLoader (unsigned int addr) {
-    char T5TxMsg[] = T5JMPCMND;
-    T5TxMsg[3] = ((char)(addr >> 8));          // low byte of address
-    T5TxMsg[4] = ((char)(addr));               // high byte of address
-    return (CANSendTimeout (CMNDID, T5TxMsg, 8, T5MESSAGETIMEOUT));
-}
-
-//
-// T5BootCSumCmnd
-//
-// Send the checksum command to Bootloader
-//
-// inputs:    none
-// return:    bool TRUE if message was sent OK,
-//                 FALSE if message could not be sent.
-//
-bool T5BootCSumCmnd() {
-    char T5TxMsg[] = T5SUMCMND;
-    return (CANSendTimeout (CMNDID, T5TxMsg, 8, T5MESSAGETIMEOUT));
-}
-
-//
-// T5BootResetCmnd
-//
-// Send 'exit and restart T5' command to the Bootloader
-//
-// inputs:    none
-// return:    bool TRUE if message was sent OK,
-//                 FALSE if message could not be sent.
-//
-bool T5BootResetCmnd() {
-    char T5TxMsg[] = T5RSTCMND;
-    return (CANSendTimeout (CMNDID, T5TxMsg, 8, T5MESSAGETIMEOUT));
-}
-
-//
-// T5BootFLASHType
-//
-// Send 'get FLASH chip types' command to the Bootloader
-//
-// inputs:    none
-// return:    bool TRUE if message was sent OK,
-//                 FALSE if message could not be sent.
-//
-bool T5BootFLASHType() {
-    char T5TxMsg[] = T5TYPCMND;
-    return (CANSendTimeout (CMNDID, T5TxMsg, 8, T5MESSAGETIMEOUT));
-}
-
-//
-// T5BootEraseCmnd
-//
-// Send 'erase FLASH chip types' command to the Bootloader
-//
-// inputs:    none
-// return:    bool TRUE if message was sent OK,
-//                 FALSE if message could not be sent.
-//
-bool T5BootEraseCmnd() {
-    char T5TxMsg[] = T5ERACMND;
-    return (CANSendTimeout (CMNDID, T5TxMsg, 8, T5MESSAGETIMEOUT));
-}
-
-//
-// T5BootDumpFLASHCmnd
-//
-// Send 'Dump FLASH BIN file' command
-//
-// inputs:    none
-// return:    bool TRUE if message was sent OK,
-//                 FALSE if message could not be sent.
-//
-extern bool T5BootDumpFLASHCmnd() {
-    char T5TxMsg[] = T5DMPCMND;
-    return (CANSendTimeout (CMNDID, T5TxMsg, 8, T5MESSAGETIMEOUT));
-}
-
-//
-// T5WaitFLASH
-//
-// Waits for the T5 ECU to send 4 bytes of FLASH data when dumping the FLASH
-//
-// CAN messages look like this:
-// A6,04,dd,dd,dd,dd,08,08
-// A6 - means FLASH dump type message
-//    04 - means (at least) 4 more bytes still to come
-//       dd,dd,dd,dd are 4 data bytes
-// The last message looks like this:
-// A6,00,dd,dd,dd,dd,08,08
-// A6 - means FLASH dump type message
-//    00 - means no more bytes after this CAN message
-//       dd,dd,dd,dd are the last 4 data bytes
-//
-// inputs:    a pointer to an array of 8 bytes for the CAN message containing FLASH data.
-// return:    a pointer to an array of 8 bytes for the CAN message containing FLASH data.
-//
-char *T5WaitFLASH(char *data) {
-    char T5RxMsg[8];
-    CANWaitTimeout(RESPID, T5RxMsg, 8, T5MESSAGETIMEOUT);
-//    if (T5RxMsg[0] != 0xC6) return FALSE;
-//    if (T5RxMsg[0] != 0x0C) return FALSE;
-    for (int i=0; i<8; i++)
-        data[i] = T5RxMsg[i];
-    return data;
-}
-
-//
-// T5BootResetCmnd
-//
-// Send 'C3 - Get last address' command to the Bootloader
-//
-// inputs:    none
-// return:    bool TRUE if message was sent OK,
-//                 FALSE if message could not be sent.
-//
-bool T5BootC3Command() {
-    char T5TxMsg[] = T5EOFCMND;
-    return (CANSendTimeout (CMNDID, T5TxMsg, 8, T5MESSAGETIMEOUT));
-}
\ No newline at end of file
--- a/T5Utils.h	Wed May 19 12:39:18 2010 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,59 +0,0 @@
-
-// T5Utils.h - information and definitions needed for communicating with the T5 ECU
-
-#include "mbed.h"
-#include "CANUtils.h"
-
-#define TRUE 1
-#define FALSE 0
-
-#define CMNDID 0x05
-#define ACK_ID 0x06
-#define RESPID 0x0C
-
-#define T5_RDCMND {0xC4,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}     // C4 Command template for reading something from the T5 ECU
-#define T5_WRCMND {0xC4,0x00,0x00,0x00,0x00,0x00,0x00,0x00}     // C4 Command template for writing something to the T5 ECU
-#define T5ACKCMND {0xC6,0x00,0x00,0x00,0x00,0x00,0x00,0x00}     // C6 Command for acknowledging receipt of last message from T5 ECU or
-                                                                // asking it to send some more data (e.g. symbol table) I'm not sure which :lol:
-#define T5_BTCMND {0xA5,0x00,0x00,0x00,0x00,0x00,0x00,0x00}     // A5 Command template for sending a bootloader to the T5 ECU
-#define T5JMPCMND {0xC1,0x00,0x00,0x00,0x00,0x00,0x00,0x00}     // C1 Command template for starting a bootloader that has been sent to the T5 ECU
-#define T5EOFCMND {0xC3,0x00,0x00,0x00,0x00,0x00,0x00,0x00}     // C3 Command for reading back the last address of FLASH in the T5 ECU
-#define T5A_DCMND {0xC5,0x00,0x00,0x00,0x00,0x00,0x00,0x00}     // C5 Command for setting analogue to digital registers (don't know what this is for)
-//#define T5RAMCMND {0xC7,0x00,0x00,0x00,0x00,0xFC,0xC4,0x77}     // C7 Command for reading T5 RAM (all the symbols and adaption data is in RAM)
-#define T5RAMCMND {0xC7,0x00,0x00,0x00,0x00,0x00,0x00,0x00}     // C7 Command for reading T5 RAM (all the symbols and adaption data is in RAM)
-
-
-#define T5DMPCMND {0xA6,0x00,0x00,0x00,0x00,0x00,0x00,0x00}     // A6 Command for dumping the T5 FLASH BIN file (Bootloader must be loaded before using)
-#define T5ERACMND {0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00}     // C0 Command for erasing T5 FLASH Chips !!! (Bootloader must be loaded before using)
-#define T5RSTCMND {0xC2,0x00,0x00,0x00,0x00,0x00,0x00,0x00}     // C2 Command for exiting the Bootloader and restarting the T5 ECU (Bootloader must be loaded before using)
-#define T5SUMCMND {0xC8,0x00,0x00,0x00,0x00,0x00,0x00,0x00}     // C8 Command for reading T5 FLASH Checksum (Bootloader must be loaded before using)
-#define T5TYPCMND {0xC9,0x00,0x00,0x00,0x00,0x00,0x00,0x00}     // C9 Command for reading T5 FLASH Chip types (Bootloader must be loaded before using)
-
-
-#define T5MESSAGETIMEOUT 500    // 500 milliseconds (half a second) - Seems to be plenty of time to wait for messages on the CAN bus
-#define T5CHECKSUMTIMEOUT 60000 // 60 seconds (60,000 milliseconds) - Usually takes less than 2 seconds so allowing 10 is plenty
-//                                                                    - Increased to 60 seconds for now because using it as erase timeout too
-
-extern bool T5Open();
-extern bool T5Close();
-extern char T5WaitResponse();
-extern bool T5WaitResponsePrint();
-extern char *T5GetSymbol(char *a_symbol);
-extern bool T5ReadCmnd(char c);
-extern bool T5WriteCmnd(unsigned int addr, char data);
-extern char *T5ReadRAM(char *data, unsigned int addr);
-extern char *T5ReadFLASH(char *data, unsigned int addr);
-extern bool T5RAMCmnd(unsigned int addr);
-extern char *T5WaitRAM(char *data);
-extern bool T5Ack();
-extern bool T5SendBootAddress(unsigned int addr, int len);
-extern bool T5SendBootFrame (char *frame);
-extern bool T5StartBootLoader (unsigned int addr);
-
-extern bool T5BootCSumCmnd();
-extern bool T5BootResetCmnd();
-extern bool T5BootFLASHType();
-extern bool T5BootEraseCmnd();
-extern bool T5BootDumpFLASHCmnd();
-extern char *T5WaitFLASH(char *data);
-extern bool T5BootC3Command();
\ No newline at end of file
--- a/Trionic5.cpp	Wed May 19 12:39:18 2010 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,728 +0,0 @@
-/*******************************************************************************
-
-Trionic5.cpp - By Sophie Dexter, April 2010
-
-This C++ module provides functions for reading and writing the FLASH chips and
-SRAM in Trionic5 ECUs. (Writing the adaption data back to SRAM not done yet).
-
-Some functions need an additional 'bootloader' program to be sent to the T5 ECU
-before they can be used. These functions are: Identifying the T5 ECU type and
-FLASH chips, dumping the FLASH chips, erasing the FLASH chips, writing to the
-FLASH chips and calculating the FLASH chips' checksum.
-
-My version of the bootloader, BOOTY.S19, includes some features not in other
-bootloaders; identifying the ECU and FLASH chip types, a 'safer' way of dumping
-the FLASH chips and the ability to program AMD 29F010 type FLASH chips (NOTE
-that AMD 29F010 FLASH programming is experimental at this stage to say the least)
-
-********************************************************************************
-
-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 "Trionic5.h"
-
-// RS232 on USB connection
-Serial pc2(USBTX, USBRX); // tx, rx
-
-// A timer for timing how long things take to happen
-Timer timer;
-
-// We use CAN on mbed pins 29(CAN_TXD) and 30(CAN_RXD).
-CAN can_temp(p30, p29);
-
-// Need to create this to be able to read and write files on the mbed 'disk'
-LocalFileSystem local("local");
-
-void Trionic5() {
-    // Start the CAN bus system
-    // Note that at the moment this is only for T5 ECUs at 615 kbits
-    CANOpen();
-
-    int counter = 0;        //counter used for testing things !?!
-
-    Trionic5ShowHelp();
-
-    while (1) {
-        // send received messages to the pc over USB connection
-        // This function displays any CAN messages that are 'missed' by the other functions
-        // Can messages might be 'missed' because they are received after a 'timeout' period
-        // or because they weren't expected, e.g. if the T5 ECU resets for some reason
-        Trionic5ShowCANMessage();
-
-//        Wait for a single command character from the PC
-        if (pc2.readable()) {
-//            char command[30] = "w0068c600000000000000";
-//            command = pc2.gets();
-            char c = (pc2.getc());
-            if ((c=='h') || (c=='H')) Trionic5ShowHelp();            // Print help
-            if (c=='\e') return;                                    // 'ESC' key to go back to mbed CAN tool menu
-//            if ((c=='s') or (c=='S')) {
-            if (c=='s') Trionic5GetSymbolTable();                    // Get the Symbol Table
-            if (c=='S') T5ReadCmnd(T5SYMBOLS);
-//            if ((c=='v') or (c=='V')) {
-            if (c=='v') Trionic5GetVersion();                        // Get the Trionic5 software version string
-            if (c=='V') T5ReadCmnd(T5VERSION);
-//            if ((c=='r') or (c=='R')) {
-            if (c=='r') Trionic5GetAdaptionData();                    // Read Adaption Data from RAM and write it to a file
-            if (c=='R') T5RAMCmnd(counter++);
-            if (c=='\r') T5ReadCmnd(CR);                            // CR - send CR type message
-
-//            if ((c=='a') or (c=='A')) {
-            if (c=='a') {                                            //  Get a single symbol from the Symbol Table
-                char symbol[40];
-                T5GetSymbol(symbol);
-                printf("%s",symbol);
-            }
-            if (c=='A') T5Ack();                                    // Just send an 'ACK' message
-            if ((c=='b') or (c=='B')) Trionic5SendBootLoader();        // Send a Bootloader file to the T5 ECU
-            if ((c=='c') or (c=='C')) Trionic5GetChecksum();        // Get Checksum from ECU (Bootloader must be uploaded first)
-            if ((c=='q') or (c=='Q')) Trionic5BootloaderReset();    // Exit the BootLoader and restart the T5 ECU
-            if ((c=='e') or (c=='E')) Trionic5EraseFLASH();            // Erase the FLASH chips
-            if ((c=='t') or (c=='T')) Trionic5GetChipTypes();        // Read back the FLASH chip types
-//            if ((c=='d') or (c=='D')) Trionic5DumpFLASH();            // DUMP the T5 ECU BIN file stored in the FLASH chips
-//            if (c=='d') Trionic5DumpFLASH();            // DUMP the T5 ECU BIN file stored in the FLASH chips
-//            if (c=='D') Trionic5DumpFLASH2();            // DUMP the T5 ECU BIN file stored in the FLASH chips
-            if ((c=='d') or (c=='D')) Trionic5DumpFLASH2();            // DUMP the T5 ECU BIN file stored in the FLASH chips
-            if ((c=='f') or (c=='F')) Trionic5SendFLASHUpdate();    // Send a FLASH update file to the T5 ECU
-            if (c=='3') Trionic5SendC3Message();            // Send the C3 message - should get last used address 0x7FFFF
-        }
-    }
-}
-
-//
-// Trionic5ShowHelp
-//
-// Displays a list of things that can be done with the T5 ECU.
-//
-// inputs:    none
-// return:    none
-//
-void Trionic5ShowHelp() {
-    printf("Trionic 5 Command Menu\r\n");
-    printf("======================\r\n");
-    printf("b - upload and start MyBooty.S19 bootloader\r\n");
-    printf("c - get T5 ECU FLASH checksum (need toupload BOOTY.S19 before using this command)\r\n");
-    printf("d - dump the T5 FLASH BIN file and write it to ORIGINAL.HEX\r\n");
-    printf("e - erase the FLASH chips in the T5 ECU\r\n");
-    printf("f - FLASH the upate file MODIFIED.S19 to the T5 ECU\r\n");
-    printf("e - erase the FLASH chips in the T5 ECU\r\n");
-    printf("r - read SRAM and write it to ADAPTION.HEX 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");
-    printf("q - exit the bootloader and reset the T5 ECU\r\n");
-    printf("t - read the FLASH chip type in the T5 ECU\r\n");
-    printf("3 - read the last used FLASH address in the T5 ECU\r\n");
-    printf("S - send 's' message (to get symbol table)\r\n");
-    printf("V - send 'S' message (to get software version)\r\n");
-    printf("'Enter' Key - send an CR message\r\n");
-    printf("a - send an ACK\r\n");
-    printf("A - read a single symbol from the symbol table\r\n");
-    printf("\r\n");
-    printf("'ESC' - return to mbed CAN tool Menu\r\n");
-    printf("\r\n");
-    printf("h/H - show this help menu\r\n");
-    return;
-}
-
-//
-// Trionic5ShowCANMessage
-//
-// Displays a CAN message in the RX buffer if there is one.
-//
-// inputs:    none
-// return:    bool TRUE if there was a message, FALSE if no message.
-//
-bool Trionic5ShowCANMessage() {
-    CANMessage can_MsgRx;
-    if (can_temp.read(can_MsgRx)) {
-        printf("w%03x%d", can_MsgRx.id, can_MsgRx.len);
-        for (char i=0; i<can_MsgRx.len; i++) {
-            printf("%02x", can_MsgRx.data[i]);
-        }
-        printf(" %c ", can_MsgRx.data[2]);
-        printf("\r\n");
-        return TRUE;
-    }
-    return FALSE;
-}
-
-//
-// Trionic5GetSymbolTable
-//
-// Gets the T5 ECU symbol table.
-// The Symbol Table is sent to the PC and saved to a file, symbols.txt, on the mbed 'local' file system 'disk'.
-//
-// inputs:    none
-// return:    bool TRUE if there all went OK, FALSE if there was an error
-//
-bool Trionic5GetSymbolTable() {
-    FILE *fp = fopen("/local/symbols.txt", "w");  // Open "symbols.txt" on the local file system for writing
-    if (!fp) return FALSE;
-    char symbol[40];
-    char response = '\0';
-    T5ReadCmnd(T5SYMBOLS);
-    response = T5WaitResponse();
-    if (response != '>')
-        return FALSE;
-//                printf("%c",response);
-    T5ReadCmnd(CR);
-    response = T5WaitResponse();
-    if (response != '>')
-        return FALSE;
-//                printf("%c",response);
-    timer.reset();
-    timer.start();
-    do {
-        T5GetSymbol(symbol);
-        printf("%s",symbol);
-        fprintf(fp,"%s",symbol);
-    } while (!StrCmp(symbol,"END\r\n"));
-    timer.stop();
-    printf("Getting the Symbol Table took %f seconds.\r\n",timer.read());
-    fclose(fp);
-    return TRUE;
-}
-
-//
-// Trionic5GetVersion
-//
-// Gets the T5 software version string.
-// The software version is is sent to the PC and saved to a file, version.txt, on the mbed 'local' file system 'disk'.
-//
-// inputs:    none
-// return:    bool TRUE if there all went OK, FALSE if there was an error
-//
-bool Trionic5GetVersion() {
-    FILE *fp = fopen("/local/version.txt", "w");  // Open "version.txt" on the local file system for writing
-    if (!fp) return FALSE;
-    char symbol[40];
-    char response = '\0';
-    T5ReadCmnd(T5VERSION);
-    response = T5WaitResponse();
-    if (response != '>')
-        return FALSE;
-//                printf("%c",response);
-    T5ReadCmnd(CR);
-    response = T5WaitResponse();
-    if (response != '>')
-        return FALSE;
-//                printf("%c",response);
-    T5GetSymbol(symbol);
-    printf("%s",symbol);
-    if (fp)
-        fprintf(fp,"%s",symbol);
-    else
-        printf("ERROR Could not open version.txt for saving\r\n");
-    fclose(fp);
-    return TRUE;
-}
-
-//
-// Trionic5GetAdaptionData
-//
-// Gets the adaption data from the T5's SRAM. 
-// The adaption data is stored in a hex file, adaption.hex, on the mbed 'local' file system 'disk'.
-//
-// Reading the Adaption data from SRAM takes about 16 seconds.
-//
-// inputs:    none
-// return:    bool TRUE if all went OK, FALSE if there was an error.
-//
-bool Trionic5GetAdaptionData() {
-    printf("getting adaption data\r\n");
-    FILE *fp = fopen("/local/adaption.hex", "w");    // Open "adaption.hex" on the local file system for writing
-    if (!fp) return FALSE;
-    printf("opened adaption data file\r\n");
-    unsigned int address = 5;                       // Mysterious reason for starting at 5 !!!
-    char RAMdata[6];
-    timer.reset();
-    timer.start();
-    for (int i=0; i<5462; i++) {                    // Mysterious number 5462 is 0x8000 / 6 - rounded up !!!
-        T5ReadRAM(RAMdata, address);
-        address += 6;
-        for (int j=0; j<6; j++) {
-            if (((i*6) + j) < T5RAMSIZE)
-                fputc(RAMdata[j],fp);
-        }
-    }
-    timer.stop();
-    printf("Getting the RAM Data took %f seconds.\r\n",timer.read());
-    fclose(fp);
-    return TRUE;
-}
-
-//
-// Trionic5SendBootLoader
-//
-// 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 Trionic5SendBootLoader() {
-    FILE *fp = fopen("/local/MyBooty.S19", "r");    // Open "booty.s19" on the local file system for reading
-    if (!fp) return FALSE;
-    int c = 0; // for some reason fgetc returns an int instead of a char
-    int count = 0; // count of bytes in the S-record can be 0xFF = 255 in decimal
-    int asize = 0; // 2,3 or 4 bytes in address
-    unsigned int address = 0; // address to put S-record
-    int checksum = 0; // checksum check at the end of each S-record line
-    char msg[8]; // Construct the bootloader frame for uploading
-    bool sent = FALSE;
-
-    timer.reset();
-    timer.start();
-    while (!sent) {
-
-        do c = fgetc (fp); // get characters until we get an 'S' (throws away \n,\r characters and other junk)
-        while (c != 'S' && c != EOF);
-//                if (c == EOF) return '\a';
-        c = fgetc(fp);        // get the S-record type 1/2/3 5 7/8/9 (Return if EOF reached)
-//                if ((c = fgetc(fp)) == EOF) return '\a';        // get the S-record type 1/2/3 5 7/8/9 (Return if EOF reached)
-        switch (c) {
-            case '0':
-                break;                  // Skip over S0 header record
-
-            case '1':
-            case '2':
-            case '3':
-                asize = 1 + 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 at least the address and the checksum so return with an error if less than this!
-                if ((c = SRecGetByte(fp)) < (asize + 1)) break;
-//                        if ((c = SRecGetByte(fp)) < 3) return '\a';
-                count = c;
-                checksum = c;
-// get the address
-                for (int i=0; i<asize; i++) {
-                    c = SRecGetByte(fp);
-                    checksum += c;
-                    address <<= 8;
-                    address |= c;
-                    count--;
-                }
-// send a bootloader address message
-                T5SendBootAddress(address, (count-1));
-//                T5WaitResponsePrint();
-                T5WaitResponse();
-// 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
-// are repeated from the previous frame. This is OK because the T5 ECU knows how many bytes to expect (because the count of bytes
-// in the S-Record is sent with the upload address) and ignores any extra bytes in the last frame.
-                for (int i=0; i<count-1; i++) {
-                    c = SRecGetByte(fp);
-                    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)) {
-                        T5SendBootFrame(msg);
-//                        T5WaitResponsePrint();
-                        T5WaitResponse();
-                    }
-                }
-// get the checksum
-                if (((checksum += SRecGetByte(fp)) | 0xFF) != 0xFF) break;
-//                if ((checksum += SRecGetByte(fp)) != 0xff) return '\a';
-                break;
-
-            case '5':
-                break;                  // Skip over S5 record types
-
-            case '7':
-            case '8':
-            case '9':
-                asize = 11 - (c - '0');  // 2, 3 or 4 bytes for address
-// 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!
-                printf("Starting the bootloader, ");
-                if ((c = SRecGetByte(fp)) != (asize + 1)) break;
-//                if ((c = SRecGetByte(fp)) < 3) return '\a';
-                printf("so far so good");
-                checksum = c;
-// get the address
-                for (int i=0; i<asize; i++) {
-                    c = SRecGetByte(fp);
-                    checksum += c;
-                    address <<= 8;
-                    address |= c;
-                }
-                printf("calculated the address, ");
-// get the checksum
-//                if (((checksum += SRecGetByte(fp)) | 0xFF) != 0xFF) break;
-//                if ((checksum += SRecGetByte(fp)) != 0xff) return '\a';
-                printf("checksum is OK, ");
-                T5StartBootLoader(address);
-//                T5WaitResponsePrint();
-                sent = TRUE;
-                printf("and we're done :-) \r\n");
-                break;
-
-// Some kind of invalid S-record type so break
-            default:
-                printf("oops - didn't recognise that S-Record \r\n");
-                return FALSE;
-//                            return SREC_FORMAT;
-        }
-    }
-    timer.stop();
-    printf("Uploading and starting the bootloader took %f seconds. \r\n",timer.read());
-    fclose(fp);
-    return TRUE;
-}
-
-//
-// Trionic5GetChecksum
-//
-// Calculates the checksum of the FLASH in the T5 ECU.
-// The 'bootloader', booty.s19, must be loaded before this function can be used.
-// The 'bootloader' actually calculates the checksum and compares it with the
-// value stored in the 'header' region at the end of the FLASH.
-//
-// The bootloader sends a single CAN message with the result e.g.
-// w00C8C800CAFEBABE0808
-//  00C - T5 response messages have an CAN id of 00C
-//     8 - All T5 messages have a message length of 8 bytes
-//      C8 - This is the checksum message type
-//        00 - 00 means OK, the checksum calculation matches the stored value which in this case is:
-//          CAFEBABE - lol :-)
-//
-// w00C8C801FFFFFFFF0808
-//        01 - 01 means calculated value doesn't matched the stored value
-//          FFFFFFFF - in this case the stored value is FFFFFFFF - the chips might be erased
-//
-// Calculating the checksum takes a little under 2 seconds.
-//
-// inputs:    none
-// return:    bool TRUE if all went OK, 
-//
-bool Trionic5GetChecksum() {
-    timer.reset();
-    timer.start();
-    T5BootCSumCmnd();
-    T5WaitResponsePrint();
-    timer.stop();
-    printf("T5 ECU took took %f seconds to calculate it's checksum.\r\n",timer.read());
-    return TRUE;
-}
-
-//
-// Trionic5BootloaderReset
-//
-// Exits the Bootloader and restart the T5 ECU
-//
-// inputs:    none
-// outputs:    bool TRUE if all went OK. 
-//
-bool Trionic5BootloaderReset() {
-    T5BootResetCmnd();
-    T5WaitResponsePrint();
-    return TRUE;
-}
-
-//
-// Trionic5GetChipTypes
-//
-// Gets the FLASH chip type fitted.
-//
-// NOTE the bootloader must be loaded in order to use this function.
-//
-// CAN messages from the T5 ECU with FLASH data look like this:
-//
-// C9,00,aa,aa,aa,aa,mm,dd,
-//
-// C9 lets us know its a FLASH id message
-//
-// aa,aa,aa,aa is the FLASH start address which we can use to work out if this is a T5.2 or T5.5 ECU
-// 0x00020000 - T5.2
-// 0x00040000 - T5.5
-//
-// mm = Manufacturer id. These can be:
-// 0x89 - Intel
-// 0x31 - CSI/CAT
-// 0x01 - AMD
-// 0x1F - Atmel
-//
-// dd = Device id. These can be:
-// 0xB8 - Intel _or_ CSI 28F512 (Fiited by Saab in T5.2)
-// 0xB4 - Intel _or_ CSI 28F010 (Fitted by Saab in T5.5)
-// 0x25 - AMD 28F512 (Fiited by Saab in T5.2)
-// 0xA7 - AMD 28F010 (Fitted by Saab in T5.5)
-// 0x20 - AMD 29F010 (Some people have put these in their T5.5)
-// 0x5D - Atmel 29C512 (Some people mave have put these in their T5.2)
-// 0xD5 - Atmel 29C010 (Some people have put these in their T5.5)
-//
-// mm = 0xFF, dd == 0xF7 probably means that the programming voltage isn't right.
-//
-// Finding out which ECU type and FLASH chips are fitted takes under a second.
-//
-// inputs:    none
-// return:    bool TRUE if all went OK.
-//
-bool Trionic5GetChipTypes() {
-    timer.reset();
-    timer.start();
-    T5BootFLASHType();
-    T5WaitResponsePrint();
-    timer.stop();
-    printf("Getting the FLASH chip id took %f seconds.\r\n",timer.read());
-    return TRUE;
-}
-
-//
-// Trionic5EraseFLASH
-//
-// Erases the FLASH Chips.
-//
-// NOTE the bootloader must be loaded in order to use this function.
-//
-// CAN messages from the T5 ECU with FLASH erase command look like this:
-//
-// C0,cc,08,08,08,08,08,08
-//
-// C0 tells us this is a response to the FLASH erase command.
-//
-// cc is a code that tells us what happened:
-//      00 - FLASH was erased OK
-//      01 - Could not erase FLASH chips to 0xFF
-//      02 - Could not write 0x00 to 28F FLASH chips
-//      03 - Unrecognised FLASH chip type (or maybe programming voltage isn't right)
-//      04 - Intel chips found, but unrecognised type
-//      05 - AMD chips found, but unrecognised type
-//      06 - CSI/Catalyst chips found, but unrecognised type
-//      07 - Atmel chips found - Atmel chips don't need to be erased
-//
-// Erasing 28F type FLASH chips takes around 22 seconds. 29F chips should be erased much more quickly.
-//
-// inputs:    none
-// return:    bool TRUE if all went OK.
-//
-bool Trionic5EraseFLASH() {
-    timer.reset();
-    timer.start();
-    T5BootEraseCmnd();
-    T5WaitResponsePrint();
-    timer.stop();
-    printf("Erasing the FLASH took %f seconds.\r\n",timer.read());
-    return TRUE;
-}
-
-//
-// Trionic5DumpFLASH
-//
-// Dumps the FLASH chip BIN file, original.hex to the mbed 'disk'
-//
-// NOTE the bootloader must be loaded in order to use this function.
-//
-// CAN messages from the T5 ECU with FLASH data look like this:
-//
-// A6,mm,dd,dd,dd,dd,08,08
-//
-// A6 lets us know its a FLASH data message
-// mm tells us if there is any more data
-//      mm == 04 means at least 4 more bytes to come
-//      mm == 00 means that these are the last FLASH data bytes
-// dd,dd,dd,dd are 4 FLASH data bytes 
-// The last 2 bytes are 08,08 they aren't and don't meean anything
-// (It would be more efficient to dump 6 bytes at a time because less
-// CAN messages would be needed but it was easier to write the
-// bootloader to send just 4 bytes so that's what I did)
-//
-// Dumping FLASH chips in a T5.5 ECU takes around 88 seconds. Dumping T5.2 ECUs should take about half of this time
-//
-// inputs:    none
-// return:    bool TRUE if all went OK.
-//
-bool Trionic5DumpFLASH() {
-    printf("getting FLASH BIN file\r\n");
-    FILE *fp = fopen("/local/original.hex", "w");    // Open "original.hex" on the local file system for writing
-    if (!fp) return FALSE;
-    printf("opened FLASH BIN file\r\n");
-    char FLASHdata[8];
-    timer.reset();
-    timer.start();
-//    int count = 0;
-    do {
-        T5BootDumpFLASHCmnd();
-//        T5WaitResponsePrint();
-        T5WaitFLASH(FLASHdata);
-        for (int j=0; j<4; j++) {
-            fputc(FLASHdata[j+2],fp);
-//        count++;
-        }
-    } while (FLASHdata[1] != 0);
-    timer.stop();
-//    printf("count = 0x%x\r\n", count);
-    printf("Getting the FLASH BIN took %f seconds.\r\n",timer.read());
-    fclose(fp);
-    return TRUE;
-}
-
-
-//
-// Trionic5DumpFLASH2
-//
-// Gets the adaption data from the T5's SRAM. 
-// The adaption data is stored in a hex file, adaption.hex, on the mbed 'local' file system 'disk'.
-//
-// Reading the Adaption data from SRAM takes about 16 seconds.
-//
-// inputs:    none
-// return:    bool TRUE if all went OK, FALSE if there was an error.
-//
-bool Trionic5DumpFLASH2() {
-    printf("getting FLASH BIN file\r\n");
-    FILE *fp = fopen("/local/original.hex", "w");    // Open "adaption.hex" on the local file system for writing
-    if (!fp) return FALSE;
-    printf("opened FLASH BIN file\r\n");
-    unsigned int address = 0x40005;                  // Mysterious reason for starting at 5 !!!
-    char FLASHdata[6];
-    timer.reset();
-    timer.start();
-    for (int i=0; i<43690; i++) {                    // Mysterious number 43690 is 0x40000 / 6
-        T5ReadFLASH(FLASHdata, address);
-        address += 6;
-        for (int j=0; j<6; j++) {
-            fputc(FLASHdata[j],fp);
-        }
-    }
-    address = 0x7FFFF;
-    T5ReadFLASH(FLASHdata, address);
-    for (int j=0; j<4; j++) {
-        fputc(FLASHdata[j+2],fp);
-    }
-    timer.stop();
-    printf("Getting the FLASH BIN took %f seconds.\r\n",timer.read());
-    fclose(fp);
-    return TRUE;
-}
-
-//
-// Trionic5SendFLASHUpdate
-//
-// Sends a FLASH update file, modified.s19 to the T5 ECU.
-// The FLASH update file is stored on the local file system and must be in S19 format.
-//
-// FLASHing a T5.5 ECU takes around 90 seconds. FLASHing T5.2 ECUs should take about half of this time
-//
-// inputs:    none
-// return:    bool TRUE if all went OK,
-//                 FALSE if the FLASH update failed for some reason.
-//
-bool Trionic5SendFLASHUpdate() {
-    FILE *fp = fopen("/local/modified.s19", "r");    // Open "modified.s19" on the local file system for reading
-    if (!fp) return FALSE;
-    printf("Opened MODIFIED.S19 ");
-    int c = 0; // for some reason fgetc returns an int instead of a char
-    int count = 0; // count of bytes in the S-record can be 0xFF = 255 in decimal
-    int asize = 0; // 2,3 or 4 bytes in address
-    unsigned int address = 0; // address to put S-record
-    int checksum = 0; // checksum check at the end
-    char msg[8]; // Construct the bootloader frame for uploading
-    bool sent = FALSE;
-
-    timer.reset();
-    timer.start();
-    while (!sent) {
-
-        do c = fgetc (fp); // get characters until we get an 'S' (throws away \n,\r characters and other junk)
-        while (c != 'S' && c != EOF);
-//                if (c == EOF) return '\a';
-        c = fgetc(fp);        // get the S-record type 1/2/3 5 7/8/9 (Return if EOF reached)
-//                if ((c = fgetc(fp)) == EOF) return '\a';        // get the S-record type 1/2/3 5 7/8/9 (Return if EOF reached)
-        switch (c) {
-            case '0':
-                break;                  // Skip over S0 header record
-
-            case '1':
-            case '2':
-            case '3':
-                asize = 1 + 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 at least the address and the checksum so return with an error if less than this!
-                if ((c = SRecGetByte(fp)) < (asize + 1)) break;
-//                        if ((c = SRecGetByte(fp)) < 3) return '\a';
-                count = c;
-                checksum = c;
-// get the address
-                for (int i=0; i<asize; i++) {
-                    c = SRecGetByte(fp);
-                    checksum += c;
-                    address <<= 8;
-                    address |= c;
-                    count--;
-                }
-                address += 0x40000;         // Only for T5.5 at the moment !!!
-// send a bootloader address message
-                T5SendBootAddress(address, (count-1));
-//                T5WaitResponsePrint();
-                T5WaitResponse();
-// 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
-// are repeated from the previous frame. This is OK because the T5 ECU knows how many bytes to expect (because the count of bytes
-// in the S-Record is sent with the upload address) and ignores any extra bytes in the last frame.
-                for (int i=0; i<count-1; i++) {
-                    c = SRecGetByte(fp);
-                    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)) {
-                        T5SendBootFrame(msg);
-//                        T5WaitResponsePrint();
-                        T5WaitResponse();
-                    }
-                }
-// get the checksum
-                if (((checksum += SRecGetByte(fp)) | 0xFF) != 0xFF) break;
-//                if ((checksum += SRecGetByte(fp)) != 0xff) return '\a';
-                break;
-
-            case '5':
-                break;                  // Skip over S5 record types
-
-            case '7':
-            case '8':
-            case '9':
-                sent = TRUE;
-                printf("and we're done :-) \r\n");
-                break;
-
-// Some kind of invalid S-record type so break
-            default:
-                printf("oops - didn't recognise that S-Record \r\n");
-                return FALSE;
-//                            return SREC_FORMAT;
-        }
-    }
-    timer.stop();
-    printf("Uploading the FLASH update file took %f seconds. \r\n",timer.read());
-    fclose(fp);
-    return TRUE;
-}
-
-//
-// Trionic5SendC3Message
-//
-// Sends a C3 Message to the T5 ECU. The reply should contain the last used FLASH address
-// which is always 0x0007FFFF
-//
-// inputs:    none
-// return:    bool TRUE if all went OK,
-//
-bool Trionic5SendC3Message() {
-    T5BootC3Command();
-    T5WaitResponsePrint();
-    printf("The Last used FLASH address message is:\r\n");
-    return TRUE;
-}
--- a/Trionic5.h	Wed May 19 12:39:18 2010 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,36 +0,0 @@
-
-// Trionic5.h - information and definitions needed for doing things with the T5 ECU
-
-#include "mbed.h"
-#include "CAN.h"
-#include "strings.h"
-#include "T5Utils.h"
-#include "SRecUtils.h"
-
-#define CR 0x0D
-#define NL 0x0A
-
-#define T5SYMBOLS 'S'
-#define T5VERSION 's'
-#define T5WRITE 'W'
-
-#define T5RAMSIZE 0x8000   // T5 ECU has 32 kbytes of RAM 0x8000 = 32,768 (same as MC68332 clock speed!?!) 
-#define T55FLASHSIZE 0x40000   // T5 ECU has 32 kbytes of RAM 0x8000 = 32,768 (same as MC68332 clock speed!?!) 
-#define T52FLASHSIZE 0x20000   // T5 ECU has 32 kbytes of RAM 0x8000 = 32,768 (same as MC68332 clock speed!?!) 
-
-extern void Trionic5();
-
-void Trionic5ShowHelp();
-bool Trionic5ShowCANMessage();
-bool Trionic5GetSymbolTable();
-bool Trionic5GetVersion();
-bool Trionic5GetAdaptionData();
-bool Trionic5SendBootLoader();
-bool Trionic5GetChecksum();
-bool Trionic5BootloaderReset();
-bool Trionic5GetChipTypes();
-bool Trionic5EraseFLASH();
-bool Trionic5DumpFLASH();
-bool Trionic5DumpFLASH2();
-bool Trionic5SendFLASHUpdate();
-bool Trionic5SendC3Message();
--- /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;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bdm.h	Tue Sep 14 21:02:04 2010 +0000
@@ -0,0 +1,32 @@
+/*******************************************************************************
+
+bdm.h
+(c) 2010 by Sophie Dexter
+
+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.
+
+*******************************************************************************/
+
+#ifndef __BDM_H__
+#define __BDM_H__
+
+#include "mbed.h"
+//
+#include "common.h"
+#include "bdmcpu32.h"
+#include "bdmtrionic.h"
+
+extern void bdm();
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bdmcpu32.cpp	Tue Sep 14 21:02:04 2010 +0000
@@ -0,0 +1,1300 @@
+/*******************************************************************************
+
+bdmcpu32.cpp
+(c) 2010 by Sophie Dexter
+
+Generic BDM functions for Just4Trionic by Just4pLeisure
+
+A derivative work based on:
+//-----------------------------------------------------------------------------
+//    CAN/BDM adapter firmware
+//    (C) Janis Silins, 2010
+//    $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 "bdmcpu32.h"
+
+// constants
+#define MCU_SETTLE_TIME     10        ///< delay to let MCU switch modes, ms
+#define CMD_BIT_COUNT       17        ///< command size, bits
+
+// BDM commands
+#define BDM_NOP             0x0000    ///< no-op
+#define BDM_GO              0x0c00    ///< resume execution
+#define BDM_WRITE           0x1800    ///< write memory
+#define BDM_READ            0x1900    ///< read memory 
+#define BDM_WSREG           0x2480    ///< write system register
+#define BDM_RSREG           0x2580    ///< read system register
+#define BDM_RDREG           0x2180    ///< read A/D register
+#define BDM_WRREG           0x2080    ///< write A/D register
+#define BDM_DUMP            0x1d00    ///< dump memory
+#define BDM_FILL            0x1c00    ///< fill memory
+#define BDM_CALL            0x0800    ///< function call
+#define BDM_RST             0x0400    ///< reset
+
+// system registers
+#define SREG_RPC            0x0
+#define SREG_PCC            0x1
+#define SREG_SR             0xb
+#define SREG_USP            0xc
+#define SREG_SSP            0xd
+#define SREG_SFC            0xe
+#define SREG_DFC            0xf
+#define SREG_ATEMP          0x8
+#define SREG_FAR            0x9
+#define SREG_VBR            0xa
+
+// BDM responses
+#define BDM_CMDCMPLTE       0x0000ffff    ///< command complete
+#define BDM_NOTREADY        0x00010000    ///< response not ready
+#define BDM_BERR            0x00010001    ///< error
+#define BDM_ILLEGAL         0x0001ffff    ///< illegal command
+
+// BDM data sizes
+#define BDM_BYTESIZE        0x00        ///< byte
+#define BDM_WORDSIZE        0x40        ///< word (2 bytes)
+#define BDM_LONGSIZE        0x80        ///< long word (4 bytes)
+
+// static variables
+static uint32_t bdm_response;        ///< result of BDM read/write operation
+
+// private functions
+bool bdm_read(uint32_t* result, uint16_t cmd, const uint32_t* addr);
+//bool bdm_read_overlap(uint32_t* result, uint16_t cmd, const uint32_t* addr, uint16_t next_cmd);
+//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_clear();
+
+//-----------------------------------------------------------------------------
+/**
+    Stops target MCU and puts into background debug mode (BDM).
+
+    @return                        status flag
+*/
+uint8_t stop_chip() {
+    // not connected
+    if (!IS_CONNECTED) {
+        return TERM_ERR;
+    }
+
+    // pull BKPT low to enter background mode (the pin must remain in output mode,
+    // otherwise the target will pull it high and we'll lose the first DSO bit)
+    PIN_BKPT.write(0);
+    // set BPKT pin as output
+    PIN_BKPT.output();
+
+    // wait for target MCU to settle
+    wait_ms(MCU_SETTLE_TIME);
+
+    // check if succeeded
+    if (!IN_BDM) {
+        // set BKPT back as input and fail
+        PIN_BKPT.input();
+        return TERM_ERR;
+    }
+
+    return TERM_OK;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Forces hardware reset on target MCU and lets it run.
+
+    @return                        status flag
+*/
+uint8_t reset_chip() {
+    // not connected
+    if (!IS_CONNECTED) {
+        return TERM_ERR;
+    }
+
+    // BKPT pin as input
+    PIN_BKPT.input();
+    // push RESET low
+    PIN_RESET.write(0);
+    // RESET pins as output
+    PIN_RESET.output();
+    // wait for MCU to settle
+    wait_ms(MCU_SETTLE_TIME);
+    // rising edge on RESET line
+    PIN_RESET.write(1);
+    // wait for MCU to settle
+    wait_ms(MCU_SETTLE_TIME);
+
+    // set RESET as an input again
+    PIN_RESET.input();
+
+    // check if succeeded
+    return IS_RUNNING ? TERM_OK : TERM_ERR;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Starts target MCU from the specified address. If address is 0, execution
+    begins at the current address in program counter.
+
+    @param            addr        start address
+
+    @return                        status flag
+*/
+uint8_t run_chip(const uint32_t* addr) {
+    // check state
+    if (!IN_BDM) {
+        return TERM_ERR;
+    }
+
+    // set program counter
+    if ((*addr > 0) && sysreg_write(SREG_RPC, addr) != TERM_OK) {
+        return TERM_ERR;
+    }
+    // resume MCU
+    bdm_clk(BDM_GO, CMD_BIT_COUNT);
+
+    // set BKPT back as input
+    PIN_BKPT.input();
+
+    return TERM_OK;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Resets target MCU and stops execution on first instruction fetch.
+
+    @return                        status flag
+*/
+uint8_t restart_chip() {
+    // not connected
+    if (!IS_CONNECTED) {
+        return TERM_ERR;
+    }
+
+    // pull BKPT low to enter background mode (the pin must remain an output,
+    // otherwise the target will pull it high and we'll lose the first DSO bit)
+    PIN_BKPT.write(0);
+    // push RESET low
+    PIN_RESET.write(0);
+    // RESET, BKPT pins as outputs
+    PIN_BKPT.output();
+    PIN_RESET.output();
+    // wait for target MCU to settle
+    wait_ms(MCU_SETTLE_TIME);
+    // rising edge on RESET line
+    PIN_RESET.write(1);
+    // wait for target MCU to settle
+    wait_ms(MCU_SETTLE_TIME);
+    // set RESET back as an input
+    PIN_RESET.input();
+
+    // check if succeeded
+    if (!IN_BDM) {
+        // set BKPT back as input and fail
+        PIN_BKPT.input();
+        return TERM_ERR;
+    }
+
+    return TERM_OK;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Sends GO command word to target MCU, then triggers breakpoint on first
+    instruction fetch.
+
+    @return                        status flag
+*/
+uint8_t step_chip() {
+    // not connected
+    if (!IS_CONNECTED) {
+        return TERM_ERR;
+    }
+
+    // resume MCU
+    bdm_clk(BDM_GO, CMD_BIT_COUNT);
+
+    // pull BKPT low to enter background mode (the pin must remain an output,
+    // otherwise the target pulls it high and we lose the first DSO bit)
+    PIN_BKPT.write(0);
+    // set BPKT pin as output
+    PIN_BKPT.output();
+
+    // wait for target MCU to settle
+//    delay_ms(MCU_SETTLE_TIME);
+    wait_ms(MCU_SETTLE_TIME);
+
+    // check if succeeded
+    if (!IN_BDM) {
+        // set BKPT back as input and fail
+        PIN_BKPT.input();
+        return TERM_ERR;
+    }
+
+    return TERM_OK;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Pulls BKPT pin low.
+*/
+uint8_t bkpt_low() {
+    PIN_BKPT.write(0);
+    PIN_BKPT.output();
+
+    return TERM_OK;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Pulls BKPT pin high.
+*/
+uint8_t bkpt_high() {
+    PIN_BKPT.write(1);
+    PIN_BKPT.output();
+
+    return TERM_OK;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Pulls RESET pin low.
+*/
+uint8_t reset_low() {
+    PIN_RESET.write(0);
+    PIN_RESET.output();
+
+    return TERM_OK;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Pulls RESET pin high.
+*/
+uint8_t reset_high() {
+    PIN_RESET.write(1);
+    PIN_RESET.output();
+
+    return TERM_OK;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Returns byte from the specified memory location; MCU must be in
+    background mode.
+
+    @param        result            value (out)
+    @param        addr            source address
+
+    @return                        status flag
+*/
+uint8_t memread_byte(uint8_t* result, const uint32_t* addr) {
+    // check state
+    if (!IN_BDM) {
+        return TERM_ERR;
+    }
+
+    // read byte
+    if (!bdm_read((uint32_t*)result, BDM_READ, addr)) {
+        // clear the interface and fail
+        bdm_clear();
+        return TERM_ERR;
+    }
+
+    return TERM_OK;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Returns word (2 bytes) from the specified memory location. Address must be
+    word-aligned and MCU must be in background mode.
+
+    @param        result            value (out)
+    @param        addr            source address
+
+    @return                        status flag
+*/
+uint8_t memread_word(uint16_t* result, const uint32_t* addr) {
+    // check state
+    if (!IN_BDM) {
+        return TERM_ERR;
+    }
+
+    // read word
+    if (!bdm_read((uint32_t*)result, BDM_READ + BDM_WORDSIZE, addr)) {
+        // clear the interface and fail
+        bdm_clear();
+        return TERM_ERR;
+    }
+
+    return TERM_OK;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Returns long word (4 bytes) from the specified memory location. Address
+    must be word-aligned and target MCU must be in background mode.
+
+    @param            result            value
+    @param            addr            source address
+
+    @return                            status flag
+*/
+uint8_t memread_long(uint32_t* result, const uint32_t* addr) {
+    // check state
+    if (!IN_BDM) {
+        return TERM_ERR;
+    }
+
+    //  read long word
+    if (!bdm_read(result, BDM_READ + BDM_LONGSIZE, addr)) {
+        // clear the interface and fail
+        bdm_clear();
+        return TERM_ERR;
+    }
+
+    return TERM_OK;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Dumps byte from the specified memory location; MCU must be in background
+    mode. Any memread_*() function must be called beforehand to set the
+    initial address.
+
+    @param        value            result (out)
+
+    @return                        status flag
+*/
+uint8_t memdump_byte(uint8_t* result) {
+    // check state
+    if (!IN_BDM) {
+        return TERM_ERR;
+    }
+
+    // dump byte
+    if (!bdm_read((uint32_t*)result, BDM_DUMP, NULL)) {
+        // clear the interface and fail
+        bdm_clear();
+        return TERM_ERR;
+    }
+
+    return TERM_OK;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    dumps word from the specified memory location; MCU must be in background
+    mode. Any memread_*() function must be called beforehand to set the
+    initial address.
+
+    @param        value            result (out)
+
+    @return                        status flag
+*/
+uint8_t memdump_word(uint16_t* result) {
+    // check state
+    if (!IN_BDM) {
+        return TERM_ERR;
+    }
+
+    // dump word
+    if (!bdm_read((uint32_t*)result, BDM_DUMP + BDM_WORDSIZE, NULL)) {
+        // clear the interface and fail
+        bdm_clear();
+        return TERM_ERR;
+    }
+
+    return TERM_OK;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Dumps long word  from the specified memory location; MCU must be in
+    background mode. Any memread_*() function must be called beforehand to set
+    the initial address.
+
+    @param        value            result (out)
+
+    @return                        status flag
+*/
+uint8_t memdump_long(uint32_t* result) {
+    // check state
+    if (!IN_BDM) {
+        return TERM_ERR;
+    }
+
+    // dump long word
+    if (!bdm_read(result, BDM_DUMP + BDM_LONGSIZE, NULL)) {
+        // clear the interface and fail
+        bdm_clear();
+        return TERM_ERR;
+    }
+
+    return TERM_OK;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Writes byte to the specified memory location; MCU must be in background
+    mode.
+
+    @param        addr            destination address
+    @param        value            value
+
+    @return                        status flag
+*/
+uint8_t memwrite_byte(const uint32_t* addr, uint8_t value) {
+    // check state
+    if (!IN_BDM) {
+        return TERM_ERR;
+    }
+
+    // write byte
+    if (!bdm_write(addr, BDM_WRITE, (uint32_t*)&value)) {
+        // clear the interface and fail
+        bdm_clear();
+        return TERM_ERR;
+    }
+
+    return TERM_OK;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Writes word to the specified memory location. Address must be word-aligned
+    and MCU must be in background mode.
+
+    @param        addr            memory address
+    @param        value            value
+
+    @return                        status flag
+*/
+uint8_t memwrite_word(const uint32_t* addr, uint16_t value) {
+    // check state
+    if (!IN_BDM) {
+        return TERM_ERR;
+    }
+
+    // write word
+    if (!bdm_write(addr, BDM_WRITE + BDM_WORDSIZE, (uint32_t*)&value)) {
+        // clear the interface and fail
+        bdm_clear();
+        return TERM_ERR;
+    }
+
+    return TERM_OK;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Writes long word to the specified memory location. Address must be
+    word-aligned and target MCU must be in background mode.
+
+    @param        addr            memory address
+    @param        value            value
+
+    @return                        status flag
+*/
+uint8_t memwrite_long(const uint32_t* addr, const uint32_t* value) {
+    // check state
+    if (!IN_BDM) {
+        return TERM_ERR;
+    }
+
+    // write long word
+    if (!bdm_write(addr, BDM_WRITE + BDM_LONGSIZE, value)) {
+        // clear the interface and fail
+        bdm_clear();
+        return TERM_ERR;
+    }
+
+    return TERM_OK;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Writes byte to the current memory location; MCU must be in background
+    mode. Any memwrite_*() function must be called beforehand to set the
+    current address.
+
+    @param        value            value
+
+    @return                        status flag
+*/
+uint8_t memfill_byte(uint8_t value) {
+    // check state
+    if (!IN_BDM) {
+        return TERM_ERR;
+    }
+
+    // fill byte
+    if (!bdm_write(NULL, BDM_FILL, (uint32_t*)&value)) {
+        // clear the interface and fail
+        bdm_clear();
+        return TERM_ERR;
+    }
+
+    return TERM_OK;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Writes word to the specified memory location; MCU must be in background
+    mode. Any memwrite_*() function must be called beforehand to set the
+    initial address.
+
+    @param        value            value
+
+    @return                        status flag
+*/
+uint8_t memfill_word(uint16_t value) {
+    // check state
+    if (!IN_BDM) {
+        return TERM_ERR;
+    }
+
+    // fill word
+    if (!IN_BDM || !bdm_write(NULL, BDM_FILL + BDM_WORDSIZE, (uint32_t*)&value)) {
+        // clear the interface and fail
+        bdm_clear();
+        return TERM_ERR;
+    }
+
+    return TERM_OK;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Writes long word to the specified memory location; MCU must be in background
+    mode. Any memwrite_*() function must be called beforehand to set the
+    initial address.
+
+    @param        value            value
+
+    @return                        status flag
+*/
+uint8_t memfill_long(const uint32_t* value) {
+    // check state
+    if (!IN_BDM) {
+        return TERM_ERR;
+    }
+
+    // fill long word
+    if (!bdm_write(NULL, BDM_FILL + BDM_LONGSIZE, value)) {
+        // clear the interface and fail
+        bdm_clear();
+        return TERM_ERR;
+    }
+
+    return TERM_OK;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Issues a read byte command to MCU.
+
+    @param        addr        address (optional)
+
+    @return                   status flag
+*/
+uint8_t memread_byte_cmd(const uint32_t* addr) {
+
+    if (!IN_BDM) return TERM_ERR;
+
+    // write command code
+    if (!bdm_command(BDM_READ + BDM_BYTESIZE)) return TERM_ERR;
+    // write the optional address
+    if (addr) {
+        if(!bdm_address(addr)) return TERM_ERR;
+    }
+
+    return TERM_OK;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Issues a read word command to MCU.
+
+    @param        addr        address (optional)
+
+    @return                   status flag
+*/
+uint8_t memread_word_cmd(const uint32_t* addr) {
+
+    if (!IN_BDM) return TERM_ERR;
+
+    // write command code
+    bdm_clk(BDM_READ + BDM_WORDSIZE, CMD_BIT_COUNT);
+    if (bdm_response > BDM_CMDCMPLTE) return TERM_ERR;
+    // write the optional address
+    if (addr) {
+        if(!bdm_address(addr)) return TERM_ERR;
+    }
+
+    return TERM_OK;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Issues a read long command to MCU.
+
+    @param        addr        address (optional)
+
+    @return                   status flag
+*/
+uint8_t memread_long_cmd(const uint32_t* addr) {
+
+    if (!IN_BDM) return TERM_ERR;
+
+    // write command code
+    bdm_clk(BDM_READ + BDM_LONGSIZE, CMD_BIT_COUNT);
+    if (bdm_response > BDM_CMDCMPLTE) return TERM_ERR;
+    // write the optional address
+    if (addr) {
+        if(!bdm_address(addr)) return TERM_ERR;
+    }
+
+    return TERM_OK;
+}
+//-----------------------------------------------------------------------------
+/**
+    Issues a write byte command to MCU.
+
+    @param        addr        address (optional)
+
+    @return                   status flag
+*/
+uint8_t memwrite_byte_cmd(const uint32_t* addr) {
+
+    if (!IN_BDM) return TERM_ERR;
+    
+    // write command code
+    if (!bdm_command(BDM_WRITE + BDM_BYTESIZE)) return TERM_ERR;
+    // write the optional address
+    if (addr) {
+        if(!bdm_address(addr)) return TERM_ERR;
+    }
+
+    return TERM_OK;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Issues a write word command to MCU.
+
+    @param        addr        address (optional)
+
+    @return                   status flag
+*/
+uint8_t memwrite_word_cmd(const uint32_t* addr) {
+
+    if (!IN_BDM) return TERM_ERR;
+
+    // write command code
+    bdm_clk(BDM_WRITE + BDM_WORDSIZE, CMD_BIT_COUNT);
+    if (bdm_response > BDM_CMDCMPLTE) return TERM_ERR;
+    // write the optional address
+    if (addr) {
+        if(!bdm_address(addr)) return TERM_ERR;
+    }
+
+    return TERM_OK;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Issues a write long command to MCU.
+
+    @param        addr        address (optional)
+
+    @return                   status flag
+*/
+uint8_t memwrite_long_cmd(const uint32_t* addr) {
+
+    if (!IN_BDM) return TERM_ERR;
+
+    // write command code
+    bdm_clk(BDM_WRITE + BDM_LONGSIZE, CMD_BIT_COUNT);
+    if (bdm_response > BDM_CMDCMPLTE) return TERM_ERR;
+    // write the optional address
+    if (addr) {
+        if(!bdm_address(addr)) return TERM_ERR;
+    }
+
+    return TERM_OK;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Gets a byte from the MCU (follows a previously sent read or dump word cmd)
+    Sends a READ_BYTE command so that commands overlap
+
+    @param        result        read result (out)
+                  addr          address (optional)
+
+    @return                     status flag
+*/
+uint8_t memread_read_byte(uint8_t* result, const uint32_t* addr) {
+
+    if (!IN_BDM) return TERM_ERR;
+    // write the optional address
+    if (addr) {
+        if(!bdm_address(addr)) return TERM_ERR;
+    }
+    // receive the response byte
+    return (bdm_get ((uint32_t*)result, BDM_BYTESIZE, BDM_READ + BDM_BYTESIZE)) ? TERM_OK : TERM_ERR;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Gets a byte from the MCU (follows a previously sent read or dump word cmd)
+    Sends a WRITE_BYTE command so that commands overlap
+
+    @param        result        read result (out)
+                  addr          address (optional)
+
+    @return                     status flag
+*/
+uint8_t memread_write_byte(uint8_t* result, const uint32_t* addr) {
+
+    if (!IN_BDM) return TERM_ERR;
+    // write the optional address
+    if (addr) {
+        if(!bdm_address(addr)) return TERM_ERR;
+    }
+    // receive the response byte
+    return (bdm_get((uint32_t*)result, BDM_BYTESIZE, BDM_WRITE + BDM_BYTESIZE)) ? TERM_OK : TERM_ERR;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Gets a byte from the MCU (follows a previously sent read or dump word cmd)
+    Sends a BDM_NOP command to end a sequence of overlapping commands
+
+    @param        result        read result (out)
+                  addr          address (optional)
+
+    @return                     status flag
+*/
+uint8_t memread_nop_byte(uint8_t* result, const uint32_t* addr) {
+
+    if (!IN_BDM) return TERM_ERR;
+    // write the optional address
+    if (addr) {
+        if(!bdm_address(addr)) return TERM_ERR;
+    }
+    // receive the response byte
+    return (bdm_get((uint32_t*)result, BDM_BYTESIZE, BDM_NOP)) ? TERM_OK : TERM_ERR;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Writes a byte to the MCU (follows a previously sent write or fill word cmd)
+    Sends a WRITE_BYTE command so that commands overlap
+
+    @param        addr          address (optional)
+                  value         value to write
+
+    @return                     status flag
+*/
+uint8_t memwrite_write_byte(const uint32_t* addr, uint8_t value) {
+
+    if (!IN_BDM) return TERM_ERR;
+    // write the optional address
+    if (addr) {
+        if(!bdm_address(addr)) return TERM_ERR;
+    }
+    // write the value
+    if (!bdm_put((uint32_t*)&value, BDM_BYTESIZE)) return TERM_ERR;
+    // wait until MCU responds
+    return (bdm_ready(BDM_WRITE + BDM_BYTESIZE)) ? TERM_OK : TERM_ERR;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Writes a byte to the MCU (follows a previously sent write or fill word cmd)
+    Sends a READ_BYTE command so that commands overlap
+
+    @param        addr          address (optional)
+                  value         value to write
+
+    @return                     status flag
+*/
+uint8_t memwrite_read_byte(const uint32_t* addr, uint8_t value) {
+
+    if (!IN_BDM) return TERM_ERR;
+    // write the optional address
+    if (addr) {
+        if(!bdm_address(addr)) return TERM_ERR;
+    }
+    // write the value
+    if (!bdm_put((uint32_t*)&value, BDM_BYTESIZE)) return TERM_ERR;
+    // wait until MCU responds
+    return (bdm_ready(BDM_READ + BDM_BYTESIZE)) ? TERM_OK : TERM_ERR;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Writes a byte to the MCU (follows a previously sent write or fill word cmd)
+    Sends a BDM_NOP command to end a sequence of overlapping commands
+
+    @param        addr          address (optional)
+                  value         value to write
+
+    @return                     status flag
+*/
+uint8_t memwrite_nop_byte(const uint32_t* addr, uint8_t value) {
+
+    if (!IN_BDM) return TERM_ERR;
+    // write the optional address
+    if (addr) {
+        if(!bdm_address(addr)) return TERM_ERR;
+    }
+    // write the value
+    if (!bdm_put((uint32_t*)&value, BDM_BYTESIZE)) return TERM_ERR;
+    // wait until MCU responds
+    return (bdm_ready(BDM_NOP)) ? TERM_OK : TERM_ERR;
+}
+
+
+//-----------------------------------------------------------------------------
+/**
+    Writes 2 words to the same address
+    The BDM commands are overlapped to make things a bit faster
+    A BDM_NOP command is then sent to end the sequence of overlapping commands
+    
+    @param        addr          address
+                  value1, 2     values to write
+
+    @return                     status flag
+*/
+uint8_t memwrite_word_write_word(const uint32_t* addr, const uint16_t value1, const uint16_t value2) {
+
+    if (!IN_BDM) return TERM_ERR;
+
+    // write command code
+    if (!bdm_command(BDM_WRITE + BDM_WORDSIZE)) return TERM_ERR;
+    // write the address
+    if (!bdm_address(addr)) return TERM_ERR;
+    // write the first value
+    if (!bdm_put((uint32_t*)&value1, BDM_WORDSIZE)) return TERM_ERR;
+    // wait until MCU responds and overlap the next write command
+    if (!bdm_ready(BDM_WRITE + BDM_WORDSIZE)) return TERM_ERR;
+    // write the address (same address for second word)
+    if (!bdm_address(addr)) return TERM_ERR;
+    // write the second value
+    if (!bdm_put((uint32_t*)&value2, BDM_WORDSIZE)) return TERM_ERR;
+    // wait until MCU responds
+    return (bdm_ready(BDM_NOP)) ? TERM_OK : TERM_ERR;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Writes a word then reads back a result from the same address
+    The BDM commands are overlapped to make things a bit faster
+    A BDM_NOP command is then sent to end the sequence of overlapping commands
+
+    @param        result        read result (out)
+                  addr          address
+                  value         value to write
+
+    @return                     status flag
+*/
+
+uint8_t memwrite_word_read_word(uint16_t* result, const uint32_t* addr, const uint16_t value) {
+
+    if (!IN_BDM) return TERM_ERR;
+
+    // write command code
+    if (!bdm_command(BDM_WRITE + BDM_WORDSIZE)) return TERM_ERR;
+    // write the address
+    if (!bdm_address(addr)) return TERM_ERR;
+    // write the value
+    if (!bdm_put((uint32_t*)&value, BDM_WORDSIZE)) return TERM_ERR;
+    // wait until MCU responds and overlap the next read command
+    if (!bdm_ready(BDM_READ + BDM_WORDSIZE)) return TERM_ERR;
+    // write the address (same address for reading the result)
+    if (!bdm_address(addr)) return TERM_ERR;
+    // receive the response word
+    return (bdm_get((uint32_t*)result, BDM_WORDSIZE, BDM_NOP)) ? TERM_OK : TERM_ERR;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Gets a word from the MCU (follows a previously sent read or dump word cmd)
+    Sends a DUMP_WORD command so that dump commands overlap
+
+    @param        result        read result (out)
+
+    @return                     status flag
+*/
+uint8_t memget_word(uint16_t* result) {
+
+    if (!IN_BDM) return TERM_ERR;
+    // receive the response word
+    return (bdm_get((uint32_t*)result, BDM_WORDSIZE, BDM_DUMP + BDM_WORDSIZE)) ? TERM_OK : TERM_ERR;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Gets a long from the MCU (follows a previously sent read or dump long cmd)
+    Sends a DUMP_LONG command so that dump commands overlap
+
+    @param        result        read result (out)
+
+    @return                     status flag
+*/
+uint8_t memget_long(uint32_t* result) {
+
+    if (!IN_BDM) return TERM_ERR;
+    // receive the response words
+    return (bdm_get(result, BDM_LONGSIZE, BDM_DUMP + BDM_LONGSIZE)) ? TERM_OK : TERM_ERR;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Reads value from system register.
+
+    @param        result            register value (out)
+    @param        reg                register
+
+    @return                        status flag
+*/
+uint8_t sysreg_read(uint32_t* result, uint8_t reg) {
+    // check state
+    if (!IN_BDM) {
+        return TERM_ERR;
+    }
+
+    // read register
+    if (!bdm_read(result, BDM_RSREG + reg, NULL)) {
+        // clear the interface and fail
+        return TERM_ERR;
+    }
+
+    return TERM_OK;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Writes value to system register.
+
+    @param        reg                register
+    @param        value            register value
+
+    @return                        status flag
+*/
+uint8_t sysreg_write(uint8_t reg, const uint32_t* value) {
+    // check state
+    if (!IN_BDM) {
+        return TERM_ERR;
+    }
+
+    // write register
+    if (!bdm_write(NULL, BDM_WSREG + reg, value)) {
+        // clear the interface and fail
+        bdm_clear();
+        return TERM_ERR;
+    }
+
+    return TERM_OK;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Reads value from A/D register.
+
+    @param        result            register value (out)
+    @param        reg                register
+
+    @return                        status flag
+*/
+uint8_t adreg_read(uint32_t* result, uint8_t reg) {
+    // check state
+    if (!IN_BDM) {
+        return TERM_ERR;
+    }
+
+    // read register
+    if (!bdm_read(result, BDM_RDREG + reg, NULL)) {
+        // clear the interface and fail
+        bdm_clear();
+        return TERM_ERR;
+    }
+
+    return TERM_OK;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Writes value to A/D register.
+
+    @param        reg                register
+    @param        value            register value
+
+    @return                        status flag
+*/
+uint8_t adreg_write(uint8_t reg, const uint32_t* value) {
+    // check state
+    if (!IN_BDM) {
+        return TERM_ERR;
+    }
+
+    // write register
+    if (!bdm_write(NULL, BDM_WRREG + reg, value)) {
+        // clear the interface and fail
+        bdm_clear();
+        return TERM_ERR;
+    }
+
+    return TERM_OK;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Issues a read command to MCU.
+
+    @param        result        read result (out)
+    @param        cmd            command sequence
+    @param        addr        address (optional)
+
+    @return                    succ / fail
+*/
+bool bdm_read(uint32_t* result, uint16_t cmd, const uint32_t* addr) {
+    *result = 0;
+
+    // write command code
+    bdm_clk(cmd, CMD_BIT_COUNT);
+    if (bdm_response > BDM_CMDCMPLTE) {
+        return false;
+    }
+
+    // write the optional address
+    if (addr) {
+        // first word
+        bdm_clk((uint16_t)(*addr >> 16), CMD_BIT_COUNT);
+        if (bdm_response > BDM_NOTREADY) {
+            return false;
+        }
+        // second word
+        bdm_clk((uint16_t)(*addr), CMD_BIT_COUNT);
+        if (bdm_response > BDM_NOTREADY) {
+            return false;
+        }
+    }
+
+    // receive response words
+    uint8_t wait_cnt;
+    for (uint8_t curr_word = 0; curr_word < ((cmd & BDM_LONGSIZE) ? 2 : 1);
+            ++curr_word) {
+        // wait while MCU prepares the response
+        wait_cnt = ERR_COUNT;
+        do {
+            bdm_clk(BDM_NOP, CMD_BIT_COUNT);
+        } while (bdm_response == BDM_NOTREADY && --wait_cnt > 0);
+
+        // save the result
+        if (bdm_response < BDM_NOTREADY) {
+            (*result) <<= 16;
+            (*result) |= bdm_response;
+        } else {
+            // result was not received
+            return false;
+        }
+    }
+
+    return true;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Issues a write command to MCU.
+
+    @param        num_words        number of additional command words
+    @param        cmd                command sequence
+
+    @return                        succ / fail
+*/
+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) {
+        return false;
+    }
+
+    // write the optional address
+    if (addr) {
+        // first word
+        bdm_clk((uint16_t)((*addr) >> 16), CMD_BIT_COUNT);
+        if (bdm_response > BDM_NOTREADY) {
+            return false;
+        }
+        // second word
+        bdm_clk((uint16_t)(*addr), CMD_BIT_COUNT);
+        if (bdm_response > BDM_NOTREADY) {
+            return false;
+        }
+    }
+
+    // write the value
+    if (cmd & BDM_LONGSIZE) {
+        bdm_clk((uint16_t)((*value) >> 16), CMD_BIT_COUNT);
+        if (bdm_response > BDM_NOTREADY) {
+            return false;
+        }
+    }
+    bdm_clk((uint16_t)(*value), CMD_BIT_COUNT);
+    if (bdm_response > BDM_NOTREADY) {
+        return false;
+    }
+
+    // wait until MCU responds
+    uint8_t wait_cnt = ERR_COUNT;
+    do {
+        // read response
+        bdm_clk(BDM_NOP, CMD_BIT_COUNT);
+    } while (bdm_response == BDM_NOTREADY && --wait_cnt > 0);
+
+    // check if command succeeded
+    return (bdm_response == BDM_CMDCMPLTE);
+}
+
+bool bdm_command (uint16_t cmd) {
+    // write command code
+    bdm_clk(cmd, CMD_BIT_COUNT);
+    return (bdm_response > BDM_NOTREADY) ? false : true;
+}
+
+bool bdm_address (const uint32_t* addr) {
+    // write an address
+    // first word
+    bdm_clk((uint16_t)((*addr) >> 16), CMD_BIT_COUNT);
+    if (bdm_response > BDM_NOTREADY) {
+        return false;
+    }
+    // second word
+    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) {
+    // receive response words
+    *result = 0;
+    uint8_t wait_cnt;
+    for (uint8_t curr_word = 0; curr_word < ((size & BDM_LONGSIZE) ? 2 : 1);
+            ++curr_word) {
+        // wait while MCU prepares the response
+        wait_cnt = ERR_COUNT;
+        do {
+            bdm_clk(next_cmd, CMD_BIT_COUNT);
+        } while (bdm_response == BDM_NOTREADY && --wait_cnt > 0);
+
+        // save the result
+        if (bdm_response < BDM_NOTREADY) {
+            (*result) <<= 16;
+            (*result) |= bdm_response;
+        } else {
+            // result was not received
+            return false;
+        }
+    }
+    return true;
+}
+
+bool bdm_put (const uint32_t* value, uint8_t size) {
+    // write the value
+    if (size & BDM_LONGSIZE) {
+        bdm_clk((uint16_t)((*value) >> 16), CMD_BIT_COUNT);
+        if (bdm_response > BDM_NOTREADY) {
+            return false;
+        }
+    }
+    bdm_clk((uint16_t)(*value), CMD_BIT_COUNT);
+    return (bdm_response > BDM_NOTREADY) ? false : true;
+}
+
+bool bdm_ready (uint16_t next_cmd) {
+    // wait until MCU responds
+    uint8_t wait_cnt = ERR_COUNT;
+    do {
+        // read response
+        bdm_clk(next_cmd, CMD_BIT_COUNT);
+    } while (bdm_response == BDM_NOTREADY && --wait_cnt > 0);
+
+    // check if command succeeded
+    return (bdm_response == BDM_CMDCMPLTE);
+}
+
+//-----------------------------------------------------------------------------
+/**
+    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) {
+//    PIN_BKPT.output();
+//    PIN_DSI.output();
+    LPC_GPIO2->FIODIR |= 0x00000004;
+    // 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();
+//    LPC_GPIO2->FIODIR &= 0xfffffffb;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Clears the BDM interface after errors.
+*/
+void bdm_clear() {
+    bdm_clk (BDM_NOP, CMD_BIT_COUNT);
+    bdm_clk (BDM_NOP, CMD_BIT_COUNT);
+    bdm_clk (BDM_NOP, CMD_BIT_COUNT);
+    bdm_clk (BDM_NOP, CMD_BIT_COUNT);
+
+    while (bdm_response > 0) {
+        bdm_clk(0, 1);
+    }
+    while (bdm_response < 1) {
+        bdm_clk(0, 1);
+    }
+    bdm_clk(0, 15);
+}
+
+//-----------------------------------------------------------------------------
+//    EOF
+//-----------------------------------------------------------------------------
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bdmcpu32.h	Tue Sep 14 21:02:04 2010 +0000
@@ -0,0 +1,108 @@
+/*******************************************************************************
+
+bdmcpu32.h
+(c) 2010 by Sophie Dexter
+
+A derivative work based on:
+//-----------------------------------------------------------------------------
+//    CAN/BDM adapter firmware
+//    (C) Janis Silins, 2010
+//    $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.
+
+*******************************************************************************/
+
+#ifndef __BDMCPU32_H__
+#define __BDMCPU32_H__
+
+#include "mbed.h"
+
+#include "common.h"
+#include "bdmtrionic.h"
+//#include "BDM.h"
+
+
+// MCU status macros
+#ifndef IGNORE_VCC_PIN
+    #define IS_CONNECTED    (PIN_PWR)
+#else
+    #define IS_CONNECTED    true
+#endif    // IGNORE_VCC_PIN
+
+#define IN_BDM              (PIN_FREEZE)
+#define IS_RUNNING          (PIN_RESET && !IN_BDM)
+
+// MCU management
+uint8_t stop_chip();
+uint8_t reset_chip();
+uint8_t run_chip(const uint32_t* addr);
+uint8_t restart_chip();
+uint8_t step_chip();
+uint8_t bkpt_low();
+uint8_t bkpt_high();
+uint8_t reset_low();
+uint8_t reset_high();
+
+// memory
+uint8_t memread_byte(uint8_t* result, const uint32_t* addr);
+uint8_t memread_word(uint16_t* result, const uint32_t* addr);
+uint8_t memread_long(uint32_t* result, const uint32_t* addr);
+uint8_t memdump_byte(uint8_t* result);
+uint8_t memdump_word(uint16_t* result);
+uint8_t memdump_long(uint32_t* result);
+uint8_t memwrite_byte(const uint32_t* addr, uint8_t value);
+uint8_t memwrite_word(const uint32_t* addr, uint16_t value);
+uint8_t memwrite_long(const uint32_t* addr, const uint32_t* value);
+uint8_t memfill_byte(uint8_t value);
+uint8_t memfill_word(uint16_t value);
+uint8_t memfill_long(const uint32_t* value);
+
+// memory split commands
+// Setup a start of a sequence of BDM operations
+// read commands
+uint8_t memread_byte_cmd(const uint32_t* addr);
+uint8_t memread_word_cmd(const uint32_t* addr);
+uint8_t memread_long_cmd(const uint32_t* addr);
+// write commands
+uint8_t memwrite_byte_cmd(const uint32_t* addr);
+uint8_t memwrite_word_cmd(const uint32_t* addr);
+uint8_t memwrite_long_cmd(const uint32_t* addr);
+// follow on commands
+// dump bytes/words/longs
+uint8_t memget_word(uint16_t* result);
+uint8_t memget_long(uint32_t* result);
+// read and write bytes
+uint8_t memwrite_write_byte(const uint32_t* addr, const uint8_t value);
+uint8_t memwrite_read_byte(const uint32_t* addr, const uint8_t value);
+uint8_t memwrite_nop_byte(const uint32_t* addr, const uint8_t value);
+uint8_t memread_read_byte(uint8_t* result, const uint32_t* addr);
+uint8_t memread_write_byte(uint8_t* result, const uint32_t* addr);
+uint8_t memread_nop_byte(uint8_t* result, const uint32_t* addr);
+//
+uint8_t memwrite_word_write_word(const uint32_t* addr, const uint16_t value1, const uint16_t value2);
+uint8_t memwrite_word_read_word(uint16_t* result, const uint32_t* addr, const uint16_t value);
+
+
+// registers
+uint8_t sysreg_read(uint32_t* result, uint8_t reg);
+uint8_t sysreg_write(uint8_t reg, const uint32_t* value);
+uint8_t adreg_read(uint32_t* result, uint8_t reg);
+uint8_t adreg_write(uint8_t reg, const uint32_t* value);
+
+// bdm part commands
+bool bdm_command (uint16_t cmd);
+bool bdm_address (const uint32_t* addr);
+bool bdm_get (uint32_t* result, uint8_t size, uint16_t next_cmd);
+bool bdm_put (const uint32_t* value, uint8_t size);
+bool bdm_ready (uint16_t next_cmd);
+
+#endif    // __BDMCPU32_H__
+//-----------------------------------------------------------------------------
+//    EOF
+//-----------------------------------------------------------------------------
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bdmtrionic.cpp	Tue Sep 14 21:02:04 2010 +0000
@@ -0,0 +1,894 @@
+/*******************************************************************************
+
+bdmtrionic.cpp
+(c) 2010 by Sophie Dexter
+
+General purpose BDM functions for Just4Trionic by Just4pLeisure
+
+A derivative work based on:
+//-----------------------------------------------------------------------------
+//    CAN/BDM adapter firmware
+//    (C) Janis Silins, 2010
+//    $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 "bdmtrionic.h"
+
+// structure for command address/value pairs
+struct mempair_t {
+    uint32_t addr;            ///< target address
+    uint16_t val;            ///< word value
+};
+
+// word write algorithm (29Fxxx)
+static const struct mempair_t am29_write [] = {
+    {0xaaaa, 0xaaaa}, {0x5554, 0x5555}, {0xaaaa, 0xa0a0},
+};
+
+// chip erase algorithms
+static const struct mempair_t am29_erase [] = {
+    {0xaaaa, 0xaaaa}, {0x5554, 0x5555}, {0xaaaa, 0x8080},
+    {0xaaaa, 0xaaaa}, {0x5554, 0x5555}, {0xaaaa, 0x1010}
+};
+
+// reset algorithms
+//static const struct mempair_t am29_reset = {0xfffe, 0xf0f0};
+static const struct mempair_t am29_reset [] = {
+    {0xaaaa, 0xaaaa}, {0x5554, 0x5555}, {0xaaaa, 0xf0f0},
+};
+
+// chip id algorithms
+static const struct mempair_t am29_id [] = {
+    {0xaaaa, 0xaaaa}, {0x5554, 0x5555}, {0xaaaa, 0x9090},
+};
+
+// ;-)
+static const struct mempair_t flash_tag [] = {
+    {0x7fe00, 0xFF4A}, {0x7fe02, 0x7573}, {0x7fe04, 0x7434}, {0x7fe06, 0x704C},
+    {0x7fe08, 0x6569}, {0x7fe0a, 0x7375}, {0x7fe0c, 0x7265}, {0x7fe0e, 0x3B29},
+};
+
+// local functions
+bool reset_am29(void);
+bool erase_am29();
+bool flash_am29(const uint32_t* addr, uint16_t value);
+bool reset_am28(void);
+bool erase_am28(const uint32_t* start_addr, const uint32_t* end_addr);
+bool flash_am28(const uint32_t* addr, uint16_t value);
+bool get_flash_id(uint8_t* make, uint8_t* type);
+
+
+//-----------------------------------------------------------------------------
+/**
+    Dumps contents of a memory block from [start_addr] up to, but not including,
+    the [end_addr] as long words (word-aligned addresses). MCU must be in
+    background mode. The operation interrupts if the break character is
+    received.
+
+    @param        start_addr        block start address
+    @param        end_addr        block end address
+
+    @return                        status flag
+*/
+
+
+uint8_t dump_flash(const uint32_t* start_addr, const uint32_t* end_addr) {
+
+    // check parametres
+    if (*start_addr > *end_addr) {
+        return TERM_ERR;
+    }
+
+    // dump memory contents
+    uint32_t curr_addr = *start_addr;
+    uint32_t value;
+
+    while ((curr_addr < *end_addr) && (pc.getc() != TERM_BREAK)) {
+        // read long word
+        if (curr_addr > *start_addr) {
+            if (memdump_long(&value) != TERM_OK) {
+                return TERM_ERR;
+            }
+        } else {
+            if (memread_long(&value, &curr_addr) != TERM_OK) {
+                return TERM_ERR;
+            }
+        }
+
+        // send memory value to host
+        printf("%08X", value);
+
+        // add the terminating character
+        if (curr_addr < *end_addr - 4) {
+            pc.putc(TERM_OK);
+            // light up the activity LED
+            //            led_on(LED_ACT);
+            led3 = 1;
+        }
+
+        curr_addr += 4;
+    }
+
+    return TERM_OK;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Dumps the contents of a T5 ECU to a BIN file on the mbed 'disk'
+    from [start_addr] up to, but not including, the [end_addr].
+    MCU must be in background mode.
+
+    @param        start_addr        block start address
+    @param        end_addr        block end address
+
+    @return                        status flag
+*/
+
+uint8_t dump_trionic() {
+
+    // Configure the MC68332 register values to prepare for flashing
+    printf("I am trying to discover what type of Trionic ECU I am connected to...\r\n");
+    prep_t5_do();
+    // Work out what type of FLASH chips we want to make a dump file for
+    uint8_t make;
+    uint8_t type;
+    get_flash_id(&make, &type);
+    // set up chip-specific functions
+    bool (*reset_func)();
+    uint32_t flash_size;
+
+    switch (type) {
+        case AMD29F400B:
+        case AMD29F400T:
+            printf("I have found AMD29F400 type FLASH chips; I must be connected to a T7 ECU :-)\r\n");
+            reset_func = &reset_am29;
+            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");
+            reset_func = &reset_am29;
+            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");
+            reset_func = &reset_am28;
+            flash_size = T55FLASHSIZE;
+            break;
+        case AMD28F512:
+        case INTEL28F512:
+            printf("I have found 28F512 type FLASH chips; I must be connected to a 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");
+            return TERM_ERR;
+    }
+
+    // reset the FLASH chips
+    if (!reset_func()) return TERM_ERR;
+
+    printf("Creating FLASH dump file...\r\n");
+    FILE *fp = fopen("/local/original.bin", "w");    // Open "original.bin" on the local file system for writing
+    if (!fp) {
+        perror ("The following error occured");
+        return TERM_ERR;
+    }
+
+// dump memory contents
+    uint32_t addr = 0x00;
+    uint32_t long_value;
+
+// setup start address to dump from
+    if (memread_long_cmd(&addr) != TERM_OK) return TERM_ERR;
+
+    timer.reset();
+    timer.start();
+
+    while (addr < flash_size) {
+        uint16_t byte_count = 0;
+        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
+        led3 = 1;
+        fwrite(file_buffer, 1, FILE_BUF_LENGTH, fp);
+        if (ferror (fp)) {
+            fclose (fp);
+            printf ("Error writing to the FLASH BIN file.\r\n");
+            return TERM_ERR;
+        }
+    }
+    // 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);
+    timer.stop();
+    printf("Getting the FLASH dump took %#.1f seconds.\r\n",timer.read());
+    fclose(fp);
+    return TERM_OK;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Erases the flash memory chip starting from [start_addr] up to, but not
+    including [end_addr] and optionally verifies the result; MCU must be in
+    background mode.
+
+    @param        flash_type        type of flash chip
+    @param        start_addr        flash start address
+    @param        end_addr        flash end address
+
+    @return                        status flag
+*/
+uint8_t erase_flash(const char* flash_type, const uint32_t* start_addr,
+                    const uint32_t* end_addr) {
+    // AM29Fxxx chips (retrofitted to Trionic 5.x; original to T7)
+    if (strncmp(flash_type, "29f010", 6) == 0 ||
+            strncmp(flash_type, "29f400", 6) == 0) {
+        return erase_am29() ? TERM_OK : TERM_ERR;
+    }
+
+    // AM28F010 chip (Trionic 5.x original)
+    if (strncmp(flash_type, "28f010", 6) == 0) {
+        return erase_am28(start_addr, end_addr) ? TERM_OK : TERM_ERR;
+    }
+
+    return TERM_ERR;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Writes a batch of long words to the flash starting from [start_addr]. The
+    operation interrupts if a break character is received. MCU must be in
+    background mode.
+
+    @param        flash_type        type of flash chip
+    @param        start_addr        block start address
+
+    @return                        status flag
+*/
+uint8_t write_flash(const char* flash_type, const uint32_t* start_addr) {
+    // set up chip-specific functions
+    bool (*reset_func)(void);
+    bool (*flash_func)(const uint32_t*, uint16_t);
+
+    // AM29Fxxx chips (retrofitted to Trionic 5.x, original to T7)
+    if (strncmp(flash_type, "29f010", 6) == 0 ||
+            strncmp(flash_type, "29f400", 6) == 0) {
+        reset_func = &reset_am29;
+        flash_func = &flash_am29;
+    } else if (strncmp(flash_type, "28f010", 6) == 0) {
+        // AM28F010 chip (Trionic 5.x original)
+        reset_func = &reset_am28;
+        flash_func = &flash_am28;
+    } else {
+        // unknown flash type
+        return TERM_ERR;
+    }
+
+    // reset the flash
+    if (!reset_func()) {
+        return TERM_ERR;
+    }
+
+    uint32_t curr_addr = *start_addr;
+    if (strncmp(flash_type, "29f010", 6) == 0) {
+        curr_addr = 0;
+    }
+
+    int rx_char = 0;
+    char rx_buf[8];
+    char* rx_ptr;
+    uint32_t long_value;
+    bool ret = true;
+
+    // ready to receive data
+    pc.putc(TERM_OK);
+
+    while (true) {
+        // receive long words from USB
+        printf("receive long words from USB\r\n");
+        rx_ptr = rx_buf;
+        do {
+            rx_char = pc.getc();
+            if (rx_char != EOF) {
+                // have got all characters for one long word
+                if (rx_ptr > &rx_buf[7]) {
+                    ret = (rx_char == TERM_OK);
+                    break;
+                }
+
+                // save the character
+                *rx_ptr++ = (char)rx_char;
+            }
+        } while (rx_char != TERM_OK && rx_char != TERM_BREAK);
+        // end writing
+        printf("end writing\r\n");
+        if (!ret || rx_char == TERM_BREAK) {
+            break;
+        }
+
+        // convert value to long word
+        printf("convert value to long word\r\n");
+        if (!ascii2int(&long_value, rx_buf, 8)) {
+            ret = false;
+            break;
+        }
+        printf("long value %08x \r\n", long_value);
+
+        // write the first word
+        printf("write the first word\r\n");
+        if (!flash_func(&curr_addr, (uint16_t)(long_value >> 16))) {
+            ret = false;
+            break;
+        }
+        curr_addr += 2;
+        // write the second word
+        printf("write the second word\r\n");
+        if (!flash_func(&curr_addr, (uint16_t)long_value)) {
+            ret = false;
+            break;
+        }
+        curr_addr += 2;
+
+        // light up the activity LED
+//        led_on(LED_ACT);
+        led3 = 1;
+    }
+
+    // reset flash
+    return (reset_func() && ret) ? TERM_OK : TERM_ERR;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Writes a BIN file to the flash starting from [start_addr].
+    The operation ends when no more bytes can be read from the BIN file.
+    MCU must be in background mode.
+
+    @param        flash_type        type of flash chip
+    @param        start_addr        block start address
+
+    @return                        status flag
+*/
+uint8_t flash_trionic() {
+    // Configure the MC68332 register values to prepare for flashing
+    printf("I am trying to discover what type of Trionic ECU I am connected to...\r\n");
+    prep_t5_do();
+    // Work out what type of FLASH chips we want to program
+    uint8_t make;
+    uint8_t type;
+    get_flash_id(&make, &type);
+    // set up chip-specific functions
+    bool (*reset_func)();
+    bool (*flash_func)(const uint32_t*, uint16_t);
+    uint32_t flash_size;
+
+    switch (type) {
+        case AMD29F400B:
+        case AMD29F400T:
+            printf("I have found AMD29F400 type FLASH chips; I must be connected to a T7 ECU :-)\r\n");
+            reset_func = &reset_am29;
+            flash_func = &flash_am29;
+            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");
+            reset_func = &reset_am29;
+            flash_func = &flash_am29;
+            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");
+            reset_func = &reset_am28;
+            flash_func = &flash_am28;
+            flash_size = T55FLASHSIZE;
+            break;
+        case AMD28F512:
+        case INTEL28F512:
+            printf("I have found 28F512 type FLASH chips; I must be connected to a T5.2 ECU :-)\r\n");
+            reset_func = &reset_am28;
+            flash_func = &flash_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");
+            return TERM_ERR;
+    }
+
+    // reset the FLASH chips
+    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
+    if (!fp) {
+        printf("Error: I could not find the BIN file MODIFIED.HEX\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
+    uint8_t stack_byte = 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;
+    rewind (fp);
+
+    if (flash_size == T52FLASHSIZE && (file_size != T52FLASHSIZE || stack_long != T5POINTER)) {
+        fclose(fp);
+        printf("The BIN file does not appear to be for a T5.2 ECU :-(\r\n");
+        printf("BIN file size: %#10x, FLASH chip size: %#010x, Pointer: %#10x.\r\n", file_size, flash_size, stack_long);
+        return TERM_ERR;
+    }
+    if (flash_size == T55FLASHSIZE && (file_size != T55FLASHSIZE || stack_long != T5POINTER)) {
+        fclose(fp);
+        printf("The BIN file does not appear to be for a T5.5 ECU :-(\r\n");
+        printf("BIN file size: %#10x, FLASH chip size: %#010x, Pointer: %#10x.\r\n", file_size, flash_size, stack_long);
+        return TERM_ERR;
+    }
+    if (flash_size == T7FLASHSIZE && (file_size != T7FLASHSIZE || stack_long != T7POINTER)) {
+        fclose(fp);
+        printf("The BIN file does not appear to be for a T7 ECU :-(\r\n");
+        printf("BIN file size: %#10x, FLASH chip size: %#010x, Pointer: %#10x.\r\n", file_size, flash_size, stack_long);
+        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 AMD29F400B:
+        case AMD29F400T:
+        case AMD29F010:
+            printf("Erasing 29F400/010 type FLASH chips...\r\n");
+            if (erase_am29() == TERM_ERR) {
+                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) == TERM_ERR) {
+                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 "Starange!"
+            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;
+    uint8_t byte_value = 0;
+//    bool ret = true;
+
+// ready to receive data
+    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");
+            break;
+        }
+        word_value |= byte_value;
+
+        // write the word if it is not 0xffff
+        if (word_value != 0xffff) {
+            if (!flash_func(&curr_addr, word_value)) break;
+        }
+        curr_addr += 2;
+
+        // make the activity LED twinkle
+        led3 = 1;
+
+    }
+
+    timer.stop();
+    fclose(fp);
+
+    if (curr_addr == flash_size) {
+        printf("Programming took %#.1f seconds.\r\n",timer.read());
+        reset_func();
+        for (uint8_t i = 0; i < 8; ++i) {
+            memread_word(&word_value, &flash_tag[i].addr);
+            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);
+    }
+
+// reset flash
+    return (reset_func() && (curr_addr == flash_size)) ? TERM_OK : TERM_ERR;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Resets an AM29Fxxx flash memory chip. MCU must be in background mode.
+
+    @param                          none
+
+    @return                         succ / fail
+*/
+bool reset_am29(void) {
+    // execute the reset command
+//    uint32_t addr = 0xfffe;
+//    return (memwrite_word(&addr, 0xf0f0) == TERM_OK);
+    // execute the algorithm
+    for (uint8_t i = 0; i < 3; ++i) {
+        if (memwrite_word(&am29_reset[i].addr, am29_reset[i].val) != TERM_OK) return false;
+    }
+    return true;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Erases an AM29Fxxx flash memory chip and verifies the result; MCU must be
+    in background mode.
+
+    @return                        succ / fail
+*/
+bool erase_am29() {
+    // reset flash
+    if (!reset_am29()) {
+        return false;
+    }
+
+    // execute the algorithm
+    for (uint8_t i = 0; i < 6; ++i) {
+        if (memwrite_word(&am29_erase[i].addr, am29_erase[i].val) != TERM_OK) {
+            reset_am29();
+            return false;
+        }
+    }
+
+    // verify the result
+    uint32_t addr = 0x0;
+    uint16_t verify_value;
+
+    uint8_t err_cnt = ERR_COUNT;
+    while (--err_cnt) {
+        // typical erase time = 1s
+        // Allow up to 25.5 seconds erase time
+        wait_ms(100);
+        if (memread_word(&verify_value, &addr) == TERM_OK && verify_value == 0xffff) {
+            // erase completed normally
+            reset_am29();
+            return true;
+        }
+    }
+
+    // erase failed
+    reset_am29();
+    return false;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Writes a word to AM29Fxxx flash memory chip and optionally verifies the
+    result; MCU must be in background mode.
+
+    @param        addr        destination address
+    @param        val            value
+
+    @return                    succ / fail
+*/
+bool flash_am29(const uint32_t* addr, uint16_t value) {
+
+    // execute the algorithm
+    for (uint8_t i = 0; i < 3; ++i) {
+        if (memwrite_word(&am29_write[i].addr, am29_write[i].val) != TERM_OK) {
+            reset_am29();
+            return false;
+        }
+    }
+    // write the value
+    if (memwrite_word(addr, value) != TERM_OK) {
+        reset_am29();
+        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);
+        uint16_t verify_value;
+        if ((memread_word(&verify_value, addr) == TERM_OK) &&
+                (verify_value == value)) {
+            // flashing successful
+            return true;
+        }
+    }
+    // writing failed
+    reset_am29();
+    return false;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Resets a AM28Fxxx flash memory chip. MCU must be in background mode.
+
+    @param      start_addr      flash start address
+
+    @return                     succ / fail
+*/
+bool reset_am28(void) {
+    uint32_t start_addr = 0x0;
+    return (memwrite_word(&start_addr, 0xffff) == TERM_OK &&
+            memwrite_word(&start_addr, 0xffff) == TERM_OK);
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Erases an AM28Fxxx flash memory chip and verifies the result; MCU must be
+    in background mode.
+
+    @param      start_addr      flash start address
+    @param      end_addr        flash end address
+
+    @return                     succ / fail
+*/
+bool erase_am28(const uint32_t* start_addr, const uint32_t* end_addr) {
+
+    // check the addresses
+    if (!start_addr || !end_addr) return false;
+
+    // reset flash
+    if (!reset_am28()) return false;
+
+    // write zeroes over entire flash space
+    uint32_t addr = *start_addr;
+
+    while (addr < *end_addr) {
+        if (!flash_am28(&addr, 0x0000)) return false;
+        addr += 2;
+//        // feedback to host computer
+//        pc.putc(TERM_OK);
+        // make the activity LED twinkle
+//        led3 = (addr & 0x400);
+        led3 = 1;
+    }
+
+    // erase flash
+    addr = *start_addr;
+    uint8_t verify_value;
+
+
+    uint16_t pulse_cnt = 0;
+    if (memwrite_byte_cmd(NULL) != TERM_OK) {
+        reset_am28();
+        return false;
+    }
+    while ((++pulse_cnt < 1000) && (addr < *end_addr)) {
+        // issue the erase command
+        if (memwrite_write_byte(&addr, 0x20) != TERM_OK ||
+                memwrite_write_byte(&addr, 0x20) != TERM_OK) break;
+        wait_ms(10);
+
+        while (addr < *end_addr) {
+            // issue the verify command
+            if (memwrite_read_byte(&addr, 0xa0) != TERM_OK) break;
+//            wait_us(6);
+            // check the written value
+            if (memread_write_byte(&verify_value, &addr) != TERM_OK) break;
+            if (verify_value != 0xff) break;
+            // succeeded need to check next address
+            addr++;
+            // make the activity LED twinkle
+            led3 = 1;
+        }
+    }
+    // the erase process ends with a BDM_WRITE + BDM_BYTESIZE command left in the BDM
+    // it is safe to use it to put one of the FLASH chips into read mode and thereby
+    // leave the BDM ready for the next command
+    memwrite_nop_byte(start_addr, 0x00);
+
+    reset_am28();
+    // check for success
+    return (addr == *end_addr) ? true : false;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Writes a byte to AM28Fxxx flash memory chip and verifies the result
+    A so called 'mask' method checks the FLASH contents and only tries
+    to program bytes that need to be programmed.
+    MCU must be in background mode.
+
+    @param      addr        destination address
+    @param      val         value
+
+    @return                 succ / fail
+*/
+bool flash_am28(const uint32_t* addr, uint16_t value) {
+
+    if (!addr) return false;
+
+    uint8_t pulse_cnt = 0;
+    uint16_t verify_value = 0;
+    uint16_t mask_value = 0xffff;
+
+    // put flash into read mode and read address
+    if (memwrite_word_read_word(&verify_value, addr, 0x0000) != TERM_OK)  return false;
+    // return if FLASH already has the correct value - e.g. not all of the FLASH is used and is 0xff
+    if (verify_value == value) return true;
+
+    while (++pulse_cnt < 25) {
+
+        // set a mask
+        if ((uint8_t)verify_value == (uint8_t)value) mask_value &= 0xff00;
+        if ((uint8_t)(verify_value >> 8) == (uint8_t)(value >> 8)) mask_value &= 0x00ff;
+
+        // write the new value
+        if (memwrite_word_write_word(addr, (0x4040 & mask_value), value) != TERM_OK) break;
+        // NOTE the BDM interface is slow enough that there is no need for a 10us delay before verifying
+//        wait_us(10);
+        // issue the verification command
+        // NOTE the BDM interface is slow enough that there is no need for a 6us delay before reading back
+        if (memwrite_word_read_word(&verify_value, addr, (0xc0c0 & mask_value)) != TERM_OK) break;
+        // check if flashing was successful;
+        if (verify_value == value) return true;
+    }
+
+    // something went wrong; reset the flash chip and return failed
+    reset_am28();
+    return false;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Does the equivalent of do prept5.do in BD32
+    Sets up all of the control registers in the MC68332 so that we can program
+    the FLASH chips
+
+    @param                  none
+
+    @return                 succ / fail
+*/
+
+uint8_t prep_t5_do(void) {
+
+    // reset and freeze the MC68332 chip
+    if (restart_chip() != TERM_OK) return TERM_ERR;
+
+    // set the 'fc' registers to allow supervisor mode access
+    uint32_t long_value = 0x05;
+    if (sysreg_write(0x0e, &long_value) != TERM_OK) return TERM_ERR;
+    if (sysreg_write(0x0f, &long_value) != TERM_OK) return TERM_ERR;
+
+    // Set MC68332 to 16 MHz (actually 16.78 MHz)
+    long_value = 0x00fffa04;
+    if (memwrite_word(&long_value, 0x7f00) != TERM_OK) return TERM_ERR;
+
+    // Disable watchdog and monitors
+    long_value = 0x00fffa21;
+    if (memwrite_byte(&long_value, 0x00) != TERM_OK) return TERM_ERR;
+
+    // Chip select pin assignments
+    long_value = 0x00fffa44;
+    if (memwrite_word(&long_value, 0x3fff) != TERM_OK) return TERM_ERR;
+
+    // Boot Chip select read only, one wait state
+    long_value = 0x00fffa48;
+    if (memwrite_word(&long_value, 0x0007) != TERM_OK) return TERM_ERR;
+    if (memfill_word(0x6870) != TERM_OK) return TERM_ERR;
+
+    // Chip select 1 and 2 upper lower bytes, zero wait states
+    long_value = 0x00fffa50;
+    if (memwrite_word(&long_value, 0x0007) != TERM_OK) return TERM_ERR;
+    if (memfill_word(0x3030) != TERM_OK) return TERM_ERR;
+    if (memfill_word(0x0007) != TERM_OK) return TERM_ERR;
+    if (memfill_word(0x5030) != TERM_OK) return TERM_ERR;
+
+    // PQS Data - turn on VPPH
+    long_value = 0x00fffc14;
+    if (memwrite_word(&long_value, 0x0040) != TERM_OK) return TERM_ERR;
+
+    // PQS Data Direction output
+    long_value = 0x00fffc17;
+    if (memwrite_byte(&long_value, 0x40) != TERM_OK) return TERM_ERR;
+    // wait for programming voltage to be ready
+    wait_ms(10);
+
+//    // Enable internal 2kByte RAM of 68332 at address 0x00100000
+//    long_value = 0x00fffb04;
+//    if (memwrite_word(&long_value, 0x1000) != TERM_OK) return TERM_ERR;
+    return TERM_OK;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Works out what type of flash chip is fitted in the ECU by reading
+    the manufacturer byte codes.
+    It is enough to use the 29Fxxx flash id algorithm because 28Fxxx
+    FLASH chips ignore the first few writes needed by the 29Fxxx chips
+    MCU must be in background mode.
+
+    @param                  make (out)
+                            type (out)
+
+    @return                 succ / fail
+*/
+bool get_flash_id(uint8_t* make, uint8_t* type) {
+
+    uint32_t  addr = 0x0;
+    uint32_t value;
+    bool ret;
+    // read id bytes algorithm for 29F010/400 FLASH chips
+    for (uint8_t i = 0; i < 3; ++i) {
+        if (memwrite_word(&am29_id[i].addr, am29_id[i].val) != TERM_OK) return false;
+    }
+    if (memread_long(&value, &addr) != TERM_OK) return false;
+    *make = (uint8_t)(value >> 24);
+    *type = (uint8_t)(value >> 8);
+    printf("FLASH id bytes: %08x, make: %02x, type: %02x\r\n", value, *make, *type);
+    switch (*type) {
+        case AMD29F400B:
+        case AMD29F400T:
+        case AMD29F010:
+        case AMD28F010:
+        case INTEL28F010:
+        case AMD28F512:
+        case INTEL28F512:
+            ret = true;
+        default:
+            ret = false;
+    }
+    return ret;
+}
+
+//-----------------------------------------------------------------------------
+//    EOF
+//-----------------------------------------------------------------------------
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bdmtrionic.h	Tue Sep 14 21:02:04 2010 +0000
@@ -0,0 +1,45 @@
+/*******************************************************************************
+
+bdmtrionic.cpp
+(c) 2010 by Sophie Dexter
+
+A derivative work based on:
+//-----------------------------------------------------------------------------
+//    CAN/BDM adapter firmware
+//    (C) Janis Silins, 2010
+//    $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.
+
+*******************************************************************************/
+
+#ifndef __BDMTRIONIC_H__
+#define __BDMTRIONIC_H__
+
+#include "mbed.h"
+
+#include "common.h"
+#include "bdmcpu32.h"
+
+// global variables
+static bool verify_flash = 1;
+
+// public functions
+uint8_t dump_flash(const uint32_t* start_addr, const uint32_t* end_addr);
+uint8_t erase_flash(const char* flash_type, const uint32_t* start_addr,
+    const uint32_t* end_addr);
+uint8_t write_flash(const char* flash_type, const uint32_t* start_addr);
+
+uint8_t prep_t5_do(void);
+uint8_t dump_trionic(void);
+uint8_t flash_trionic(void);
+
+#endif
+//-----------------------------------------------------------------------------
+//    EOF
+//-----------------------------------------------------------------------------
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/can232.cpp	Tue Sep 14 21:02:04 2010 +0000
@@ -0,0 +1,205 @@
+/*******************************************************************************
+
+can232.cpp
+(c) 2010 by Sophie Dexter
+portions (c) 2009, 2010 by Janis Silins (johnc)
+
+Lawicel CAN232 type functions for Just4Trionic by Just4pLeisure
+
+********************************************************************************
+
+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 "can232.h"
+
+// constants
+#define CMD_BUF_LENGTH      32              ///< command buffer size
+
+// command characters
+
+#define CMD_CLOSE           'C'             ///< Close the CAN device
+#define CMD_OPEN            'O'             ///< Open the CAN device (do this before an S/s command)
+
+#define CMD_PRESET_SPEED    'S'             ///< Sn: set preconfigured speeds 
+#define CMD_SPEED_0         '0'             ///< 10 kbits
+#define CMD_SPEED_1         '1'             ///< 20 kbits
+#define CMD_SPEED_2         '2'             ///< 50 kbits
+#define CMD_SPEED_3         '3'             ///< 100 kbits
+#define CMD_SPEED_4         '4'             ///< 125 kbits
+#define CMD_SPEED_5         '5'             ///< 250 kbits
+#define CMD_SPEED_6         '6'             ///< 500 kbits
+#define CMD_SPEED_7         '7'             ///< 800 kbits
+#define CMD_SPEED_8         '8'             ///< 1 mbits
+#define CMD_DIRECT_SPEED    's'             ///< sxxyy: set the CAN bus speed registers directly
+///< xx: BTR0 register setting
+///< yy: BTR1 register setting
+
+#define CMD_SEND_11BIT      't'             ///< tiiildd..: send 11 bit id CAN frame
+///< iii: identfier 0x0..0x7ff
+///< l: Number of data bytes in CAN frame 0..8
+///< dd..: data byte values 0x0..0xff (l pairs)
+#define CMD_SEND_29BIT      'T'             ///< Tiiiiiiiildd..: send 29 bit id CAN frame
+///< iiiiiiii: identifier 0x0..0x1fffffff
+///< l: Number of data bytes in CAN frame 0..8
+///< dd..: data byte values 0x0..0xff (l pairs)
+
+
+#define CMD_READ_FLAGS      'F'             ///< Read flags !?!
+
+#define CMD_ACCEPT_CODE     'M'             ///< Mxxxxxxxx: Acceptance code e.g. 0x00000000 } accept
+#define CMD_ACCEPT_MASK     'm'             ///< mxxxxxxxx: Acceptance mask e.g. 0xffffffff } all
+
+#define CMD_VERSION         'V'             ///< Replies with Firmware and hardware version numbers; 2 bytes each
+#define CMD_SERIAL_NUMBER   'N'             ///< Replies with serial number; 4 bytes
+
+#define CMD_TIMESTAMP       'Z'             ///< Zn: n=0 means timestamp off, n=1 means timestamp is on
+///< Replies a value in milliseconds with two bytes 0x0..0xfa5f
+///< equivalent to 0..60 seconds
+
+
+
+// static variables
+static char cmd_buffer[CMD_BUF_LENGTH];     ///< command string buffer
+static uint32_t can_id;                     ///< can message id
+static uint32_t can_len;                    ///< can message length
+static uint8_t can_msg[8];                  ///< can message frame - up to 8 bytes
+
+// private functions
+uint8_t execute_can_cmd();
+
+// 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 can232() {
+
+    // main loop
+    *cmd_buffer = '\0';
+    char ret;
+    char rx_char;
+    can_open();
+    can.attach(&show_can_message);
+//    bool (*reset_func)();
+    while (true) {
+        // read chars from USB
+//        Trionic5ShowCANMessage();
+        if (pc.readable()) {
+            rx_char = pc.getc();
+            switch (rx_char) {
+                // 'ESC' key to go back to mbed Just4Trionic 'home' menu
+                case '\e':
+                    can_close();
+                    can.attach(NULL);
+                    return;
+                // end-of-command reached
+                case TERM_OK :
+                    // execute command and return flag via USB
+                    ret = execute_can_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_can_cmd() {
+    uint8_t cmd_length = strlen(cmd_buffer);
+    char cmd = *(cmd_buffer + 1);
+
+    // command groups
+    switch (*cmd_buffer) {
+            // adapter commands
+        case CMD_SEND_11BIT:
+            if (cmd_length < 7) return TERM_ERR;
+            GET_NUMBER(&can_id, -1, 3);
+            GET_NUMBER(&can_len, 2, 1);
+            if (cmd_length < (4 + (can_len * 2))) return TERM_ERR;
+            for (uint8_t i = 0; i < (uint8_t)can_len; i++) {
+                uint32_t result;
+                GET_NUMBER(&result, (3 + (i * 2)), 2);
+                can_msg[i] = (uint8_t)result;
+            }
+            return (can_send_timeout (can_id, (char*)can_msg, (uint8_t)can_len, 500)) ? TERM_OK : TERM_ERR;
+
+        case CMD_SEND_29BIT:
+            break;
+            
+        case CMD_CLOSE:
+            can_close();
+            return TERM_OK;
+        case CMD_OPEN:
+            can_open();
+            return TERM_OK;
+            
+        case CMD_PRESET_SPEED:
+            CHECK_ARGLENGTH(0);
+            switch (cmd) {
+                    // get firmware version
+                case CMD_SPEED_0:
+                    return (can.frequency(10000)) ? TERM_OK : TERM_ERR;
+                case CMD_SPEED_1:
+                    return (can.frequency(20000)) ? TERM_OK : TERM_ERR;
+                case CMD_SPEED_2:
+                    return (can.frequency(50000)) ? TERM_OK : TERM_ERR;
+                case CMD_SPEED_3:
+                    return (can.frequency(100000)) ? TERM_OK : TERM_ERR;
+                case CMD_SPEED_4:
+                    return (can.frequency(125000)) ? TERM_OK : TERM_ERR;
+                case CMD_SPEED_5:
+                    return (can.frequency(250000)) ? TERM_OK : TERM_ERR;
+                case CMD_SPEED_6:
+                    return (can.frequency(500000)) ? TERM_OK : TERM_ERR;
+                case CMD_SPEED_7:
+                    return (can.frequency(800000)) ? TERM_OK : TERM_ERR;
+                case CMD_SPEED_8:
+                    return (can.frequency(1000000)) ? TERM_OK : TERM_ERR;
+            }
+            break;
+            
+        case CMD_DIRECT_SPEED:
+            CHECK_ARGLENGTH(0);
+            switch (cmd) {
+                case CMD_SPEED_0:
+                    return (can.frequency(47619)) ? TERM_OK : TERM_ERR;
+                case CMD_SPEED_1:
+                    return (can.frequency(500000)) ? TERM_OK : TERM_ERR;
+                case CMD_SPEED_2:
+                    return (can.frequency(615000)) ? TERM_OK : TERM_ERR;
+            }
+            break;
+    }
+
+    // unknown command
+    return TERM_ERR;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/can232.h	Tue Sep 14 21:02:04 2010 +0000
@@ -0,0 +1,25 @@
+/*******************************************************************************
+
+can232.h
+(c) 2010 by Sophie Dexter
+portions (c) 2009, 2010 by Janis Silins (johnc)
+
+********************************************************************************
+
+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 __CAN232_H__
+#define __CAN232_H__
+
+#include "mbed.h"
+
+#include "common.h"
+#include "canutils.h"
+
+extern void can232();
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/canutils.cpp	Tue Sep 14 21:02:04 2010 +0000
@@ -0,0 +1,117 @@
+/*******************************************************************************
+
+canutils.cpp
+(c) 2010 by Sophie Dexter
+
+General purpose CAN bus functions for Just4Trionic by Just4pLeisure
+Functions that work with the CAN bus directly. Anything to do with the CAN bus
+must (should anyway) be done by one of these 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 "canutils.h"
+
+//CAN can2(p30, p29);
+// Use a timer to see if things take too long
+Timer CANTimer;
+
+
+void can_open() {
+    // activate external can transceiver
+    can.reset();
+    can_rs_pin = 0;
+}
+
+void can_close() {
+    // disable external can transceiver
+    can_rs_pin = 1;
+    can.reset();
+}
+
+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
+//    LPC_CAN2->BTR = 0x370002;
+    return (can.frequency(speed)) ? TERM_OK : TERM_ERR;
+}
+
+
+void show_can_message() {
+    CANMessage can_MsgRx;
+    if (can.read(can_MsgRx)) {
+        printf("w%03x%d", can_MsgRx.id, can_MsgRx.len);
+        for (char i=0; i<can_MsgRx.len; i++) {
+            printf("%02x", can_MsgRx.data[i]);
+        }
+        printf("\r\n");
+    }
+}
+
+//
+// Sends a CAN Message, returns FALSE if the message wasn't sent in time
+//
+// inputs:  integer CAN message 'id', pointer to 'frame', integer message length and integer timeout
+// 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) {
+    CANTimer.reset();
+    CANTimer.start();
+    while (CANTimer.read_ms() < timeout) {
+        if (can.write(CANMessage(id, frame, len))) {
+            CANTimer.stop();
+            led1 = 1;
+            return TRUE;
+        }
+    }
+    can.reset();
+    CANTimer.stop();
+    return FALSE;
+}
+
+//
+// Waits for a CAN Message with the specified 'id' for a time specified by the 'timeout'
+// All other messages are ignored
+// The CAN message frame is returned using the pointer to 'frame'
+//
+// inputs:    integer CAN message 'id', pointer to 'frame' for returning the data
+//          integer expected length of message, len and integer for the waiting time 'timeout'
+//
+// 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) {
+    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");
+//            */
+            led2 = 1;
+            if (CANMsgRx.id == id) {
+                CANTimer.stop();
+//                if (T5MsgRx.len != len)
+//                    return FALSE;
+                for (int i=0; i<len; i++)
+                    frame[i] = CANMsgRx.data[i];
+                return TRUE;
+            }
+        }
+    }
+    can.reset();
+    CANTimer.stop();
+    return FALSE;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/canutils.h	Tue Sep 14 21:02:04 2010 +0000
@@ -0,0 +1,30 @@
+/*******************************************************************************
+
+canutils.h - information and definitions needed for the CAN bus
+(c) 2010 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 __CANUTILS_H__
+#define __CANUTILS_H__
+
+#include "CAN.h"
+#include "mbed.h"
+
+#include "common.h"
+
+extern void can_open();
+extern void can_close();
+extern uint8_t can_set_speed(uint32_t speed);
+extern void show_can_message();
+
+extern bool can_send_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);
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/common.h	Tue Sep 14 21:02:04 2010 +0000
@@ -0,0 +1,102 @@
+/*******************************************************************************
+
+common.h - information and definitions needed by parts of Just4Trionic
+(c) by 2010 Sophie Dexter
+portions (c) 2009, 2010 by Janis Silins (johnc)
+
+********************************************************************************
+
+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 __COMMON_H__
+#define __COMMON_H__
+
+//#include <stdint.h>
+//#include <stdbool.h>
+
+#include "mbed.h"
+
+#include "sizedefs.h"
+#include "strings.h"
+#include "interfaces.h"
+
+// build configuration
+//#define IGNORE_VCC_PIN            ///< uncomment to ignore the VCC pin
+
+// constants
+#define FW_VERSION_MAJOR    0x1     ///< firmware version
+#define FW_VERSION_MINOR    0x1        
+
+#define CR 0x0D
+#define NL 0x0A
+#define BELL 0x07
+
+#define TRUE 1
+#define FALSE 0
+
+
+// bit macros
+#define SETBIT(x,y)         (x |= (y))                ///< set bit y in byte x
+#define CLEARBIT(x,y)       (x &= (~(y)))            ///< clear bit y in byte x
+#define CHECKBIT(x,y)       (((x) & (y)) == (y))    ///< check bit y in byte x
+
+// command return flags and character constants
+#define TERM_OK             13            ///< command terminator or success flag
+#define TERM_ERR            7            ///< error flag
+#define TERM_BREAK          0x1b        ///< command break flag
+
+#define ERR_COUNT           255            ///< maximum error cycles
+
+#define FILE_BUF_LENGTH      0x1000              ///< file buffer size
+static char file_buffer[FILE_BUF_LENGTH];     ///< file buffer
+
+// FLASH chip manufacturer id values
+#define AMD                 0x01
+#define CSI                 0x31
+#define INTEL               0x89
+
+// FLASH chip type values
+#define INTEL28F512         0xB8
+#define AMD28F512           0x25
+#define INTEL28F010         0xB4
+#define AMD28F010           0xA7
+#define AMD29F010           0x20
+#define AMD29F400T          0x23
+#define AMD29F400B          0xAB
+//#define 29F400T             0x2223
+//#define 29F400B             0x22AB
+
+// TRIONIC ECU Start addresses
+#define T52FLASHSTART       0x60000
+#define T55FLASHSTART       0x40000
+#define T7FLASHSTART        0x00000
+
+// TRIONIC ECU FLASH sizes
+#define T52FLASHSIZE        0x20000
+#define T55FLASHSIZE        0x40000
+#define T7FLASHSIZE         0x80000
+
+// TRIONIC ECU Last address
+#define TRIONICLASTADDR     0x7FFFF
+
+// TRIONIC ECU RAM sizes
+#define T5RAMSIZE           0x8000
+#define T7RAMSIZE           0x8000
+
+// Initial Stack pointer values used by Trionic (1st 4 bytes of BIN file)
+#define T5POINTER           0xFFFFF7FC
+#define T7POINTER           0xFFFFEFFC
+
+// public functions
+void led_on(uint8_t led);
+bool ascii2int(uint32_t* val, const char* str, uint8_t length);
+
+#endif              // __COMMON_H__
+
+//-----------------------------------------------------------------------------
+//    EOF
+//-----------------------------------------------------------------------------
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/interfaces.cpp	Tue Sep 14 21:02:04 2010 +0000
@@ -0,0 +1,60 @@
+/*******************************************************************************
+
+interfaces.cpp
+(c) 2010 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.
+
+*******************************************************************************/
+
+#include "interfaces.h"
+
+//Serial pc(USBTX, USBRX); // tx, rx
+Serial          pc(USBTX, USBRX);
+
+// A timer for timing how long things take to happen
+Timer timer;
+
+// We use CAN on mbed pins 29(CAN_TXD) and 30(CAN_RXD).
+CAN can(p30, p29);
+// CAN_RS pin at Philips PCA82C250 can bus controller.
+// activate transceiver by pulling this pin to GND.
+// (Rise and fall slope controlled by resistor R_s)
+// (+5V result in tranceiver standby mode)
+// For further information see datasheet page 4
+DigitalOut can_rs_pin(p28);
+
+// Need to create this to be able to read and write files on the mbed 'disk'
+LocalFileSystem local("local");
+
+
+DigitalIn       PIN_PWR(p19);               // power supply
+DigitalIn       PIN_NC(p20);                // connection signal
+DigitalInOut    PIN_BERR(p21);              // double bus fault input - will be an input when it is working properly
+DigitalInOut    PIN_BKPT(p22);              // breakpoint/serial clock
+DigitalInOut    PIN_RESET(p23);             // reset signal
+DigitalInOut    PIN_DSI(p24);               // data input (to ECU) signal
+DigitalIn       PIN_DS(p25);                // data strobe signal (not used)
+DigitalIn       PIN_FREEZE(p26);            // freeze signal
+DigitalIn       PIN_DSO(p27);               // data output (from ECU) signal
+
+//LEDS
+
+// Use the LEDs to if anything is happening
+
+DigitalOut      led1(LED1);                 // LED1 CAN send
+DigitalOut      led2(LED2);                 // LED2 CAN receive
+DigitalOut      led3(LED3);                 // BDM activity LED
+DigitalOut      led4(LED4);                 // Error LED
+
+Ticker ticker;
+
+void leds_off() {
+    led1 = 0;
+    led2 = 0;
+    led3 = 0;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/interfaces.h	Tue Sep 14 21:02:04 2010 +0000
@@ -0,0 +1,50 @@
+/*******************************************************************************
+
+interfaces.cpp - information and definitions about Just4Trionic external interfaces
+(c) 2010 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 __INTERFACES_H__
+#define __INTERFACES_H__
+
+#include "mbed.h"
+
+extern Serial           pc;                     //Serial pc(USBTX, USBRX); // tx, rx
+
+extern CAN              can;                    //Serial pc(USBTX, USBRX); // tx, rx
+extern DigitalOut       can_rs_pin;             //
+
+extern LocalFileSystem  local;                  //Serial pc(USBTX, USBRX); // tx, rx
+
+extern Timer            timer;
+
+extern DigitalIn        PIN_PWR;                // power supply
+extern DigitalIn        PIN_NC;                 // connection signal
+extern DigitalInOut     PIN_BERR;               // double bus fault input - will be an input when it is working properly
+extern DigitalInOut     PIN_BKPT;               // breakpoint/serial clock
+extern DigitalInOut     PIN_RESET;              // reset signal
+extern DigitalInOut     PIN_DSI;                // data input (to ECU) signal
+extern DigitalIn        PIN_DS;                 // data strobe signal (not used)
+extern DigitalIn        PIN_FREEZE;             // freeze signal
+extern DigitalIn        PIN_DSO;                // data output (from ECU) signal
+
+//LEDS
+
+// Use the LEDs to see if anything is happening
+extern DigitalOut       led1;                   // LED1 CAN send
+extern DigitalOut       led2;                   // LED2 CAN receive
+extern DigitalOut       led3;                   // BDM activity LE
+extern DigitalOut       led4;                   // Error LED
+
+extern Ticker           ticker;
+
+void leds_off(void);
+
+#endif          // __INTERFACES_H__
\ No newline at end of file
--- a/main.cpp	Wed May 19 12:39:18 2010 +0000
+++ b/main.cpp	Tue Sep 14 21:02:04 2010 +0000
@@ -1,7 +1,8 @@
 /*******************************************************************************
 
-Just4Trionic by Just4pLeisure    
+Just4Trionic by Just4pLeisure
 *****************************
+(c) 2010 by Sophie Dexter
 
 Whilst I have written this program myself I could not have done it without
 a lot of help and the original ideas and programs written by:
@@ -12,7 +13,10 @@
 Tomi Liljemark - Lots of information and programs about the Saab CAN bus
 http://pikkupossu.1g.fi/tomi/projects/projects.html.
 Scott Howard - Author of the BDM software.
-Plus inspiration and ideas from many others, including johnc.
+Janis Silins - Valued contributor at http://www.ecuproject.com and creator of
+USBBDM. For sharing his BDM software (which also had a very useful method of
+entering commands)
+Plus inspiration and ideas from many others...
 
 Sophie x
 
@@ -24,7 +28,33 @@
 
 ********************************************************************************
 
-Version 1 (04/2010)- The basic functions are working, but not very easy to use
+Version 1.1 (09/2010) - Still very crude way of doing things
+
+Additions since Version 1:
+    The BDM interface is now working
+        Based on Janis Silin's BDM software with modifications and additions
+            Detect which type of FLASH chip is fitted to work out type of ECU
+            Modifications to FLASH algorithms - I think my algorithms are
+            closer to the datasheet methods. Still to do:
+                Separate pulse counters for 28Fxxx erase
+                DQ7 and DQ5 checking method for 29Fxxx FLASH
+        Works for T5.5 ECUs with 28F010 and 29F010 chips
+        Probably works with T5.2 ECUs (chip detection method)
+        MAY work with T7 ECUs ('prep' method may need changes - I can't test T7)
+        NOTE: Some of Janis' original BDM commands may not work, or at least
+        not as originally intended
+    Lawicell CAN232 interface partially working
+        Only a few Lawicell message types to open/close, set speed and write
+    Trionic5 CAN functions
+        All-in-one 'D' and 'F' commands to DUMP and FLASH BIN files
+            Lots of checking for errors, either works or says it failed
+            No need to interpret the cryptic CAN messages anymore
+        Should now work for T5.2 and T5.5 ECUs
+        Detects FLASH chip type and works out which ECU is connected T5.2/5.5
+
+********************************************************************************
+
+Version 1 (04/2010)- The basic CAN functions are working
 
 I have decided to 'release' this software somewhat prematurely because the FLASH
 chips in my spare ECU have 'died' and I don't know when I will be able to do
@@ -51,63 +81,126 @@
 *******************************************************************************/
 
 #include "mbed.h"
-
-#include "strings.h"
-#include "BDM.h"
-#include "CAN232.h"
-#include "Trionic5.h"
-
-Serial pc(USBTX, USBRX); // tx, rx
+//
+#include "common.h"
+#include "bdm.h"
+#include "can232.h"
+#include "t5can.h"
 
-#define CR 0x0D
-#define NL 0x0A
-#define BELL 0x07
+// constants
+#define CMD_BUF_LENGTH      32              ///< command buffer size
 
-#define TRUE 1
-#define FALSE 0
+// static variables
+static char cmd_buffer[CMD_BUF_LENGTH];     ///< command string buffer
 
-void ShowHelp();
+// private functions
+uint8_t execute_just4trionic_cmd();
+void show_just4trionic_help();
 
 int main() {
     // fast serial speed
 //    pc.baud(921600);
     pc.baud(115200);
-    // make plenty of space for command from RS232
-    char command[5];
-    ShowHelp();
-    while (1) {
-// Only get 2 characters, the command and \r
-// For now I cannot work out how to use gets() so only single characters
-// can be used for commands :-(
-//
-// At the moment only option '5' does anything - the Trionic5 functions
-//
-        pc.gets(command,2);
-        int len = strlen(command);
-        if (len != 1) 
-            printf ("\a");
-        else if (ToUpper(command[0]) == 'B')
-            BDM();
-        else if (ToUpper(command[0]) == 'O')
-            CAN232();
-        else if (ToUpper(command[0]) == '5')
-            Trionic5();
-        else if (ToUpper(command[0]) == 'H')
-            ShowHelp();
-//  Unrecognised so ring the BELL :(
-        else
-            printf ("\a");
+
+    // the address of the function to be attached (leds_off) and the interval (0.1 seconds)
+    // This 'ticker' turns off the activity LEDs so that they don't stay on if something has gone wrong
+    ticker.attach(&leds_off, 0.1);
+
+    // clear incoming buffer
+    // sometimes TeraTerm gets 'confused'. johnc does this in his code
+    // hopefully this will fix the problem
+    // unfortunately it doesn't, but it seems like a good idea
+    char rx_char;
+    while (pc.readable())
+        rx_char = pc.getc();
+
+    show_just4trionic_help();
+
+    // main loop
+    *cmd_buffer = '\0';
+    char ret;
+    while (true) {
+        // read chars from USB
+        // send received messages to the pc over USB connection
+        // This function displays any CAN messages that are 'missed' by the other functions
+        // Can messages might be 'missed' because they are received after a 'timeout' period
+        // or because they weren't expected, e.g. if the T5 ECU resets for some reason
+        t5_can_show_can_message();
+        if (pc.readable()) {
+            // turn Error LED off for next command
+            led4 = 0;
+            rx_char = pc.getc();
+            switch (rx_char) {
+                    // end-of-command reached
+                case TERM_OK :
+                    // execute command and return flag via USB
+                    timer.reset();
+                    timer.start();
+                    ret = execute_just4trionic_cmd();
+                    show_just4trionic_help();
+                    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;
+            }
+        }
     }
 }
 
-void ShowHelp() {
+//-----------------------------------------------------------------------------
+/**
+    Executes a command and returns result flag (does not transmit the flag
+    itself).
+
+    @return                    command flag (success / failure)
+*/
+uint8_t execute_just4trionic_cmd() {
+
+
+//    uint8_t cmd_length = strlen(cmd_buffer);
+    // command groups
+    switch (*cmd_buffer) {
+//            CHECK_ARGLENGTH(0);
+        case 'b':
+        case 'B':
+            bdm();
+            return TERM_OK;
+        case 'o':
+        case 'O':
+            can232();
+            return TERM_OK;
+        case '5':
+            t5_can();
+            return TERM_OK;
+        case 'h':
+        case 'H':
+            return TERM_OK;
+        default:
+            break;
+    }
+
+// unknown command
+    return TERM_ERR;
+}
+
+void show_just4trionic_help() {
     printf("Just4Trionic Command Menu\r\n");
     printf("=========================\r\n");
-    printf("b/B - Start BDM interface (NOT DONE)\r\n");
-    printf("o/O - Open Lawicel CAN232 type interface (NOT DONE)\r\n");
+    printf("b/B - Start BDM interface\r\n");
+    printf("o/O - Open Lawicel CAN232 type interface\r\n");
     printf("5   - Start Trionic5 ECU CAN interface\r\n");
     printf("\r\n");
     printf("h/H - show this help menu\r\n");
+    printf("\r\n");
     return;
-}
-
+}
\ No newline at end of file
--- a/mbed.bld	Wed May 19 12:39:18 2010 +0000
+++ b/mbed.bld	Tue Sep 14 21:02:04 2010 +0000
@@ -1,1 +1,1 @@
-http://mbed.org/users/mbed_official/code/mbed/builds/49a220cc26e0
+http://mbed.org/users/mbed_official/code/mbed/builds/9114680c05da
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sizedefs.h	Tue Sep 14 21:02:04 2010 +0000
@@ -0,0 +1,42 @@
+/*******************************************************************************
+
+sizedefs.h - definitions of types used in Just4Trionic by Just4pLeisure
+(c) 2010 by Sophie Dexter
+portions (c) 2009, 2010 by Janis Silins (johnc)
+
+A derivative work based on:  
+ * sizedefs.h - define parameter types for BDM package
+ * Copyright (C) 1992 by Scott Howard, all rights reserved
+ * Permission is hereby granted to freely copy and use this code or derivations thereof
+ * as long as no charge is made to anyone for its use
+ *
+ * this file defines the types BYTE, WORD, and LONG to declare types
+ * that match the data sizes used in the target microcontroller(s)
+ * BYTE is one byte, WORD is two bytes, LONG is 4 bytes
+ * these are all unsigned quantities
+ * change these definitions if you are using a compiler with different default sizes
+ */
+
+/*******************************************************************************
+
+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 __SIZEDEFS_H__
+#define __SIZEDEFS_H__
+
+#define BYTE unsigned char
+// For MBED / ARM Cortex3 use 'unsigned short' for WORD (2 bytes)
+#define WORD unsigned short
+#define LONG unsigned long
+
+#define uint8_t unsigned char
+#define uint16_t unsigned short
+#define uint32_t unsigned long
+
+#endif
+
+/* end of sizedefs.h */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/srecutils.cpp	Tue Sep 14 21:02:04 2010 +0000
@@ -0,0 +1,54 @@
+/*******************************************************************************
+
+srecutils.h
+(c) 2010 by Sophie Dexter
+
+Functions for manipulating Motorala S-records
+
+********************************************************************************
+
+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 "srecutils.h"
+
+// SRecGetByte
+//
+// Returns an int which is a single byte made up from two ascii characters read from an S-record file
+//
+// inputs:    a file pointer for the S-record file
+// return:    an integer which is the byte in hex format
+
+int SRecGetByte(FILE *fp) {
+    int c = 0;
+    int retbyte = 0;
+
+    for(int i=0; i<2; i++) {
+        if ((c = fgetc(fp)) == EOF) return -1;
+        c -= (c > '9') ? ('A' - 10) : '0';
+        retbyte = (retbyte << 4) + c;
+    }
+    return retbyte;
+}
+
+// SRecGetAddress
+//
+// Returns an int which is the address part of the S-record line
+// The S-record type 1/2/3 or 9/8/7 determines if there are 2, 3 or 4 bytes in the address
+//
+// inputs:    an integer which is the number of bytes that make up the address; 2, 3 or 4 bytes
+//            a file pointer for the S-record file
+// return:    an integer which is the load address for the S-record
+
+int SRecGetAddress(int size, FILE *fp) {
+    int address = 0;
+    for (int i = 0; i<size; i++)
+    {
+        address <<= 8;
+        address |= SRecGetByte (fp);
+    }
+    return address;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/srecutils.h	Tue Sep 14 21:02:04 2010 +0000
@@ -0,0 +1,19 @@
+/*******************************************************************************
+
+srecutils.h - information and definitions needed for working with S-Records
+(c) 2010 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.
+
+*******************************************************************************/
+
+#include "mbed.h"
+
+#include "common.h"
+
+extern int SRecGetByte(FILE *fp);
+extern int SRecGetAddress(int size, FILE *fp);
--- a/strings.cpp	Wed May 19 12:39:18 2010 +0000
+++ b/strings.cpp	Tue Sep 14 21:02:04 2010 +0000
@@ -1,6 +1,7 @@
 /*******************************************************************************
 
-Strings.cpp - By Sophie Dexter, April 2010
+strings.cpp 
+(c) 2010 by Sophie Dexter
 
 This C++ module provides functions for working with 'strings' of ascii 'char's
 
@@ -15,6 +16,7 @@
 accept liability for any damage arising from its use.
 
 *******************************************************************************/
+
 #include "strings.h"
 
 // copies a string, s2, (array of chars) to another string, s1.
@@ -81,4 +83,81 @@
         s++;
     }
     return s;
-}
\ No newline at end of file
+}
+
+// StrAddc    adds a single char to the end of a string
+
+char *StrAddc (char *s, const char c) {
+  char *s1 = s;
+
+// Find the end of the string 's'
+  while (*s)
+    *s++;
+// add the new character
+  *s++ = c;
+// put the end of string character at its new position
+  *s = '\0';
+  return s1;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Converts an ASCII character to low nibble of a byte.
+
+    @param        rx_byte            character to convert
+    
+    @return                        resulting value            
+*/
+uint8_t ascii2nibble(char str)
+{
+    return str >= 'a' ? (str - 'a' + 10) & 0x0f :
+        (str >= 'A' ? (str - 'A' + 10) & 0x0f :
+        (str - '0') & 0x0f);
+}
+
+//-----------------------------------------------------------------------------
+/**
+    Converts an ASCII string to integer (checks string contents beforehand).
+
+    @param        val                destination integer
+    @param        str                pointer to source string
+    @param        length            length of source string
+
+    @return                        succ / fail
+*/
+bool ascii2int(uint32_t* val, const char* str, uint8_t length)
+{
+    // nothing to convert
+    if (!str || length < 1)
+    {
+        *val = 0;
+        return false;
+    }
+
+    // check string contents
+    uint8_t shift;
+    for (shift = 0; shift < length; ++shift)
+    {
+        if (!isxdigit(*(str + shift)))
+        {
+            // not a hex value
+            *val = 0;
+            return false;    
+        } 
+    }
+
+    // convert string
+    *val = ascii2nibble(*(str++));
+    for (shift = 1; shift < length; ++shift)
+    {
+        *val <<= 4;
+        *val += ascii2nibble(*(str++));
+    }
+    return true;
+}
+
+int isxdigit ( int ch )
+{
+    return (unsigned int)( ch         - '0') < 10u  ||
+           (unsigned int)((ch | 0x20) - 'a') <  6u;
+}
--- a/strings.h	Wed May 19 12:39:18 2010 +0000
+++ b/strings.h	Tue Sep 14 21:02:04 2010 +0000
@@ -1,12 +1,27 @@
+/*******************************************************************************
 
-// strings.h - information and definitions needed for working with strings of characters (ascii 'char')
+strings.h - information and definitions needed for working with strings of
+characters (ascii 'char') 
+(c) 2010 by Sophie Dexter
+
+********************************************************************************
 
-#define TRUE 1
-#define FALSE 0
+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 "common.h"
+#include "sizedefs.h"
 
 extern char *StrCpy(char *s1, char *s2);
 extern int StrLen(char *s);
 extern bool StrCmp(char *s1, char *s2);
 extern char ToUpper(char c);
 extern char ToLower(char c);
-extern char *aToh(char *s);
\ No newline at end of file
+extern char *aToh(char *s);
+extern char *StrAddc (char *s, const char c);
+extern uint8_t ascii2nibble(char str);
+extern bool ascii2int(uint32_t* val, const char* str, uint8_t length);
+extern int isxdigit ( int ch );
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/t5can.cpp	Tue Sep 14 21:02:04 2010 +0000
@@ -0,0 +1,1020 @@
+/*******************************************************************************
+
+trionic5.cpp - CAN Bus functions for Just4Trionic by Just4pLeisure
+(c) 2010 by Sophie Dexter
+
+This C++ module provides functions for reading and writing the FLASH chips and
+SRAM in Trionic5 ECUs. (Writing the adaption data back to SRAM not done yet).
+
+Some functions need an additional 'bootloader' program to be sent to the T5 ECU
+before they can be used. These functions are: Identifying the T5 ECU type and
+FLASH chips, dumping the FLASH chips, erasing the FLASH chips, writing to the
+FLASH chips and calculating the FLASH chips' checksum.
+
+My version of the bootloader, BOOTY.S19, includes some features not in other
+bootloaders; identifying the ECU and FLASH chip types, a 'safer' way of dumping
+the FLASH chips and the ability to program AMD 29F010 type FLASH chips
+
+********************************************************************************
+
+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 "t5can.h"
+
+// constants
+#define CMD_BUF_LENGTH      32              ///< command buffer size
+
+// 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
+
+static uint32_t flash_start = 0;
+
+// private functions
+uint8_t execute_t5_cmd();
+void t5_can_show_help();
+void t5_can_show_full_help();
+
+void t5_can() {
+    // Start the CAN bus system
+    // Note that at the moment this is only for T5 ECUs at 615 kbits
+    can_open();
+    can_set_speed(615000);
+
+    t5_can_show_help();
+
+    // main loop
+    *cmd_buffer = '\0';
+    char ret;
+    char rx_char;
+    while (true) {
+        // read chars from USB
+        // send received messages to the pc over USB connection
+        // This function displays any CAN messages that are 'missed' by the other functions
+        // Can messages might be 'missed' because they are received after a 'timeout' period
+        // or because they weren't expected, e.g. if the T5 ECU resets for some reason
+        t5_can_show_can_message();
+        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':
+                    can_close();
+                    return;
+                    // end-of-command reached
+                case TERM_OK :
+                    // execute command and return flag via USB
+                    timer.reset();
+                    timer.start();
+                    ret = execute_t5_cmd();
+                    pc.putc(ret);
+                    printf("Completed in %.1f seconds.\r\n", timer.read());
+                    // 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_t5_cmd() {
+
+
+//    uint8_t cmd_length = strlen(cmd_buffer);
+    // command groups
+    switch (*cmd_buffer) {
+//            CHECK_ARGLENGTH(0);
+            // Get the Symbol Table
+        case 's':
+            return t5_can_get_symbol_table()
+                   ? TERM_OK : TERM_ERR;
+        case 'S':
+            return T5ReadCmnd(T5SYMBOLS)
+                   ? TERM_OK : TERM_ERR;
+
+            // Get the Trionic5 software version string
+        case 'v':
+            return t5_can_get_version()
+                   ? TERM_OK : TERM_ERR;
+        case 'V':
+            return T5ReadCmnd(T5VERSION)
+                   ? TERM_OK : TERM_ERR;
+
+            // Read Adaption Data from RAM and write it to a file
+        case 'r':
+        case 'R':
+            return t5_can_get_adaption_data()
+                   ? TERM_OK : TERM_ERR;
+
+            // CR - send CR type message
+        case '\0':
+            return T5ReadCmnd(CR)
+                   ? TERM_OK : TERM_ERR;
+
+            //  Get a single symbol from the Symbol Table
+        case 'a':
+            char symbol[40];
+            T5GetSymbol(symbol);
+            printf("%s",symbol);
+            return TERM_OK;
+
+            // Just send an 'ACK' message
+        case 'A':
+            return T5Ack()
+                   ? TERM_OK : TERM_ERR;
+
+            // Send a Bootloader file to the T5 ECU
+        case 'b':
+        case 'B':
+            return t5_can_send_boot_loader()
+                   ? TERM_OK : TERM_ERR;
+
+            // Get Checksum from ECU (Bootloader must be uploaded first)
+        case 'c':
+        case 'C':
+            return t5_can_get_checksum()
+                   ? TERM_OK : TERM_ERR;
+
+            // Exit the BootLoader and restart the T5 ECU
+        case 'q':
+        case 'Q':
+            return t5_can_bootloader_reset()
+                   ? TERM_OK : TERM_ERR;
+
+            // Erase the FLASH chips
+        case 'e':
+        case 'E':
+            return t5_can_erase_flash()
+                   ? TERM_OK : TERM_ERR;
+
+            // Read back the FLASH chip types
+        case 't':
+        case 'T':
+            return t5_can_get_start_and_chip_types(&flash_start)
+                   ? TERM_OK : TERM_ERR;
+
+            // DUMP the T5 ECU BIN file stored in the FLASH chips
+        case 'd':
+            // NOTE 'd' command Just4TESTING! only dumps T5.5 ECU
+            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())
+                return TERM_ERR;
+            if (!t5_can_get_start_and_chip_types(&flash_start)) {
+                t5_can_bootloader_reset();
+                return TERM_ERR;
+            }
+            return (t5_can_dump_flash(flash_start) && t5_can_bootloader_reset())
+                   ? TERM_OK : TERM_ERR;
+
+            // 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)
+                   ? TERM_OK : TERM_ERR;
+        case 'F':
+            if (!t5_can_send_boot_loader())
+                return TERM_ERR;
+            if (!t5_can_get_start_and_chip_types(&flash_start)) {
+                t5_can_bootloader_reset();
+                return TERM_ERR;
+            }
+            if (!t5_can_get_checksum())
+                led4 = 1;
+            if (!t5_can_erase_flash()) {
+                t5_can_bootloader_reset();
+                return TERM_ERR;
+            }
+            return (t5_can_send_flash_bin_update(flash_start) && t5_can_get_checksum() && t5_can_bootloader_reset())
+                   ? TERM_OK : TERM_ERR;
+
+            // Send the C3 message - should get last used address 0x7FFFF
+        case '3':
+            return t5_can_get_last_address()
+                   ? TERM_OK : TERM_ERR;
+
+            // Print help
+        case 'h':
+            t5_can_show_help();
+            return TERM_OK;
+        case 'H':
+            t5_can_show_full_help();
+            return TERM_OK;
+        default:
+            t5_can_show_help();
+            break;
+    }
+    // unknown command
+    return TERM_ERR;
+}
+
+//
+// Trionic5ShowHelp
+//
+// Displays a list of things that can be done with the T5 ECU.
+//
+// inputs:    none
+// return:    none
+//
+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("\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");
+    printf("v - read T5 ECU software version, display it and write it to VERSION.TXT\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;
+}
+//
+// t5_can_show_full_help
+//
+// Displays a complete list of things that can be done with the T5 ECU.
+//
+// inputs:    none
+// return:    none
+//
+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("\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("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");
+    printf("q - exit the bootloader and reset the T5 ECU\r\n");
+    printf("t - read the FLASH chip type in the T5 ECU\r\n");
+    printf("3 - read the last used FLASH address in the T5 ECU\r\n");
+    printf("S - send 's' message (to get symbol table)\r\n");
+    printf("V - send 'S' message (to get software version)\r\n");
+    printf("'Enter' Key - send an CR message\r\n");
+    printf("a - send an ACK\r\n");
+    printf("A - read a single symbol from the symbol table\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;
+}
+
+//
+// t5_can_show_can_message
+//
+// Displays a CAN message in the RX buffer if there is one.
+//
+// inputs:    none
+// return:    bool TRUE if there was a message, FALSE if no 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);
+        for (char i=0; i<can_MsgRx.len; i++) {
+            printf("%02x", can_MsgRx.data[i]);
+        }
+        printf(" %c ", can_MsgRx.data[2]);
+        printf("\r\n");
+        return TRUE;
+    }
+    return FALSE;
+}
+
+//
+// t5_can_get_symbol_table
+//
+// Gets the T5 ECU symbol table.
+// The Symbol Table is saved to a file, symbols.txt, on the mbed 'local' file system 'disk'.
+//
+// inputs:    none
+// return:    bool TRUE if there all went OK, FALSE if there was an error
+//
+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) {
+        perror ("The following error occured");
+        return FALSE;
+    }
+    char symbol[40];
+    T5ReadCmnd(T5SYMBOLS);
+    if (T5WaitResponse() != '>') {
+        fclose(fp);
+        return FALSE;
+    }
+    T5ReadCmnd(CR);
+    if (T5WaitResponse() != '>') {
+        fclose(fp);
+        return FALSE;
+    }
+    do {
+        T5GetSymbol(symbol);
+//        printf("%s",symbol);
+        if (fprintf(fp,"%s",symbol) < 0) {
+            fclose (fp);
+            printf ("ERROR Writing to the symbols.txt file!\r\n");
+            return FALSE;
+        };
+    } while (!StrCmp(symbol,"END\r\n"));
+    fclose(fp);
+    return TRUE;
+}
+
+//
+// t5_can_get_version
+//
+// Gets the T5 software version string.
+// The software version is is sent to the PC and saved to a file, version.txt, on the mbed 'local' file system 'disk'.
+//
+// inputs:    none
+// return:    bool TRUE if there all went OK, FALSE if there was an error
+//
+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");
+        return FALSE;
+    }
+    char symbol[40];
+    T5ReadCmnd(T5VERSION);
+    if (T5WaitResponse() != '>') {
+        fclose(fp);
+        return FALSE;
+    }
+    T5ReadCmnd(CR);
+    if (T5WaitResponse() != '>') {
+        fclose(fp);
+        return FALSE;
+    }
+    T5GetSymbol(symbol);
+    printf("%s",symbol);
+    if (fprintf(fp,"%s",symbol) < 0) {
+        fclose (fp);
+        printf ("ERROR Writing to the version.txt file!\r\n");
+        return FALSE;
+    };
+    fclose(fp);
+    printf("The version.txt file has been saved.\r\n");
+    return TRUE;
+}
+
+//
+// Trionic5GetAdaptionData
+//
+// Gets the adaption data from the T5's SRAM.
+// The adaption data is stored in a hex file, adaption.RAM, on the mbed 'local' file system 'disk'.
+//
+// Reading the Adaption data from SRAM takes about 6.5 seconds.
+//
+// inputs:    none
+// return:    bool TRUE if all went OK, FALSE if there was an error.
+//
+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) {
+        printf("ERROR: Unable to open a file for the adaption data!\r\n");
+        return FALSE;
+    }
+    unsigned int address = 5;                       // Mysterious reason for starting at 5 !!!
+    char RAMdata[6];
+    while (address < T5RAMSIZE) {
+        if (!t5_can_read_data(RAMdata, address)) {
+            fclose (fp);
+            printf ("Error reading from the CAN bus.\r\n");
+            return FALSE;
+        }
+        address += 6;
+        if (fwrite(RAMdata, 1, 6, fp) != 6) {
+            fclose (fp);
+            printf ("Error writing to the SRAM adaption file.\r\n");
+            return FALSE;
+        }
+    }
+    // There are a few more bytes to get because because the SRAM file is not an exact multiple of 6 bytes!
+    // the % (modulo) mathematics function tells us how many bytes there are still to get
+    if (!t5_can_read_data(RAMdata, (T5RAMSIZE - 1))) {
+        fclose (fp);
+        printf ("Error reading from the CAN bus.\r\n");
+        return FALSE;
+    }
+    if (fwrite((RAMdata + 6 - (T5RAMSIZE % 6)), 1, (T5RAMSIZE % 6), fp) != (T5RAMSIZE % 6)) {
+        fclose (fp);
+        printf ("Error writing to the SRAM adaption file.\r\n");
+        return FALSE;
+    }
+    fclose(fp);
+    return TRUE;
+}
+
+//
+// t5_can_send_boot_loader
+//
+// 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() {
+    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) {
+        printf("Error: I could not find the bootloader file MyBooty.S19\r\n");
+        return FALSE;
+    }
+    int c = 0; // for some reason fgetc returns an int instead of a char
+    uint8_t count = 0; // count of bytes in the S-record can be 0xFF = 255 in decimal
+    uint8_t asize = 0; // 2,3 or 4 bytes in address
+    uint32_t address = 0; // address to put S-record
+    uint8_t checksum = 0; // checksum check at the end of each S-record line
+    char msg[8]; // Construct the bootloader frame for uploading
+    bool sent = FALSE;
+
+    while (!sent) {
+// get characters until we get an 'S' (throws away \n,\r characters and other junk)
+        do c = fgetc (fp);
+        while (c != 'S' && c != EOF);
+//                if (c == EOF) return '\a';
+        c = fgetc(fp);        // get the S-record type 1/2/3 5 7/8/9 (Return if EOF reached)
+//                if ((c = fgetc(fp)) == EOF) return '\a';        // get the S-record type 1/2/3 5 7/8/9 (Return if EOF reached)
+        switch (c) {
+            case '0':
+                break;                  // Skip over S0 header record
+
+            case '1':
+            case '2':
+            case '3':
+                asize = 1 + 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 at least the address and the checksum so return with an error if less than this!
+                if ((c = SRecGetByte(fp)) < (asize + 1)) break;
+//                        if ((c = SRecGetByte(fp)) < 3) return '\a';
+                count = c;
+                checksum = c;
+// get the address
+                for (uint8_t i=0; i<asize; i++) {
+                    c = SRecGetByte(fp);
+                    checksum += c;
+                    address <<= 8;
+                    address |= c;
+                    count--;
+                }
+// send a bootloader address message
+                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
+// are repeated from the previous frame. This is OK because the T5 ECU knows how many bytes to expect (because the count of bytes
+// in the S-Record is sent with the upload address) and ignores any extra bytes in the last frame.
+                for (uint8_t i=0; i<count-1; i++) {
+                    c = SRecGetByte(fp);
+                    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 (!t5_can_send_boot_frame(msg)) {
+                            fclose(fp);
+                            return FALSE;
+                        }
+                }
+// get the checksum
+                if ((checksum += SRecGetByte(fp)) != 0xFF) {
+                    printf("Error in S-record, checksum = %2x\r\n", checksum);
+                    fclose(fp);
+                    return FALSE;
+                }
+                break;
+
+            case '5':
+                break;                  // Skip over S5 record types
+
+            case '7':
+            case '8':
+            case '9':
+                asize = 11 - (c - '0');  // 2, 3 or 4 bytes for address
+// 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;
+//                if ((c = SRecGetByte(fp)) < 3) return '\a';
+                checksum = c;
+// get the address
+                for (uint8_t i=0; i<asize; i++) {
+                    c = SRecGetByte(fp);
+                    checksum += c;
+                    address <<= 8;
+                    address |= c;
+                }
+// get the checksum
+                if ((checksum += SRecGetByte(fp)) != 0xFF) {
+                    fclose(fp);
+                    printf("Error in S-record, checksum = %2x\r\n", checksum);
+                    return FALSE;
+                }
+                T5StartBootLoader(address);
+//                T5WaitResponsePrint();
+                sent = TRUE;
+                break;
+
+// Some kind of invalid S-record type so break
+            default:
+                fclose(fp);
+                printf("oops - didn't recognise that S-Record \r\n");
+                return FALSE;
+        }
+    }
+    fclose(fp);
+    return TRUE;
+}
+
+//
+// t5_can_get_checksum
+//
+// Calculates the checksum of the FLASH in the T5 ECU.
+// The 'bootloader', booty.s19, must be loaded before this function can be used.
+// The 'bootloader' actually calculates the checksum and compares it with the
+// value stored in the 'header' region at the end of the FLASH.
+//
+// The bootloader sends a single CAN message with the result e.g.
+// w00C8C800CAFEBABE0808
+//  00C - T5 response messages have an CAN id of 00C
+//     8 - All T5 messages have a message length of 8 bytes
+//      C8 - This is the checksum message type
+//        00 - 00 means OK, the checksum calculation matches the stored value which in this case is:
+//          CAFEBABE - lol :-)
+//
+// w00C8C801FFFFFFFF0808
+//        01 - 01 means calculated value doesn't matched the stored value
+//          FFFFFFFF - in this case the stored value is FFFFFFFF - the chips might be erased
+//
+// Calculating the checksum takes a little under 2 seconds.
+//
+// inputs:    none
+// return:    bool TRUE if all went OK,
+//
+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");
+        return FALSE;
+    }
+    printf("The FLASH checksum value is %#010x.\r\n", checksum);
+    return TRUE;
+}
+
+//
+// t5_can_bootloader_reset
+//
+// Exit the Bootloader and restart the T5 ECU
+//
+// inputs:    none
+// outputs:    bool TRUE if all went OK.
+//
+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");
+        return FALSE;
+    }
+    return TRUE;
+}
+
+//
+// t5_can_get_start_and_chip_types
+//
+// Gets the FLASH chip type fitted.
+//
+// NOTE the bootloader must be loaded in order to use this function.
+//
+// CAN messages from the T5 ECU with FLASH data look like this:
+//
+// C9,00,aa,aa,aa,aa,mm,dd,
+//
+// C9 lets us know its a FLASH id message
+//
+// aa,aa,aa,aa is the FLASH start address which we can use to work out if this is a T5.2 or T5.5 ECU
+// 0x00020000 - T5.2
+// 0x00040000 - T5.5
+//
+// mm = Manufacturer id. These can be:
+// 0x89 - Intel
+// 0x31 - CSI/CAT
+// 0x01 - AMD
+// 0x1F - Atmel
+//
+// dd = Device id. These can be:
+// 0xB8 - Intel _or_ CSI 28F512 (Fiited by Saab in T5.2)
+// 0xB4 - Intel _or_ CSI 28F010 (Fitted by Saab in T5.5)
+// 0x25 - AMD 28F512 (Fiited by Saab in T5.2)
+// 0xA7 - AMD 28F010 (Fitted by Saab in T5.5)
+// 0x20 - AMD 29F010 (Some people have put these in their T5.5)
+// 0x5D - Atmel 29C512 (Some people mave have put these in their T5.2)
+// 0xD5 - Atmel 29C010 (Some people have put these in their T5.5)
+//
+// mm = 0xFF, dd == 0xF7 probably means that the programming voltage isn't right.
+//
+// Finding out which ECU type and FLASH chips are fitted takes under a second.
+//
+// inputs:    start     T5 ecu start address
+// return:    bool      TRUE if all went OK.
+//
+bool t5_can_get_start_and_chip_types(uint32_t* start) {
+    *start = 0;
+    uint8_t make = 0;
+    uint8_t type = 0;
+    if (!t5_boot_get_flash_type(start, &make, &type)) {
+        printf("Error trying to find out the ECU's first address and FLASH chip type!\r\n");
+        return FALSE;
+    }
+    printf("This is a T5.%s ECU with ", ((*start == T52FLASHSTART) ? "2" : "5"));
+    switch (make) {
+        case AMD:
+            printf("AMD ");
+            break;
+        case CSI:
+            printf("CSI ");
+            break;
+        case INTEL:
+            printf("INTEL ");
+            break;
+        default:
+            printf("UNKNOWN FLASH chips - check pin65 has enough volts!\r\n");
+    }
+    switch (type) {
+        case AMD28F512:
+        case INTEL28F512:
+            printf("28F512 FLASH chips.\r\n");
+            break;
+        case AMD28F010:
+        case INTEL28F010:
+            printf("28F010 FLASH chips.\r\n");
+            break;
+        case AMD29F010:
+            printf("29F010 FLASH chips.\r\n");
+            break;
+        default:
+            printf("UNKNOWN - check pin65 has enough volts!\r\n");
+            return FALSE;
+    }
+    return TRUE;
+}
+
+//
+// t5_can_erase_flash
+//
+// Erases the FLASH Chips.
+//
+// NOTE the bootloader must be loaded in order to use this function.
+//
+// CAN messages from the T5 ECU with FLASH erase command look like this:
+//
+// C0,cc,08,08,08,08,08,08
+//
+// C0 tells us this is a response to the FLASH erase command.
+//
+// cc is a code that tells us what happened:
+//      00 - FLASH was erased OK
+//      01 - Could not erase FLASH chips to 0xFF
+//      02 - Could not write 0x00 to 28F FLASH chips
+//      03 - Unrecognised FLASH chip type (or maybe programming voltage isn't right)
+//      04 - Intel chips found, but unrecognised type
+//      05 - AMD chips found, but unrecognised type
+//      06 - CSI/Catalyst chips found, but unrecognised type
+//      07 - Atmel chips found - Atmel chips don't need to be erased
+//
+// Erasing 28F type FLASH chips takes around 22 seconds. 29F chips take around 4 seconds.
+//
+// inputs:    none
+// return:    bool TRUE if all went OK.
+//
+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");
+        return FALSE;
+    }
+    return TRUE;
+}
+
+//
+// t5_can_dump_flash
+//
+// Dumps the FLASH chip BIN file, original.bin to the mbed 'disk'
+//
+// NOTE the bootloader must be loaded in order to use this function.
+//
+// Dumping FLASH chips in a T5.5 ECU takes around 35 seconds.
+// Dumping T5.2 ECUs should take about half of this time
+//
+// inputs:    start     start address of the T5.x FLASH
+
+// return:    bool TRUE if all went OK, FALSE if there was an error.
+//
+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) {
+        perror ("The following error occured");
+        return FALSE;
+    }
+    uint32_t address = start + 5;                  // Mysterious reason for starting at 5 !!!
+    char FLASHdata[6];
+    while (address < TRIONICLASTADDR) {
+        if (!t5_can_read_data(FLASHdata, address)) {
+            fclose (fp);
+            printf ("Error reading from the CAN bus.\r\n");
+            return FALSE;
+        }
+        address += 6;
+        if (fwrite(FLASHdata, 1, 6, fp) != 6) {
+            fclose (fp);
+            printf ("Error writing to the FLASH BIN file.\r\n");
+            return FALSE;
+        }
+    }
+    // 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
+    if (!t5_can_read_data(FLASHdata, (TRIONICLASTADDR))) {
+        fclose (fp);
+        printf ("Error reading from the CAN bus.\r\n");
+        return FALSE;
+    }
+    if (fwrite((FLASHdata + 6 - ((TRIONICLASTADDR - start +1) % 6)), 1, ((TRIONICLASTADDR - start +1) % 6), fp) != ((TRIONICLASTADDR - start +1) % 6)) {
+        fclose (fp);
+        printf ("Error writing to the FLASH BIN file.\r\n");
+        return FALSE;
+    }
+    fclose(fp);
+    return TRUE;
+}
+
+
+//
+// t5_can_send_flash_bin_update
+//
+// Sends a FLASH update file, modified.hex 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
+//
+// inputs:    start     start address of the T5.x FLASH
+
+// 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) {
+    printf("Programming the FLASH chips.\r\n");
+    FILE *fp = fopen("/local/modified.hex", "r");    // Open "modified.s19" on the local file system for reading
+    if (!fp) {
+        printf("Error: I could not find the BIN file MODIFIED.HEX\r\n");
+        return FALSE;
+    }
+
+    // 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
+    uint8_t stack_byte = 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;
+    rewind (fp);
+
+    if (start == T52FLASHSTART && (file_size != T52FLASHSIZE || stack_long != T5POINTER)) {
+        fclose(fp);
+        printf("The BIN file does not appear to be for a T5.2 ECU :-(\r\n");
+        printf("BIN file size: %#10x, FLASH chip size: %#010x, Pointer: %#10x.\r\n", file_size, T52FLASHSIZE, stack_long);
+        return TERM_ERR;
+    }
+    if (start == T55FLASHSTART && (file_size != T55FLASHSIZE || stack_long != T5POINTER)) {
+        fclose(fp);
+        printf("The BIN file does not appear to be for a T5.5 ECU :-(\r\n");
+        printf("BIN file size: %#10x, FLASH chip size: %#010x, Pointer: %#10x.\r\n", file_size, T55FLASHSIZE, stack_long);
+        return TERM_ERR;
+    }
+
+    char msg[8]; // Construct the bootloader frame for uploading
+    uint32_t curr_addr = start; // address to put FLASH data
+    uint8_t byte_value = 0;
+
+    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");
+            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
+// in the S-Record is sent with the upload address) and ignores any extra bytes in the last frame.
+        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");
+                return FALSE;
+            }
+            msg[1+(i%7)] = byte_value;
+            if (i%7 == 0) msg[0]=i;     // set the index number
+            if ((i%7 == 6) || (i == 0x80 - 1))
+                if (!t5_can_send_boot_frame(msg)) {
+                    fclose(fp);
+                    printf("Error sending CAN message");
+                    return FALSE;
+                }
+        }
+    }
+    fclose(fp);
+    return TRUE;
+}
+
+//
+// t5_can_send_flash_s19_update
+//
+// Sends a FLASH update file, modified.s19 to the T5 ECU.
+// The FLASH update file is stored on the local file system and must be in S19 format.
+//
+// FLASHing a T5.5 ECU takes around 60 seconds. FLASHing T5.2 ECUs should take about half of this time
+//
+// inputs:    start     start address of the T5.x FLASH
+
+// 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) {
+    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) {
+        printf("Error: I could not find the BIN file MODIFIED.S19\r\n");
+        return FALSE;
+    }
+    int c = 0; // for some reason fgetc returns an int instead of a char
+    uint8_t count = 0; // count of bytes in the S-record can be 0xFF = 255 in decimal
+    uint8_t asize = 0; // 2,3 or 4 bytes in address
+    uint32_t address = 0; // address to put S-record
+    uint8_t checksum = 0; // checksum check at the end
+    char msg[8]; // Construct the bootloader frame for uploading
+    bool sent = FALSE;
+
+    while (!sent) {
+
+        do c = fgetc (fp); // get characters until we get an 'S' (throws away \n,\r characters and other junk)
+        while (c != 'S' && c != EOF);
+//                if (c == EOF) return '\a';
+        c = fgetc(fp);        // get the S-record type 1/2/3 5 7/8/9 (Return if EOF reached)
+//                if ((c = fgetc(fp)) == EOF) return '\a';        // get the S-record type 1/2/3 5 7/8/9 (Return if EOF reached)
+        switch (c) {
+            case '0':
+                break;                  // Skip over S0 header record
+
+            case '1':
+            case '2':
+            case '3':
+                asize = 1 + 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 at least the address and the checksum so return with an error if less than this!
+                if ((c = SRecGetByte(fp)) < (asize + 1)) {
+                    fclose(fp);
+                    printf("Error in S-record address");
+                    return FALSE;
+                }
+                count = c;
+                checksum = c;
+// get the address
+                for (uint8_t i=0; i<asize; i++) {
+                    c = SRecGetByte(fp);
+                    checksum += c;
+                    address <<= 8;
+                    address |= c;
+                    count--;
+                }
+// send a bootloader address message - Adding the start address that was supplied (for T5.2/T5.5)
+                if (!t5_can_send_boot_address((address + start), (count - 1))) {
+                    fclose(fp);
+                    printf("Error sending CAN message");
+                    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
+// are repeated from the previous frame. This is OK because the T5 ECU knows how many bytes to expect (because the count of bytes
+// in the S-Record is sent with the upload address) and ignores any extra bytes in the last frame.
+                for (uint8_t i=0; i<count-1; i++) {
+                    c = SRecGetByte(fp);
+                    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 (!t5_can_send_boot_frame(msg)) {
+                            fclose(fp);
+                            printf("Error sending CAN message");
+                            return FALSE;
+                        }
+                }
+// get the checksum
+                if ((checksum += SRecGetByte(fp)) != 0xFF) {
+                    fclose(fp);
+                    printf("Error in S-record, checksum = %2x\r\n", checksum);
+                    return FALSE;
+                }
+                break;
+
+            case '5':
+                break;                  // Skip over S5 record types
+
+            case '7':
+            case '8':
+            case '9':
+                sent = TRUE;
+                break;
+
+// Some kind of invalid S-record type so break
+            default:
+                printf("oops - didn't recognise that S-Record\r\n");
+                fclose(fp);
+                return FALSE;
+        }
+    }
+    fclose(fp);
+    return TRUE;
+}
+
+//
+// t5_can_get_last_address
+//
+// Sends a C3 Message to the T5 ECU. The reply should contain the last used FLASH address
+// which is always 0x0007FFFF
+//
+// The last 2 bytes of the message might be useful to work out whether or not the bootloader
+// has been loaded. The 'mode' value will be 0x0808 when the bootloader is running or 0x89b8
+// when it isn't.
+//
+// inputs:    none
+// return:    bool TRUE if all went OK,
+//
+bool t5_can_get_last_address() {
+    uint32_t last_address = 0;
+    uint16_t mode = 0;
+    if (!t5_boot_c3_command(&last_address, &mode)) {
+        printf("Error trying to find out the ECU's last address and mode!\r\n");
+        return FALSE;
+    }
+    printf("The Last used FLASH address is: %#010x, mode %#06x\r\n", last_address, mode);
+    return TRUE;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/t5can.h	Tue Sep 14 21:02:04 2010 +0000
@@ -0,0 +1,46 @@
+/*******************************************************************************
+
+t5can.h - information and definitions needed for doing things with the T5 ECU
+(c) 2010 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 __T5CAN_H__
+#define __T5CAN_H__
+
+#include "mbed.h"
+#include "CAN.h"
+
+#include "common.h"
+#include "strings.h"
+#include "t5utils.h"
+#include "srecutils.h"
+
+#define T5SYMBOLS 'S'
+#define T5VERSION 's'
+#define T5WRITE 'W'
+
+extern void t5_can();
+
+void t5_can_show_help();
+bool t5_can_show_can_message();
+bool t5_can_get_symbol_table();
+bool t5_can_get_version();
+bool t5_can_get_adaption_data();
+bool t5_can_send_boot_loader();
+bool t5_can_get_checksum();
+bool t5_can_bootloader_reset();
+bool t5_can_get_start_and_chip_types(uint32_t* start);
+bool t5_can_erase_flash();
+bool t5_can_dump_flash(uint32_t start);
+bool t5_can_send_flash_s19_update(uint32_t start);
+bool t5_can_send_flash_bin_update(uint32_t start);
+bool t5_can_get_last_address();
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/t5utils.cpp	Tue Sep 14 21:02:04 2010 +0000
@@ -0,0 +1,411 @@
+/*******************************************************************************
+
+t5utils.cpp
+(c) 2010 by Sophie Dexter
+
+This C++ module provides functions for communicating simple messages to and from
+the T5 ECU
+
+********************************************************************************
+
+WARNING: Use at your own risk, sadly this software comes with no guarantees.
+This software is provided 'free' and in good faith, but the author does not
+accept liability for any damage arising from its use.
+
+*******************************************************************************/
+
+#include "t5utils.h"
+
+//
+// T5Open enables the CAN chip and sets the CAN speed to 615 kbits.
+//
+// This function is a 'quick fix' for now.
+//
+// inputs:    none
+// return:    bool TRUE if all went OK,
+//
+bool T5Open() {
+    can_open ();
+    return TRUE;
+}
+
+//
+// T5Close disables the CAN chip.
+//
+// This function is a 'quick fix' for now.
+//
+// inputs:    none
+// return:    bool TRUE if all went OK,
+//
+bool T5Close() {
+    can_close ();
+    return TRUE;
+}
+
+//
+// T5WaitResponse
+//
+// Waits for a response message with the correct message id from the T5 ECU.
+// The response is a single ascii character from the symboltable.
+//
+// Returns an error ('BELL' character) if:
+//      a response is not received before the timeout
+//      the message length is less than 8 bytes (all messages should be 8 bytes)
+//      the message type is incorrect
+//
+// inputs:    none
+// return:    a single char that is the response from the T5 ECU
+//
+char T5WaitResponse() {
+    char T5RxMsg[8];
+    if (!can_wait_timeout(RESPID, T5RxMsg, 8, T5MESSAGETIMEOUT)) return '\a';
+    if (T5RxMsg[0] != 0xC6) return '\a';
+    return T5RxMsg[2];
+}
+
+//
+//
+// T5WaitResponsePrint
+//
+// Waits for a response message with the correct message id from the T5 ECU and displays the whole message:
+//
+// wiiildddddddddddddddd
+//  iii - is the CAN message id
+//     l - is the message length, should always be 8 for T5 messages
+//      dd,dd,dd,dd,dd,dd,dd,dd are the CAN message data bytes
+//
+// Returns an error if:
+//      a response is not received before the timeout
+//      the message length is less than 8 bytes (all messages should be 8 bytes)
+//      the message type is incorrect
+//
+// Inputs:    none
+// return:    bool TRUE if a qualifying message was received
+//                 FALSE if a message wasn't received in time, had the wrong id etc...
+//
+bool T5WaitResponsePrint() {
+    char T5RxMsg[8];
+    if (!can_wait_timeout(RESPID, T5RxMsg, 8, T5MESSAGETIMEOUT)) return FALSE;
+    printf("w%03x8", RESPID);
+    for (char i=0; i<8; i++) {
+        printf("%02x", T5RxMsg[i]);
+    }
+    printf("\n\r");
+    return TRUE;
+}
+
+// T5GetSymbol
+//
+// Reads a single symbol name (in the symbol table) from the T5 ECU.
+// T5GetSymbol sends ACK messages to the T5 ECU and stores the
+// reply characters in a string until a '\n' character is received
+// when the function returns with the pointer to that string.
+//
+// inputs:    a pointer to the string used to store the symbol name.
+// return:    a pointer to the string used to store the symbol name.
+//
+char *T5GetSymbol(char *s) {
+    do {
+        if (T5Ack()) {
+        }
+        *s = T5WaitResponse();
+    } while (*s++ != '\n');
+    *s = '\0';
+    return s;
+}
+
+// T5ReadCmnd
+//
+// Sends a 'read' type command to the T5 ECU. 'read' commands are used to read something from the T5 ECU.
+//
+// inputs:    a 'char' which is the type of 'read' requested (e.g. symbol table, version etc).
+// return:    bool TRUE if the message was sent within the timeout period,
+//                 FALSE if the message couldn't be sent.
+//
+bool T5ReadCmnd(char c) {
+    char T5TxMsg[] = T5_RDCMND;
+    T5TxMsg[1] = c;
+    return (can_send_timeout (CMNDID, T5TxMsg, 8, T5MESSAGETIMEOUT));
+}
+
+//
+// T5WriteCmnd is unfinished
+//
+bool T5WriteCmnd(unsigned int addr, char data) {
+    return FALSE;
+}
+
+
+
+// t5_can_read_data
+//
+// Reads 6 bytes of the data from the SRAM or FLASH in the T5 ECU.
+//
+// There is something back-to-front about the way this works, but it does :-)
+//
+// inputs:    a pointer to an array of 6 bytes for storing the data read from the T5 ECU.
+//            the address to read SRAM data from in the T5 ECU
+// return:    a pointer to an array of 6 bytes for storing the data read from the T5 ECU.
+//            bool TRUE if the message was sent within the timeout period,
+//                 FALSE if the message couldn't be sent.
+//
+bool t5_can_read_data(char *data, uint32_t addr) {
+
+    // send a can message to the T5 with the address we want to read from
+    char T5TxMsg[] = T5RAMCMND;
+    T5TxMsg[1] = ((uint8_t)(addr >> 24));         // high high byte of address
+    T5TxMsg[2] = ((uint8_t)(addr >> 16));         // high low byte of address
+    T5TxMsg[3] = ((uint8_t)(addr >> 8));          // low high byte of address
+    T5TxMsg[4] = ((uint8_t)(addr));               // low low byte of address
+    // if the message cannot be sent then there is a problem
+    if (!can_send_timeout (CMNDID, T5TxMsg, 8, T5MESSAGETIMEOUT))
+        return FALSE;
+    // wait for the T5 to reply with some data
+    char T5RxMsg[8];
+    // if a message is not received, has the wrong type or indicates an error then there is a problem
+    if ((!can_wait_timeout(RESPID, T5RxMsg, 8, T5MESSAGETIMEOUT)) || (T5RxMsg[0] != T5TxMsg[0]) || (T5RxMsg[1] != 0x00))
+        return FALSE;
+    for (int i=2; i<8; i++)
+        data[7-i] = T5RxMsg[i];
+    return TRUE;
+}
+
+// T5Ack
+//
+// Sends an 'ACK' message to the T5 ECU to prompt the T5 to send the next
+// ascii character from the symboltable
+//
+// Returns an error if:
+//      the 'ACK' message cannot be sent before the timeout
+//
+// inputs:    none
+// return:    bool TRUE if message was sent OK,
+//                 FALSE if message could not be sent.
+
+bool T5Ack() {
+    char T5TxMsg[] = T5ACKCMND;
+    return (can_send_timeout (CMNDID, T5TxMsg, 8, T5MESSAGETIMEOUT));
+}
+
+//
+// t5_can_send_boot_address
+//
+// Send an address where 'bootloader' or FLASH CAN messages are uploaded to.
+// The number of bytes (up to 0x7F) that will be sent in the following CAN messages is also sent.
+//
+// inputs:    an unsigned int, the address where messages should be sent.
+//            an int, the number of bytes (up to 0x7F) that will be sent in the following CAN messages.
+// return:    bool TRUE if message was sent OK,
+//                 FALSE if message could not be sent.
+//
+bool t5_can_send_boot_address(uint32_t addr, uint8_t len) {
+    // send a can message to the T5 with the address and number of bytes we are going to send
+    char T5TxMsg[] = T5_BTCMND;
+    T5TxMsg[1] = ((uint8_t)(addr >> 24));         // high high byte of address
+    T5TxMsg[2] = ((uint8_t)(addr >> 16));         // high low byte of address
+    T5TxMsg[3] = ((uint8_t)(addr >> 8));          // low high byte of address
+    T5TxMsg[4] = ((uint8_t)(addr));               // low low byte of address
+    T5TxMsg[5] = (len);                           // number of bytes to upload (sent in following messages)
+    // if the message cannot be sent then there is a problem
+    if (!can_send_timeout (CMNDID, T5TxMsg, 8, T5MESSAGETIMEOUT))
+        return FALSE;
+    // wait for the T5 to reply
+    char T5RxMsg[8];
+    // if a message is not received, has the wrong type or indicates an error then there is a problem
+    return ((!can_wait_timeout(RESPID, T5RxMsg, 8, T5MESSAGETIMEOUT)) || (T5RxMsg[0] != T5TxMsg[0]) || (T5RxMsg[1] != 0x00))
+        ? FALSE : TRUE;
+}
+
+//
+// t5_can_send_boot_frame
+//
+// Upload 'bootloader' or new FLASH byts to T5 ECU in CAN messages
+//
+// The CAN messages are made up of 1 byte which is added to the address given in the T5SendBootAddress meaassge
+// followed by 7 bytes of data.
+// The first byte normally starts at 0x00 and increases by 7 in following messages until another T5SendBootAddress message is sent e.g.
+// 00,dd,dd,dd,dd,dd,dd,dd,dd 'dd' bytes are the data bytes, 7 in each CAN message except the last one which may have less.
+// 07,dd,dd,dd,dd,dd,dd,dd,dd
+// 0E,dd,dd,dd,dd,dd,dd,dd,dd (0x0E is 14)
+// 15,dd,dd,dd,dd,dd,dd,dd,dd (0x15 is 21)
+// etc.
+//
+// inputs:    a pointer to an array of 8 bytes to be sent to the T5 ECU SRAM or FLASH.
+// return:    bool TRUE if message was sent OK,
+//                 FALSE if message could not be sent.
+//
+bool t5_can_send_boot_frame (char *T5TxMsg) {
+    // send a can message to the T5 with the bytes we are sending
+    if (!can_send_timeout (CMNDID, T5TxMsg, 8, T5MESSAGETIMEOUT))
+        return FALSE;
+    // wait for the T5 to reply
+    char T5RxMsg[8];
+    // if a message is not received, has the wrong type or indicates an error then there is a problem
+    return ((!can_wait_timeout(RESPID, T5RxMsg, 8, T5MESSAGETIMEOUT)) || (T5RxMsg[0] != T5TxMsg[0]) || (T5RxMsg[1] != 0x00))
+        ? FALSE : TRUE;
+}
+
+//
+// T5StartBootLoader
+//
+// Send the jump to address to the T5 ECU for starting the 'bootloader'.
+// The jump address must be somewhere in RAM (addresses 0x0000 to 0x8000).
+// (The start address comes from the S7/8/9 line in the S19 file.)
+//
+// inputs:    an unsigned int, the address to jump to start of 'bootloader'.
+// return:    bool TRUE if message was sent OK,
+//                 FALSE if message could not be sent.
+//
+bool T5StartBootLoader (uint32_t addr) {
+    char T5TxMsg[] = T5JMPCMND;
+    T5TxMsg[3] = ((uint8_t)(addr >> 8));          // low byte of address
+    T5TxMsg[4] = ((uint8_t)(addr));               // high byte of address
+    return (can_send_timeout (CMNDID, T5TxMsg, 8, T5MESSAGETIMEOUT));
+}
+
+//
+// t5_boot_checksum_command
+//
+// Send the checksum command to Bootloader
+//
+// inputs:    none
+// return:    bool TRUE if message was sent OK,
+//                 FALSE if message could not be sent.
+//
+bool t5_boot_checksum_command(uint32_t* result) {
+    *result = 0;
+    // send a can message to the T5 requesting that it calculates the BIN file checksum
+    char T5TxMsg[] = T5SUMCMND;
+    if (!can_send_timeout (CMNDID, T5TxMsg, 8, T5MESSAGETIMEOUT))
+        return FALSE;
+    // wait for the T5 to reply
+    char T5RxMsg[8];
+    // if a message is not received, has the wrong type or indicates an error then there is a problem
+    if ((!can_wait_timeout(RESPID, T5RxMsg, 8, T5CHECKSUMTIMEOUT)) || (T5RxMsg[0] != T5TxMsg[0]) || (T5RxMsg[1] != 0x00))
+        return FALSE;
+// get the checksum
+    for (uint8_t i=0; i<4; i++) {
+        *result <<= 8;
+        *result |= T5RxMsg[i+2];
+    }
+    return TRUE;
+}
+
+//
+// t5_boot_reset_command
+//
+// Send 'exit and restart T5' command to the Bootloader
+//
+// inputs:    none
+// return:    bool TRUE if message was sent OK,
+//                 FALSE if message could not be sent.
+//
+bool t5_boot_reset_command() {
+    // send a can message to the T5 telling it to reset the ECU
+    char T5TxMsg[] = T5RSTCMND;
+    if (!can_send_timeout (CMNDID, T5TxMsg, 8, T5MESSAGETIMEOUT))
+        return FALSE;
+    // wait for the T5 to reply
+    char T5RxMsg[8];
+    // if a message is not received, has the wrong type or indicates an error then there is a problem
+    if ((!can_wait_timeout(RESPID, T5RxMsg, 8, T5MESSAGETIMEOUT)) || (T5RxMsg[0] != T5TxMsg[0]) || (T5RxMsg[1] != 0x00))
+        return FALSE;
+    // wait for the T5 to reset
+    // if a message is not received, has the wrong type or indicates an error then there is a problem
+    return (!can_wait_timeout(RSETID, T5RxMsg, 8, T5MESSAGETIMEOUT))
+        ? FALSE : TRUE;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    t5_boot_get_flash_type
+    Send 'get FLASH chip types' command to the Bootloader
+
+    @param      result      start address of T5.x FLASH
+                make        FLASH chip manufacturer code
+                type        FLASH chip type code
+
+    @return     bool        TRUE if message was sent OK,
+                            FALSE if message could not be sent.
+*/
+bool t5_boot_get_flash_type(uint32_t* result, uint8_t* make, uint8_t* type) {
+    *result = 0;
+    *make = 0;
+    *type = 0;
+    // send a can message to the T5 requesting that it tells us the type of FLASH chips
+    char T5TxMsg[] = T5TYPCMND;
+    if (!can_send_timeout (CMNDID, T5TxMsg, 8, T5MESSAGETIMEOUT))
+        return FALSE;
+    // wait for the T5 to reply
+    char T5RxMsg[8];
+    // if a message is not received, has the wrong type or indicates an error then there is a problem
+    if ((!can_wait_timeout(RESPID, T5RxMsg, 8, T5MESSAGETIMEOUT)) || (T5RxMsg[0] != T5TxMsg[0]) || (T5RxMsg[1] != 0x00))
+        return FALSE;
+    // get the start address
+    for (uint8_t i=0; i<4; i++) {
+        *result <<= 8;
+        *result |= T5RxMsg[i+2];
+    }
+    // get the manufacture code
+    *make = T5RxMsg[6];
+    // get the FLASH type code
+    *type = T5RxMsg[7];
+    return TRUE;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    t5_boot_erase_command
+    Send 'erase FLASH chip types' command to the Bootloader
+
+    @param      none
+
+    @return     bool        TRUE if message was sent OK,
+                            FALSE if message could not be sent.
+*/
+bool t5_boot_erase_command() {
+    // send a can message to the T5 telling it to erase the FLASH chips
+    char T5TxMsg[] = T5ERACMND;
+    if (!can_send_timeout (CMNDID, T5TxMsg, 8, T5MESSAGETIMEOUT))
+        return FALSE;
+    // wait for the T5 to reply
+    char T5RxMsg[8];
+    // if a message is not received, has the wrong type or indicates an error then there is a problem
+    return ((!can_wait_timeout(RESPID, T5RxMsg, 8, T5ERASETIMEOUT)) || (T5RxMsg[0] != T5TxMsg[0]) || (T5RxMsg[1] != 0x00))
+        ? FALSE : TRUE;
+}
+
+//-----------------------------------------------------------------------------
+/**
+    t5_boot_c3_command
+    Send 'C3 - Get last address' command to the Bootloader
+
+    @param      result      last address of T5 FLASH
+                mode        might indicate if bootloader is loaded
+
+    @return     bool        TRUE if message was sent OK,
+                            FALSE if message could not be sent.
+*/
+bool t5_boot_c3_command(uint32_t* result, uint16_t* mode) {
+    *result = 0;
+    *mode = 0;
+    // send a can message to the T5 requesting that it tells us the last address of FLASH
+    char T5TxMsg[] = T5EOFCMND;
+    if (!can_send_timeout (CMNDID, T5TxMsg, 8, T5MESSAGETIMEOUT))
+        return FALSE;
+    // wait for the T5 to reply
+    char T5RxMsg[8];
+    // if a message is not received, has the wrong type or indicates an error then there is a problem
+    if ((!can_wait_timeout(RESPID, T5RxMsg, 8, T5MESSAGETIMEOUT)) || (T5RxMsg[0] != T5TxMsg[0]) || (T5RxMsg[1] != 0x00))
+        return FALSE;
+// get the checksum
+    for (uint8_t i=0; i<4; i++) {
+        *result <<= 8;
+        *result |= T5RxMsg[i+2];
+    }
+    for (uint8_t i=0; i<2; i++) {
+        *mode <<= 8;
+        *mode |= T5RxMsg[i+6];
+    }
+    return TRUE;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/t5utils.h	Tue Sep 14 21:02:04 2010 +0000
@@ -0,0 +1,61 @@
+
+// t5utils.h - information and definitions needed for communicating with the T5 ECU
+
+// (C) 2010, Sophie Dexter
+
+#ifndef __T5UTILS_H__
+#define __T5UTILS_H__
+
+#include "mbed.h"
+
+#include "common.h"
+#include "canutils.h"
+
+#define CMNDID 0x05
+#define ACK_ID 0x06
+#define RESPID 0x0C
+#define RSETID 0x08
+
+#define T5_RDCMND {0xC4,0x00,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}     // C4 Command template for reading something from the T5 ECU
+#define T5_WRCMND {0xC4,0x00,0x00,0x00,0x00,0x00,0x00,0x00}     // C4 Command template for writing something to the T5 ECU
+#define T5ACKCMND {0xC6,0x00,0x00,0x00,0x00,0x00,0x00,0x00}     // C6 Command for acknowledging receipt of last message from T5 ECU or
+                                                                // asking it to send some more data (e.g. symbol table) I'm not sure which :lol:
+#define T5_BTCMND {0xA5,0x00,0x00,0x00,0x00,0x00,0x00,0x00}     // A5 Command template for sending a bootloader to the T5 ECU
+#define T5JMPCMND {0xC1,0x00,0x00,0x00,0x00,0x00,0x00,0x00}     // C1 Command template for starting a bootloader that has been sent to the T5 ECU
+#define T5EOFCMND {0xC3,0x00,0x00,0x00,0x00,0x00,0x00,0x00}     // C3 Command for reading back the last address of FLASH in the T5 ECU
+#define T5A_DCMND {0xC5,0x00,0x00,0x00,0x00,0x00,0x00,0x00}     // C5 Command for setting analogue to digital registers (don't know what this is for)
+#define T5RAMCMND {0xC7,0x00,0x00,0x00,0x00,0x00,0x00,0x00}     // C7 Command for reading T5 RAM (all the symbols and adaption data is in RAM)
+
+
+#define T5ERACMND {0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00}     // C0 Command for erasing T5 FLASH Chips !!! (Bootloader must be loaded before using)
+#define T5RSTCMND {0xC2,0x00,0x00,0x00,0x00,0x00,0x00,0x00}     // C2 Command for exiting the Bootloader and restarting the T5 ECU (Bootloader must be loaded before using)
+#define T5SUMCMND {0xC8,0x00,0x00,0x00,0x00,0x00,0x00,0x00}     // C8 Command for reading T5 FLASH Checksum (Bootloader must be loaded before using)
+#define T5TYPCMND {0xC9,0x00,0x00,0x00,0x00,0x00,0x00,0x00}     // C9 Command for reading T5 FLASH Chip types (Bootloader must be loaded before using)
+
+#define T5STARTMSG {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0x00}    // T5 sends this message whenever the ignition is turned on? - message id is RESPID
+#define T5RESETMSG {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}    // T5 sends this message to say that it has reset - message id is RSETID
+
+#define T5MESSAGETIMEOUT 500            // 500 milliseconds (half a second) - Seems to be plenty of time to wait for messages on the CAN bus
+#define T5CHECKSUMTIMEOUT 2000          // 2 seconds (2,000 milliseconds) - Usually takes less than a second so allowing 2 is plenty
+#define T5ERASETIMEOUT 40000            // 40 seconds (60,000 milliseconds) - Usually takes less than 20 seconds so allowing 40 is plenty
+
+extern bool T5Open();
+extern bool T5Close();
+extern char T5WaitResponse();
+extern bool T5WaitResponsePrint();
+extern char *T5GetSymbol(char *a_symbol);
+extern bool T5ReadCmnd(char c);
+extern bool T5WriteCmnd(uint32_t addr, char data);
+extern bool t5_can_read_data(char *data, uint32_t addr);
+extern bool T5Ack();
+extern bool t5_can_send_boot_address(uint32_t addr, uint8_t len);
+extern bool t5_can_send_boot_frame(char *T5TxMsg);
+extern bool T5StartBootLoader (uint32_t addr);
+
+extern bool t5_boot_checksum_command(uint32_t* result);
+extern bool t5_boot_reset_command();
+extern bool t5_boot_get_flash_type(uint32_t* result, uint8_t* make, uint8_t* type);
+extern bool t5_boot_erase_command();
+extern bool t5_boot_c3_command(uint32_t* result, uint16_t* mode);
+
+#endif
\ No newline at end of file