Dual CANbus monitor and instrumentation cluster. Presently tuned for the Nissan Leaf EV.
Dependencies: SPI_TFTx2_ILI9341 TFT_fonts TOUCH_TFTx2_ILI9341 mbed
Fork of CANary_corrupt by
main.cpp
00001 // main.cpp 00002 // 00003 //To Do: 00004 // * Add 50% charge option 00005 // * Add linear efficiency graph with 10 minute values 00006 // * Add in-device config editor 00007 // * Change pack volt color when CVLI fails 00008 // * Add tire pressure cal (40psi for me = FR 38, RR 38.2, FL 37.8, RL 38 - maybe 2psi error on my tire gauge?) 00009 // * Be more efficient with write buffer (use msgLen instead of always storing 8 bytes) 00010 // * fix bug where charging while on screws up efficiency computation 00011 // * find better kWh estimate than gids 00012 00013 // rev208 00014 // 00015 00016 // Include this before other header files 00017 #include "precompile.h" 00018 00019 #include "mbed.h" 00020 #include "CAN.h" 00021 #include "ff.h" 00022 #include "PowerControl.h" 00023 #include "EthernetPowerControl.h" 00024 #include "utility.h" 00025 #include "displayModes.h" 00026 #include "TOUCH_TFTx2.h" 00027 00028 char revStr[7] = "208"; 00029 unsigned long maxTarget = 1000; 00030 FATFS USBdrive; 00031 LocalFileSystem local("local"); 00032 unsigned char wait5secs = 5; 00033 // to write to USB Flash Drives, or equivalent (SD card in Reader/Writer) 00034 // class10 SDcard in Reader/Writer recommended 00035 FRESULT mfr = f_mount(0,&USBdrive); 00036 00037 time_t seconds ; 00038 00039 Ticker autoPoll; 00040 Ticker playback; 00041 Ticker msgReq; 00042 Ticker geiger; 00043 Timer timer; 00044 00045 DigitalOut led1(LED1); 00046 DigitalOut led2(LED2); 00047 DigitalOut led3(LED3); 00048 DigitalOut led4(LED4); 00049 00050 InterruptIn touchpad(p17); 00051 CAN can1(p9, p10); // CAN1 (EV) uses pins 9 and 10 (rx, tx) and pin 8 (rs) 00052 DigitalOut can1SleepMode(p8); // Use pin 8 to control the sleep mode of can2 00053 CAN can2(p30, p29); // CAN2 (CAR) uses pins 30 and 29 (rx, tx) and pin 28 (rs) 00054 DigitalOut can2SleepMode(p28); // Use pin 28 to control the sleep mode of can1 00055 AnalogIn mon12V(p15); 00056 #if USE_ILI9341 == 1 00057 TOUCH_TFTx2 tt(p16, p17, p19, p20, p11, p12, p13, p6, p7, p5, p14, "TFT"); // x+, x-, y+, y-, mosi, miso, sclk, cs0, cs1, reset, dc 00058 #else 00059 TOUCH_TFTx2 tt(p16, p17, p19, p20, p11, p12, p13, p6, p7, p5, "TFT"); // x+,x-,y+,y-,mosi, miso, sclk, cs0, cs1, reset 00060 #endif 00061 PwmOut dled(p23); 00062 PwmOut spkr(p21); 00063 00064 bool debugMode = false; 00065 bool usbEn = false; 00066 bool logEn = false; 00067 bool logOpen = false; 00068 bool yesBattLog = true; // gg - Batt Log 00069 unsigned char tNavRow = 3; // gg - 4x4 touch 00070 bool brakeMon = false; // disable until desired value read from config 00071 bool regenMon = false; 00072 bool heaterMon = false; 00073 bool autoSync = false; // auto clock sync on powerup 00074 bool syncDone = true; 00075 bool heaterOn = false; 00076 bool lHeaterOn = false; 00077 bool CCon = false; 00078 bool lCCon = false; 00079 bool checkFWupdate = true; 00080 00081 FILE *hfile; // history file 00082 FILE *rfile; 00083 FILE *file; 00084 FIL efile; // external usb file 00085 FRESULT efr; // external file access flags 00086 FILINFO fno; 00087 eDIR dir; 00088 char *fn; /* This function assumes non-Unicode configuration */ 00089 FRESULT res; 00090 unsigned int bytesRW; 00091 char logFileName[35] = ""; 00092 char writeBuffer[maxBufLen][13] __attribute__ ((section("AHBSRAM1"))); // buffer for USB write 00093 char indexLastMsg[0x800]={0}; // index table for last message 00094 CANMessage lastMsg[100]; // table to store last message of eachtype 00095 00096 unsigned char battData[BatDataBufMax]={0}; // 7 * 0x3D = BatDataBufMax 00097 00098 unsigned char msgChanged[100]; // inidcates which bytes changed 00099 char c; 00100 volatile int writePointer = 0; 00101 int readPointer=0; 00102 volatile unsigned short secsNoCarCanMsg = canTimeout; 00103 volatile unsigned short secsNoEvCanMsg = canTimeout; 00104 volatile unsigned short secsNoTouch = 0; 00105 volatile unsigned short secsTouch = 0; 00106 volatile bool carCanIdle,evCanIdle,userIdle; 00107 bool touched=false; //flag to read touchscreen 00108 bool longTouch=false; //flag for long touch 00109 bool extraLongTouch=false; //flag for long touch 00110 unsigned char whichTouched = 0; 00111 char counter = 0; 00112 unsigned char dMode[2] = {mainScreen,brakeScreen}; //display mode 00113 unsigned char sMode = 0; // setup mode 00114 unsigned char lastDMode[2] = {0,0}; //last screen mode 00115 unsigned char dtMode = 0; 00116 char displayLog[20][40]; 00117 unsigned char displayLoc = 0; 00118 unsigned int fwCount=1; 00119 unsigned char indexOffset = 1; 00120 bool showCP = false; 00121 bool logCP = false; //Turbo3 00122 bool logOnce = false; 00123 bool repeatPoll = true; 00124 bool headlights = false; 00125 bool miles_kmbar = true; 00126 bool tick = false; 00127 bool ZeroSecTick = false; 00128 float ledHi = 0.5; // Bright LED value (until config file read) 00129 float ledLo = 0.5; // Dim LED value (until config file read) 00130 unsigned short pollInt = 300; // polling interval=5 minutes (until config file read) 00131 bool accOn = false; // Accessories on 00132 bool laccOn = false; 00133 float scale12V = 16.2; // R1:R2 ratio 00134 float kWperGid = 0.080; 00135 int daysLog = 999; // How many days of log files to save 00136 unsigned short startGids = 0; // Gids at start of trip 00137 unsigned short dailyGids = 0; // Gids per day 00138 bool getGids = false; 00139 signed long mWs_x4 = 0; 00140 unsigned short numWsamples = 0; 00141 unsigned short numSsamples = 0; 00142 unsigned long keypad = 0; 00143 unsigned char uidx = 99; 00144 float accV = 0; 00145 float accV2 = 0; 00146 float CCkW = 0; 00147 bool playbackEn = false; 00148 bool playbackOpen = false; 00149 //float playbackInt = 0.05; //read messages every 50 ms 00150 float playbackInt = 0.005; //read messages every 5 ms 00151 bool step = false; 00152 char header[5]; 00153 char data[8]; 00154 signed long motorRPM; 00155 unsigned char skin = ttSkin ; 00156 unsigned char dtePeriod = 14; //ten minute averaging interval 00157 float CCkWh_trip[4]={0}; 00158 float kWh_trip[4]={0}; 00159 float miles_trip[4]={0}; 00160 float curEff = 0; 00161 float maxTripEff = 0; 00162 float minTripEff = 5; 00163 float maxTripMiles = 0; 00164 float maxTripkWh = 1; 00165 float maxTripCCkWh = 0; 00166 float minTripMiles = 5; 00167 float minTripkWh = 1; 00168 float minTripCCkWh = 0; 00169 float mph[39]={0}; 00170 float kW[39]={0}; 00171 float mpkWh[39]={0}; 00172 float mpkWh_noCC=0; 00173 float unloadedV_x2,Resr,curRmax,curRmin,redRmax,redRmin,incRmax,incRmin; 00174 signed short Imax, Imin; 00175 // Logarithmic division scale (roughly - snapped to common units of time) 00176 float timeConstant[39] = {1, 1.58, 2.51, 3.98, 6.31, 10, 15.8, 25.1, 39.8, 60, // 1 minute 00177 60*1.58, 60*2.51, 60*3.98, 60*6.31, 60*10, 60*15.8, 60*25.1, 60*39.8, 60*60, // 1 hour 00178 60*60*1.58, 60*60*2.51, 60*60*3.98, 60*60*6.31, 60*60*10, 60*60*15.8, 60*60*24, // 1 day 00179 60*60*24*1.58, 60*60*24*2.51, 60*60*24*3.98, 60*60*24*6.31, 60*60*24*10, 60*60*24*15.8, 60*60*24*30, // 1 month 00180 60*60*24*39.8, 60*60*24*63.1, 60*60*24*100, 60*60*24*158, 60*60*24*251, 60*60*24*365}; // 1 year 00181 bool tock = false; 00182 unsigned short pointerSep; 00183 unsigned char reqMsgCnt = 99; 00184 unsigned long Ah_x10000 = 0; 00185 unsigned long SOC_x10000 = 0; 00186 unsigned short SOH2_x100 = 0; 00187 float maxTemp = 0; 00188 bool metric = false; 00189 bool shunt[96]={0}; 00190 bool charging=false; 00191 bool showHealth=false; 00192 unsigned char saveDmode[2] = {99, 99}; 00193 bool moving=false; 00194 unsigned short chirpInt; 00195 unsigned short uMsgId[8] = {0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000}; // messages to display on debug screen msgId:byte 00196 char uCmdBus = 1; // 1 = EVCan ; 2 = CarCan 00197 short uCmdId = 0x79b; 00198 char uCmdLen = 8; 00199 char uCmdData[8] = {0x02, 0x21, 0x02, 0xff, 0xff, 0xff, 0xff, 0xff}; 00200 int daysUptoMonth[12] = {0,31,59,90,120,151,181,212,243,273,304,334}; 00201 unsigned short modelYear = 2011; 00202 bool idir, lidir; 00203 bool enableSound=true; 00204 bool clearTest=true; 00205 unsigned long tbScalar = 72464; 00206 unsigned long rbScalar = 8696; 00207 unsigned long fbScalar = 132; 00208 int effCheckTime = 3; 00209 bool ignoreDayData = true; 00210 unsigned short cgids,lgids=0; 00211 unsigned short whpg[300]={0}; 00212 float wh[300]; 00213 float maxWhpg,minWh,whOff; 00214 00215 int main() { 00216 char sTemp[40]; 00217 unsigned long secs; 00218 unsigned short i,j; 00219 unsigned char display=0,lwt=0; 00220 point lastTouch; 00221 float average; 00222 tt.set_orientation(1); 00223 tt.background(Black); 00224 tt.set_display(2); // select both displays 00225 tt.cls(); 00226 tt.foreground(White); 00227 tt.set_font((unsigned char*) Arial12x12_prop); // select the font 00228 tt.locate(0,0); 00229 tt.claim(stdout); // send stdout to the TFT display 00230 touchpad.rise(&touch_ISR); 00231 tt.wfi(); // enable interrupt on touch 00232 dled.period(0.001); 00233 dled = ledHi; // turn on display LED 80% 00234 spkr = 0; 00235 Resr = 0.075; // initial guess of Resr 00236 timer.start() ; 00237 RTC_Init(); // start the RTC Interrupts that sync the timer 00238 struct tm t,lt; // pointer to a static tm structure 00239 NVIC_SetPriority(CAN_IRQn, 2); //set can priority just below RTC 00240 NVIC_SetPriority(TIMER3_IRQn, 3); //set ticker priority just below can 00241 00242 seconds = time(NULL); 00243 t = *localtime(&seconds); 00244 lt = t; // initialize 00245 // is it a date before 2012 ? 00246 if ((t.tm_year + 1900) < 2012 ) { 00247 // before 2013 so update year to make date entry easier 00248 t.tm_year = 2013 - 1900; 00249 // set the RTC 00250 set_time(mktime(&t)); 00251 seconds = time(NULL); 00252 } 00253 t = *localtime(&seconds) ; 00254 strftime(sTemp, 32, "%a %m/%d/%Y %X\n", &t); 00255 printMsg(sTemp); // record RTC 00256 00257 // revision 00258 sprintf(sTemp,"CANary firmware rev%s\n", revStr); // gg - for Logging the revision 00259 printMsg(sTemp); // revision 00260 00261 for(i=0;i<300;i++){ // initialize wh lookup 00262 wh[i]=i*kWperGid*1000; 00263 } 00264 00265 //read efficiency history data 00266 hfile = fopen("/local/ehist.cny", "r"); 00267 if (hfile!=NULL){ // found a efficiency history file 00268 for(i=0;i<39;i++){ 00269 if(!feof(hfile)){ 00270 fscanf(hfile,"%f %f\r\n",&mph[i],&kW[i]); 00271 mpkWh[i]=mph[i]/kW[i]; 00272 if(i==dtePeriod) mpkWh_noCC=mpkWh[i]; 00273 } 00274 } 00275 if(!feof(hfile)){ 00276 fscanf(hfile,"%f %f\r\n",&maxTripEff,&minTripEff); 00277 } 00278 if(!feof(hfile)){ 00279 fscanf(hfile,"%f\r\n",&Resr); 00280 } 00281 if(!feof(hfile)){ 00282 fscanf(hfile,"%f %f\r\n",&maxTripMiles,&minTripMiles); 00283 } 00284 if(!feof(hfile)){ 00285 fscanf(hfile,"%f %f\r\n",&maxTripkWh,&minTripkWh); 00286 } 00287 if(!feof(hfile)){ 00288 fscanf(hfile,"%f %f\r\n",&maxTripCCkWh,&minTripCCkWh); 00289 } 00290 for(i=0;i<300;i++){ 00291 if(feof(hfile)) break; 00292 fscanf(hfile,"%f\r\n",&wh[i]); 00293 } 00294 fclose(hfile); 00295 printMsg("History Loaded.\n"); // History loaded 00296 } else { // create initial file 00297 printMsg("History not found. Created.\n"); // history not found, created 00298 for(i=0;i<39;i++){ 00299 // Pre-load with 4 mpkWh @ 40 mph 00300 mph[i]=40*timeConstant[i]; 00301 kW[i]=10*timeConstant[i]; 00302 mpkWh[i]=4; 00303 } 00304 } 00305 00306 // Read config file 00307 readConfig(); 00308 if (brakeMon){ 00309 geiger.attach(&chirp,0.02); 00310 } 00311 if (repeatPoll) { // enable autopolling if enabled 00312 autoPoll.attach(&autoPollISR,pollInt); 00313 } 00314 00315 // Start monitors 00316 can1.monitor(true); // set to snoop mode 00317 can2.monitor(true); // set to snoop mode 00318 can1.frequency(500000); 00319 can2.frequency(500000); 00320 can1SleepMode = VP230Sleep; // Turn on Monitor_only Mode 00321 can2SleepMode = VP230Sleep; // Turn on Monitor_only Mode 00322 can1.attach(&recieve1); 00323 can2.attach(&recieve2); 00324 00325 touched=false; 00326 longTouch=false; 00327 extraLongTouch=false; 00328 secsNoTouch=2; 00329 secsTouch=0; 00330 00331 while (true) { 00332 if (!logOpen) { // Open new file if one is not already open 00333 if(logEn&&usbEn){ //logging enabled and USB device detected 00334 strftime(logFileName, 32, "%m%d%H%M.alc", &t); //mmddhhmm.alc 00335 efr = f_open(&efile,logFileName,FA_WRITE|FA_OPEN_ALWAYS); 00336 seconds = time(NULL); 00337 t = *localtime(&seconds) ; 00338 lastDMode[0]=99;//force refresh 00339 lastDMode[1]=99;//force refresh 00340 if(efr != FR_OK){ 00341 sprintf(sTemp,"\nERR:%d Unable to open %s\n\n\n\n",efr,logFileName); 00342 printMsg(sTemp); // cannot open alc file 00343 logEn=false; 00344 usbEn=detectUSB(); 00345 beep(1000,0.25); 00346 wait_ms(500); 00347 beep(1000,0.25); 00348 } else { 00349 logOpen = true; 00350 readPointer=writePointer; 00351 sprintf(sTemp,"Starting Can Log %s\n",logFileName); 00352 printMsg(sTemp); // starting alc log file 00353 00354 logTS(); // Date Time at start 00355 logEvent("Starting"); // Log startup msg for testing 00356 sprintf(sTemp,"Cr%s",revStr); 00357 logEvent(sTemp); // gg - log firmware version 00358 beep(2000,0.25); 00359 file = fopen("/local/loglog.txt", "a"); // save filename log 00360 fprintf(file,"%s\r\n",logFileName); 00361 fclose(file); 00362 } 00363 }//logging enabled and USB detected 00364 } else { // if (logOpen) 00365 pointerSep=(writePointer+maxBufLen-readPointer)%maxBufLen; 00366 if (pointerSep>(maxBufLen/16)||carCanIdle||!logEn) { 00367 // Dump buffer if > 1/16 full or canbus has stopped 00368 if (efr != FR_OK) { 00369 logOpen = false; 00370 printMsg("Failed to append log file.\n"); // failed to append 00371 beep(3000,0.25); 00372 beep(1500,0.25); 00373 beep(750,0.25); 00374 beep(375,0.25); 00375 logEn=false; 00376 usbEn=detectUSB(); 00377 } else { 00378 while (readPointer != writePointer) { 00379 efr=f_write(&efile,&writeBuffer[readPointer][0],13,&bytesRW); 00380 if(++readPointer >= maxBufLen){ 00381 readPointer=0; 00382 led4 = !led4; 00383 } 00384 } 00385 } 00386 } // if > 1/16 full, canbus has stopped, or logging stopped 00387 if (!logEn) { 00388 sprintf(sTemp,"Stopping Can Log %s\n",logFileName); 00389 printMsg(sTemp); // stopping alc log file 00390 f_close(&efile); 00391 logOpen=false; 00392 pointerSep=0; 00393 led4=false; 00394 } 00395 } // if logOpen 00396 if (carCanIdle && (evCanIdle || !logOpen) && userIdle && !playbackEn) { // canbus idle --> sleep to save power 00397 if (repeatPoll) { // stop autopolling if enabled 00398 autoPoll.detach(); 00399 } 00400 if (logOpen){ //close file to dump buffer 00401 f_close(&efile); 00402 } else { //detach EVcan so only carcan will trigger wake 00403 can1.attach(NULL); 00404 }// if (logOpen) 00405 00406 // Take advantage of the idle time to clear some room on USB drive 00407 if(logEn && usbEn){ 00408 seconds = time(NULL); 00409 t = *localtime(&seconds) ; 00410 int fmon; 00411 int fday; 00412 int ftime; 00413 int fdays; 00414 res = f_opendir(&dir, ""); //Get USB contents 00415 if(res == FR_OK) { 00416 for (i=1;i<200;i++) { 00417 res = f_readdir(&dir, &fno); /* Read a directory item */ 00418 if (res != FR_OK || fno.fname[0] == 0) break; /* Break on error or end of dir */ 00419 //if (fno.fname[0] == '.') continue; /* Ignore dot entry */ 00420 fn = fno.fname; 00421 if (fno.fattrib & AM_DIR) { /* It is a directory */ 00422 continue; // Do nothing 00423 } else { /* It is a file. */ 00424 if(sscanf(fn,"%2d%2d%4d.alc",&fmon,&fday,&ftime)==3){ 00425 fdays = fday + daysUptoMonth[fmon-1]; //Leap years save one extra day at the end of February 00426 if (fdays>(t.tm_mday+daysUptoMonth[t.tm_mon])){//file cannot be from the future so must be very old 00427 fdays = fdays - 365; 00428 } 00429 if ((fdays+daysLog)<(t.tm_mday+daysUptoMonth[t.tm_mon])){ // Delete all files more than daysLog old 00430 sprintf(sTemp,"%02d%02d%04d.alc",fmon,fday,ftime); 00431 f_unlink(sTemp); 00432 sprintf(sTemp,"Deleted logfile %02d%02d%04d.alc\n",fmon,fday,ftime); 00433 printMsg(sTemp); 00434 } 00435 } 00436 } 00437 } 00438 //f_closedir(&dir); 00439 } 00440 wait(2); // wait a few seconds to ensure file access 00441 } //if logen 00442 seconds = time(NULL); 00443 t = *localtime(&seconds) ; 00444 strftime(sTemp, 40, "Sleeping: %a %m/%d/%Y %X\n", &t); 00445 printMsg(sTemp); // sleeping date time 00446 updateDisplay(0); //Added for turbo3 who has a display override and wants to see the sleep message before going to sleep 00447 updateDisplay(1); 00448 //LPC_RTC->CIIR=0x00; // block RTC interrupts 00449 led1=0; 00450 led2=0; 00451 led3=0; 00452 led4=0; 00453 dled=0; // turn off display 00454 secs = time(NULL); // seconds past 12:00:00 AM 1 Jan 1900 00455 while (secsNoCarCanMsg>canTimeout && (secsNoEvCanMsg>canTimeout || !logOpen) && !touched) { 00456 //DeepPowerDown(); 00457 tt.wfi(); //enable touch interrupt 00458 //__wfi(); // freeze CPU and wait for interrupt (from canbus or touch) 00459 Sleep(); 00460 } 00461 if (!logOpen){ // Re-attach EVcan 00462 can1.attach(&recieve1); 00463 } 00464 secsNoTouch=2; 00465 secsTouch=0; 00466 carCanIdle=secsNoCarCanMsg>canTimeout; 00467 evCanIdle=secsNoEvCanMsg>canTimeout; 00468 dled=ledHi; // turn on display LED 00469 seconds = time(NULL); 00470 t = *localtime(&seconds) ; 00471 strftime(sTemp, 40, "Waking: %a %m/%d/%Y %X\n", &t); 00472 printMsg(sTemp); // wakeup date time 00473 if (time(NULL)>(secs+1800)) { 00474 if (logOpen){ 00475 f_close(&efile); 00476 logOpen = false; // Start new file if asleep for more than 30 minutes 00477 } // if (logOpen) 00478 if (secsNoTouch>100) secsNoTouch = 100; // also mostly reset user Idle counter 00479 } else if (logOpen){ // insert timestamp on each wake if logging enabled (disabled for now) 00480 efr = f_open(&efile,logFileName,FA_WRITE|FA_OPEN_ALWAYS); 00481 f_lseek(&efile,0xffffffff); // goto end of file (append existing) 00482 logEvent("WakingUp"); // gg - use messeges 00483 logTS(); // Date-Time at wakeup 00484 } 00485 if (repeatPoll) { // re-enable autopolling if enabled 00486 autoPoll.attach(&autoPollISR,pollInt); 00487 } 00488 wait5secs=5; // Refresh screen after 5 seconds 00489 } // if idle 00490 00491 if(touched){ // call touchscreen procedure if touch interrupt detected 00492 lastTouch = tt.get_touch(); 00493 lastTouch = tt.to_pixel(lastTouch); // convert to pixel pos 00494 if((lastTouch.x!=639)&&(lastTouch.x!=319)&&(lastTouch.y!=239)){ // filter phantom touches 00495 if (userIdle) { 00496 secsNoTouch=2; // Ignore first touch if user idle 00497 userIdle=false; 00498 } else { 00499 secsNoTouch=0; 00500 } 00501 if (lastTouch.x>320){ 00502 whichTouched=1; 00503 } else { 00504 whichTouched=0; 00505 } 00506 if (whichTouched!=lwt){ 00507 lastDMode[lwt]=99; // Repaint lastTouched 00508 lwt=whichTouched; 00509 if(sMode==2){ // Exit keypad mode if other screen touched 00510 sMode=0; // end keypad mode 00511 if(saveDmode[0]<=maxScreens) 00512 dMode[0]=saveDmode[0]; 00513 if(saveDmode[1]<=maxScreens) 00514 dMode[1]=saveDmode[1]; 00515 lastDMode[0]=99; 00516 lastDMode[1]=99; 00517 uidx=99; 00518 } 00519 } 00520 if (sMode==0) sMode = 1; //Go to select mode1 unless already in select mode2 00521 } 00522 //sprintf(sTemp,"%d,%d ",lastTouch.x,lastTouch.y); 00523 //printMsg(sTemp); // touch x,y - for debug 00524 touched = false; // clear interrupt flag 00525 } 00526 //--------------- 00527 // gg - 4x4 touch 00528 //unsigned char tScrn = 0 ; // screen 0 00529 unsigned char tCol ; 00530 unsigned char tRow ; 00531 00532 if (!userIdle) { 00533 if(longTouch&&(sMode<2)){ //long touch 00534 if (dMode[whichTouched]==watchScreen) { 00535 whichTouched = whichTouched ^ 1; //long press opens keypad on *other* screen 00536 lwt=whichTouched; 00537 saveDmode[0]=dMode[0]; 00538 saveDmode[1]=dMode[1]; 00539 dMode[whichTouched]=offScreen; 00540 sMode=2; //start numPad entry mode 00541 keypad=0; 00542 if((lastTouch.y>64)&&(lastTouch.y<184)){ 00543 uidx=(lastTouch.y-64)/30; 00544 uidx*=2; 00545 if((lastTouch.x%320)>160){ 00546 uidx+=1; 00547 } 00548 }else{ 00549 uidx=99; 00550 } 00551 secsTouch=0; 00552 } else if (dMode[whichTouched]==cmdScreen) { 00553 whichTouched = whichTouched ^ 1; //long press opens keypad on *other* screen 00554 lwt=whichTouched; 00555 saveDmode[0]=dMode[0]; 00556 saveDmode[1]=dMode[1]; 00557 dMode[whichTouched]=offScreen; 00558 sMode=2; //start numPad entry mode 00559 keypad=0; 00560 if((lastTouch.y>34)&&(lastTouch.y<184)){ 00561 uidx=(lastTouch.y-4)/30; 00562 }else{ 00563 uidx=99; 00564 } 00565 secsTouch=0; 00566 } 00567 } else if (secsNoTouch<2) {// Recently touched 00568 secsNoTouch +=2; // increment to prevent double touch 00569 if (sMode==0) sMode = 1; //Go to select mode1 unless already in select mode2 00570 //sprintf(sTemp,"button %d %d,%d %d\n",i,buttonX(lastTouch.x,3),buttonY(lastTouch.y,3),lastTouch.x); 00571 //printMsg(sTemp); // button parms - for debug 00572 switch (sMode) { 00573 case 0: // no select 00574 break; 00575 case 1: // select screen 00576 //-------------- 00577 // gg - 4x4 touch 00578 tCol = buttonX(lastTouch.x,4) ; 00579 if( tCol >= 4 ){ tCol -= 4; } // touch is on screen 1 00580 00581 tRow = buttonY(lastTouch.y,4) ; 00582 00583 highlightButton( tCol,tRow, whichTouched, 4,4) ; // gg - highlight 00584 00585 if( tRow == tNavRow ) tRow = 7 ; // gg 00586 switch ( (tCol*10) + tRow ) { 00587 //--------------------------------- 00588 case 00: // top row, left button on screen 0 or 1 00589 if (dMode[whichTouched]==monitorScreen||dMode[whichTouched]==changedScreen) { 00590 indexOffset=indexOffset>4?indexOffset-4:1; 00591 } else if (dMode[whichTouched] == indexScreen) { // gg - index 00592 dMode[whichTouched] = mainScreen ; // GoTo Main Screen 00593 sMode=0; 00594 } else if (dMode[whichTouched]==config2Screen) { 00595 wait_ms(500); 00596 tt.background(Black); 00597 tt.calibrate(); 00598 } else if (dMode[whichTouched]==playbackScreen) { // slower 00599 playbackInt *=2; 00600 if(playbackEn){ 00601 playback.detach(); 00602 playback.attach(&playbackISR,playbackInt); 00603 } 00604 } else { 00605 lastDMode[whichTouched]=99;//repaint to clear highlight 00606 } 00607 break; 00608 //----------------------------------------------- 00609 case 10: // 1,0 (col left of center,top row) on screen 0 or 1 00610 if (dMode[whichTouched]==changedScreen) { 00611 for(j=0;j<100;j++) msgChanged[j]=0; // clear changed data 00612 lastDMode[whichTouched]=99;//force refresh 00613 sMode=0; 00614 } else if (dMode[whichTouched] == indexScreen) { // gg - index 00615 sMode=0; 00616 dMode[whichTouched] = brakeScreen ; // GoTo Brake Screen 00617 } else if (dMode[whichTouched]==cpScreen) { 00618 reqMsgCnt=0; 00619 msgReq.attach(&sendReq,0.015); 00620 } else if (dMode[whichTouched]==cpHistScreen) { // gg - hist 00621 reqMsgCnt=0; 00622 msgReq.attach(&sendReq,0.015); 00623 } else if (dMode[whichTouched]==cpBarScreen) { // gg - cpbars 00624 reqMsgCnt=0; 00625 msgReq.attach(&sendReq,0.015); 00626 } else if (dMode[whichTouched]==configScreen) { 00627 mbed_reset(); 00628 } else if (dMode[whichTouched]==config2Screen) { // reset DTE Max/Min 00629 maxTripEff = 0; 00630 minTripEff = 5; 00631 beep(2000,0.25); 00632 for(i=0;i<300;i++){ // initialize wh lookup 00633 wh[i]=i*kWperGid*1000; 00634 } 00635 } else if (dMode[whichTouched]==playbackScreen) { // pause/unpause 00636 playbackEn=!playbackEn; 00637 if(playbackEn){ 00638 playback.attach(&playbackISR,playbackInt); 00639 } else { 00640 playback.detach(); 00641 } 00642 } else { 00643 lastDMode[whichTouched]=99;//repaint to clear highlight 00644 } 00645 00646 break; 00647 //-------------------------------------- 00648 case 20: // col 2 and row 0 on either screen 0 or 1 00649 if (dMode[whichTouched]==monitorScreen||dMode[whichTouched]==changedScreen) { 00650 indexOffset=indexOffset<77?indexOffset+4:80; 00651 } else if (dMode[whichTouched] == indexScreen) { // gg - index 00652 dMode[whichTouched] = effScreen ; // GoTo EFF Screen 00653 sMode=0; 00654 } else if (dMode[whichTouched]==configScreen) { 00655 dMode[whichTouched]=mainScreen; 00656 //write efficiency history data 00657 hfile = fopen("/local/ehist.cny", "w"); 00658 if (hfile!=NULL){ // found a efficiency history file 00659 for(i=0;i<39;i++){ 00660 fprintf(hfile,"%f %f\r\n",mph[i],kW[i]); 00661 } 00662 fprintf(hfile,"%f %f\r\n",maxTripEff,minTripEff); // Save max and min 00663 fprintf(hfile,"%f \r\n",Resr); // Save series resistance 00664 fprintf(hfile,"%f %f\r\n",maxTripMiles,minTripMiles); // Save max and min 00665 fprintf(hfile,"%f %f\r\n",maxTripkWh,minTripkWh); // Save max and min 00666 fprintf(hfile,"%f %f\r\n",maxTripCCkWh,minTripCCkWh); // Save max and min 00667 for(i=0;i<300;i++){ 00668 fprintf(hfile,"%f\r\n",wh[i]); 00669 } 00670 fclose(hfile); 00671 } 00672 beep(2000,0.25); 00673 saveConfig(); 00674 beep(2000,0.25); 00675 } else if (dMode[whichTouched]==config2Screen) { 00676 showHealth = !showHealth; 00677 } else if (dMode[whichTouched]==playbackScreen) { // faster 00678 if(playbackInt>.002){ 00679 playbackInt/=2; 00680 if(playbackEn){ 00681 playback.detach(); 00682 playback.attach(&playbackISR,playbackInt); 00683 } 00684 } 00685 } else { 00686 lastDMode[whichTouched]=99;//repaint to clear highlight 00687 } 00688 00689 break; 00690 00691 case 30: // right-most on top row 00692 00693 if (dMode[whichTouched]==config2Screen) { 00694 // step through skins 00695 if( skin < maxSkin ) skin += 1 ; 00696 else skin = 0 ; 00697 00698 // repaint both screens, I think 00699 lastDMode[whichTouched]=99;//repaint to clear highlight 00700 // and re-paint the other screen too, to see new skin there 00701 lastDMode[whichTouched ^ 1]=99; // repaint other screen (^ = XOR) 00702 } else if (dMode[whichTouched] == indexScreen) { // gg - index 00703 dMode[whichTouched] = healthScreen ; // Goto health screen 00704 sMode=0; 00705 } else if (dMode[whichTouched] == watchScreen) { 00706 clearTest=true; 00707 } else if ((dMode[whichTouched] == cmdScreen)&&debugMode) { 00708 if (uCmdBus==1) { // EVcan 00709 can1.monitor(false); // set to active mode 00710 can1.write(CANMessage(uCmdId, uCmdData, uCmdLen)); 00711 wait_ms(50); 00712 if (reqMsgCnt==99) 00713 can1.monitor(true); // restore to snoop unless other message outstanding 00714 } else if (uCmdBus==2){ 00715 can2.monitor(false); // set to active mode 00716 can2.write(CANMessage(uCmdId, uCmdData, uCmdLen)); 00717 wait_ms(50); 00718 if (reqMsgCnt==99) 00719 can2.monitor(true); // restore to snoop unless other message outstanding 00720 } 00721 } else { // top-right corner always mute/unmute unless used by specific screen 00722 enableSound = !enableSound; 00723 if(!enableSound) spkr=0; 00724 lastDMode[whichTouched]=99;//repaint to clear highlight 00725 } 00726 00727 break; 00728 //---------------------------------- 00729 //---------------------------------- 00730 case 01: // left col middle row 00731 if (dMode[whichTouched]==configScreen) { 00732 logEn = !logEn; 00733 } else if (dMode[whichTouched] == indexScreen) { // gg - index 00734 dMode[whichTouched] = cpScreen ; // GoTo CP Data Screen 00735 sMode=0; 00736 } else if (dMode[whichTouched]==dateScreen){ 00737 dtMode=(dtMode<5)?dtMode+1:0; 00738 lastDMode[whichTouched]=99; 00739 } else { 00740 lastDMode[whichTouched]=99;//repaint to clear highlight 00741 } 00742 00743 break; 00744 //------------------------------ 00745 case 11: 00746 if (dMode[whichTouched]==configScreen){ 00747 repeatPoll = !repeatPoll; 00748 if (repeatPoll) { 00749 autoPoll.attach(&autoPollISR,pollInt); 00750 } else { 00751 autoPoll.detach(); 00752 } 00753 } else if (dMode[whichTouched] == indexScreen) { // gg - index 00754 dMode[whichTouched] = cpHistScreen ; // GoTo CP Hist Screen 00755 sMode=0; 00756 } else if (dMode[whichTouched]==playbackScreen) { 00757 // Start/stop playback 00758 if(!playbackOpen){ 00759 if(!carCanIdle){ 00760 printMsg("Cannot playback while connected to canbus\n"); 00761 }else if(!logOpen){ 00762 efr = f_open(&efile,"playback.alc",FA_READ|FA_OPEN_EXISTING); 00763 lastDMode[whichTouched]=99;//force refresh 00764 if(efr != FR_OK){ 00765 printMsg("Unable to open /usb/playback.alc\n"); // no playback.alc 00766 beep(1000,0.25); 00767 usbEn=detectUSB(); 00768 } else { 00769 playbackOpen = true; 00770 playbackEn=true; 00771 playback.attach(&playbackISR,playbackInt); 00772 printMsg("Starting playback\n"); // start playback 00773 beep(2000,0.25); 00774 can1.attach(NULL);// Stop recieving EVCAN data 00775 can2.attach(NULL);// Stop recieving CARCAN data 00776 } 00777 } else { 00778 printMsg("Must stop logging first\n"); 00779 } 00780 } else { 00781 playback.detach(); 00782 f_close(&efile); 00783 playbackOpen=false; 00784 playbackEn=false; 00785 can1.attach(&recieve1);// Restore EVCAN data recieve 00786 can2.attach(&recieve2);// Restore EVCAN data recieve 00787 lastDMode[whichTouched]=99; 00788 } 00789 } else if (dMode[whichTouched]==dateScreen){ 00790 upDate(dtMode,true); 00791 lastDMode[whichTouched]=99; 00792 } else { 00793 lastDMode[whichTouched]=99;//repaint to clear highlight 00794 } 00795 00796 break; 00797 //--------------------------------- 00798 case 21: // col 2 row 1 00799 if (dMode[whichTouched]==configScreen) { // gg - Batt Log Enable Button 00800 yesBattLog = !yesBattLog; 00801 } else if (dMode[whichTouched] == indexScreen) { // gg - index 00802 dMode[whichTouched] = cpBarScreen ; // GoTo CP Bars Screen 00803 sMode=0; 00804 } else if (dMode[whichTouched]==dateScreen){ 00805 upDate(dtMode,false); 00806 lastDMode[whichTouched]=99; 00807 } else { 00808 lastDMode[whichTouched]=99;//repaint to clear highlight 00809 } 00810 00811 break; 00812 00813 case 31: // col 3 row 1 00814 if (dMode[whichTouched]==config2Screen) { // gg - Batt Log Enable Button 00815 debugMode = !debugMode; 00816 } else if (dMode[whichTouched] == indexScreen) { // gg - index 00817 dMode[whichTouched] = configScreen ; // GoTo Config Screen 00818 } else if (dMode[whichTouched]==tripScreen) { // Cancel day trip meter 00819 ignoreDayData=true; 00820 lastDMode[whichTouched]=99;//repaint to clear highlight 00821 } else if ((dMode[whichTouched]==dateScreen)&&accOn){ 00822 syncDone=false; // initiate clock sync 00823 lastDMode[whichTouched]=99; 00824 } else if (dMode[whichTouched]==configScreen) { 00825 if(!headlights){ 00826 ledHi += 0.025; 00827 if (ledHi>1.0) ledHi=1.0; 00828 } else { 00829 ledLo += 0.025; 00830 if (ledLo>1.0) ledLo=1.0; 00831 } 00832 } else { 00833 lastDMode[whichTouched]=99;//repaint to clear highlight 00834 } 00835 break; 00836 00837 //----------------------------------- 00838 case 02: // left col, bottom row (not nav) 00839 if (dMode[whichTouched] == indexScreen) { // gg - index 00840 dMode[whichTouched] = playbackScreen ; // GoTo Playback Screen 00841 } else if (dMode[whichTouched]==configScreen) { 00842 brakeMon = !brakeMon; 00843 if(brakeMon){ 00844 geiger.attach(&chirp,0.02); 00845 }else{ 00846 geiger.detach(); 00847 } 00848 } else if (dMode[whichTouched]==config2Screen) { 00849 autoSync = !autoSync; 00850 } else { 00851 lastDMode[whichTouched]=99;//repaint to clear highlight 00852 } 00853 break; 00854 00855 case 12: // left-middle col, bottom row (not nav) 00856 if (dMode[whichTouched]==configScreen) { 00857 regenMon = !regenMon; 00858 } else if (dMode[whichTouched]==config2Screen) { // gg - index 00859 dMode[whichTouched] = dateScreen ; // GoTo Set Date/Time Screen 00860 } else { 00861 lastDMode[whichTouched]=99;//repaint to clear highlight 00862 } 00863 break; 00864 00865 case 22: // right-middle col, bottom row (not nav) 00866 if (dMode[whichTouched]==indexScreen) { // gg - index 00867 dMode[whichTouched] = logScreen ; 00868 sMode=0; 00869 } else if (dMode[whichTouched]==configScreen) { 00870 heaterMon = !heaterMon; 00871 } else if (dMode[whichTouched]==config2Screen) { 00872 updateConfig(); 00873 lastDMode[whichTouched]=99;//force refresh 00874 sMode=0; 00875 } else { 00876 lastDMode[whichTouched]=99;//repaint to clear highlight 00877 } 00878 break; 00879 00880 case 32: // right col, bottom row (not nav) 00881 if (dMode[whichTouched]==config2Screen) { 00882 logEn=false; 00883 updateFirmware(); 00884 } else if (dMode[whichTouched]==tripScreen) { 00885 // Reset custom trip meter 00886 miles_trip[2]=0; 00887 kWh_trip[2]=0; 00888 CCkWh_trip[2]=0; 00889 sMode=0; 00890 lastDMode[whichTouched]=99;//repaint to clear highlight 00891 } else if (dMode[whichTouched]==indexScreen) { 00892 dMode[whichTouched] = tripScreen ; 00893 sMode=0; 00894 } else if (dMode[whichTouched]==dateScreen){ 00895 autoSync=!autoSync; // toggle autoSync mode 00896 lastDMode[whichTouched]=99; 00897 } else if (dMode[whichTouched]==configScreen) { 00898 if(!headlights){ 00899 ledHi -= 0.1; 00900 if (ledHi<0) ledHi=0; 00901 } else { 00902 ledLo -= 0.1; 00903 if (ledLo<0) ledLo=0; 00904 } 00905 } else { 00906 lastDMode[whichTouched]=99;//repaint to clear highlight 00907 } 00908 break; 00909 00910 //----------------------------------- 00911 //----------------------------------- 00912 // Prev Navigation 00913 case 07: // col 0 row tNavRow 00914 dMode[whichTouched]=dMode[whichTouched]>0?dMode[whichTouched]-1:maxScreens; 00915 break; 00916 //----------------------------------- 00917 // Select Screen Navigation 00918 case 17: 00919 sMode=0; 00920 lastDMode[whichTouched]=99; // Repaint 00921 break; 00922 //----------------------------------- 00923 // Index Navigation 00924 case 27: // col 2 row tNavRow 00925 dMode[whichTouched]= indexScreen ; // gg - index 00926 break; 00927 //------------------------------------ 00928 // Next Navigation 00929 case 37: // lower right on Nav Line gg - move next 00930 dMode[whichTouched]=dMode[whichTouched]<maxScreens?dMode[whichTouched]+1:0; 00931 break; 00932 //------------------------------------ 00933 //------------------------------------ 00934 default: 00935 lastDMode[whichTouched]=99;//repaint to clear highlight 00936 break; 00937 } 00938 break; 00939 case 2: // numpad 00940 tCol = buttonX(lastTouch.x,5) ; 00941 if( tCol >= 5 ){ tCol -= 5; } // touch is on screen 1 00942 tRow = buttonY(lastTouch.y,4) ; 00943 highlightButton( tCol,tRow, whichTouched, 5,4) ; // gg - highlight 00944 if(tCol<4){ 00945 keypad = keypad<<4; // shift left 00946 keypad += tRow*4+tCol; // add next digit 00947 } else { 00948 switch ( tRow ) { 00949 case 0: // col 4 row 0 00950 keypad = keypad>>4; // shift right 00951 break; 00952 case 1: // col 4 row 1 00953 break; 00954 case 2: // col 4 row 2 00955 break; 00956 case 3: // col 4 row 3 00957 sMode=0; // end keypad mode 00958 if(saveDmode[0]<=maxScreens) 00959 dMode[0]=saveDmode[0]; 00960 if(saveDmode[1]<=maxScreens) 00961 dMode[1]=saveDmode[1]; 00962 lastDMode[0]=99; 00963 lastDMode[1]=99; 00964 uidx=99; 00965 longTouch=false; 00966 break; 00967 default: 00968 break; 00969 } 00970 } 00971 break; 00972 case 3: 00973 break; 00974 default: 00975 break; 00976 } // case sMode 00977 } //recently touched 00978 } else if(sMode==1) { // userIdle if not in hex entry mode 00979 sMode=0; 00980 lastDMode[whichTouched]=99; //LAJ 00981 } //!userIdle 00982 00983 // Sound tone on power reversal 00984 idir=(kW[0]>0)?true:false; 00985 if(regenMon){ 00986 if (idir&&!lidir){ 00987 beep(800,0.02); // Started sinking current 00988 }else if(!idir&&lidir){ 00989 beep(3200,0.02); // Started regen 00990 } 00991 } 00992 lidir=idir; 00993 00994 if(tick){ // Executes once a second 00995 tick=false; 00996 carCanIdle=(++secsNoCarCanMsg>canTimeout)?true:false; 00997 evCanIdle=(++secsNoEvCanMsg>canTimeout)?true:false; 00998 if(tt.is_touched()){ 00999 if(checkFWupdate){ 01000 updateFirmware(); 01001 } 01002 }else{ 01003 //userIdle=(++secsNoTouch>userTimeout)?true:false; 01004 secsTouch = 0; 01005 } 01006 longTouch = (++secsTouch>2); 01007 extraLongTouch = (secsTouch>10); 01008 if(extraLongTouch){ //Reset if extra long touch 01009 mbed_reset(); 01010 } 01011 checkFWupdate=false; // Only check once at USB insertion or poweron 01012 lCCon = CCon; 01013 CCkW = (lastMsg[indexLastMsg[0x510]].data[3]&0x7f)*0.125; 01014 if(lastMsg[indexLastMsg[0x510]].data[3]&0x80){ 01015 CCon=true; // On when button pushed 01016 } else if(CCkW==0) { 01017 CCon=false; // Off when power drops back to zero 01018 } 01019 if(!CCon && lCCon){ 01020 lastDMode[0]=99;//force refresh 01021 lastDMode[1]=99;//force refresh 01022 } 01023 headlights = (lastMsg[indexLastMsg[0x358]].data[1]&0x80)?true:false; // headlight/turn signal indicator 01024 if(heaterOn){ 01025 lHeaterOn=true; // Only indicate heater once per power cycle 01026 } 01027 heaterOn =((lastMsg[indexLastMsg[0x54f]].data[5]&0x3f)>2)?true:false; 01028 if(heaterMon && heaterOn && !lHeaterOn){ //Heat on alarm 01029 beep3(800,0.25,1200,0.25,1600,0.25); 01030 } 01031 if(accOn&&indexLastMsg[0x355]>0){ 01032 miles_kmbar = (lastMsg[indexLastMsg[0x355]].data[4]&0x20)?true:false; // indicates selected distance units 01033 metric = !miles_kmbar; 01034 } 01035 accV=floor(mon12V*scale12V*10+0.5)/10; //Round to nearest 10th 01036 accOn=(playbackOpen||(accV>5))?true:false; 01037 moving=(mph[0]>0.1); 01038 charging=(lastMsg[indexLastMsg[0x5bf]].data[4]>0x40)?true:false; // MSB=QC, MSB-1=L2 01039 if (laccOn&&!accOn){ // Car turned off 01040 dailyGids += startGids-((lastMsg[indexLastMsg[0x5bc]].data[0]<<2)+(lastMsg[indexLastMsg[0x5bc]].data[1]>>6)); 01041 lHeaterOn=false; 01042 if (showHealth&&!playbackOpen){ 01043 if (saveDmode[0]>maxScreens){ 01044 saveDmode[0]=dMode[0]; 01045 saveDmode[1]=dMode[1]; 01046 } 01047 dMode[0]=healthScreen; 01048 dMode[1]=tripScreen; 01049 secsNoTouch=2;// Keep display on a few seconds 01050 sMode=0; 01051 userIdle=false; 01052 } 01053 if (repeatPoll) { // Log on shutdown if autopoll enabled 01054 tripLog(); // Write trip log on powerdown 01055 } 01056 //write efficiency history data 01057 hfile = fopen("/local/ehist.cny", "w"); 01058 if (hfile!=NULL){ // found a efficiency history file 01059 for(i=0;i<39;i++){ 01060 fprintf(hfile,"%f %f\r\n",mph[i],kW[i]); 01061 } 01062 fprintf(hfile,"%f %f\r\n",maxTripEff,minTripEff); // Save max and min 01063 fprintf(hfile,"%f \r\n",Resr); // Save series resistance 01064 fprintf(hfile,"%f %f\r\n",maxTripMiles,minTripMiles); // Save max and min 01065 fprintf(hfile,"%f %f\r\n",maxTripkWh,minTripkWh); // Save max and min 01066 fprintf(hfile,"%f %f\r\n",maxTripCCkWh,minTripCCkWh); // Save max and min 01067 for(i=0;i<300;i++){ 01068 fprintf(hfile,"%f\r\n",wh[i]); 01069 } 01070 fclose(hfile); 01071 } 01072 } 01073 if (!laccOn&&accOn){ // Car turned on 01074 lHeaterOn=false; 01075 getGids=true; 01076 miles_trip[0]=0; 01077 kWh_trip[0]=0; 01078 CCkWh_trip[0]=0; 01079 seconds = time(NULL); 01080 t = *localtime(&seconds); 01081 if(miles_trip[1]<1){ // charged since last trip 01082 01083 // Adjust wh lookup with whpg data 01084 maxWhpg=0; 01085 minWh=0; 01086 whOff=0; 01087 for(i=1;i<300;i++){ 01088 if(whpg[i]>maxWhpg){ //Find maxWhpg and associated Wh 01089 maxWhpg = (float) whpg[i]; 01090 minWh = wh[i]; 01091 if(debugMode){ 01092 sprintf(sTemp,"maxWhpg=%3.1f; minWh=%3.1f\n", maxWhpg, minWh); 01093 printMsg(sTemp); 01094 } 01095 } 01096 if(whpg[i]>0){ // Compute adjustment to measured range 01097 whOff = (maxWhpg-(float)whpg[i])-(wh[i]-minWh); 01098 }else if(whpg[i-1]>0){ // Compute final offset for rest of range 01099 whOff = maxWhpg-(wh[i]-minWh); 01100 if(debugMode){ 01101 sprintf(sTemp,"whOff=%3.1f\n", whOff); 01102 printMsg(sTemp); 01103 } 01104 } 01105 wh[i] += 0.1*whOff; // Add offset; use last known good offset when no data 01106 whpg[i-1]=0; 01107 } 01108 whpg[299]=0; 01109 01110 // Check and reset daily efficiency if charged since last trip and at least 24 hours has past 01111 if((t.tm_yday>lt.tm_yday)&&(t.tm_hour>effCheckTime)){ 01112 if (!ignoreDayData&&(miles_trip[3]>15)){ // Ignore low mileage data 01113 curEff = miles_trip[3]/kWh_trip[3]; // Get current daily efficiency 01114 if (maxTripEff<curEff) { 01115 maxTripEff=curEff; 01116 maxTripMiles=miles_trip[3]; 01117 maxTripkWh=kWh_trip[3]; 01118 maxTripCCkWh=CCkWh_trip[3]; 01119 printMsg("New max efficiency.\n"); 01120 } 01121 if (minTripEff>curEff) { 01122 minTripEff=curEff; 01123 minTripMiles=miles_trip[3]; 01124 minTripkWh=kWh_trip[3]; 01125 minTripCCkWh=CCkWh_trip[3]; 01126 printMsg("New min efficiency.\n"); 01127 } 01128 } 01129 // Clear daily efficiency data 01130 dailyGids=0; 01131 miles_trip[3]=0; 01132 kWh_trip[3]=0; 01133 CCkWh_trip[3]=0; 01134 ignoreDayData=false; 01135 lt=t; // Remember when counters were cleared (start time for new data) 01136 } 01137 if(lt.tm_yday>t.tm_yday){ //Fix for new year 01138 lt=t; 01139 } 01140 } // Charged since last trip 01141 wait5secs=5; 01142 if (showHealth&&!playbackOpen){ 01143 if (saveDmode[0]>maxScreens){ 01144 saveDmode[0]=dMode[0]; 01145 } 01146 dMode[0]=healthScreen; 01147 } 01148 syncDone=!autoSync; // clear syncDone flag if autoSync enabled 01149 } // Car turned on 01150 laccOn=accOn; 01151 if(!accOn&&userIdle&&!playbackEn){ // Car off and no user activity - turn off screen 01152 dled = 0; 01153 if (saveDmode[0]<=maxScreens){ 01154 dMode[0]=saveDmode[0]; 01155 saveDmode[0]=99; 01156 } 01157 if (saveDmode[1]<=maxScreens){ 01158 dMode[1]=saveDmode[1]; 01159 saveDmode[1]=99; 01160 } 01161 }else if(!headlights){ 01162 dled = ledHi; 01163 } else { 01164 dled = ledLo; 01165 } 01166 cgids=(lastMsg[indexLastMsg[0x5bc]].data[0]<<2)+(lastMsg[indexLastMsg[0x5bc]].data[1]>>6); 01167 if(getGids){ 01168 startGids=cgids; //Get gids 01169 if((startGids>0)&&(startGids<300)){ // Ignore bogus values at startup 01170 getGids=false; 01171 lgids=startGids; // initialize wh/gid array 01172 } 01173 } 01174 if((cgids>0)&&(cgids<300)){ 01175 if(cgids!=lgids){ 01176 if((kWh_trip[1]+CCkWh_trip[1])>0){ 01177 whpg[cgids] = (unsigned short) (1000*(kWh_trip[1]+CCkWh_trip[1])); // Save kWh for each gid since last charge 01178 }else{ 01179 whpg[cgids] = 0; 01180 } 01181 lgids=cgids; 01182 } 01183 } 01184 if(wait5secs>0){ // Wait a few seconds after poweron to give BMS time to measure CP's 01185 wait5secs-=1; 01186 if(wait5secs==0){ 01187 if (repeatPoll) { // Poll on startup if autopoll enabled 01188 logOnce=true; 01189 reqMsgCnt=0; 01190 msgReq.attach(&sendReq,0.015); 01191 lastDMode[0]=99; 01192 lastDMode[1]=99; 01193 } 01194 } 01195 } 01196 //remove health screen once moving 01197 if(moving&&(saveDmode[0]<=maxScreens)&&(wait5secs==0)){ 01198 dMode[0]=saveDmode[0]; 01199 saveDmode[0]=99; 01200 } 01201 01202 //compute historic efficiency 01203 if(numSsamples>0){ // Avoid div0 01204 // calibrated to dash mph which reads slightly fast. 01205 // 227 would give more accurate mph for MXV4s@40psi - 11.75" distance from center of tire to pavement 01206 // but then efficiency estimation would not track miles driven as read from the odometer so 01207 // making CANary have the same error as the Leaf instrumentation 01208 mph[0]=((float) motorRPM)/numSsamples/110; 01209 } else { 01210 mph[0]=0; 01211 } 01212 if(mph[0]>99){ 01213 mph[0]=0; 01214 } 01215 numSsamples=0; 01216 01217 if(numWsamples>0){ // Avoid div0 01218 mpkWh[0]=mph[0]; 01219 kW[0]=((float) mWs_x4)/numWsamples/4e3; 01220 mpkWh[0]/=kW[0]; 01221 if (mpkWh[0]<0) { 01222 mpkWh[0]=99;// negative means inf. 01223 } 01224 kW[0]-=CCkW; // subtract climate control power from recorded value 01225 } else { 01226 kW[0]=0; 01227 mpkWh[0]=0; 01228 } 01229 numWsamples=0; 01230 01231 //if(accOn&&!charging){ // Calculate averages 01232 if(moving){ // Calculate averages for DTE. Freeze when not moving. 01233 for(i=1;i<39;i++){ 01234 average=mph[i]/timeConstant[i]; 01235 mph[i]-=average; 01236 mph[i]+=mph[0]; 01237 mpkWh[i]=average; 01238 average=kW[i]/timeConstant[i]; 01239 kW[i]-=average; 01240 kW[i]+=kW[0]; 01241 if(i==dtePeriod) mpkWh_noCC=mpkWh[i]/average; // compute efficiency w/o CC for dtePeriod 01242 average+=CCkW; //add climate control power back in for display 01243 mpkWh[i]/=average; 01244 if (mpkWh[i]<0) { 01245 mpkWh[i]=99;// negative means inf. 01246 } 01247 } 01248 } 01249 01250 if (!charging){ 01251 miles_trip[0]+=mph[0]/3600; // per trip 01252 miles_trip[1]+=mph[0]/3600; // per charge 01253 miles_trip[2]+=mph[0]/3600; // user 01254 miles_trip[3]+=mph[0]/3600; // per day/roundtrip 01255 kWh_trip[0]+=kW[0]/3600; 01256 kWh_trip[1]+=kW[0]/3600; 01257 kWh_trip[2]+=kW[0]/3600; 01258 kWh_trip[3]+=kW[0]/3600; 01259 CCkWh_trip[0]+=CCkW/3600; 01260 CCkWh_trip[1]+=CCkW/3600; 01261 CCkWh_trip[2]+=CCkW/3600; 01262 CCkWh_trip[3]+=CCkW/3600; 01263 } else { // charging so reset per charge trip meter 01264 miles_trip[1]=0; 01265 kWh_trip[1]=0; 01266 CCkWh_trip[1]=0; 01267 } 01268 01269 motorRPM=0; 01270 mWs_x4=0; 01271 01272 // Compute ESR 01273 if((Imax-Imin)<40){ // do nothing - insufficient delta_I to measure 01274 unloadedV_x2 = (curRmax+curRmin)/2; 01275 }else if ((redRmax-redRmin)<(curRmax-curRmin)) { // less variation on reduced Resr 01276 Resr-=0.001; 01277 unloadedV_x2 = (redRmax+redRmin)/2; 01278 } else if ((incRmax-incRmin)<(curRmax-curRmin)) { // less variation on increased Resr 01279 Resr+=0.001; 01280 unloadedV_x2 = (incRmax+incRmin)/2; 01281 } else { // current Resr is still best answer 01282 unloadedV_x2 = (curRmax+curRmin)/2; 01283 } 01284 curRmin=1000; 01285 curRmax=0; 01286 incRmin=1000; 01287 incRmax=0; 01288 redRmin=1000; 01289 redRmax=0; 01290 Imax=-1000; 01291 Imin=1000; 01292 01293 if(logCP&&usbEn){ 01294 if(logOnce){ 01295 tripLog(); 01296 logOnce=false; 01297 } 01298 logPackVoltages(); // Turbo3, only call 01299 } 01300 if(!usbEn){ 01301 usbEn=detectUSB(); // Keep looking if none found 01302 if(usbEn){ 01303 //Read USB directory 01304 sprintf(sTemp,"Reading USB drive\n"); 01305 printMsg(sTemp); 01306 res = f_opendir(&dir, ""); /* Open the directory */ 01307 if(res == FR_OK) { 01308 for (i=1;i<20;i++) { 01309 res = f_readdir(&dir, &fno); /* Read a directory item */ 01310 if (res != FR_OK || fno.fname[0] == 0) break; /* Break on error or end of dir */ 01311 //if (fno.fname[0] == '.') continue; /* Ignore dot entry */ 01312 fn = fno.fname; 01313 if (fno.fattrib & AM_DIR) { /* It is a directory */ 01314 sprintf(sTemp,"dir: %s\n", fn); 01315 printMsg(sTemp); 01316 } else { /* It is a file. */ 01317 sprintf(sTemp,"%s\n", fn); 01318 printMsg(sTemp); 01319 } 01320 } 01321 //f_closedir(&dir); 01322 } 01323 // Force update to clear USB init garbage 01324 lastDMode[0]=99; 01325 lastDMode[1]=99; 01326 checkFWupdate=true; // Check if screen touched to updateFW 01327 } //if(detectUSB) 01328 } else { 01329 usbEn=detectUSB(); // Check to see if it is still inserted 01330 if(!usbEn){ 01331 sprintf(sTemp,"USB disconnected\n"); 01332 printMsg(sTemp); 01333 mfr = f_mount(0,&USBdrive); // Prepare for next insertion 01334 01335 } 01336 } 01337 if(!syncDone){ 01338 syncDone=syncDateTime(); 01339 } 01340 tock=true; 01341 } // tick 01342 01343 if(step){ // playback 01344 if(playbackOpen&&playbackEn){ 01345 for(i=0;i<120;i++){ 01346 if(!f_eof(&efile)){ 01347 efr=f_read(&efile,&header,5,&bytesRW); 01348 efr=f_read(&efile,&data,8,&bytesRW); 01349 logCan(header[0],CANMessage(0x7ff&((header[4]<<8)+header[3]), data, 8)); // Playback 01350 } else { 01351 f_close(&efile); // restart 01352 efr = f_open(&efile,"playback.alc",FA_READ|FA_OPEN_EXISTING); 01353 lastDMode[whichTouched]=99;//force refresh 01354 beep(2000,0.25); 01355 } 01356 } 01357 } 01358 step=false; 01359 } 01360 01361 display=display<1?display+1:0; // toggle display 01362 updateDisplay(display); 01363 } //while (true) 01364 }
Generated on Sun Jul 17 2022 01:46:20 by 1.7.2