Dodge/Chrysler Radio Emulator Connect to Interior CAN bus
Dependencies: mbed SDFileSystem
Revision 0:9bc41d70bdd3, committed 2011-01-31
- Comitter:
- rtgree01
- Date:
- Mon Jan 31 05:13:04 2011 +0000
- Commit message:
Changed in this revision
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