Dodge/Chrysler Radio Emulator Connect to Interior CAN bus
Dependencies: mbed SDFileSystem
radioEmulator.cpp
- Committer:
- rtgree01
- Date:
- 2011-01-31
- Revision:
- 0:9bc41d70bdd3
File content as of revision 0:9bc41d70bdd3:
#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]); } }