.

Dependencies:   SDHCFileSystem mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 //CANcan.cpp
00002 //A dual canbus monitoring "blackbox" application for the Nissan Leaf
00003 //Dumps all messages to a file on the SDRAM
00004 //Todo:
00005 //  Get timestamp on files
00006 //  
00007 // Connections:
00008 //LEAF OBD
00009 //1:                
00010 //2:
00011 //3:    AVCAN-L     White/Blue
00012 //4:   
00013 //5:    VSS         Brown,White/Brown
00014 //6:    CARCAN-H    Green                   --> VP230b:7
00015 //7:
00016 //8:    12V-SW      Orange,White/Orange
00017 //9:
00018 //10:
00019 //11:   AVCAN-H     Blue
00020 //12:   EVCAN-L     White/Grey              --> VP230a:6
00021 //13:   EVCAN-H     Grey                    --> VP230a:7
00022 //14:   CARCAN-L    White/Green             --> VP230b:6
00023 //15:                                     6V
00024 //16:   12V-AON     Red/Blue,Blue/Red ----|<---- LPC1768:2
00025 //note 1: pins 4 & 5 longer
00026 //note 2: pins 12 & 13 next to key
00027 //note 3: pins 1 & 9 on right side looking into male connector with key on bottom
00028 
00029 //VP230{a,b}
00030 //1:D   
00031 //2:GND 
00032 //3:VCC 
00033 //4:R   
00034 //5:Vref
00035 //6:CANL        --> OBD:12,14
00036 //7:CANH        --> OBD:13,6
00037 //8:RS          --> LPC1768:27,28
00038 
00039 //LPC1768
00040 //1:    VSS                      6V
00041 //2:    VIN  (4.5-9V supply) ---->|---- OBD:16
00042 //3:        NC:VB
00043 //4:        NC:nR
00044 //5:    SPI:MOSI   -->  6:SDRAM:DI
00045 //6:    SPI:MISO   -->  2:SDRAM:DO
00046 //7:    SPI:SCLK   -->  4:SDRAM:SCLK
00047 //8:    CS         -->  7:SDRAM:CS
00048 //9:    CAN1:RX    -->  4:CAN1:R
00049 //10:   CAN1:TX    -->  1:CAN1:D
00050 //11:       NC:RS         -->  4:LCD:RS
00051 //12:       NC:E          -->  6:LCD:E
00052 //13:       NC:D4         -->  11:LCD:D4
00053 //14:       NC:D5         -->  12:LCD:D5
00054 //15:       NC:D6         -->  13:LCD:D6
00055 //16:       NC:D7         -->  14:LCD:D7
00056 //17:   CD         -->  1:SDRAM:CD
00057 //18:       NC:MON12V     -->  4K to 12V, 1K to VSS  (To be implemented)
00058 //19:   PB2
00059 //20:   PB1
00060 //21:       NC:Spkr+
00061 //22:       NC:Spkr-           (optional complimentary output for more volume)
00062 //23:       NC:pwm
00063 //24:       NC:LEDBLU     -->  18:LCD:BLU (only used for tri-color displays)
00064 //25:       NC:LEDGRN     -->  17:LCD:GRN (only used for tri-color displays)
00065 //26:       NC:LEDRED     -->  16:LCD:RED
00066 //27:   CAN1:Sleep -->  8:CAN1:RS
00067 //28:   CAN2:Sleep -->  8:CAN2:RS
00068 //29:   CAN2:TX    -->  1:CAN2:D
00069 //30:   CAN2:RX    -->  4:CAN2:R
00070 //31:       NC:USB_D+
00071 //32:       NC:USB_D-
00072 //33:       NC:Eth_TD+
00073 //34:       NC:Eth_TD-
00074 //35:       NC:Eth_RD+
00075 //36:       NC:Eth_RD-
00076 //37:       NC:IF+
00077 //38:       NC:IF-
00078 //39:       NC:5Vout (only available when connected as USB device)
00079 //40:   VCC3.3
00080 // Set serial to 460800; RX:LF
00081 #include "mbed.h"
00082 #include "CAN.h"
00083 #include "SDHCFileSystem.h"
00084 
00085 #define upLine "\033[1A"
00086 #define maxBufLen 2048
00087 #define canTimeout 5
00088 #define maxFileNum 30
00089 #define pollInt 60
00090 #define BatDataBaseG1 0x00 // 6 frames - SOH, SOC, Ah
00091 #define BatDataBaseG2 0x06 // 29 frames - Cell Pair data
00092 #define BatDataBaseG3 0x23 // 5 frames
00093 #define BatDataBaseG4 0x28 // 3 frames - Temperature data
00094 #define BatDataBaseG5 0x2B // 11 frames
00095 #define BatDataBaseG6 0x36 // 4 frames
00096 #define BatDataBaseG7 0x3A
00097 #define BatDataBufMax 0x196 // 7 x 3A bytes
00098 
00099 //void Log (char *message);
00100 //void LogErr (char *message);
00101 //void autoPollISR();
00102 //void sendReq();
00103 extern "C" void mbed_reset();
00104 
00105 time_t seconds ;
00106 DigitalIn CD(p17); 
00107 DigitalIn PB1( p20 );
00108 SDFileSystem sd(p5, p6, p7, p8, "sd" ); // SDFileSystem::SDFileSystem(PinName mosi, PinName miso, PinName sclk, PinName cs, const char* name)
00109 Timer timer;
00110 DigitalOut led1(LED1);
00111 DigitalOut led2(LED2);
00112 DigitalOut led3(LED3);
00113 DigitalOut led4(LED4);
00114 CAN can1(p9, p10);      // CAN1 uses pins 9 and 10 (rx, tx) and pin 27 (rs)
00115 DigitalOut can1_SleepMode(p27);     // Use pin 27 to control the sleep mode of can1
00116 CAN can2(p30, p29);     // CAN2 uses pins 30 and 29 (rx, tx) and pin 28 (rs)
00117 DigitalOut can2_SleepMode(p28);     // Use pin 28 to control the sleep mode of can2
00118 bool logOpen = false;
00119 FILE *rfile;
00120 FILE *file;
00121 char fileName[35] = "" ;
00122 char writeBuffer[maxBufLen][13];
00123 char c;
00124 volatile int writePointer = 0;
00125 volatile int secsIdle = 0;
00126 volatile bool canIdle = false;
00127 Serial pc(USBTX, USBRX);
00128 Ticker autoPoll;
00129 Ticker msgReq;
00130 unsigned char reqMsgCnt = 99;
00131 
00132 extern "C" void RTC_IRQHandler() {
00133     timer.reset(); // zero ms at the-seconds-tic
00134     canIdle=(++secsIdle>canTimeout);
00135     LPC_RTC->ILR |= (1<<0); // clear interrupt to prepare for next
00136 }
00137 
00138 extern "C" void RTC_Init (void) {
00139     LPC_RTC->ILR=0x00; // set up the RTC interrupts
00140     LPC_RTC->CIIR=0x01; // interrupts each second
00141     LPC_RTC->CCR = 0x01;  // Clock enable
00142     //NVIC_SetPriority( RTC_IRQn, 10 );
00143     NVIC_EnableIRQ( RTC_IRQn );
00144 }
00145 
00146 unsigned short getTimeStamp() {
00147     int msec = timer.read_ms() ; // read ms from the timer
00148     unsigned long secs = time(NULL); // seconds past 12:00:00 AM 1 Jan 1900
00149     int isecs = secs%60 ; // modulo 60 for 0-59 seconds from RTC
00150     return ((isecs<<10)+msec) ; // return the two byte time stamp
00151 }
00152 
00153 void readLog (){
00154     unsigned char c;
00155     int i=0;
00156     char lastMsgNum[]={0,0};
00157     char curMsgNum[]={0,0};
00158     char canNum=0;
00159     pc.printf("printing file\n");
00160     file = fopen(fileName, "r");
00161     if (file == NULL) {
00162         pc.printf("no file found\n");
00163     }
00164     while (!feof(file)) {
00165         c=fgetc(file);
00166         pc.printf("%02x ",c);
00167         if (i==0){
00168             canNum=c;
00169         }else if (i==5){
00170             curMsgNum[canNum]=c;
00171         }
00172         if (++i>12) {
00173             if (curMsgNum[canNum]>(lastMsgNum[canNum]+1)) {
00174                 pc.printf(" ***");
00175             }
00176             lastMsgNum[canNum]=curMsgNum[canNum];
00177             pc.printf("\n");
00178             i=0;
00179         }
00180     }
00181     pc.printf("\n\n");
00182     fclose(file);
00183 }
00184 
00185 void logCan (char mtype, CANMessage canRXmsg) {
00186     unsigned short ts = getTimeStamp();
00187     unsigned long secs = time(NULL); // seconds past 12:00:00 AM 1 Jan 1900
00188     if(canRXmsg.id>0) {
00189         writeBuffer[writePointer][0]=mtype;
00190         writeBuffer[writePointer][1]=((secs%60)<<2)+((ts&0x300)>>8);
00191         writeBuffer[writePointer][2]=ts&0xff;
00192         writeBuffer[writePointer][3]=canRXmsg.id&0xff;
00193         writeBuffer[writePointer][4]=(canRXmsg.id>>8)+(canRXmsg.len<<4);
00194         for (int i = 5; i<13; i++){
00195             writeBuffer[writePointer][i]=canRXmsg.data[i-5];
00196         }
00197         if (++writePointer >= maxBufLen) {
00198             writePointer = 0;
00199             led4 = !led4;
00200         }
00201     }
00202 }
00203 
00204 void logTS () {
00205     CANMessage tsMsg;
00206     unsigned long secs = time(NULL); // seconds past 12:00:00 AM 1 Jan 1900
00207     tsMsg.id=0xfff;
00208     tsMsg.len=0xf;
00209     tsMsg.data[0]=secs&0xff;
00210     tsMsg.data[1]=(secs>>8)&0xff;
00211     tsMsg.data[2]=(secs>>16)&0xff;
00212     tsMsg.data[3]=secs>>24;
00213     tsMsg.data[4]=0xff;
00214     tsMsg.data[5]=0xff;
00215     tsMsg.data[6]=0xff;
00216     tsMsg.data[7]=0xff;
00217     logCan(0,tsMsg);
00218 }
00219 void recieve1() {
00220     CANMessage msg1;
00221     secsIdle=0; // reset deadman switch
00222     can1.read(msg1);
00223     if(logOpen)
00224         logCan(2, msg1);
00225     led1 = !led1;
00226 }
00227 
00228 void recieve2() {
00229     CANMessage msg2;
00230     secsIdle=0; // reset deadman switch
00231     can2.read(msg2);
00232     if(logOpen)
00233         logCan(1, msg2);
00234     led2 = !led2;
00235 }
00236 
00237 void sendReq() {
00238     static char data[8] = {0x02, 0x21, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff};
00239     if(reqMsgCnt<99){
00240         switch (reqMsgCnt){
00241             case BatDataBaseG1:
00242                 can1.monitor(false); // set to active mode
00243                 can1_SleepMode = 0; // enable TX
00244                 data[0]=0x02; //change to request group 1
00245                 data[1]=0x21;
00246                 data[2]=0x01;
00247                 break;
00248             case BatDataBaseG2: // group 1 has 6 frames
00249                 data[0]=0x02; //change to request group 2 (cp data)
00250                 data[1]=0x21;
00251                 data[2]=0x02;
00252                 break;
00253             case BatDataBaseG3: // group 2 has 29 frames
00254                 data[0]=0x02; //change to request group 3
00255                 data[1]=0x21;
00256                 data[2]=0x03;
00257                 break;
00258             case BatDataBaseG4: // group 3 has 5 frames
00259                 data[0]=0x02; //change to request group 4 (temperature)
00260                 data[1]=0x21;
00261                 data[2]=0x04;
00262                 break;
00263             case BatDataBaseG5: // group 4 has 3 frames
00264                 data[0]=0x02; //change to request group 5
00265                 data[1]=0x21;
00266                 data[2]=0x05;
00267                 break;
00268             case BatDataBaseG6: // group 4 has 3 frames
00269                 data[0]=0x02; //change to request group 5
00270                 data[1]=0x21;
00271                 data[2]=0x06;
00272                 break;
00273             case BatDataBaseG7: // group 5 has 11 frames
00274                 reqMsgCnt = 99;
00275                 can1_SleepMode = 1; // disable TX
00276                 can1.monitor(true); // set to snoop mode
00277                 msgReq.detach(); // stop ticker
00278             default:
00279                 data[0]=0x30; //change to request next line message
00280                 data[1]=0x01;
00281                 data[2]=0x00;
00282         }
00283         can1.write(CANMessage(0x79b, data, 8));
00284         reqMsgCnt++;
00285     }
00286 }
00287 
00288 void autoPollISR(){
00289     reqMsgCnt = 0; //reset message counter
00290     msgReq.attach(&sendReq,0.015);
00291 }
00292 
00293 int main() {
00294     int readPointer=0;
00295     int fmon;
00296     int fday;
00297     int ftime;
00298     char sTemp[35];
00299     unsigned long secs;
00300     bool bit = false;
00301     pc.baud(460800);        // change serial interface to pc to 450800, 8N1
00302     can1.frequency(500000);
00303     can2.frequency(500000);
00304     can1_SleepMode = 1;         // Monitor_only Mode
00305     can2_SleepMode = 1;         // Monitor_only Mode
00306     CD.mode(PullUp) ; //SDRAM Chip Detect
00307     PB1.mode(PullUp) ; //Pushbutton 1
00308     can1.attach(&recieve1);
00309     can2.attach(&recieve2);
00310     autoPoll.attach(&autoPollISR,pollInt); // Poll battery data every 60 seconds
00311     msgReq.attach(&sendReq,0.015);  // Each poll message separated by 15ms
00312         
00313     timer.start() ;
00314     RTC_Init(); // start the RTC Interrupts that sync the timer
00315 
00316     struct tm t; // pointer to a static tm structure
00317 
00318     seconds = time(NULL);
00319     t = *localtime(&seconds) ;
00320     strftime(sTemp, 32, "%a %m/%d/%Y %X", &t);
00321     pc.printf("\nCurrent time set to:  %s\n", sTemp); // DAY MM/DD/YYYY HH:MM:SS
00322     wait(1.1);  // give time to sync
00323     
00324     if (PB1==0) { //set time if pb pressed
00325 
00326         pc.printf("\nEnter year (yyyy):");
00327         pc.scanf("%s", &sTemp);
00328         t.tm_year = atoi(sTemp);
00329         
00330         pc.printf("\nEnter month (mm):");
00331         pc.scanf("%2s", &sTemp);
00332         t.tm_mon = atoi(sTemp);
00333         
00334         pc.printf("\nEnter day (dd):");
00335         pc.scanf("%2s", &sTemp);
00336         t.tm_mday = atoi(sTemp);
00337         
00338         pc.printf("\nEnter hour (hh):");
00339         pc.scanf("%2s", &sTemp);
00340         t.tm_hour = atoi(sTemp);
00341         
00342         pc.printf("\nEnter minute (mm):");
00343         pc.scanf("%2s", &sTemp);
00344         t.tm_min = atoi(sTemp);
00345         
00346         pc.printf("\nEnter seconds (ss):");
00347         pc.scanf("%2s", &sTemp);
00348         t.tm_sec = atoi(sTemp);
00349 
00350         // adjust for tm structure required values
00351         t.tm_year = t.tm_year - 1900;
00352         t.tm_mon = t.tm_mon - 1;
00353 
00354         // set the RTC
00355         set_time(mktime(&t));
00356         seconds = time(NULL);
00357 
00358         pc.printf("\nRTC set to:  " );
00359         strftime(sTemp, 32, "%a %m/%d/%Y %X", localtime(&seconds));
00360         pc.printf("%s\n", sTemp); // DAY MM/DD/YYYY HH:MM:SS
00361     }
00362     
00363     while (true) {
00364         if(CD == 1) {
00365             if (!logOpen) { // Open new file if one is not already open
00366                 seconds = time(NULL);
00367                 t = *localtime(&seconds) ;
00368                 strftime(fileName, 32, "/sd/%m%d%H%M.alc", &t); //mmddhhmm.alc
00369 
00370                 pc.printf("Using file %s\n",fileName);
00371                 file = fopen(fileName, "ab");
00372                 pc.printf("Using file2 %s\n",fileName);
00373                 
00374                 if(file==NULL){
00375                     pc.printf("\nUnable to open canlog\n\n\n\n");
00376                     mbed_reset();
00377                 } else {
00378                     logOpen = true;
00379                     readPointer=writePointer;
00380                     pc.printf("\nStarting Can Log %s\n",fileName);
00381                     logTS();
00382                     fclose(file);
00383                     file = fopen("/sd/loglog.txt", "a");
00384                     fprintf(file,"%s\r\n",fileName);
00385                     fclose(file);
00386                 }
00387             } // if (!logOpen)
00388             do {
00389                 if (((writePointer+maxBufLen-readPointer)%maxBufLen)>(maxBufLen/2)||canIdle||(PB1==0)) {
00390                     // Dump buffer if > 1/2 full, canbus has stopped, or PB1 pressed
00391                     if (logOpen) {
00392                         file = fopen(fileName, "ab");
00393                         if (file == NULL) {
00394                             logOpen = false;
00395                             pc.printf("Failed to append log file.\n\n");
00396                         } else {
00397                             while (readPointer != writePointer) {
00398                                 for (int j = 0; j<13; j++){
00399                                     fprintf(file,"%c",writeBuffer[readPointer][j]);
00400                                 }
00401                                 if(++readPointer >= maxBufLen)
00402                                     readPointer=0;
00403                             }
00404                             led3 = !led3;
00405                             fclose(file);
00406                         }
00407                     } // if (logOpen)
00408                 } // if > 1/2 full, canbus has stopped, or PB1 pressed
00409                 if (canIdle) { // canbus idle --> sleep to save power
00410                     // First take advantage of the idle time to clear some room
00411                     
00412                     bit = false;
00413                     rfile = fopen("/sd/loglog.txt", "r");
00414                     file = fopen("/sd/loglog.new", "w");
00415                     while (!feof(rfile)) {
00416                         fscanf(rfile,"/sd/%2d%2d%4d.alc\r\n",&fmon,&fday,&ftime);
00417                         //if ((fmon < 12) || (t.tm_mon > 1)){
00418                         //    fday = fday + fmon*31; //crude - february will store 3 extra days of data
00419                         //}
00420                         //if ((fday+14)<(t.tm_mday+t.tm_mon*31)){ // Delete all files more than ~14 days old
00421                         if (((fmon<=t.tm_mon)&&(fday<t.tm_mday))||(fmon>t.tm_mon+2)){ // Delete all files more than 1 month old
00422                             bit=true;
00423                             sprintf(sTemp,"/sd/%02d%02d%04d.alc",fmon,fday,ftime);
00424                             if ((remove(sTemp)==NULL)) {
00425                                 pc.printf("Removed file %s\n",sTemp);
00426                             }
00427                         }else{
00428                             fprintf(file,"/sd/%02d%02d%04d.alc\r\n",fmon,fday,ftime);
00429                         }
00430                     }
00431                     fclose (file);
00432                     fclose (rfile);
00433                     if (bit) {
00434                         remove ("/sd/loglog.txt");
00435                         //rename not working so do it the hard way
00436                         //rename ("/sd/loglog.new","/sd/loglog.txt");
00437                         rfile = fopen("/sd/loglog.new", "r");
00438                         file = fopen("/sd/loglog.txt", "w");
00439                         while (!feof(rfile)) {
00440                             fscanf(rfile,"%s\r\n",&sTemp);
00441                             fprintf(file,"%s\r\n",sTemp);
00442                         }
00443                         fclose (file);
00444                         fclose (rfile);
00445                     }
00446                     remove ("/sd/loglog.new");                    
00447                     wait(5); // wait a few seconds to ensure SDRAM is done
00448 
00449                     pc.printf("Putting uC to sleep.\n");
00450                     //LPC_RTC->CIIR=0x00; // block RTC interrupts
00451                     led1=0;
00452                     led2=0;
00453                     led3=0;
00454                     led4=0;
00455                     secs = time(NULL); // seconds past 12:00:00 AM 1 Jan 1900
00456                     while (secsIdle>canTimeout) {
00457                         //DeepPowerDown();
00458                         __wfi(); // freeze CPU and wait for interrupt (from canbus)
00459                     }
00460                     canIdle=false;
00461                     pc.printf("Waking uC.\n");
00462                     if (time(NULL)>(secs+1800)) {
00463                         logOpen = false; // Start new file if asleep for more than 30 minutes
00464                     } else { // insert timestamp on each wake
00465                         logTS();
00466                     }
00467                     //LPC_RTC->CIIR=0x01; // re-enable RTC interrupts
00468                 }
00469                 wait(0.2); // We get >2K messages per second
00470             } while ((PB1==1)&&(CD==1)&&logOpen); // keep going until button or SDram removed
00471 
00472             if (PB1==0) {
00473                 led1=0;
00474                 led2=0;
00475                 led3=0;
00476                 led4=0;
00477                 pc.printf("Log stopped\n\n");
00478                 logOpen=false;
00479                 wait(5); // wait 5 seconds to give time to remove SDRAM if desired
00480                 if (PB1==0)
00481                     readLog(); // dump file if PB still pressed
00482             }
00483         } else {
00484             pc.printf("\nNo SDRAM Inserted.\n\n");
00485             logOpen=false;
00486             led1=!led1;
00487             led2=led1;
00488             led3=led1;
00489             led4=led1;
00490             wait(5);
00491         } //if (CD==1)
00492     } //while (true)
00493 }