Library to control Dodge LX (83.3k) CAN devices

Dependencies:   DodgeRadioLib EthernetWrapperLib OBDIILib mbed

radioEmulator.cpp

Committer:
rtgree01
Date:
2011-12-30
Revision:
1:90487a39d54e
Parent:
0:4d16a55d0eec
Child:
2:e8b13ea2881b

File content as of revision 1:90487a39d54e:

#include "mbed.h"
#include "radioEmulator.h"

DigitalOut led1(LED1);
DigitalOut led2(LED2);
DigitalOut led3(LED3);
DigitalOut led4(LED4);

Timer timer;
int begin, end;
Serial pc(USBTX, USBRX); // tx, rx

#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()
{
    ethBusy = false;
    eth = new EthernetNetIf(IpAddr(10,10,10,2), IpAddr(255,255,255,0), IpAddr(10,10,10,1), IpAddr(10,10,10,1));
    EthernetErr ethErr = eth->setup();
    if(ethErr)
    {
        printf("Error %d in setup.\n", ethErr);
        return;
    }
    printf("Setup OK\r\n");
    printf("Size of radiostate = %d\r\n", sizeof(RadioState));
    
    multicast = new Host(IpAddr(239, 192, 1, 100), 50000, NULL); //Join multicast group on port 50000
    
    udp.setOnEvent(this, &RadioEmulator::onUDPSocketEvent);
    
    udp.bind(*multicast);
        
    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);
        }
    }
    
    printf("starting\r\n");
    
    memset(&status, 0, sizeof(status));  
    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++)
    {
        sprintf(status._siriusTextLine[i], "Fun line text # %d", i);
    }

    PowerUp();
    
    ReceivedHostMsg = false;
    statusTicker.attach(this, &RadioEmulator::SendStatusToHost, 0.1);

    opMode = standalone;
    HostTimeout.attach(this, &RadioEmulator::CheckHostTimeout, 1);
    
    printf("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::WriteCANMessages()
{
    if (radioOn)
    {
        led2 = !led2;
        SendRadioModeMsg();
        SendEVICMsg();
        SendStereoSettingsMsg();
        SendHostMessages();
    }
}

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] = 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)
        {
            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 << 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)
        {
            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;

    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::SendHostMessages()
{
    if (hostMessages.size() > 0)
    {
        can2->write(hostMessages.front());
        
        hostMessages.pop_front();
    }
}

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
               
        status.SWCButtons = 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]) >> 7;
    }
    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]);
            }
            
            printf("%d: %s\r\n", i, status._siriusTextLine[i]);
        }
    }
}

void RadioEmulator::readCANbus(void)
{
    if (can2->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 multicast3(IpAddr(239, 192, 1, 100), 41000, NULL); //Join multicast group on port 50000
        
        while (ethBusy == true) {};
        ethBusy = true;
        udp.sendto(buffer, 11, &multicast3);
        ethBusy = false;
    }
    
    if (needToParseCANMessage)
    {           
        needToParseCANMessage = false;   
        
        ParseCANMessage(can_MsgRx);
    }
}

void RadioEmulator::HostComm(void)
{
    Net::poll();              
}

void RadioEmulator::onUDPSocketEvent(UDPSocketEvent e)
{
    switch(e)
    {
        case UDPSOCKET_READABLE: //The only event for now
            char buf[64] = {0};
            Host host;
            while( int len = udp.recvfrom( buf, 63, &host ) )
            {
                if( len <= 0 )
                    break;
                    
                HandleHostComm(buf, len);
            }
        break;
    }
}

void RadioEmulator::HandleHostComm(char *msg, int len)
{
    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;
            
            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::SendStatusToHost(void)
{
    int size = sizeof(status);
    
    if (opMode == standalone)
    {
        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)
                    ChangeSiriusStation(status._siriusChan+1, false);
            }
            else if ((prevSWC & 0x00000001) != 0)
            {
                for (int i = 0; i < 5; i++)
                {
//                    SendWOLPacket();
                }
            }
        }
    }

    prevSWC = status.SWCButtons;

    status.count++;    
    RadioState tempStatus;
    memcpy(&tempStatus, &status, size);
    char *data = (char *)&tempStatus;
 
    static Host multicast2(IpAddr(239, 192, 1, 100), 51000, NULL); //Join multicast group on port 50000
    while (ethBusy == true) {};
    ethBusy = true;
    udp.sendto(data, size, &multicast2);
    ethBusy = false;
}

void RadioEmulator::PowerUp(void)
{
    led1 = 1;
    poweredDown = 0;
    needToParseCANMessage = false;   
    LPC_CAN2->BTR = 0x52001C;
    *can_RS = 0;
    ReceivedCANMsg = false;

/*
#ifdef CHECK_HW_SHUTDOWN
    canIRQ->rise(this, &RadioEmulator::StartEmulation);
#else
*/
    StartEmulation();
//#endif
}

void RadioEmulator::StartEmulation(void)
{
//    canIRQ->rise(0);
    
    CANBusTicker.attach(this, &RadioEmulator::WriteCANMessages, 0.5);

    ChangeSiriusStation(status._siriusChan, true);
    
//    CANTimeout.attach(this, &RadioEmulator::CheckCANTimeout, 1);

/*    
    for (int i = 0; i < 5; i++)
    {
        SendWOLPacket();
    }
*/
}

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::RestartCAN(void)
{
    if (poweredDown == 5)
    {
        canIRQ->rise(NULL);
        PowerUp();
    }
    poweredDown++;
}

void RadioEmulator::SendWOLPacket(void)
{
    unsigned char data[102];
    memset(data, 0xff, 6);
    
    for (int i = 0; i < 16; i++)
    {
        memcpy(data + 6 + (16 * i), hostMACAddress, 6);
    }
    static Host wol(IpAddr(10, 10, 10, 255), 7, NULL);

    while (ethBusy == true) {};
    ethBusy = true;    
    udp.sendto((char *)data, 102, &wol);
    ethBusy = false;
}