.

Dependencies:   SDHCFileSystem mbed

main.cpp

Committer:
TickTock
Date:
2013-12-11
Revision:
26:30ceff44a936
Parent:
25:bfbe84136774

File content as of revision 26:30ceff44a936:

//CANcan.cpp
//A dual canbus monitoring "blackbox" application for the Nissan Leaf
//Dumps all messages to a file on the SDRAM
//Todo:
//  Get timestamp on files
//  
// Connections:
//LEAF OBD
//1:                
//2:
//3:    AVCAN-L     White/Blue
//4:   
//5:    VSS         Brown,White/Brown
//6:    CARCAN-H    Green                   --> VP230b:7
//7:
//8:    12V-SW      Orange,White/Orange
//9:
//10:
//11:   AVCAN-H     Blue
//12:   EVCAN-L     White/Grey              --> VP230a:6
//13:   EVCAN-H     Grey                    --> VP230a:7
//14:   CARCAN-L    White/Green             --> VP230b:6
//15:                                     6V
//16:   12V-AON     Red/Blue,Blue/Red ----|<---- LPC1768:2
//note 1: pins 4 & 5 longer
//note 2: pins 12 & 13 next to key
//note 3: pins 1 & 9 on right side looking into male connector with key on bottom

//VP230{a,b}
//1:D   
//2:GND 
//3:VCC 
//4:R   
//5:Vref
//6:CANL        --> OBD:12,14
//7:CANH        --> OBD:13,6
//8:RS          --> LPC1768:27,28

//LPC1768
//1:    VSS                      6V
//2:    VIN  (4.5-9V supply) ---->|---- OBD:16
//3:        NC:VB
//4:        NC:nR
//5:    SPI:MOSI   -->  6:SDRAM:DI
//6:    SPI:MISO   -->  2:SDRAM:DO
//7:    SPI:SCLK   -->  4:SDRAM:SCLK
//8:    CS         -->  7:SDRAM:CS
//9:    CAN1:RX    -->  4:CAN1:R
//10:   CAN1:TX    -->  1:CAN1:D
//11:       NC:RS         -->  4:LCD:RS
//12:       NC:E          -->  6:LCD:E
//13:       NC:D4         -->  11:LCD:D4
//14:       NC:D5         -->  12:LCD:D5
//15:       NC:D6         -->  13:LCD:D6
//16:       NC:D7         -->  14:LCD:D7
//17:   CD         -->  1:SDRAM:CD
//18:       NC:MON12V     -->  4K to 12V, 1K to VSS  (To be implemented)
//19:   PB2
//20:   PB1
//21:       NC:Spkr+
//22:       NC:Spkr-           (optional complimentary output for more volume)
//23:       NC:pwm
//24:       NC:LEDBLU     -->  18:LCD:BLU (only used for tri-color displays)
//25:       NC:LEDGRN     -->  17:LCD:GRN (only used for tri-color displays)
//26:       NC:LEDRED     -->  16:LCD:RED
//27:   CAN1:Sleep -->  8:CAN1:RS
//28:   CAN2:Sleep -->  8:CAN2:RS
//29:   CAN2:TX    -->  1:CAN2:D
//30:   CAN2:RX    -->  4:CAN2:R
//31:       NC:USB_D+
//32:       NC:USB_D-
//33:       NC:Eth_TD+
//34:       NC:Eth_TD-
//35:       NC:Eth_RD+
//36:       NC:Eth_RD-
//37:       NC:IF+
//38:       NC:IF-
//39:       NC:5Vout (only available when connected as USB device)
//40:   VCC3.3
// Set serial to 460800; RX:LF
#include "mbed.h"
#include "CAN.h"
#include "SDHCFileSystem.h"

#define upLine "\033[1A"
#define maxBufLen 2048
#define canTimeout 5
#define maxFileNum 30
#define pollInt 60
#define BatDataBaseG1 0x00 // 6 frames - SOH, SOC, Ah
#define BatDataBaseG2 0x06 // 29 frames - Cell Pair data
#define BatDataBaseG3 0x23 // 5 frames
#define BatDataBaseG4 0x28 // 3 frames - Temperature data
#define BatDataBaseG5 0x2B // 11 frames
#define BatDataBaseG6 0x36 // 4 frames
#define BatDataBaseG7 0x3A
#define BatDataBufMax 0x196 // 7 x 3A bytes

//void Log (char *message);
//void LogErr (char *message);
//void autoPollISR();
//void sendReq();
extern "C" void mbed_reset();

time_t seconds ;
DigitalIn CD(p17); 
DigitalIn PB1( p20 );
SDFileSystem sd(p5, p6, p7, p8, "sd" ); // SDFileSystem::SDFileSystem(PinName mosi, PinName miso, PinName sclk, PinName cs, const char* name)
Timer timer;
DigitalOut led1(LED1);
DigitalOut led2(LED2);
DigitalOut led3(LED3);
DigitalOut led4(LED4);
CAN can1(p9, p10);      // CAN1 uses pins 9 and 10 (rx, tx) and pin 27 (rs)
DigitalOut can1_SleepMode(p27);     // Use pin 27 to control the sleep mode of can1
CAN can2(p30, p29);     // CAN2 uses pins 30 and 29 (rx, tx) and pin 28 (rs)
DigitalOut can2_SleepMode(p28);     // Use pin 28 to control the sleep mode of can2
bool logOpen = false;
FILE *rfile;
FILE *file;
char fileName[35] = "" ;
char writeBuffer[maxBufLen][13];
char c;
volatile int writePointer = 0;
volatile int secsIdle = 0;
volatile bool canIdle = false;
Serial pc(USBTX, USBRX);
Ticker autoPoll;
Ticker msgReq;
unsigned char reqMsgCnt = 99;

extern "C" void RTC_IRQHandler() {
    timer.reset(); // zero ms at the-seconds-tic
    canIdle=(++secsIdle>canTimeout);
    LPC_RTC->ILR |= (1<<0); // clear interrupt to prepare for next
}

extern "C" void RTC_Init (void) {
    LPC_RTC->ILR=0x00; // set up the RTC interrupts
    LPC_RTC->CIIR=0x01; // interrupts each second
    LPC_RTC->CCR = 0x01;  // Clock enable
    //NVIC_SetPriority( RTC_IRQn, 10 );
    NVIC_EnableIRQ( RTC_IRQn );
}

unsigned short getTimeStamp() {
    int msec = timer.read_ms() ; // read ms from the timer
    unsigned long secs = time(NULL); // seconds past 12:00:00 AM 1 Jan 1900
    int isecs = secs%60 ; // modulo 60 for 0-59 seconds from RTC
    return ((isecs<<10)+msec) ; // return the two byte time stamp
}

void readLog (){
    unsigned char c;
    int i=0;
    char lastMsgNum[]={0,0};
    char curMsgNum[]={0,0};
    char canNum=0;
    pc.printf("printing file\n");
    file = fopen(fileName, "r");
    if (file == NULL) {
        pc.printf("no file found\n");
    }
    while (!feof(file)) {
        c=fgetc(file);
        pc.printf("%02x ",c);
        if (i==0){
            canNum=c;
        }else if (i==5){
            curMsgNum[canNum]=c;
        }
        if (++i>12) {
            if (curMsgNum[canNum]>(lastMsgNum[canNum]+1)) {
                pc.printf(" ***");
            }
            lastMsgNum[canNum]=curMsgNum[canNum];
            pc.printf("\n");
            i=0;
        }
    }
    pc.printf("\n\n");
    fclose(file);
}

void logCan (char mtype, CANMessage canRXmsg) {
    unsigned short ts = getTimeStamp();
    unsigned long secs = time(NULL); // seconds past 12:00:00 AM 1 Jan 1900
    if(canRXmsg.id>0) {
        writeBuffer[writePointer][0]=mtype;
        writeBuffer[writePointer][1]=((secs%60)<<2)+((ts&0x300)>>8);
        writeBuffer[writePointer][2]=ts&0xff;
        writeBuffer[writePointer][3]=canRXmsg.id&0xff;
        writeBuffer[writePointer][4]=(canRXmsg.id>>8)+(canRXmsg.len<<4);
        for (int i = 5; i<13; i++){
            writeBuffer[writePointer][i]=canRXmsg.data[i-5];
        }
        if (++writePointer >= maxBufLen) {
            writePointer = 0;
            led4 = !led4;
        }
    }
}

void logTS () {
    CANMessage tsMsg;
    unsigned long secs = time(NULL); // seconds past 12:00:00 AM 1 Jan 1900
    tsMsg.id=0xfff;
    tsMsg.len=0xf;
    tsMsg.data[0]=secs&0xff;
    tsMsg.data[1]=(secs>>8)&0xff;
    tsMsg.data[2]=(secs>>16)&0xff;
    tsMsg.data[3]=secs>>24;
    tsMsg.data[4]=0xff;
    tsMsg.data[5]=0xff;
    tsMsg.data[6]=0xff;
    tsMsg.data[7]=0xff;
    logCan(0,tsMsg);
}
void recieve1() {
    CANMessage msg1;
    secsIdle=0; // reset deadman switch
    can1.read(msg1);
    if(logOpen)
        logCan(2, msg1);
    led1 = !led1;
}

void recieve2() {
    CANMessage msg2;
    secsIdle=0; // reset deadman switch
    can2.read(msg2);
    if(logOpen)
        logCan(1, msg2);
    led2 = !led2;
}

void sendReq() {
    static char data[8] = {0x02, 0x21, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff};
    if(reqMsgCnt<99){
        switch (reqMsgCnt){
            case BatDataBaseG1:
                can1.monitor(false); // set to active mode
                can1_SleepMode = 0; // enable TX
                data[0]=0x02; //change to request group 1
                data[1]=0x21;
                data[2]=0x01;
                break;
            case BatDataBaseG2: // group 1 has 6 frames
                data[0]=0x02; //change to request group 2 (cp data)
                data[1]=0x21;
                data[2]=0x02;
                break;
            case BatDataBaseG3: // group 2 has 29 frames
                data[0]=0x02; //change to request group 3
                data[1]=0x21;
                data[2]=0x03;
                break;
            case BatDataBaseG4: // group 3 has 5 frames
                data[0]=0x02; //change to request group 4 (temperature)
                data[1]=0x21;
                data[2]=0x04;
                break;
            case BatDataBaseG5: // group 4 has 3 frames
                data[0]=0x02; //change to request group 5
                data[1]=0x21;
                data[2]=0x05;
                break;
            case BatDataBaseG6: // group 4 has 3 frames
                data[0]=0x02; //change to request group 5
                data[1]=0x21;
                data[2]=0x06;
                break;
            case BatDataBaseG7: // group 5 has 11 frames
                reqMsgCnt = 99;
                can1_SleepMode = 1; // disable TX
                can1.monitor(true); // set to snoop mode
                msgReq.detach(); // stop ticker
            default:
                data[0]=0x30; //change to request next line message
                data[1]=0x01;
                data[2]=0x00;
        }
        can1.write(CANMessage(0x79b, data, 8));
        reqMsgCnt++;
    }
}

void autoPollISR(){
    reqMsgCnt = 0; //reset message counter
    msgReq.attach(&sendReq,0.015);
}

int main() {
    int readPointer=0;
    int fmon;
    int fday;
    int ftime;
    char sTemp[35];
    unsigned long secs;
    bool bit = false;
    pc.baud(460800);        // change serial interface to pc to 450800, 8N1
    can1.frequency(500000);
    can2.frequency(500000);
    can1_SleepMode = 1;         // Monitor_only Mode
    can2_SleepMode = 1;         // Monitor_only Mode
    CD.mode(PullUp) ; //SDRAM Chip Detect
    PB1.mode(PullUp) ; //Pushbutton 1
    can1.attach(&recieve1);
    can2.attach(&recieve2);
    autoPoll.attach(&autoPollISR,pollInt); // Poll battery data every 60 seconds
    msgReq.attach(&sendReq,0.015);  // Each poll message separated by 15ms
        
    timer.start() ;
    RTC_Init(); // start the RTC Interrupts that sync the timer

    struct tm t; // pointer to a static tm structure

    seconds = time(NULL);
    t = *localtime(&seconds) ;
    strftime(sTemp, 32, "%a %m/%d/%Y %X", &t);
    pc.printf("\nCurrent time set to:  %s\n", sTemp); // DAY MM/DD/YYYY HH:MM:SS
    wait(1.1);  // give time to sync
    
    if (PB1==0) { //set time if pb pressed

        pc.printf("\nEnter year (yyyy):");
        pc.scanf("%s", &sTemp);
        t.tm_year = atoi(sTemp);
        
        pc.printf("\nEnter month (mm):");
        pc.scanf("%2s", &sTemp);
        t.tm_mon = atoi(sTemp);
        
        pc.printf("\nEnter day (dd):");
        pc.scanf("%2s", &sTemp);
        t.tm_mday = atoi(sTemp);
        
        pc.printf("\nEnter hour (hh):");
        pc.scanf("%2s", &sTemp);
        t.tm_hour = atoi(sTemp);
        
        pc.printf("\nEnter minute (mm):");
        pc.scanf("%2s", &sTemp);
        t.tm_min = atoi(sTemp);
        
        pc.printf("\nEnter seconds (ss):");
        pc.scanf("%2s", &sTemp);
        t.tm_sec = atoi(sTemp);

        // adjust for tm structure required values
        t.tm_year = t.tm_year - 1900;
        t.tm_mon = t.tm_mon - 1;

        // set the RTC
        set_time(mktime(&t));
        seconds = time(NULL);

        pc.printf("\nRTC set to:  " );
        strftime(sTemp, 32, "%a %m/%d/%Y %X", localtime(&seconds));
        pc.printf("%s\n", sTemp); // DAY MM/DD/YYYY HH:MM:SS
    }
    
    while (true) {
        if(CD == 1) {
            if (!logOpen) { // Open new file if one is not already open
                seconds = time(NULL);
                t = *localtime(&seconds) ;
                strftime(fileName, 32, "/sd/%m%d%H%M.alc", &t); //mmddhhmm.alc

                pc.printf("Using file %s\n",fileName);
                file = fopen(fileName, "ab");
                pc.printf("Using file2 %s\n",fileName);
                
                if(file==NULL){
                    pc.printf("\nUnable to open canlog\n\n\n\n");
                    mbed_reset();
                } else {
                    logOpen = true;
                    readPointer=writePointer;
                    pc.printf("\nStarting Can Log %s\n",fileName);
                    logTS();
                    fclose(file);
                    file = fopen("/sd/loglog.txt", "a");
                    fprintf(file,"%s\r\n",fileName);
                    fclose(file);
                }
            } // if (!logOpen)
            do {
                if (((writePointer+maxBufLen-readPointer)%maxBufLen)>(maxBufLen/2)||canIdle||(PB1==0)) {
                    // Dump buffer if > 1/2 full, canbus has stopped, or PB1 pressed
                    if (logOpen) {
                        file = fopen(fileName, "ab");
                        if (file == NULL) {
                            logOpen = false;
                            pc.printf("Failed to append log file.\n\n");
                        } else {
                            while (readPointer != writePointer) {
                                for (int j = 0; j<13; j++){
                                    fprintf(file,"%c",writeBuffer[readPointer][j]);
                                }
                                if(++readPointer >= maxBufLen)
                                    readPointer=0;
                            }
                            led3 = !led3;
                            fclose(file);
                        }
                    } // if (logOpen)
                } // if > 1/2 full, canbus has stopped, or PB1 pressed
                if (canIdle) { // canbus idle --> sleep to save power
                    // First take advantage of the idle time to clear some room
                    
                    bit = false;
                    rfile = fopen("/sd/loglog.txt", "r");
                    file = fopen("/sd/loglog.new", "w");
                    while (!feof(rfile)) {
                        fscanf(rfile,"/sd/%2d%2d%4d.alc\r\n",&fmon,&fday,&ftime);
                        //if ((fmon < 12) || (t.tm_mon > 1)){
                        //    fday = fday + fmon*31; //crude - february will store 3 extra days of data
                        //}
                        //if ((fday+14)<(t.tm_mday+t.tm_mon*31)){ // Delete all files more than ~14 days old
                        if (((fmon<=t.tm_mon)&&(fday<t.tm_mday))||(fmon>t.tm_mon+2)){ // Delete all files more than 1 month old
                            bit=true;
                            sprintf(sTemp,"/sd/%02d%02d%04d.alc",fmon,fday,ftime);
                            if ((remove(sTemp)==NULL)) {
                                pc.printf("Removed file %s\n",sTemp);
                            }
                        }else{
                            fprintf(file,"/sd/%02d%02d%04d.alc\r\n",fmon,fday,ftime);
                        }
                    }
                    fclose (file);
                    fclose (rfile);
                    if (bit) {
                        remove ("/sd/loglog.txt");
                        //rename not working so do it the hard way
                        //rename ("/sd/loglog.new","/sd/loglog.txt");
                        rfile = fopen("/sd/loglog.new", "r");
                        file = fopen("/sd/loglog.txt", "w");
                        while (!feof(rfile)) {
                            fscanf(rfile,"%s\r\n",&sTemp);
                            fprintf(file,"%s\r\n",sTemp);
                        }
                        fclose (file);
                        fclose (rfile);
                    }
                    remove ("/sd/loglog.new");                    
                    wait(5); // wait a few seconds to ensure SDRAM is done

                    pc.printf("Putting uC to sleep.\n");
                    //LPC_RTC->CIIR=0x00; // block RTC interrupts
                    led1=0;
                    led2=0;
                    led3=0;
                    led4=0;
                    secs = time(NULL); // seconds past 12:00:00 AM 1 Jan 1900
                    while (secsIdle>canTimeout) {
                        //DeepPowerDown();
                        __wfi(); // freeze CPU and wait for interrupt (from canbus)
                    }
                    canIdle=false;
                    pc.printf("Waking uC.\n");
                    if (time(NULL)>(secs+1800)) {
                        logOpen = false; // Start new file if asleep for more than 30 minutes
                    } else { // insert timestamp on each wake
                        logTS();
                    }
                    //LPC_RTC->CIIR=0x01; // re-enable RTC interrupts
                }
                wait(0.2); // We get >2K messages per second
            } while ((PB1==1)&&(CD==1)&&logOpen); // keep going until button or SDram removed

            if (PB1==0) {
                led1=0;
                led2=0;
                led3=0;
                led4=0;
                pc.printf("Log stopped\n\n");
                logOpen=false;
                wait(5); // wait 5 seconds to give time to remove SDRAM if desired
                if (PB1==0)
                    readLog(); // dump file if PB still pressed
            }
        } else {
            pc.printf("\nNo SDRAM Inserted.\n\n");
            logOpen=false;
            led1=!led1;
            led2=led1;
            led3=led1;
            led4=led1;
            wait(5);
        } //if (CD==1)
    } //while (true)
}