Dual CANbus monitor and instrumentation cluster
Dependencies: SPI_TFTx2 TFT_fonts TOUCH_TFTx2 beep mbed
Fork of CANary by
main.cpp
00001 // main.cpp 00002 // 00003 //To Do: 00004 // * Audible friction brake feedback 00005 // * User-configurable watchpoint 00006 // * Add 50% charge option 00007 // * Add coasting regen to regen/braking display 00008 // * Change semilog efficiency graph to linear with 10 minute values 00009 // * Add additional 79b bank readouts 00010 // * Add ability to transfer settings config file to/from USB 00011 // * Subtract accessory power from efficiency history (add back in when displaying) 00012 00013 #include "mbed.h" 00014 #include "CAN.h" 00015 #include "beep.h" 00016 #include "ff.h" 00017 #include "PowerControl.h" 00018 #include "EthernetPowerControl.h" 00019 #include "utility.h" 00020 #include "displayModes.h" 00021 #include "TOUCH_TFTx2.h" 00022 00023 char revStr[7] = "125"; // gg - revision string, max 6 characters 00024 00025 FATFS USBdrive; 00026 LocalFileSystem local("local"); 00027 bool waitasec = true; 00028 unsigned char wait5secs = 5; 00029 // to write to USB Flash Drives, or equivalent (SD card in Reader/Writer) 00030 // class10 SDcard in Reader/Writer recommended 00031 FRESULT mfr = f_mount(0,&USBdrive); 00032 time_t seconds ; 00033 00034 Ticker autoPoll; 00035 Ticker playback; 00036 Ticker msgReq; 00037 Timer timer; 00038 00039 DigitalOut led1(LED1); 00040 DigitalOut led2(LED2); 00041 DigitalOut led3(LED3); 00042 DigitalOut led4(LED4); 00043 00044 InterruptIn touchpad(p17); 00045 CAN can1(p9, p10); // CAN1 (EV) uses pins 9 and 10 (rx, tx) and pin 8 (rs) 00046 DigitalOut can1SleepMode(p8); // Use pin 8 to control the sleep mode of can2 00047 CAN can2(p30, p29); // CAN2 (CAR) uses pins 30 and 29 (rx, tx) and pin 28 (rs) 00048 DigitalOut can2SleepMode(p28); // Use pin 28 to control the sleep mode of can1 00049 AnalogIn mon12V(p15); 00050 TOUCH_TFTx2 tt(p16, p17, p19, p20, p11, p12, p13, p6, p7, p5, "TFT"); // x+,x-,y+,y-,mosi, miso, sclk, cs0, cs1, reset 00051 PwmOut dled(p23); 00052 Beep spkr(p21); 00053 00054 bool debugMode = false; 00055 bool usbEn = false; 00056 bool logEn = true; 00057 bool logOpen = false; 00058 bool yesBattLog = true; // gg - Batt Log 00059 unsigned char tNavRow = 3; // gg - 4x4 touch 00060 00061 FILE *hfile; // history file 00062 FIL efile; // external usb file 00063 FRESULT efr; // external file access flags 00064 unsigned int bytesRW; 00065 char fileName[35] = ""; 00066 char writeBuffer[maxBufLen][13] __attribute__ ((section("AHBSRAM1"))); // buffer for USB write 00067 char indexLastMsg[0x800]={0}; // index table for last message 00068 CANMessage lastMsg[100]; // table to store last message of eachtype 00069 00070 unsigned char battData[BatDataBufMax]={0}; // 7 * 0x3D = BatDataBufMax 00071 00072 unsigned char msgChanged[100]; // inidcates which bytes changed 00073 char c; 00074 volatile int writePointer = 0; 00075 int readPointer=0; 00076 volatile unsigned short secsNoMsg = 0; 00077 volatile unsigned short secsNoTouch = 0; 00078 volatile bool canIdle; 00079 volatile bool userIdle; 00080 bool touched=false; //flag to read touchscreen 00081 unsigned char whichTouched = 0; 00082 char counter = 0; 00083 unsigned char dMode[2] = {mainScreen,brakeScreen}; //display mode 00084 unsigned char sMode = 0; // setup mode 00085 unsigned char lastDMode[2] = {0,0}; //last screen mode 00086 unsigned char dtMode = 6; 00087 char displayLog[20][40]; 00088 unsigned char displayLoc = 0; 00089 unsigned int fwCount=1; 00090 unsigned char indexOffset = 1; 00091 bool showCP = false; 00092 bool logCP = false; //Turbo3 00093 bool logOnce = false; 00094 bool repeatPoll = true; 00095 bool headlights = false; 00096 bool tick = false; 00097 bool ZeroSecTick = false; 00098 float ledHi = 0.8; // Bright LED value (until config file read) 00099 float ledLo = 0.1; // Dim LED value (until config file read) 00100 unsigned short pollInt = 300; // polling interval=5 minutes (until config file read) 00101 bool accOn = false; // Accessories on 00102 bool laccOn = false; 00103 float scale12V = 16.2; // R1:R2 ratio 00104 signed long mWs_x4 = 0; 00105 unsigned short numWsamples = 0; 00106 unsigned short numSsamples = 0; 00107 float accV = 0; 00108 bool playbackEn = false; 00109 bool playbackOpen = false; 00110 //float playbackInt = 0.05; //read messages every 50 ms 00111 float playbackInt = 0.005; //read messages every 5 ms 00112 bool step = false; 00113 char header[5]; 00114 char data[8]; 00115 signed long motorRPM; 00116 unsigned char skin = ttSkin ; 00117 unsigned char dtePeriod = 14; //ten minute averaging interval 00118 float kWh_trip[3]={0}; 00119 float miles_trip[3]={0}; 00120 float mph[39]={0}; 00121 float kW[39]={0}; 00122 float mpkWh[39]={0}; 00123 float unloadedV_x2,Resr,curRmax,curRmin,redRmax,redRmin,incRmax,incRmin; 00124 signed short Imax, Imin; 00125 // Logarithmic division scale (roughly - snapped to common units of time) 00126 float timeConstant[39] = {1, 1.58, 2.51, 3.98, 6.31, 10, 15.8, 25.1, 39.8, 60, // 1 minute 00127 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 00128 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 00129 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 00130 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 00131 bool tock = false; 00132 unsigned short pointerSep; 00133 unsigned char reqMsgCnt = 99; 00134 unsigned long Ah_x10000 = 0; 00135 unsigned long SOC_x10000 = 0; 00136 unsigned short SOH_x100 = 0; 00137 float maxTemp = 0; 00138 bool metric = false; 00139 bool shunt[96]={0}; 00140 bool charging=false; 00141 00142 int main() { 00143 //can1SleepMode.mode(OpenDrain); 00144 //can2SleepMode.mode(OpenDrain); 00145 char sTemp[40]; 00146 unsigned long secs; 00147 unsigned char i,j,display=0,lwt=0; 00148 point lastTouch; 00149 float average; 00150 tt.set_orientation(1); 00151 tt.background(Black); 00152 tt.set_display(2); // select both displays 00153 tt.cls(); 00154 tt.claim(stdout); // send stdout to the TFT display 00155 touchpad.rise(&touch_ISR); 00156 tt.wfi(); // enable interrupt on touch 00157 dled = 0.8; // turn on display LED 80% 00158 Resr = 0.075; // initial guess of Resr 00159 timer.start() ; 00160 RTC_Init(); // start the RTC Interrupts that sync the timer 00161 struct tm t; // pointer to a static tm structure 00162 NVIC_SetPriority(CAN_IRQn, 2); //set can priority just below RTC 00163 NVIC_SetPriority(TIMER3_IRQn, 3); //set ticker priority just below can 00164 00165 seconds = time(NULL); 00166 t = *localtime(&seconds) ; 00167 // is it a date before 2012 ? 00168 if ((t.tm_year + 1900) < 2012 ) { 00169 // before 2013 so update year to make date entry easier 00170 t.tm_year = 2013 - 1900; 00171 // set the RTC 00172 set_time(mktime(&t)); 00173 seconds = time(NULL); 00174 } 00175 t = *localtime(&seconds) ; 00176 strftime(sTemp, 32, "%a %m/%d/%Y %X\n", &t); 00177 printMsg(sTemp); // record RTC 00178 00179 // revision 00180 sprintf(sTemp,"CANary firmware rev%s\n", revStr); // gg - for Logging the revision 00181 printMsg(sTemp); // revision 00182 00183 secsNoMsg = 0; 00184 00185 //read efficiency history data 00186 hfile = fopen("/local/ehist.cny", "r"); 00187 if (hfile!=NULL){ // found a efficiency history file 00188 for(i=0;i<39;i++){ 00189 if(!feof(hfile)){ 00190 fscanf(hfile,"%f %f\r\n",&mph[i],&kW[i]); 00191 mpkWh[i]=mph[i]/kW[i]; 00192 } 00193 } 00194 fclose(hfile); 00195 printMsg("History Loaded.\n"); // History loaded 00196 } else { // create initial file 00197 printMsg("History not found. Created.\n"); // history not found, created 00198 for(i=0;i<39;i++){ 00199 // Pre-load with 4 mpkWh @ 40 mph 00200 mph[i]=40*timeConstant[i]; 00201 kW[i]=10*timeConstant[i]; 00202 mpkWh[i]=4; 00203 } 00204 } 00205 00206 // Read config file 00207 readConfig(); 00208 if (repeatPoll) { // enable autopolling if enabled 00209 autoPoll.attach(&autoPollISR,pollInt); 00210 } 00211 00212 // Start monitors 00213 can1.monitor(true); // set to snoop mode 00214 can2.monitor(true); // set to snoop mode 00215 can1.frequency(500000); 00216 can2.frequency(500000); 00217 can1SleepMode = VP230Sleep; // Turn on Monitor_only Mode 00218 can2SleepMode = VP230Sleep; // Turn on Monitor_only Mode 00219 can1.attach(&recieve1); 00220 can2.attach(&recieve2); 00221 00222 touched=false; 00223 secsNoTouch=2; 00224 while (true) { 00225 if (!logOpen) { // Open new file if one is not already open 00226 if(logEn&&usbEn){ //logging enables and USB device detected 00227 strftime(fileName, 32, "%m%d%H%M.alc", &t); //mmddhhmm.alc 00228 efr = f_open(&efile,fileName,FA_WRITE|FA_OPEN_ALWAYS); 00229 seconds = time(NULL); 00230 t = *localtime(&seconds) ; 00231 lastDMode[0]=99;//force refresh 00232 lastDMode[1]=99;//force refresh 00233 if(efr != FR_OK){ 00234 sprintf(sTemp,"\nERR:%d Unable to open %s\n\n\n\n",efr,fileName); 00235 printMsg(sTemp); // cannot open alc file 00236 logEn=false; 00237 spkr.beep(1000,0.25); 00238 wait_ms(500); 00239 spkr.beep(1000,0.25); 00240 } else { 00241 logOpen = true; 00242 readPointer=writePointer; 00243 sprintf(sTemp,"Starting Can Log %s\n",fileName); 00244 printMsg(sTemp); // starting alc log file 00245 00246 logTS(); // Date Time at start 00247 logEvent("Starting"); // Log startup msg for testing 00248 sprintf(sTemp,"Cr%s",revStr); 00249 logEvent(sTemp); // gg - log firmware version 00250 spkr.beep(2000,0.25); 00251 } 00252 }//logging enabled and USB detected 00253 } else { // if (logOpen) 00254 pointerSep=(writePointer+maxBufLen-readPointer)%maxBufLen; 00255 if (pointerSep>(maxBufLen/16)||canIdle||!logEn) { 00256 // Dump buffer if > 1/16 full or canbus has stopped 00257 //if (&efile == NULL) { 00258 if (efr != FR_OK) { 00259 logOpen = false; 00260 printMsg("Failed to append log file.\n"); // failed to append 00261 spkr.beep(3000,0.25); 00262 spkr.beep(1500,0.25); 00263 spkr.beep(750,0.25); 00264 spkr.beep(375,0.25); 00265 logEn=false; 00266 } else { 00267 while (readPointer != writePointer) { 00268 efr=f_write(&efile,&writeBuffer[readPointer][0],13,&bytesRW); 00269 if(++readPointer >= maxBufLen){ 00270 readPointer=0; 00271 led4 = !led4; 00272 } 00273 } 00274 } 00275 } // if > 1/16 full, canbus has stopped, or logging stopped 00276 if (!logEn) { 00277 sprintf(sTemp,"Stopping Can Log %s\n",fileName); 00278 printMsg(sTemp); // stopping alc log file 00279 f_close(&efile); 00280 logOpen=false; 00281 pointerSep=0; 00282 led4=false; 00283 } 00284 } // if logOpen 00285 if (canIdle&&userIdle&&!playbackEn) { // canbus idle --> sleep to save power 00286 if (repeatPoll) { // stop autopolling if enabled 00287 autoPoll.detach(); 00288 } 00289 if (logOpen){ //close file to dump buffer 00290 f_close(&efile); 00291 } // if (logOpen) 00292 seconds = time(NULL); 00293 t = *localtime(&seconds) ; 00294 strftime(sTemp, 40, "Sleeping: %a %m/%d/%Y %X\n", &t); 00295 printMsg(sTemp); // sleeping date time 00296 updateDisplay(0); //Added for turbo3 who has a display override and wants to see the sleep message before going to sleep 00297 updateDisplay(1); 00298 //LPC_RTC->CIIR=0x00; // block RTC interrupts 00299 led1=0; 00300 led2=0; 00301 led3=0; 00302 led4=0; 00303 dled=0; // turn off display 00304 secs = time(NULL); // seconds past 12:00:00 AM 1 Jan 1900 00305 while (secsNoMsg>canTimeout && !touched) { 00306 //DeepPowerDown(); 00307 tt.wfi(); //enable touch interrupt 00308 //__wfi(); // freeze CPU and wait for interrupt (from canbus or touch) 00309 Sleep(); 00310 } 00311 lastDMode[0]=99; 00312 lastDMode[1]=99; 00313 secsNoTouch=2; 00314 canIdle=secsNoMsg>canTimeout; 00315 dled=0.8; // turn on display LED 00316 seconds = time(NULL); 00317 t = *localtime(&seconds) ; 00318 strftime(sTemp, 40, "Waking: %a %m/%d/%Y %X\n", &t); 00319 printMsg(sTemp); // wakeup date time 00320 if (time(NULL)>(secs+1800)) { 00321 if (logOpen){ 00322 f_close(&efile); 00323 logOpen = false; // Start new file if asleep for more than 30 minutes 00324 } // if (logOpen) 00325 if (secsNoTouch>100) secsNoTouch = 100; // also mostly reset user Idle counter 00326 } else if (logOpen){ // insert timestamp on each wake if logging enabled (disabled for now) 00327 efr = f_open(&efile,fileName,FA_WRITE|FA_OPEN_ALWAYS); 00328 f_lseek(&efile,0xffffffff); // goto end of file (append existing) 00329 logEvent("WakingUp"); // gg - use messeges 00330 logTS(); // Date-Time at wakeup 00331 } 00332 if (repeatPoll) { // re-enable autopolling if enabled 00333 autoPoll.attach(&autoPollISR,pollInt); 00334 } 00335 } // if idle 00336 00337 if(touched){ // call touchscreen procedure if touch interrupt detected 00338 lastTouch = tt.get_touch(); 00339 lastTouch = tt.to_pixel(lastTouch); // convert to pixel pos 00340 if((lastTouch.x!=639)&&(lastTouch.x!=319)&&(lastTouch.y!=239)){ // filter phantom touches 00341 if (userIdle) { 00342 secsNoTouch=2; // Ignore first touch if user idle 00343 userIdle=false; 00344 } else { 00345 secsNoTouch=0; 00346 } 00347 if (lastTouch.x>320){ 00348 whichTouched=1; 00349 } else { 00350 whichTouched=0; 00351 } 00352 if (whichTouched!=lwt){ 00353 lastDMode[lwt]=99; // Repaint lastTouched 00354 lwt=whichTouched; 00355 } 00356 sMode = 1; 00357 } 00358 //sprintf(sTemp,"%d,%d ",lastTouch.x,lastTouch.y); 00359 //printMsg(sTemp); // touch x,y - for debug 00360 touched = false; // clear interrupt flag 00361 } 00362 //--------------- 00363 // gg - 4x4 touch 00364 //unsigned char tScrn = 0 ; // screen 0 00365 unsigned char tCol ; 00366 unsigned char tRow ; 00367 00368 if (!userIdle) { 00369 if (secsNoTouch<2) {// Recently touched 00370 secsNoTouch +=2; // increment to prevent double touch 00371 sMode = 1; 00372 //sprintf(sTemp,"button %d %d,%d %d\n",i,buttonX(lastTouch.x,3),buttonY(lastTouch.y,3),lastTouch.x); 00373 //printMsg(sTemp); // button parms - for debug 00374 switch (sMode) { 00375 case 0: // no select 00376 break; 00377 case 1: // select screen 00378 //-------------- 00379 // gg - 4x4 touch 00380 tCol = buttonX(lastTouch.x,4) ; 00381 if( tCol >= 4 ){ tCol -= 4; } // touch is on screen 1 00382 00383 tRow = buttonY(lastTouch.y,4) ; 00384 00385 highlightButton( tCol,tRow, whichTouched, 4,4) ; // gg - highlight 00386 00387 if( tRow == tNavRow ) tRow = 7 ; // gg 00388 switch ( (tCol*10) + tRow ) { 00389 //--------------------------------- 00390 case 00: // top row, left button on screen 0 or 1 00391 if (dMode[whichTouched]==monitorScreen||dMode[whichTouched]==changedScreen) { 00392 indexOffset=indexOffset>4?indexOffset-4:1; 00393 } else if (dMode[whichTouched] == indexScreen) { // gg - index 00394 dMode[whichTouched] = mainScreen ; // GoTo Main Screen 00395 sMode=0; 00396 } else if (dMode[whichTouched]==configScreen) { 00397 wait_ms(500); 00398 tt.background(Black); 00399 tt.calibrate(); 00400 } else if (dMode[whichTouched]==playbackScreen) { // slower 00401 playbackInt *=2; 00402 if(playbackEn){ 00403 playback.detach(); 00404 playback.attach(&playbackISR,playbackInt); 00405 } 00406 } else { 00407 lastDMode[whichTouched]=99;//repaint to clear highlight 00408 } 00409 break; 00410 //----------------------------------------------- 00411 case 10: // 1,0 (col left of center,top row) on screen 0 or 1 00412 if (dMode[whichTouched]==changedScreen) { 00413 for(j=0;j<100;j++) msgChanged[j]=0; // clear changed data 00414 lastDMode[whichTouched]=99;//force refresh 00415 } else if (dMode[whichTouched] == indexScreen) { // gg - index 00416 sMode=0; 00417 dMode[whichTouched] = brakeScreen ; // GoTo Brake Screen 00418 } else if (dMode[whichTouched]==cpScreen) { 00419 reqMsgCnt=0; 00420 msgReq.attach(&sendReq,0.015); 00421 } else if (dMode[whichTouched]==cpHistScreen) { // gg - hist 00422 reqMsgCnt=0; 00423 msgReq.attach(&sendReq,0.015); 00424 } else if (dMode[whichTouched]==cpBarScreen) { // gg - cpbars 00425 reqMsgCnt=0; 00426 msgReq.attach(&sendReq,0.015); 00427 } else if (dMode[whichTouched]==configScreen) { 00428 mbed_reset(); 00429 } else if (dMode[whichTouched]==playbackScreen) { // pause/unpause 00430 playbackEn=!playbackEn; 00431 if(playbackEn){ 00432 playback.attach(&playbackISR,playbackInt); 00433 } else { 00434 playback.detach(); 00435 } 00436 } else { 00437 lastDMode[whichTouched]=99;//repaint to clear highlight 00438 } 00439 00440 break; 00441 //-------------------------------------- 00442 case 20: // col 2 and row 0 on either screen 0 or 1 00443 if (dMode[whichTouched]==monitorScreen||dMode[whichTouched]==changedScreen) { 00444 indexOffset=indexOffset<77?indexOffset+4:80; 00445 } else if (dMode[whichTouched] == indexScreen) { // gg - index 00446 dMode[whichTouched] = effScreen ; // GoTo EFF Screen 00447 sMode=0; 00448 } else if (dMode[whichTouched]==configScreen) { 00449 printMsg("Saving config file.\n"); // saving config 00450 saveConfig(); 00451 spkr.beep(2000,0.25); 00452 } else if (dMode[whichTouched]==playbackScreen) { // faster 00453 if(playbackInt>.002){ 00454 playbackInt/=2; 00455 if(playbackEn){ 00456 playback.detach(); 00457 playback.attach(&playbackISR,playbackInt); 00458 } 00459 } 00460 } else { 00461 lastDMode[whichTouched]=99;//repaint to clear highlight 00462 } 00463 00464 break; 00465 00466 case 30: // right-most on top row 00467 00468 if (dMode[whichTouched]==configScreen) { 00469 // step through skins 00470 if( skin < maxSkin ) skin += 1 ; 00471 else skin = 0 ; 00472 00473 // repaint both screens, I think 00474 lastDMode[whichTouched]=99;//repaint to clear highlight 00475 // and re-paint the other screen too, to see new skin there 00476 lastDMode[whichTouched ^ 1]=99; // repaint other screen (^ = XOR) 00477 } else if (dMode[whichTouched] == indexScreen) { // gg - index 00478 dMode[whichTouched] = healthScreen ; // Goto health screen 00479 sMode=0; 00480 } else { 00481 lastDMode[whichTouched]=99;//repaint to clear highlight 00482 } 00483 00484 break; 00485 //---------------------------------- 00486 //---------------------------------- 00487 case 01: // left col middle row 00488 if (dMode[whichTouched]==configScreen) { 00489 logEn = !logEn; 00490 } else if (dMode[whichTouched] == indexScreen) { // gg - index 00491 dMode[whichTouched] = cpScreen ; // GoTo CP Data Screen 00492 sMode=0; 00493 } else if (dMode[whichTouched]==dateScreen){ 00494 dtMode=(dtMode<6)?dtMode+1:0; 00495 lastDMode[whichTouched]=99; 00496 } else { 00497 lastDMode[whichTouched]=99;//repaint to clear highlight 00498 } 00499 00500 break; 00501 //------------------------------ 00502 case 11: 00503 if (dMode[whichTouched]==configScreen){ 00504 repeatPoll = !repeatPoll; 00505 if (repeatPoll) { 00506 autoPoll.attach(&autoPollISR,pollInt); 00507 } else { 00508 autoPoll.detach(); 00509 } 00510 } else if (dMode[whichTouched] == indexScreen) { // gg - index 00511 dMode[whichTouched] = cpHistScreen ; // GoTo CP Hist Screen 00512 sMode=0; 00513 } else if (dMode[whichTouched]==playbackScreen) { 00514 // Start/stop playback 00515 if(!playbackOpen){ 00516 if(!canIdle){ 00517 printMsg("Cannot playback while connected to canbus\n"); 00518 }else if(!logOpen){ 00519 efr = f_open(&efile,"playback.alc",FA_READ|FA_OPEN_EXISTING); 00520 lastDMode[whichTouched]=99;//force refresh 00521 if(efr != FR_OK){ 00522 printMsg("Unable to open /usb/playback.alc\n"); // no playback.alc 00523 spkr.beep(1000,0.25); 00524 } else { 00525 playbackOpen = true; 00526 playbackEn=true; 00527 playback.attach(&playbackISR,playbackInt); 00528 printMsg("Starting playback\n"); // start playback 00529 spkr.beep(2000,0.25); 00530 can1.attach(&doNothing);// Stop recieving CAN data 00531 can2.attach(&doNothing); 00532 } 00533 } else { 00534 printMsg("Must stop logging first\n"); 00535 } 00536 } else { 00537 playback.detach(); 00538 f_close(&efile); 00539 playbackOpen=false; 00540 playbackEn=false; 00541 can1.attach(&recieve1);// Restore CAN data recieve 00542 can2.attach(&recieve2); 00543 lastDMode[whichTouched]=99; 00544 } 00545 } else if (dMode[whichTouched]==dateScreen){ 00546 upDate(dtMode,true); 00547 lastDMode[whichTouched]=99; 00548 } else { 00549 lastDMode[whichTouched]=99;//repaint to clear highlight 00550 } 00551 00552 break; 00553 //--------------------------------- 00554 case 21: // col 2 row 1 00555 if (dMode[whichTouched]==configScreen) { // gg - Batt Log Enable Button 00556 yesBattLog = !yesBattLog; 00557 } else if (dMode[whichTouched] == indexScreen) { // gg - index 00558 dMode[whichTouched] = cpBarScreen ; // GoTo CP Bars Screen 00559 sMode=0; 00560 } else if (dMode[whichTouched]==dateScreen){ 00561 upDate(dtMode,false); 00562 lastDMode[whichTouched]=99; 00563 } else { 00564 lastDMode[whichTouched]=99;//repaint to clear highlight 00565 } 00566 00567 break; 00568 00569 case 31: // col 3 row 1 00570 if (dMode[whichTouched]==configScreen) { // gg - Batt Log Enable Button 00571 debugMode = !debugMode; 00572 } else if (dMode[whichTouched] == indexScreen) { // gg - index 00573 dMode[whichTouched] = configScreen ; // GoTo Config Screen 00574 } else if (dMode[whichTouched] == tripScreen) { 00575 miles_trip[1]=0; 00576 kWh_trip[1]=0; 00577 sMode=0; 00578 lastDMode[whichTouched]=99;//repaint to clear highlight 00579 } else { 00580 lastDMode[whichTouched]=99;//repaint to clear highlight 00581 } 00582 break; 00583 00584 //----------------------------------- 00585 case 02: // left col, bottom row (not nav) 00586 if (dMode[whichTouched] == indexScreen) { // gg - index 00587 dMode[whichTouched] = playbackScreen ; // GoTo Playback Screen 00588 } else if (dMode[whichTouched]==configScreen) { 00589 metric = !metric; // toggle metric/imperial display 00590 } else { 00591 lastDMode[whichTouched]=99;//repaint to clear highlight 00592 } 00593 break; 00594 00595 case 12: // left-middle col, bottom row (not nav) 00596 if (dMode[whichTouched] == indexScreen) { // gg - index 00597 dMode[whichTouched] = dateScreen ; // GoTo Set Date/Time Screen 00598 } else { 00599 lastDMode[whichTouched]=99;//repaint to clear highlight 00600 } 00601 break; 00602 00603 case 22: // right-middle col, bottom row (not nav) 00604 if (dMode[whichTouched] == indexScreen) { // gg - index 00605 dMode[whichTouched] = logScreen ; 00606 } else { 00607 lastDMode[whichTouched]=99;//repaint to clear highlight 00608 } 00609 break; 00610 00611 case 32: // right col, bottom row (not nav) 00612 if (dMode[whichTouched] == configScreen) { 00613 logEn=false; 00614 updateFirmware(); 00615 } else if (dMode[whichTouched] == tripScreen) { 00616 miles_trip[2]=0; 00617 kWh_trip[2]=0; 00618 sMode=0; 00619 lastDMode[whichTouched]=99;//repaint to clear highlight 00620 } else if (dMode[whichTouched] == indexScreen) { 00621 dMode[whichTouched] = tripScreen ; 00622 } else { 00623 lastDMode[whichTouched]=99;//repaint to clear highlight 00624 } 00625 break; 00626 00627 //----------------------------------- 00628 //----------------------------------- 00629 // Prev Navigation 00630 case 07: // col 0 row tNavRow 00631 dMode[whichTouched]=dMode[whichTouched]>0?dMode[whichTouched]-1:maxScreens; 00632 break; 00633 //----------------------------------- 00634 // Select Screen Navigation 00635 case 17: 00636 //secsNoTouch = userTimeout; // immediately exit config mode 00637 sMode=0; 00638 lastDMode[whichTouched]=99; // Repaint 00639 break; 00640 //----------------------------------- 00641 // Index Navigation 00642 case 27: // col 2 row tNavRow 00643 dMode[whichTouched]= indexScreen ; // gg - index 00644 break; 00645 //------------------------------------ 00646 // Next Navigation 00647 case 37: // lower right on Nav Line gg - move next 00648 dMode[whichTouched]=dMode[whichTouched]<maxScreens?dMode[whichTouched]+1:0; 00649 break; 00650 //------------------------------------ 00651 //------------------------------------ 00652 default: 00653 lastDMode[whichTouched]=99;//repaint to clear highlight 00654 break; 00655 } 00656 break; 00657 case 2: // numpad 00658 break; 00659 case 3: 00660 break; 00661 default: 00662 break; 00663 } // case sMode 00664 } //recently touched 00665 } else { // userIdle 00666 if(sMode==1){ 00667 sMode=0; 00668 lastDMode[whichTouched]=99; 00669 } 00670 } 00671 00672 if(tick){ // Executes once a second 00673 tick=false; 00674 headlights = (lastMsg[indexLastMsg[0x358]].data[1]&0x80)?true:false; // headlight/turn signal indicator 00675 accV=floor(mon12V*scale12V*10+0.5)/10; //Round to nearest 10th 00676 accOn=(accV>5)?true:false; 00677 charging=(mph[0]<0.1)&&(kW[0]<-1); // not moving and generating energy so much be charging 00678 if(laccOn&&!accOn){ // Car turned off 00679 if (repeatPoll) { // Log on shutdown if autopoll enabled 00680 tripLog(); // Write trip log on powerdown 00681 } 00682 //write efficiency history data 00683 hfile = fopen("/local/ehist.cny", "w"); 00684 if (hfile!=NULL){ // found a efficiency history file 00685 for(i=0;i<39;i++){ 00686 fprintf(hfile,"%f %f\r\n",mph[i],kW[i]); 00687 } 00688 fclose(hfile); 00689 } 00690 } 00691 if(!laccOn&&accOn){ // Car turned on 00692 miles_trip[0]=0; 00693 kWh_trip[0]=0; 00694 wait5secs=5; 00695 } 00696 laccOn=accOn; 00697 if(!accOn&&!logEn&&userIdle&&!playbackEn){ // Car off and logging disabled and no user activity 00698 dled = 0; 00699 }else if(!headlights){ 00700 dled = ledHi; 00701 } else { 00702 dled = ledLo; 00703 } 00704 if(wait5secs>0){ // Wait a few seconds after poweron to give BMS time to measure CP's 00705 wait5secs-=1; 00706 if (repeatPoll&&(wait5secs==0)) { // Poll on startup if autopoll enabled 00707 logOnce=true; 00708 reqMsgCnt=0; 00709 msgReq.attach(&sendReq,0.015); 00710 } 00711 } 00712 00713 //compute historic efficiency 00714 if(numSsamples>0){ // Avoid div0 00715 mph[0]=((float) motorRPM)/numSsamples/220; // Empirically derived with MXV4s - may change with different wheels&tires 00716 } else { 00717 mph[0]=0; 00718 } 00719 if(mph[0]>99){ 00720 mph[0]=0; 00721 } 00722 numSsamples=0; 00723 00724 if(numWsamples>0){ // Avoid div0 00725 mpkWh[0]=mph[0]; 00726 kW[0]=((float) mWs_x4)/numWsamples/4e3; 00727 mpkWh[0]/=kW[0]; 00728 if (mpkWh[0]<0) { 00729 mpkWh[0]=99;// negative means inf. 00730 } 00731 } else { 00732 kW[0]=0; 00733 mpkWh[0]=0; 00734 } 00735 numWsamples=0; 00736 00737 if (!charging){ 00738 miles_trip[0]+=mph[0]/3600; 00739 miles_trip[1]+=mph[0]/3600; 00740 miles_trip[2]+=mph[0]/3600; 00741 kWh_trip[0]+=kW[0]/3600; 00742 kWh_trip[1]+=kW[0]/3600; 00743 kWh_trip[2]+=kW[0]/3600; 00744 } 00745 00746 motorRPM=0; 00747 mWs_x4=0; 00748 00749 // Compute ESR 00750 if((Imax-Imin)<40){ // do nothing - insufficient delta_I to measure 00751 unloadedV_x2 = (curRmax+curRmin)/2; 00752 }else if ((redRmax-redRmin)<(curRmax-curRmin)) { 00753 Resr-=0.001; 00754 unloadedV_x2 = (redRmax+redRmin)/2; 00755 } else if ((incRmax-incRmin)<(curRmax-curRmin)) { 00756 Resr+=0.001; 00757 unloadedV_x2 = (incRmax+incRmin)/2; 00758 } else { 00759 unloadedV_x2 = (curRmax+curRmin)/2; 00760 } 00761 curRmin=1000; 00762 curRmax=0; 00763 incRmin=1000; 00764 incRmax=0; 00765 redRmin=1000; 00766 redRmax=0; 00767 Imax=-1000; 00768 Imin=1000; 00769 00770 if((accOn||playbackEn)&&!charging){ 00771 for(i=1;i<39;i++){ 00772 average=mph[i]/timeConstant[i]; 00773 mph[i]-=average; 00774 mph[i]+=mph[0]; 00775 mpkWh[i]=average; 00776 average=kW[i]/timeConstant[i]; 00777 if(!charging){ //Not charging - so include in efficiency data 00778 kW[i]-=average; 00779 kW[i]+=kW[0]; 00780 } 00781 mpkWh[i]/=average; 00782 if (mpkWh[i]<0) { 00783 mpkWh[i]=99;// negative means inf. 00784 } 00785 //mpkWh[i]=floor(mpkWh[i]*10+0.5)/10; // Round to nearest 10th 00786 } 00787 } 00788 if(logCP&&usbEn){ 00789 if(logOnce){ 00790 tripLog(); 00791 logOnce=false; 00792 } 00793 logPackVoltages(); // Turbo3, only call 00794 } 00795 if(!usbEn&&!waitasec){ 00796 usbEn=detectUSB(); // Keep looking if none found 00797 } 00798 waitasec=false; // work around to avoid hang when USB tries to init immediately 00799 tock=true; 00800 } // tick 00801 00802 display=display<1?display+1:0; // toggle display 00803 updateDisplay(display); 00804 00805 if(step){ // playback 00806 if(playbackOpen&&playbackEn){ 00807 for(i=0;i<120;i++){ 00808 if(!f_eof(&efile)){ 00809 efr=f_read(&efile,&header,5,&bytesRW); 00810 efr=f_read(&efile,&data,8,&bytesRW); 00811 logCan(header[0],CANMessage(0x7ff&((header[4]<<8)+header[3]), data, 8)); // Playback 00812 } else { 00813 f_close(&efile); // restart 00814 efr = f_open(&efile,"playback.alc",FA_READ|FA_OPEN_EXISTING); 00815 lastDMode[whichTouched]=99;//force refresh 00816 spkr.beep(2000,0.25); 00817 } 00818 } 00819 } 00820 step=false; 00821 } 00822 00823 } //while (true) 00824 }
Generated on Tue Jul 12 2022 18:15:08 by 1.7.2