Library to control Dodge LX (83.3k) CAN devices
Dependents: DodgeRadioEmulatorv30
radioEmulator.cpp
- Committer:
- rtgree01
- Date:
- 2013-01-25
- Revision:
- 2:ade5ba8a9d37
- Parent:
- 1:6dcab41a32df
File content as of revision 2:ade5ba8a9d37:
#include "mbed.h" #include "radioEmulator.h" DigitalOut led1(LED1); DigitalOut led2(LED2); DigitalOut led3(LED3); DigitalOut led4(LED4); DigitalOut reverse(p15); #undef CHECK_HW_SHUTDOWN //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(CAN *can, DigitalOut *rs, InterruptIn *irq, bool wdTO) { printf("RadioEmulator Initializing\r\n"); HostSock = new UDPSock(new Host(IpAddr(), 50000, NULL), 64, this); CANDevice = can; can_RS = rs; canIRQ = irq; reverse = 0; prevSWC = 0; memset(&status, 0, sizeof(status)); memset(&siriusdata, 0, 512); status.marker1 = 0x42; status.marker2 = 0x42; status.marker3 = 0x42; status.marker4 = 0x42; status._radioMode = SAT; // readInitFile(); status._volume = 10; status._bass = 15; status._mid = 13; status._treble = 14; status._balance = 10; status._fade = 10; for (int i = 0; i < 8; i++) { if (wdTO) { sprintf(&siriusdata[i * 64], "WATCH DOG TIMED OUT"); } else { sprintf(&siriusdata[i * 64], "Fun line text # %d", i); } } PowerUp(); printf("RadioEmulator initialized\n\r"); } /* 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); } if (strcmp(temp, "MAC") == 0) { char temp2[64]; fscanf(fp, "%s", temp2); char *pEnd; hostMACAddress[0] = strtoul(temp2, &pEnd, 16); hostMACAddress[1] = strtoul(pEnd, &pEnd, 16); hostMACAddress[2] = strtoul(pEnd, &pEnd, 16); hostMACAddress[3] = strtoul(pEnd, &pEnd, 16); hostMACAddress[4] = strtoul(pEnd, &pEnd, 16); hostMACAddress[5] = strtoul(pEnd, &pEnd, 16); } } 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::PowerUp(void) { led1 = 1; needToParseCANMessage = false; ReceivedCANMsg = false; LPC_CAN2->BTR = 0x52001C; *can_RS = 0; // Wake up the CAN Transceiver sleeping = false; writeCANFlag = false; CANBusTicker.attach(this, &RadioEmulator::WriteCANMessages, 1); ChangeSiriusStation(status._siriusChan, true); ReceivedHostMsg = false; statusFlag = false; statusTicker.attach(this, &RadioEmulator::SendStatusToHost, 0.1); opMode = standalone; hostTimeoutFlag = false; HostTimeout.attach(this, &RadioEmulator::CheckHostTimeout, 1); CANTimeoutFlag = false; canIRQ->rise(0); // only enable this if trying to power up/down the processor // CANTimeout.attach(this, &RadioEmulator::CheckCANTimeout, 1); } void RadioEmulator::PowerDown(void) { led1 = 0; // Need to Power Down CANBusTicker.detach(); CANTimeout.detach(); statusTicker.detach(); HostTimeout.detach(); *can_RS = 1; powerUpIRQCounter = 0; sleeping = true; needToWakeUp = false; canIRQ->rise(this, &RadioEmulator::CANActivity); } void RadioEmulator::Operate(void) { if (sleeping) { if (needToWakeUp) { PowerUp(); needToWakeUp = false; } return; } if (writeCANFlag) { writeCANFlag = false; led2 = !led2; SendRadioModeMsg(); SendEVICMsg(); SendStereoSettingsMsg(); SendHostMessages(); } if (statusFlag) { statusFlag = false; if (opMode == standalone) { StandaloneSWI(); } prevSWC = status.SWCButtons; status.count++; static Host statusHost(IpAddr(224,1,2,3), 51000, NULL); //Join multicast group on port 50000 HostSock->SendTo(&statusHost, sizeof(status), (char *)&status); if ((status.count % 10) == 0) { static Host siriusTextHost(IpAddr(224,1,2,3), 61000, NULL); //Join multicast group on port 50000 HostSock->SendTo(&siriusTextHost, 512, siriusdata); } } if (hostTimeoutFlag) { hostTimeoutFlag = false; if (!ReceivedHostMsg) { led4 = 1; opMode = standalone; } else { led4 = 0; } ReceivedHostMsg = false; } // only enable this if trying to power up/down the processor if (CANTimeoutFlag) { CANTimeoutFlag = false; if (!ReceivedCANMsg) { PowerDown(); } ReceivedCANMsg = false; } readCANbus(); } void RadioEmulator::StandaloneSWI() { if (status.SWCButtons == 0) { if ((prevSWC & 0x00000004) != 0) { if (status._volume > 0) status._volume --; } else if ((prevSWC & 0x00000002) != 0) { if (status._volume < 40) status._volume ++; } else if ((prevSWC & 0x00000010) != 0) { if (status._siriusChan > 0) ChangeSiriusStation(status._siriusChan-1, false); } else if ((prevSWC & 0x00000008) != 0) { if ((status._siriusChan < 256) && (status._siriusChan > 0)) ChangeSiriusStation(status._siriusChan+1, false); } else if ((prevSWC & 0x00000001) != 0) { } } } 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); CANDevice->write(msg); } void RadioEmulator::SendRadioModeMsg() { CANMessage msg; msg.id = 0x09F; msg.len = 8; msg.data[7] = 0x0f; 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) && (status._amPreset < 16)) { 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) && (status._fmPreset < 16)) { 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 << 4; msg.data[1] = 0x20; msg.data[0] |= 0x03; msg.data[2] = status._cdTrackNum; msg.data[4] = status._cdHours; msg.data[5] = status._cdMinutes; msg.data[6] = status._cdSeconds; } else if (status._radioMode == SAT) { if ((status._siriusPreset >= 0) && (status._siriusPreset < 16)) { msg.data[0] = (status._siriusPreset + 1) << 4; } msg.data[0] |= 0x04; msg.data[1] = 0; 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; CANDevice->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) && (status._amPreset < 16)) { 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) && (status._fmPreset < 16)) { msg.data[0] = (status._fmPreset + 1) << 4; } msg.data[0] |= 0x01; msg.data[1] = (status._fmFreq & 0xFF00) >> 8; msg.data[2] = (status._fmFreq & 0x00FF); } CANDevice->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; CANDevice->write(msg); } void RadioEmulator::SendHostMessages() { if (hostMessages.size() > 0) { CANDevice->write(hostMessages.front()); hostMessages.pop_front(); } } void RadioEmulator::ChangeSiriusStation(int station, bool turn_on) { if (station == 0) { return; } CANMessage msg; msg.id = 0x3B0; msg.len = 6; if (turn_on) { msg.data[0] = 21; } else { msg.data[0] = 23; } msg.data[1] = station; CANDevice->write(msg); memset(msg.data, 0, 8); msg.data[1] = station; CANDevice->write(msg); status._siriusChan = station; memset(&siriusdata, 0, 512); } void RadioEmulator::ParseCANMessage(CANMessage can_MsgRx) { // 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)) { } if (can_MsgRx.id == 0x000) { /* if (can_MsgRx.data[0] > 1) { radioOn = true; } else { radioOn = false; } */ 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]) >> 7; // what are the other 4 bytes? } else if (can_MsgRx.id == 0x003) { status._brake = can_MsgRx.data[3] & 0x01; status._gear = can_MsgRx.data[4]; if (status._gear == 'R') { reverse = 1; } else { reverse = 0; } } else 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) { } } else if (can_MsgRx.id == 0x14) { status._odometer = (can_MsgRx.data[0] << 16) + (can_MsgRx.data[1] << 8) + can_MsgRx.data[2]; // what are the other 4 bytes? } 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 >= 0) && (part < 3)) { for (int i = 1; i < 8; i++) { status._vin[(part*7) + 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 == 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); } } 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]; } } else if (can_MsgRx.id == 0x3a0) { // note = 0x01 // volume up = 0x02 // volume down = 0x04 // up arrow = 0x08 // down arrow = 0x10 // right arrow = 0x20 status.SWCButtons = can_MsgRx.data[0]; } else if (can_MsgRx.id == 0x3bd) { ReadSiriusText((char *)can_MsgRx.data); } } void RadioEmulator::ReadSiriusText(char *data) { int num = (data[0] & 0xF0) >> 4; if ((num > 7) || (num < 0)) { return; } int part = (data[0] & 0x0E) >> 1; if ((part > 7) || (part < 0)) { return; } if ((data[0] & 0x01) != 0) { memset(&siriusdata[num * 64], 0, 64); } memset(&siriusdata[(num * 64) + (part * 7)], 0, 7); for (int i = 1; i < 8; i++) { siriusdata[(num * 64) + (part * 7) + (i-1)] = data[i]; } /* int cls = (data[0] & 0x0F) >> 1; if (cls - 1 == 0) { for (int i = 0; i < 8; i++) { memset(st.TextLine[i], 0, 64); for (int j = 0; j < 8; j++) { strcat(st.TextLine[i], siriusText[i][j]); } printf("%d: %s\r\n", i, st.TextLine[i]); } } */ } void RadioEmulator::readCANbus(void) { if (CANDevice->read(can_MsgRx)) { led3 = !led3; needToParseCANMessage = true; ReceivedCANMsg = true; char buffer[11]; buffer[0] = (can_MsgRx.id & 0xFF00) >> 8; buffer[1] = can_MsgRx.id & 0x00FF; buffer[2] = can_MsgRx.len; memcpy(&buffer[3], can_MsgRx.data, 8); static Host monitorHost(IpAddr(224,1,2,3), 41000, NULL); HostSock->SendTo(&monitorHost, can_MsgRx.len + 3, buffer); } if (needToParseCANMessage) { needToParseCANMessage = false; ParseCANMessage(can_MsgRx); } } void RadioEmulator::ReceivedData(int socketStatus, int len, char *msg) { 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: if (len >= 11) { 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: if (len >= 6) { status._siriusChan = msg[5]; ChangeSiriusStation(msg[5], false); } break; case 0x03: if (len >= 11) { 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; case 0x04: // CANMessage canMsg; // canMsg.id = msg[5] + (msg[6] << 8); // canMsg.len = msg[7]; // memcpy(canMsg.data, msg + 8, canMsg.len); // hostMessages.push_back(canMsg); break; } } } void RadioEmulator::WriteCANMessages() { writeCANFlag = true; } void RadioEmulator::SendStatusToHost(void) { statusFlag = true; } void RadioEmulator::CheckHostTimeout(void) { hostTimeoutFlag = true; } // only enable this if trying to power up/down the processor void RadioEmulator::CheckCANTimeout(void) { CANTimeoutFlag = true; } void RadioEmulator::CANActivity(void) { if (powerUpIRQCounter == 5) { canIRQ->rise(0); needToWakeUp = true; } powerUpIRQCounter++; }