Dodge/Chrysler Radio Emulator Connect to Interior CAN bus

Dependencies:   mbed SDFileSystem

Files at this revision

API Documentation at this revision

Comitter:
rtgree01
Date:
Mon Jan 31 05:13:04 2011 +0000
Commit message:

Changed in this revision

FATFileSystem.lib Show annotated file Show diff for this revision Revisions of this file
MODSERIAL.lib Show annotated file Show diff for this revision Revisions of this file
RadioState.h Show annotated file Show diff for this revision Revisions of this file
SDFileSystem.lib Show annotated file Show diff for this revision Revisions of this file
WatchDogTimer.cpp Show annotated file Show diff for this revision Revisions of this file
WatchDogTimer.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
radioEmulator.cpp Show annotated file Show diff for this revision Revisions of this file
radioEmulator.h Show annotated file Show diff for this revision Revisions of this file
diff -r 000000000000 -r 9bc41d70bdd3 FATFileSystem.lib
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/FATFileSystem.lib	Mon Jan 31 05:13:04 2011 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_unsupported/code/fatfilesystem/
\ No newline at end of file
diff -r 000000000000 -r 9bc41d70bdd3 MODSERIAL.lib
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MODSERIAL.lib	Mon Jan 31 05:13:04 2011 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/AjK/code/MODSERIAL/#a93a62eeeb9d
diff -r 000000000000 -r 9bc41d70bdd3 RadioState.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/RadioState.h	Mon Jan 31 05:13:04 2011 +0000
@@ -0,0 +1,62 @@
+#ifndef RADIOSTATE_H
+#define RADIOSTATE
+
+enum radioMode { AM, FM, CD, SAT, VES, MAX_MODE };
+
+struct RadioState
+{
+    radioMode _radioMode;
+    
+    int _amPreset;
+    int _amFreq;
+    
+    int _fmPreset;
+    int _fmFreq;
+    
+    int _cdNum;
+    int _cdTrackNum;
+    int _cdHours;
+    int _cdMinutes;
+    int _cdSeconds;
+    char _cdTime[8];
+    
+    int _siriusPreset;
+    int _siriusChan;
+    char _siriusTextLine[8][64];
+    
+    int _evicMode;
+    int _evicPreset;
+    int _evicFreq;
+    
+    int _volume;
+    int _balance;
+    int _fade;
+    int _bass;
+    int _mid;
+    int _treble;
+    
+    float _batteryVoltage;
+    int _driverHeatedSeatLevel;
+    int _passHeatedSeatLevel;
+    char _vin[24];
+    int _headlights;
+    int _dimmerMode;
+    int _dimmer;
+    int _gear;
+    int _brake;
+    int _parkingBrake;
+    char _vesControls[32];
+    int _keyPosition;
+    int _rpm;
+    int _fanRequested;
+    int _fanOn;
+    int _rearDefrost;
+    int _fuel;
+    int _speed;
+    
+    int SWCButtons;
+    int currentSWCAction;
+};
+
+
+#endif
\ No newline at end of file
diff -r 000000000000 -r 9bc41d70bdd3 SDFileSystem.lib
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SDFileSystem.lib	Mon Jan 31 05:13:04 2011 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/simon/code/SDFileSystem/#b1ddfc9a9b25
diff -r 000000000000 -r 9bc41d70bdd3 WatchDogTimer.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/WatchDogTimer.cpp	Mon Jan 31 05:13:04 2011 +0000
@@ -0,0 +1,18 @@
+#include "WatchDogTimer.h"
+
+void WatchDogTimer::kick(float s)
+{
+    LPC_WDT->WDCLKSEL = 0x1;                // Set CLK src to PCLK
+    uint32_t clk = SystemCoreClock / 16;    // WD has a fixed /4 prescaler, PCLK default is /4
+    LPC_WDT->WDTC = s * (float)clk;
+    LPC_WDT->WDMOD = 0x3;                   // Enabled and Reset
+    kick();
+}
+
+// "kick" or "feed" the dog - reset the watchdog timer
+// by writing this required bit pattern
+void WatchDogTimer::kick()
+{
+    LPC_WDT->WDFEED = 0xAA;
+    LPC_WDT->WDFEED = 0x55;
+}
diff -r 000000000000 -r 9bc41d70bdd3 WatchDogTimer.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/WatchDogTimer.h	Mon Jan 31 05:13:04 2011 +0000
@@ -0,0 +1,19 @@
+#ifndef WATCHDOGTIMER_H
+#define WATCHDOGTIMER_H
+
+#include "mbed.h"
+
+// Simon's Watchdog code from
+// http://mbed.org/forum/mbed/topic/508/
+class WatchDogTimer
+{
+public:
+// Load timeout value in watchdog timer and enable
+    void kick(float s);
+
+// "kick" or "feed" the dog - reset the watchdog timer
+// by writing this required bit pattern
+    void kick();
+};
+
+#endif
\ No newline at end of file
diff -r 000000000000 -r 9bc41d70bdd3 main.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Mon Jan 31 05:13:04 2011 +0000
@@ -0,0 +1,21 @@
+#include "mbed.h"
+#include "radioEmulator.h"
+#include "WatchDogTimer.h"
+
+RadioEmulator *radio;
+
+WatchDogTimer wdt;
+
+int main()
+{
+    wdt.kick(2);
+    radio = new RadioEmulator();
+    
+    while (1)
+    {
+        radio->readCANbus();
+        radio->HostComm();
+        
+        wdt.kick();        
+    }
+}
diff -r 000000000000 -r 9bc41d70bdd3 mbed.bld
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Mon Jan 31 05:13:04 2011 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/e2ac27c8e93e
diff -r 000000000000 -r 9bc41d70bdd3 radioEmulator.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/radioEmulator.cpp	Mon Jan 31 05:13:04 2011 +0000
@@ -0,0 +1,816 @@
+#include "mbed.h"
+#include "radioEmulator.h"
+
+DigitalOut led1(LED1);
+DigitalOut led2(LED2);
+DigitalOut led3(LED3);
+DigitalOut led4(LED4);
+
+//LocalFileSystem local("local");
+#include "SDFileSystem.h"
+
+SDFileSystem sd(p5, p6, p7, p8, "sd"); // the pinout on the mbed Cool Components workshop board
+
+char RadioEmulator::unlock[6] = {0x03,0x02,0x00,0x40,0x87,0xa5};
+char RadioEmulator::lock[6] = {0x01, 0x02, 0x00, 0x40, 0x87, 0xa5};
+char RadioEmulator::trunk[6] = {0x05, 0x02, 0x00, 0x40, 0x87, 0xa5};
+
+RadioEmulator::RadioEmulator()
+{
+    usb = new MODSERIAL(USBTX, USBRX, 1024, 128, NULL); // tx, rx
+    usb->baud(115200);
+    
+    can2 = new CAN(p30,p29);
+    can_RS = new DigitalOut(p28);
+    canIRQ = new InterruptIn(p27);
+
+    serialCounter = 0;
+    prevSWC = 0;
+    radioOn = false;
+    for (int i = 0; i < 8; i++)
+    {
+        for (int j = 0; j < 8; j++)
+        {
+            memset(siriusText[i][j], 0, 8);
+        }
+    }
+    
+//    usb->printf("starting\r\n");
+    
+    memset(&status, 0, sizeof(status));    
+    status._radioMode = SAT;
+//    readInitFile();
+    status._volume = 10;
+    status._bass = 15;
+    status._mid = 13;
+    status._treble = 14;
+    status._balance = 10;
+    status._fade = 10;
+
+    PowerUp();
+    
+    ReceivedHostMsg = false;
+    statusTicker.attach(this, &RadioEmulator::SendStatusToHost, 0.1);
+
+    opMode = standalone;
+    HostTimeout.attach(this, &RadioEmulator::CheckHostTimeout, 1);
+    
+    for (int i = 0; i < 6; i++)
+    {
+        buttonClicks[i] = 0;
+        buttonHeld[i] = false;
+    }
+    reportButtonClick = false;
+    buttonClickTimedOut = false;        
+}
+
+void RadioEmulator::readInitFile()
+{
+    FILE *fp = fopen("/sd/stereo.txt", "r");  // Open "out.txt" on the local file system for writing
+    char temp[100];
+        
+    while ( fscanf(fp, "%s", temp) > 0)
+    {
+        if (strcmp(temp, "volume") == 0)
+        {
+            fscanf(fp, "%d", &status._volume);
+        }
+        if (strcmp(temp, "bass") == 0)
+        {
+            fscanf(fp, "%d", &status._bass);
+        }
+        if (strcmp(temp, "mid") == 0)
+        {
+            fscanf(fp, "%d", &status._mid);
+        }
+        if (strcmp(temp, "treble") == 0)
+        {
+            fscanf(fp, "%d", &status._treble);
+        }
+        if (strcmp(temp, "balance") == 0)
+        {
+            fscanf(fp, "%d", &status._balance);
+        }
+        if (strcmp(temp, "fade") == 0)
+        {
+            fscanf(fp, "%d", &status._fade);
+        }
+    }
+    
+    fclose(fp);
+}
+
+void RadioEmulator::writeInitFile()
+{
+    FILE *fp = fopen("/sd/stereo.txt", "w");  // Open "out.txt" on the local file system for writing
+
+    fprintf(fp,"volume %d\r\n", status._volume);
+    fprintf(fp,"bass %d\r\n", status._bass);
+    fprintf(fp,"mid %d\r\n", status._mid);
+    fprintf(fp,"treble %d\r\n", status._treble);
+    fprintf(fp,"balance %d\r\n", status._balance);
+    fprintf(fp,"fade %d\r\n", status._fade);
+    fclose(fp);
+}
+
+void RadioEmulator::SendOnMsg()
+{
+    CANMessage msg;
+    msg.id = 0x416;
+    msg.len = 8;
+    char temp[8] = {0xfe, 0x1b, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff};
+    memcpy(msg.data, temp, 8);
+    can2->write(msg);
+}
+
+void RadioEmulator::SendRadioModeMsg()
+{
+    CANMessage msg;
+    msg.id = 0x09F;
+    msg.len = 8;
+
+    msg.data[7] = 0x11;
+    msg.data[6] = 0xff;
+    msg.data[5] = 0xff;
+    msg.data[4] = 0xff;
+    msg.data[3] = 0x07;
+    msg.data[2] = 0x00;
+    msg.data[1] = 0x00;
+    msg.data[0] = 0x00;
+
+    if (status._radioMode == AM)
+    {
+        if (status._amPreset != 0)
+        {
+            msg.data[0] = (status._amPreset + 1) << 4;
+        }
+        msg.data[1] = (status._amFreq & 0xFF00) >> 8;
+        msg.data[2] = (status._amFreq & 0x00FF);
+    }
+    else if (status._radioMode == FM)
+    {
+        if (status._fmPreset != 0)
+        {
+            msg.data[0] = (status._fmPreset + 1) << 4;
+        }
+        msg.data[0] = 0x01;
+        msg.data[1] = (status._fmFreq & 0xFF00) >> 8;
+        msg.data[2] = (status._fmFreq & 0x00FF);
+    }
+    else if (status._radioMode == CD)
+    {
+        msg.data[0] = ((status._cdNum + 1) << 4) + 0x3;
+        msg.data[2] = status._cdTrackNum;
+        msg.data[5] = status._cdHours;
+        msg.data[6] = status._cdMinutes;
+        msg.data[7] = status._cdSeconds;
+    }
+    else if (status._radioMode == SAT)
+    {
+        if (status._siriusPreset != 0)
+        {
+            msg.data[0] = (status._siriusPreset + 1) << 4;
+        }
+        msg.data[0] |= 0x04;
+        msg.data[1] = (status._fmFreq & 0xFF00) >> 8;
+        msg.data[2] = status._siriusChan;
+    }
+    else if (status._radioMode == VES)
+    {
+        msg.data[0] = 0x16;
+        msg.data[1] = 0x10;
+        msg.data[2] = 0x01;
+    }
+
+    msg.data[1] |= 0x10;
+
+    can2->write(msg);
+}
+
+void RadioEmulator::SendEVICMsg()
+{
+    CANMessage msg;
+    msg.id = 0x394;
+    msg.len = 6;
+    
+    memset(msg.data, 0, 8);
+
+    if (status._radioMode == AM)
+    {
+        if (status._amPreset != 0)
+        {
+            msg.data[0] = (status._amPreset + 1) << 4;
+        }
+        msg.data[1] = (status._amFreq & 0xFF00) >> 8;
+        msg.data[2] = (status._amFreq & 0x00FF);
+    }
+    else
+    {
+        if (status._fmPreset != 0)
+        {
+            msg.data[0] = (status._fmPreset + 1) << 4;
+        }
+        msg.data[0] = 0x01;
+        msg.data[1] = (status._fmFreq & 0xFF00) >> 8;
+        msg.data[2] = (status._fmFreq & 0x00FF);
+    }
+
+    can2->write(msg);
+}
+
+void RadioEmulator::SendStereoSettingsMsg()
+{
+    CANMessage msg;
+    msg.id = 0x3D0;
+    msg.len = 7;
+
+    msg.data[0] = status._volume;
+    msg.data[1] = status._balance;
+    msg.data[2] = status._fade;
+    msg.data[3] = status._bass;
+    msg.data[4] = status._mid;
+    msg.data[5] = status._treble;
+
+    can2->write(msg);
+}
+
+void RadioEmulator::ChangeSiriusStation(int station, bool turn_on)
+{
+    CANMessage msg;
+    msg.id = 0x3B0;
+    msg.len = 6;
+
+    if (turn_on)
+    {
+        msg.data[0] = 21;
+    }
+    else
+    {
+        msg.data[0] = 23;
+    }
+    msg.data[1] = station;
+
+    can2->write(msg);
+
+    memset(msg.data, 0, 8);
+    msg.data[1] = station;
+
+    can2->write(msg);
+    
+    status._siriusChan = station;
+}
+
+void RadioEmulator::ParseCANMessage(CANMessage can_MsgRx)
+{
+    if (can_MsgRx.id == 0x000)
+    {
+        if (can_MsgRx.data[0] > 1)
+        {
+            radioOn = true;
+        }
+        else
+        {
+            radioOn = false;
+        }
+    }
+    
+    // this message seems to be a message requesting all other devices
+    // to start announcing their presence
+    if ((can_MsgRx.id >= 0x400) && (can_MsgRx.data[0] == 0xfd))
+    {
+//      SendOnMsg();
+    }
+    
+    if (can_MsgRx.id == 0x012)
+    {
+        if (memcmp(can_MsgRx.data, unlock, 6) == 0)
+        {
+        }
+        else if (memcmp(can_MsgRx.data, lock, 6) == 0)
+        {
+        }
+        else if (memcmp(can_MsgRx.data, trunk, 6) == 0)
+        {
+        }
+    }
+
+    if (can_MsgRx.id == 0x1bd)
+    {
+        // SDAR status
+        
+        if (status._siriusChan == 0)
+        {
+            status._siriusChan = can_MsgRx.data[1];
+        }
+
+        if (can_MsgRx.data[0] == 0x85)
+        {
+            ChangeSiriusStation(status._siriusChan, true);
+        }
+        
+        if (status._siriusChan != can_MsgRx.data[1])
+        {
+            ChangeSiriusStation(status._siriusChan, true);
+        }
+    }
+    
+    if (can_MsgRx.id == 0x3bd)
+    {
+        ReadSiriusText((char *)can_MsgRx.data);
+    }
+
+    if (can_MsgRx.id == 0x3a0)
+    {        
+        // note = 0x01
+        // volume up = 0x02
+        // volume down = 0x04
+        // up arrow = 0x08
+        // down arrow = 0x10
+        // right arrow = 0x20
+               
+
+        for ( int i = 0; i < 6; i++)
+        {
+            if (((can_MsgRx.data[0] & (0x01 << i)) == (0x01 << i)) && ((prevSWC & (0x01 << i)) == 0))
+            {
+                buttonTimeout.detach();
+                buttonClicks[i] ++;
+                buttonClickTimedOut = false;
+                buttonTimeout.attach_us(this, &RadioEmulator::ClickTimeout, 200 * 1000);
+            }
+            else if (((can_MsgRx.data[0] & (0x01 << i)) == 0) && ((prevSWC & (0x01 << i)) != 0))
+            {
+                buttonHeld[i] = false;
+                
+                if (buttonClickTimedOut == true)
+                {
+                    buttonClickTimedOut = false;
+                    buttonClicks[i] = 0;
+                }
+            }
+        }
+
+        prevSWC = can_MsgRx.data[0];
+    }
+
+
+    if (can_MsgRx.id == 0x000)
+    {
+        status._keyPosition = can_MsgRx.data[0];
+    }
+    else if (can_MsgRx.id == 0x002)
+    {
+        status._rpm = (can_MsgRx.data[0] << 8) + can_MsgRx.data[1];
+        status._speed = ((can_MsgRx.data[2] << 8) + can_MsgRx.data[3]) / 200;
+    }
+    else if (can_MsgRx.id == 0x003)
+    {
+        status._brake = can_MsgRx.data[3] & 0x01;
+        status._gear = can_MsgRx.data[4];
+    }
+    else if (can_MsgRx.id == 0x15)
+    {
+        status._batteryVoltage = (float)(can_MsgRx.data[1]) / 10;
+    }
+    else if (can_MsgRx.id == 0x01b)
+    {
+        // vin number
+        int part = can_MsgRx.data[0];
+        if (part < 3)
+        {
+            for (int i = 1; i < 8; i++)
+            {
+                status._vin[(part*8) + i-1] = can_MsgRx.data[i];
+            }
+        }
+    }
+    else if (can_MsgRx.id == 0x0d0)
+    {
+        if (can_MsgRx.data[0] == 0x80)
+        {
+            status._parkingBrake = true;
+        }
+        else
+        {
+            status._parkingBrake = false;
+        }                    
+    }
+    else if (can_MsgRx.id == 0x0EC)
+    {
+        if ((can_MsgRx.data[0] & 0x40) == 0x40)
+        {
+            status._fanRequested = true;
+        }
+        else
+        {
+            status._fanRequested = false;
+        }
+
+        if ((can_MsgRx.data[0] & 0x01) == 0x01)
+        {
+            status._fanOn = true;
+        }
+        else
+        {
+            status._fanOn = false;
+        }
+    }
+    else if (can_MsgRx.id == 0x159)
+    {
+        status._fuel = can_MsgRx.data[5];
+    }
+    else if (can_MsgRx.id == 0x1a2)
+    {
+        if ((can_MsgRx.data[0] & 0x80) == 0x80)
+        {
+            status._rearDefrost = true;
+        }
+        else
+        {
+            status._rearDefrost = false;
+        }
+
+        if ((can_MsgRx.data[0] & 0x40) == 0x40)
+        {
+            status._fanRequested = true;
+        }
+        else
+        {
+            status._fanRequested = false;
+        }
+
+        if ((can_MsgRx.data[0] & 0x01) == 0x01)
+        {
+            status._fanOn = true;
+        }
+        else
+        {
+            status._fanOn = false;
+        }
+    }
+    else if (can_MsgRx.id == 0x1c8)
+    {
+        status._headlights = can_MsgRx.data[0];
+    }
+    else if (can_MsgRx.id == 0x210)
+    {
+        status._dimmerMode = can_MsgRx.data[0];
+        if (can_MsgRx.data[0] == 0x03)
+        {
+            status._dimmer = -1;
+        }
+        else if (can_MsgRx.data[0] == 0x02)
+        {
+            status._dimmer = can_MsgRx.data[1];
+        }
+    }
+
+}
+
+void RadioEmulator::ReadSiriusText(char *data)
+{
+    int num = (data[0] & 0xF0) >> 4;
+    if (num > 7)
+    {
+        return;
+    }
+    
+    if ((data[0] & 0x01) == 1)
+    {
+        for (int i = 0; i < 8; i++)
+        {
+            memset(siriusText[num][i], 0, 8);
+        }
+    }
+    int part = (data[0] & 0x0E) >> 1;
+    if (part > 7)
+    {
+        return;
+    }
+    
+    memset(siriusText[num][part], 0, 8);
+    char tempString[8] = "";
+    memset(tempString,0,8);
+    
+    for (int i = 1; i < 8; i++)
+    {
+        tempString[i-1] = data[i];
+    }
+    
+    strncpy(siriusText[num][part],tempString,7);
+
+    int cls = (data[0] & 0x0F) >> 1;
+    if (cls - 1 == 0)
+    {
+        for (int i = 0; i < 8; i++)
+        {
+            memset(status._siriusTextLine[i], 0, 64);
+            for (int j = 0; j < 8; j++)
+            {
+                strcat(status._siriusTextLine[i], siriusText[i][j]);
+            }
+            
+//            usb->printf("%d: %s\r\n", i, status._siriusTextLine[i]);
+        }
+    }
+}
+
+void RadioEmulator::readCANbus(void)
+{
+    if (can2->read(can_MsgRx))
+    {
+        led3 = !led3;
+        needToParseCANMessage = true;
+        ReceivedCANMsg = true;
+    }
+    
+    if (needToParseCANMessage)
+    {           
+        needToParseCANMessage = false;   
+        
+        ParseCANMessage(can_MsgRx);
+    }
+}
+
+void RadioEmulator::HostComm(void)
+{               
+    if (usb->readable())
+    {
+        msg[serialCounter] = usb->getc();
+        serialCounter++;
+        
+        if (serialCounter == 4)
+        {
+            if ((msg[0] != 0x42) || (msg[1] != 0x42) || (msg[2] != 0x42) || (msg[3] != 0x42))
+            {
+                serialCounter = 0;
+                msg[0] = msg[1];
+                msg[1] = msg[2];
+                msg[2] = msg[3];
+            }
+        }
+    }
+
+    if (serialCounter > 13)
+    {
+        serialCounter = 0;
+        
+        if ((msg[0] == 0x42) && (msg[1] == 0x42) && (msg[2] == 0x42) && (msg[3] == 0x42))
+        {
+            ReceivedHostMsg = true;
+            
+            switch (msg[4])
+            {
+                case 0x00:
+                    opMode = slave;
+                break;
+                
+                case 0x01:
+                    status._volume = msg[5];
+                    status._balance = msg[6];
+                    status._fade = msg[7];
+                    status._bass = msg[8];
+                    status._mid = msg[9];
+                    status._treble = msg[10];
+                    
+//                    writeInitFile();
+                break;
+                
+                case 0x02:
+                    status._siriusChan = msg[5];
+                    ChangeSiriusStation(msg[5], false);
+                break;
+                
+                case 0x03:
+                    status._radioMode = (radioMode)msg[5];
+                    
+                    switch (status._radioMode)
+                    {
+                        case AM:
+                            status._amPreset = msg[6];
+                            status._amFreq = msg[7] + (msg[8] << 8);
+                        break;
+                        
+                        case FM:
+                            status._fmPreset = msg[6];
+                            status._fmFreq = msg[7] + (msg[8] << 8);
+                        break;
+                        
+                        case SAT:
+                            status._siriusPreset = msg[6];
+                            status._siriusChan = msg[7];
+                        break;
+                        
+                        case CD:
+                            status._cdNum = msg[6];
+                            status._cdTrackNum = msg[7];
+                            status._cdHours = msg[8];
+                            status._cdMinutes = msg[9];
+                            status._cdSeconds =  msg[10];
+                        break;
+                        
+                        case VES:
+                        break;
+                    }
+                break;
+                    
+            }
+
+        }
+    }
+}
+
+
+void RadioEmulator::ClickTimeout(void)
+{
+    for ( int i = 0; i < 6; i++)
+    {
+        buttonClickTimedOut = true;
+        buttonTimeout.detach();
+        if ((prevSWC & (0x01 << i)) == (0x01 << i))
+        {
+            buttonHeld[i] = true;
+        }
+        else
+        {
+            buttonHeld[i] = false;
+        }
+    }
+}
+
+void RadioEmulator::PowerUp(void)
+{
+    led1 = 1;
+    poweredDown = 0;
+    needToParseCANMessage = false;   
+    LPC_CAN2->BTR = 0x52001C;
+    *can_RS = 0;
+    ReceivedCANMsg = false;
+
+    canIRQ->rise(this, &RadioEmulator::StartEmulation);
+//    StartEmulation();
+}
+
+void RadioEmulator::StartEmulation(void)
+{
+    canIRQ->rise(0);
+    
+    CANBusTicker.attach(this, &RadioEmulator::WriteCANMessages, 0.5);
+
+    ChangeSiriusStation(status._siriusChan, true);
+    
+    CANTimeout.attach(this, &RadioEmulator::CheckCANTimeout, 1);
+}
+
+//------------------------------------------------------------------------------------------
+// These are all interrupts
+void RadioEmulator::RestartCAN(void)
+{
+    if (poweredDown == 5)
+    {
+        canIRQ->rise(NULL);
+        PowerUp();
+    }
+    poweredDown++;
+}
+
+void RadioEmulator::WriteCANMessages()
+{
+    if (radioOn)
+    {
+        led2 = !led2;
+        SendRadioModeMsg();
+        SendEVICMsg();
+        SendStereoSettingsMsg();
+    }
+}
+
+void RadioEmulator::CheckCANTimeout(void)
+{
+    if (!ReceivedCANMsg)
+    {
+        led1 = 0;
+        // Need to Power Down
+        CANBusTicker.detach();
+        CANTimeout.detach(); 
+                
+        *can_RS = 1;
+        
+        canIRQ->rise(this, &RadioEmulator::RestartCAN);
+    }
+    
+    ReceivedCANMsg = false;
+}
+
+void RadioEmulator::CheckHostTimeout(void)
+{
+    if (!ReceivedHostMsg)
+    {
+        led4 = 1;
+        opMode = standalone;
+    }
+    else
+    {
+        led4 = 0;
+    }
+
+    ReceivedHostMsg = false;
+}
+
+void RadioEmulator::SendStatusToHost(void)
+{
+    int size = sizeof(status);
+    
+    bool holding = false;    
+    if (buttonClickTimedOut == true)
+    {
+        // an action has occurred.... but are we still holding a button?
+        status.currentSWCAction = 0;
+        for (int i = 0; i < 6; i++)
+        {
+            status.currentSWCAction |= buttonClicks[i] << (2 * i);
+            if (buttonHeld[i] != true)
+            {
+                buttonClicks[i] = 0;
+            }
+            else
+            {
+                holding = true;
+            }
+        }
+    }
+    else
+    {
+        status.currentSWCAction = 0;
+    }
+    
+    static int okToSend = 0;
+    if (holding)
+    {
+        if (okToSend < 2)
+        {
+            status.currentSWCAction = 0;
+            okToSend++;
+        }
+        else
+        {
+            okToSend = 0;
+        }
+    }
+    else
+    {
+        okToSend = 0;
+    }
+    
+    status.SWCButtons = prevSWC;
+    
+    if (opMode == standalone)
+    {
+        if (status.currentSWCAction != 0)
+        {
+            if (buttonClicks[2] != 0)
+            {
+                if (status._volume > 0)
+                    status._volume --;
+            }
+            else if (buttonClicks[1] != 0)
+            {
+                if (status._volume < 40)
+                    status._volume ++;
+            }
+            else if (buttonClicks[4] != 0)
+            {
+                if (status._siriusChan > 0)
+                    ChangeSiriusStation(status._siriusChan-1, false);
+            }
+            else if (buttonClicks[3] != 0)
+            {
+                if (status._siriusChan < 256)
+                    ChangeSiriusStation(status._siriusChan+1, false);
+            }
+
+//            writeInitFile();
+        }
+    }
+    
+
+    RadioState tempStatus;
+    memcpy(&tempStatus, &status, size);
+    char *data = (char *)&tempStatus;
+ 
+    usb->putc(0x42);
+    usb->putc(0x42);
+    usb->putc(0x42);
+    usb->putc(0x42);
+
+    for (int i = 0; i < size; i++)
+    {
+        while(!usb->writeable())
+        {
+            wait_us(10);
+        }
+        
+        usb->putc(data[i]);
+    }
+
+}
diff -r 000000000000 -r 9bc41d70bdd3 radioEmulator.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/radioEmulator.h	Mon Jan 31 05:13:04 2011 +0000
@@ -0,0 +1,85 @@
+#ifndef RADIOEMULATOR_H
+#define RADIOEMULATOR_H
+
+#include "mbed.h"
+#include "MODSERIAL.h"
+
+#include "RadioState.h"
+
+class RadioEmulator
+{
+public:
+    RadioEmulator();
+    ~RadioEmulator() {};
+    
+    void readCANbus(void);
+    void HostComm(void);
+
+//private:
+
+    MODSERIAL *usb;
+    void serialReceiver(void);
+    
+    void StartEmulation();
+    void SendOnMsg();
+    void SendEVICMsg();
+    void SendRadioModeMsg();
+    void SendStereoSettingsMsg();
+    void ChangeSiriusStation(int station, bool turn_on);
+    
+    void readInitFile();
+    void writeInitFile();
+    void PowerUp(void);
+    
+    void WriteCANMessages();
+    Ticker CANBusTicker;
+    
+    void SendStatusToHost();
+    Ticker statusTicker;
+    
+    CAN *can2;
+    CANMessage can_MsgRx;
+    DigitalOut *can_RS;
+    InterruptIn *canIRQ;
+    void RestartCAN(void);
+    
+    int poweredDown;
+      
+    bool radioOn;
+    
+    void ParseCANMessage(CANMessage can_MsgRx);
+    void ReadSiriusText(char *data);    
+    char siriusText[8][8][8];
+    
+    
+    char serialCounter;
+    char msg[14];    
+
+    static char unlock[6];
+    static char lock[6];
+    static char trunk[6];
+    
+    
+    RadioState status;    
+    
+    Timeout buttonTimeout;
+    void ClickTimeout(void);
+    int prevSWC;
+    int buttonClicks[6];
+    bool buttonHeld[6];
+    bool reportButtonClick;
+    bool buttonClickTimedOut;
+
+    bool ReceivedCANMsg;
+    void CheckCANTimeout(void);
+    Ticker CANTimeout;
+    bool needToParseCANMessage;
+
+    bool ReceivedHostMsg;
+    void CheckHostTimeout(void);
+    Ticker HostTimeout;
+    
+    enum {standalone, slave} opMode;
+};
+
+#endif
\ No newline at end of file