test fork
Dependencies: SPI_TFTx2 SPI_TFTx2_ILI9341 TFT_fonts TOUCH_TFTx2 mbed
Fork of CANary_9341 by
Diff: main.cpp
- Revision:
- 129:8991d0de01ab
- Parent:
- 64:a2b3c7201faa
- Parent:
- 128:25314f339565
- Child:
- 130:1a9d2a6d99ce
--- a/main.cpp Wed Apr 10 13:31:35 2013 +0000 +++ b/main.cpp Sun Jul 21 23:59:00 2013 +0000 @@ -1,33 +1,39 @@ // main.cpp - +// //To Do: -// * USB device detect -// * Ability to update binary from the thumb-drive (requires file timestamp) // * Audible friction brake feedback // * User-configurable watchpoint -// * Better graphical DTE display with historic efficiency information considered and displayed // * Add 50% charge option -// * Tire Pressure Sensor display +// * Add coasting regen to regen/braking display +// * Change semilog efficiency graph to linear with 10 minute values +// * Add additional 79b bank readouts +// * Add ability to transfer settings config file to/from USB +// * Subtract accessory power from efficiency history (add back in when displaying) #include "mbed.h" #include "CAN.h" #include "beep.h" -#include "MSCFileSystem.h" +#include "ff.h" #include "PowerControl.h" #include "EthernetPowerControl.h" #include "utility.h" #include "displayModes.h" #include "TOUCH_TFTx2.h" +char revStr[7] = "128b"; // gg - revision string, max 6 characters + +FATFS USBdrive; LocalFileSystem local("local"); - +bool waitasec = true; +unsigned char wait5secs = 5; // to write to USB Flash Drives, or equivalent (SD card in Reader/Writer) -MSCFileSystem fs("usb"); // to write to a USB Flash Drive - +// class10 SDcard in Reader/Writer recommended +FRESULT mfr = f_mount(0,&USBdrive); time_t seconds ; Ticker autoPoll; Ticker playback; +Ticker msgReq; Timer timer; DigitalOut led1(LED1); @@ -45,22 +51,30 @@ PwmOut dled(p23); Beep spkr(p21); -bool logEn = false, logOpen = false; -bool yesBattLog = false ; // gg - Batt Log -unsigned char tNavRow = 3 ; // gg - 4x4 touch +bool debugMode = false; +bool usbEn = false; +bool logEn = false; +bool logOpen = false; +bool yesBattLog = true; // gg - Batt Log +unsigned char tNavRow = 3; // gg - 4x4 touch -FILE *cfile; -FILE *file; -char fileName[35] = "" ; -char writeBuffer[maxBufLen][13]; // buffer for USB write +FILE *hfile; // history file +FIL efile; // external usb file +FRESULT efr; // external file access flags +unsigned int bytesRW; +char fileName[35] = ""; +char writeBuffer[maxBufLen][13] __attribute__ ((section("AHBSRAM1"))); // buffer for USB write char indexLastMsg[0x800]={0}; // index table for last message CANMessage lastMsg[100]; // table to store last message of eachtype -unsigned char battData[256]={0}; + +unsigned char battData[BatDataBufMax]={0}; // 7 * 0x3D = BatDataBufMax + unsigned char msgChanged[100]; // inidcates which bytes changed char c; volatile int writePointer = 0; -volatile int secsNoMsg = 0; -volatile int secsNoTouch = 0; +int readPointer=0; +volatile unsigned short secsNoMsg = 0; +volatile unsigned short secsNoTouch = 0; volatile bool canIdle; volatile bool userIdle; bool touched=false; //flag to read touchscreen @@ -69,16 +83,18 @@ unsigned char dMode[2] = {mainScreen,brakeScreen}; //display mode unsigned char sMode = 0; // setup mode unsigned char lastDMode[2] = {0,0}; //last screen mode -unsigned char dtMode = 6; +unsigned char dtMode = 0; char displayLog[20][40]; unsigned char displayLoc = 0; +unsigned int fwCount=1; unsigned char indexOffset = 1; bool showCP = false; -bool pollCP = false; bool logCP = false; //Turbo3 -bool repeatPoll = false; +bool logOnce = false; +bool repeatPoll = true; bool headlights = false; bool tick = false; +bool ZeroSecTick = false; float ledHi = 0.8; // Bright LED value (until config file read) float ledLo = 0.1; // Dim LED value (until config file read) unsigned short pollInt = 300; // polling interval=5 minutes (until config file read) @@ -92,41 +108,48 @@ bool playbackEn = false; bool playbackOpen = false; //float playbackInt = 0.05; //read messages every 50 ms -float playbackInt = 0.005; //read messages every 50 ms +float playbackInt = 0.005; //read messages every 5 ms bool step = false; char header[5]; char data[8]; signed long motorRPM; -unsigned char skin = 0; +unsigned char skin = ttSkin ; unsigned char dtePeriod = 14; //ten minute averaging interval +float kWh_trip[3]={0}; +float miles_trip[3]={0}; float mph[39]={0}; float kW[39]={0}; float mpkWh[39]={0}; +float unloadedV_x2,Resr,curRmax,curRmin,redRmax,redRmin,incRmax,incRmin; +signed short Imax, Imin; // Logarithmic division scale (roughly - snapped to common units of time) float timeConstant[39] = {1, 1.58, 2.51, 3.98, 6.31, 10, 15.8, 25.1, 39.8, 60, // 1 minute 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 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 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 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 -bool updateDTE = false; +bool tock = false; +unsigned short pointerSep; +unsigned char reqMsgCnt = 99; +unsigned long Ah_x10000 = 0; +unsigned long SOC_x10000 = 0; +unsigned short SOH_x100 = 0; +float maxTemp = 0; +bool metric = false; +bool shunt[96]={0}; +bool charging=false; +bool showHealth=false; +unsigned char saveDmode=99; +bool moving=false; int main() { - int readPointer=0; + //can1SleepMode.mode(OpenDrain); + //can2SleepMode.mode(OpenDrain); char sTemp[40]; unsigned long secs; unsigned char i,j,display=0,lwt=0; point lastTouch; float average; - - can1.monitor(true); // set to snoop mode - can2.monitor(true); // set to snoop mode - can1.frequency(500000); - can2.frequency(500000); - can1SleepMode = 1; // Turn on Monitor_only Mode - can2SleepMode = 1; // Turn on Monitor_only Mode - can1.attach(&recieve1); - can2.attach(&recieve2); - tt.set_orientation(1); tt.background(Black); tt.set_display(2); // select both displays @@ -135,12 +158,12 @@ touchpad.rise(&touch_ISR); tt.wfi(); // enable interrupt on touch dled = 0.8; // turn on display LED 80% - + Resr = 0.075; // initial guess of Resr timer.start() ; RTC_Init(); // start the RTC Interrupts that sync the timer struct tm t; // pointer to a static tm structure - NVIC_SetPriority(TIMER3_IRQn, 1); //set ticker priority - NVIC_SetPriority(CAN_IRQn, 2); //higher than can (so RTC sync works) + NVIC_SetPriority(CAN_IRQn, 2); //set can priority just below RTC + NVIC_SetPriority(TIMER3_IRQn, 3); //set ticker priority just below can seconds = time(NULL); t = *localtime(&seconds) ; @@ -154,64 +177,27 @@ } t = *localtime(&seconds) ; strftime(sTemp, 32, "%a %m/%d/%Y %X\n", &t); - logMsg(sTemp); + printMsg(sTemp); // record RTC // revision - sprintf(sTemp,"CANary firmware rev64\n"); - logMsg(sTemp); - - // Look for new binary on thumbdrive - // Can't make this work right now since USB doesn't attach the right timestamp (so new binary isn't loaded) - /*cfile = fopen("/usb/CANary.bin", "rb"); - lastDMode[whichTouched]=99;//force refresh - if (cfile!=NULL){ //found a new binary on the thumbdrive so copy it over - sprintf(sTemp,"New binary found.\n"); - logMsg(sTemp); - file = fopen("/local/CANary.bin", "wb"); - if (file==NULL){ //failed to open destination - sprintf(sTemp,"Unable to open destination file.\n"); - logMsg(sTemp); - } else { - tt.set_display(2); - tt.foreground(White); - tt.background(Black); - tt.cls(); - tt.locate(1,40); - printf("%s\n","Copying binary - Do no remove power."); - tt.locate(1,80); - printf("CANary will reset when complete.\n"); - wait(1); //Wait 1 sec for display DMA to finish before writing file - while ( int size = fread( writeBuffer, sizeof(char), maxBufLen*13, cfile )){ - fwrite( writeBuffer, sizeof(char), size, file ); - led4=led3; - led3=led2; - led2=led1; - led1=!led4; - } - fclose(cfile); - fclose(file); - remove("/usb/CANary.bin"); // delete original - mbed_reset(); //restart - } - }*/ + sprintf(sTemp,"CANary firmware rev%s\n", revStr); // gg - for Logging the revision + printMsg(sTemp); // revision secsNoMsg = 0; //read efficiency history data - cfile = fopen("/local/ehist.cny", "r"); - if (cfile!=NULL){ // found a efficiency history file + hfile = fopen("/local/ehist.cny", "r"); + if (hfile!=NULL){ // found a efficiency history file for(i=0;i<39;i++){ - if(!feof(cfile)){ - fscanf(cfile,"%f %f\r\n",&mph[i],&kW[i]); + if(!feof(hfile)){ + fscanf(hfile,"%f %f\r\n",&mph[i],&kW[i]); mpkWh[i]=mph[i]/kW[i]; } } - fclose(cfile); - sprintf(sTemp,"History Loaded.\n"); - logMsg(sTemp); + fclose(hfile); + printMsg("History Loaded.\n"); // History loaded } else { // create initial file - sprintf(sTemp,"History not found. Created.\n"); - logMsg(sTemp); + printMsg("History not found. Created.\n"); // history not found, created for(i=0;i<39;i++){ // Pre-load with 4 mpkWh @ 40 mph mph[i]=40*timeConstant[i]; @@ -222,71 +208,94 @@ // Read config file readConfig(); + if (repeatPoll) { // enable autopolling if enabled + autoPoll.attach(&autoPollISR,pollInt); + } + + // Start monitors + can1.monitor(true); // set to snoop mode + can2.monitor(true); // set to snoop mode + can1.frequency(500000); + can2.frequency(500000); + can1SleepMode = VP230Sleep; // Turn on Monitor_only Mode + can2SleepMode = VP230Sleep; // Turn on Monitor_only Mode + can1.attach(&recieve1); + can2.attach(&recieve2); touched=false; secsNoTouch=2; while (true) { if (!logOpen) { // Open new file if one is not already open - if(logEn){ //logging enable + if(logEn&&usbEn){ //logging enabled and USB device detected + strftime(fileName, 32, "%m%d%H%M.alc", &t); //mmddhhmm.alc + efr = f_open(&efile,fileName,FA_WRITE|FA_OPEN_ALWAYS); seconds = time(NULL); t = *localtime(&seconds) ; - strftime(fileName, 32, "/usb/%m%d%H%M.alc", &t); //mmddhhmm.alc - //sprintf(sTemp,"Using file %s\n",fileName); - //logMsg(sTemp); - file = fopen(fileName, "ab"); - lastDMode[whichTouched]=99;//force refresh - if(file==NULL){ - sprintf(sTemp,"\nUnable to open %s\n\n\n\n",fileName); - logMsg(sTemp); + lastDMode[0]=99;//force refresh + lastDMode[1]=99;//force refresh + if(efr != FR_OK){ + sprintf(sTemp,"\nERR:%d Unable to open %s\n\n\n\n",efr,fileName); + printMsg(sTemp); // cannot open alc file logEn=false; spkr.beep(1000,0.25); + wait_ms(500); + spkr.beep(1000,0.25); } else { logOpen = true; readPointer=writePointer; sprintf(sTemp,"Starting Can Log %s\n",fileName); - logMsg(sTemp); - logTS(); + printMsg(sTemp); // starting alc log file + + logTS(); // Date Time at start + logEvent("Starting"); // Log startup msg for testing + sprintf(sTemp,"Cr%s",revStr); + logEvent(sTemp); // gg - log firmware version spkr.beep(2000,0.25); } - }//logging enabled + }//logging enabled and USB detected } else { // if (logOpen) - if (((writePointer+maxBufLen-readPointer)%maxBufLen)>(maxBufLen/16)||canIdle||!logEn) { + pointerSep=(writePointer+maxBufLen-readPointer)%maxBufLen; + if (pointerSep>(maxBufLen/16)||canIdle||!logEn) { // Dump buffer if > 1/16 full or canbus has stopped - if (file == NULL) { + //if (&efile == NULL) { + if (efr != FR_OK) { logOpen = false; - sprintf(sTemp,"Failed to append log file.\n"); - logMsg(sTemp); - spkr.beep(1000,0.25); + printMsg("Failed to append log file.\n"); // failed to append + spkr.beep(3000,0.25); + spkr.beep(1500,0.25); + spkr.beep(750,0.25); + spkr.beep(375,0.25); logEn=false; } else { - if (((writePointer+maxBufLen-readPointer)%maxBufLen)>(maxBufLen*7/8)) { // Hi-water mark - sprintf(sTemp,"Write buffer overrun.\n"); - logMsg(sTemp); - spkr.beep(1000,0.25); + while (readPointer != writePointer) { + efr=f_write(&efile,&writeBuffer[readPointer][0],13,&bytesRW); + if(++readPointer >= maxBufLen){ + readPointer=0; + led4 = !led4; + } } - while (readPointer != writePointer) { - for (j = 0; j<13; j++){ - fprintf(file,"%c",writeBuffer[readPointer][j]); - } - if(++readPointer >= maxBufLen) - readPointer=0; - } - led4 = !led4; } } // if > 1/16 full, canbus has stopped, or logging stopped if (!logEn) { - fclose(file); + sprintf(sTemp,"Stopping Can Log %s\n",fileName); + printMsg(sTemp); // stopping alc log file + f_close(&efile); logOpen=false; + pointerSep=0; + led4=false; } } // if logOpen if (canIdle&&userIdle&&!playbackEn) { // canbus idle --> sleep to save power - if (logOpen){ - fclose(file); - } // if (logOpen)*/ + if (repeatPoll) { // stop autopolling if enabled + autoPoll.detach(); + } + if (logOpen){ //close file to dump buffer + f_close(&efile); + } // if (logOpen) seconds = time(NULL); t = *localtime(&seconds) ; strftime(sTemp, 40, "Sleeping: %a %m/%d/%Y %X\n", &t); - logMsg(sTemp); + printMsg(sTemp); // sleeping date time updateDisplay(0); //Added for turbo3 who has a display override and wants to see the sleep message before going to sleep updateDisplay(1); //LPC_RTC->CIIR=0x00; // block RTC interrupts @@ -302,20 +311,29 @@ //__wfi(); // freeze CPU and wait for interrupt (from canbus or touch) Sleep(); } + lastDMode[0]=99; + lastDMode[1]=99; secsNoTouch=2; canIdle=secsNoMsg>canTimeout; - //userIdle=!touched; dled=0.8; // turn on display LED seconds = time(NULL); t = *localtime(&seconds) ; strftime(sTemp, 40, "Waking: %a %m/%d/%Y %X\n", &t); - logMsg(sTemp); + printMsg(sTemp); // wakeup date time if (time(NULL)>(secs+1800)) { - logOpen = false; // Start new file if asleep for more than 30 minutes + if (logOpen){ + f_close(&efile); + logOpen = false; // Start new file if asleep for more than 30 minutes + } // if (logOpen) if (secsNoTouch>100) secsNoTouch = 100; // also mostly reset user Idle counter } else if (logOpen){ // insert timestamp on each wake if logging enabled (disabled for now) - file = fopen(fileName, "ab"); - logTS(); + efr = f_open(&efile,fileName,FA_WRITE|FA_OPEN_ALWAYS); + f_lseek(&efile,0xffffffff); // goto end of file (append existing) + logEvent("WakingUp"); // gg - use messeges + logTS(); // Date-Time at wakeup + } + if (repeatPoll) { // re-enable autopolling if enabled + autoPoll.attach(&autoPollISR,pollInt); } } // if idle @@ -341,7 +359,7 @@ sMode = 1; } //sprintf(sTemp,"%d,%d ",lastTouch.x,lastTouch.y); - //logMsg(sTemp); + //printMsg(sTemp); // touch x,y - for debug touched = false; // clear interrupt flag } //--------------- @@ -355,7 +373,7 @@ secsNoTouch +=2; // increment to prevent double touch sMode = 1; //sprintf(sTemp,"button %d %d,%d %d\n",i,buttonX(lastTouch.x,3),buttonY(lastTouch.y,3),lastTouch.x); - //logMsg(sTemp); + //printMsg(sTemp); // button parms - for debug switch (sMode) { case 0: // no select break; @@ -372,10 +390,13 @@ if( tRow == tNavRow ) tRow = 7 ; // gg switch ( (tCol*10) + tRow ) { //--------------------------------- - case 00: // 00 on screen 0 or 1 + case 00: // top row, left button on screen 0 or 1 if (dMode[whichTouched]==monitorScreen||dMode[whichTouched]==changedScreen) { - indexOffset=indexOffset>4?indexOffset-4:1; - } else if (dMode[whichTouched]==config1Screen) { + indexOffset=indexOffset>4?indexOffset-4:1; + } else if (dMode[whichTouched] == indexScreen) { // gg - index + dMode[whichTouched] = mainScreen ; // GoTo Main Screen + sMode=0; + } else if (dMode[whichTouched]==configScreen) { wait_ms(500); tt.background(Black); tt.calibrate(); @@ -390,17 +411,23 @@ } break; //----------------------------------------------- - case 10: // 1,0 (col,row) on screen 0 or 1 + case 10: // 1,0 (col left of center,top row) on screen 0 or 1 if (dMode[whichTouched]==changedScreen) { for(j=0;j<100;j++) msgChanged[j]=0; // clear changed data lastDMode[whichTouched]=99;//force refresh + } else if (dMode[whichTouched] == indexScreen) { // gg - index + sMode=0; + dMode[whichTouched] = brakeScreen ; // GoTo Brake Screen } else if (dMode[whichTouched]==cpScreen) { - pollCP=true; + reqMsgCnt=0; + msgReq.attach(&sendReq,0.015); } else if (dMode[whichTouched]==cpHistScreen) { // gg - hist - pollCP=true; + reqMsgCnt=0; + msgReq.attach(&sendReq,0.015); } else if (dMode[whichTouched]==cpBarScreen) { // gg - cpbars - pollCP=true; - } else if (dMode[whichTouched]==config1Screen) { + reqMsgCnt=0; + msgReq.attach(&sendReq,0.015); + } else if (dMode[whichTouched]==configScreen) { mbed_reset(); } else if (dMode[whichTouched]==playbackScreen) { // pause/unpause playbackEn=!playbackEn; @@ -418,9 +445,11 @@ case 20: // col 2 and row 0 on either screen 0 or 1 if (dMode[whichTouched]==monitorScreen||dMode[whichTouched]==changedScreen) { indexOffset=indexOffset<77?indexOffset+4:80; - } else if (dMode[whichTouched]==config1Screen) { - sprintf(sTemp,"Saving config file.\n"); - logMsg(sTemp); + } else if (dMode[whichTouched] == indexScreen) { // gg - index + dMode[whichTouched] = effScreen ; // GoTo EFF Screen + sMode=0; + } else if (dMode[whichTouched]==configScreen) { + printMsg("Saving config file.\n"); // saving config saveConfig(); spkr.beep(2000,0.25); } else if (dMode[whichTouched]==playbackScreen) { // faster @@ -431,19 +460,41 @@ playback.attach(&playbackISR,playbackInt); } } - }else{ + } else { + lastDMode[whichTouched]=99;//repaint to clear highlight + } + + break; + + case 30: // right-most on top row + + if (dMode[whichTouched]==configScreen) { + // step through skins + if( skin < maxSkin ) skin += 1 ; + else skin = 0 ; + + // repaint both screens, I think + lastDMode[whichTouched]=99;//repaint to clear highlight + // and re-paint the other screen too, to see new skin there + lastDMode[whichTouched ^ 1]=99; // repaint other screen (^ = XOR) + } else if (dMode[whichTouched] == indexScreen) { // gg - index + dMode[whichTouched] = healthScreen ; // Goto health screen + sMode=0; + } else { lastDMode[whichTouched]=99;//repaint to clear highlight } break; //---------------------------------- //---------------------------------- - case 01: // col 0 row 1 - if (dMode[whichTouched]==config1Screen) { + case 01: // left col middle row + if (dMode[whichTouched]==configScreen) { logEn = !logEn; - if (!logEn) repeatPoll=false; // disable auto polling, too + } else if (dMode[whichTouched] == indexScreen) { // gg - index + dMode[whichTouched] = cpScreen ; // GoTo CP Data Screen + sMode=0; } else if (dMode[whichTouched]==dateScreen){ - dtMode=(dtMode<6)?dtMode+1:0; + dtMode=(dtMode<5)?dtMode+1:0; lastDMode[whichTouched]=99; } else { lastDMode[whichTouched]=99;//repaint to clear highlight @@ -452,40 +503,42 @@ break; //------------------------------ case 11: - if (dMode[whichTouched]==config1Screen){ - repeatPoll = !repeatPoll&&logEn; + if (dMode[whichTouched]==configScreen){ + repeatPoll = !repeatPoll; if (repeatPoll) { autoPoll.attach(&autoPollISR,pollInt); } else { autoPoll.detach(); } + } else if (dMode[whichTouched] == indexScreen) { // gg - index + dMode[whichTouched] = cpHistScreen ; // GoTo CP Hist Screen + sMode=0; } else if (dMode[whichTouched]==playbackScreen) { // Start/stop playback if(!playbackOpen){ - if(!logOpen){ - file = fopen("/usb/playback.alc", "rb"); + if(!canIdle){ + printMsg("Cannot playback while connected to canbus\n"); + }else if(!logOpen){ + efr = f_open(&efile,"playback.alc",FA_READ|FA_OPEN_EXISTING); lastDMode[whichTouched]=99;//force refresh - if(file==NULL){ - sprintf(sTemp,"Unable to open /usb/playback.alc\n"); - logMsg(sTemp); + if(efr != FR_OK){ + printMsg("Unable to open /usb/playback.alc\n"); // no playback.alc spkr.beep(1000,0.25); } else { playbackOpen = true; playbackEn=true; playback.attach(&playbackISR,playbackInt); - sprintf(sTemp,"Starting playback\n"); - logMsg(sTemp); + printMsg("Starting playback\n"); // start playback spkr.beep(2000,0.25); can1.attach(&doNothing);// Stop recieving CAN data can2.attach(&doNothing); } } else { - sprintf(sTemp,"Must stop logging first\n"); - logMsg(sTemp); + printMsg("Must stop logging first\n"); } } else { playback.detach(); - fclose(file); + f_close(&efile); playbackOpen=false; playbackEn=false; can1.attach(&recieve1);// Restore CAN data recieve @@ -502,9 +555,11 @@ break; //--------------------------------- case 21: // col 2 row 1 - if (dMode[whichTouched]==config1Screen) { // gg - Batt Log Enable Button + if (dMode[whichTouched]==configScreen) { // gg - Batt Log Enable Button yesBattLog = !yesBattLog; - + } else if (dMode[whichTouched] == indexScreen) { // gg - index + dMode[whichTouched] = cpBarScreen ; // GoTo CP Bars Screen + sMode=0; } else if (dMode[whichTouched]==dateScreen){ upDate(dtMode,false); lastDMode[whichTouched]=99; @@ -514,6 +569,66 @@ break; + case 31: // col 3 row 1 + if (dMode[whichTouched]==configScreen) { // gg - Batt Log Enable Button + debugMode = !debugMode; + } else if (dMode[whichTouched] == indexScreen) { // gg - index + dMode[whichTouched] = configScreen ; // GoTo Config Screen + } else if (dMode[whichTouched] == tripScreen) { + miles_trip[1]=0; + kWh_trip[1]=0; + sMode=0; + lastDMode[whichTouched]=99;//repaint to clear highlight + } else { + lastDMode[whichTouched]=99;//repaint to clear highlight + } + break; + + //----------------------------------- + case 02: // left col, bottom row (not nav) + if (dMode[whichTouched] == indexScreen) { // gg - index + dMode[whichTouched] = playbackScreen ; // GoTo Playback Screen + } else if (dMode[whichTouched]==configScreen) { + metric = !metric; // toggle metric/imperial display + } else { + lastDMode[whichTouched]=99;//repaint to clear highlight + } + break; + + case 12: // left-middle col, bottom row (not nav) + if (dMode[whichTouched] == configScreen) { // gg - index + dMode[whichTouched] = dateScreen ; // GoTo Set Date/Time Screen + } else { + lastDMode[whichTouched]=99;//repaint to clear highlight + } + break; + + case 22: // right-middle col, bottom row (not nav) + if (dMode[whichTouched] == indexScreen) { // gg - index + dMode[whichTouched] = logScreen ; + } else if (dMode[whichTouched]==configScreen) { + showHealth = !showHealth; + } else { + lastDMode[whichTouched]=99;//repaint to clear highlight + } + break; + + case 32: // right col, bottom row (not nav) + if (dMode[whichTouched] == configScreen) { + logEn=false; + updateFirmware(); + } else if (dMode[whichTouched] == tripScreen) { + miles_trip[2]=0; + kWh_trip[2]=0; + sMode=0; + lastDMode[whichTouched]=99;//repaint to clear highlight + } else if (dMode[whichTouched] == indexScreen) { + dMode[whichTouched] = tripScreen ; + } else { + lastDMode[whichTouched]=99;//repaint to clear highlight + } + break; + //----------------------------------- //----------------------------------- // Prev Navigation @@ -530,7 +645,7 @@ //----------------------------------- // Index Navigation case 27: // col 2 row tNavRow - dMode[whichTouched]= mainScreen; // indexScreen ; // gg - index + dMode[whichTouched]= indexScreen ; // gg - index break; //------------------------------------ // Next Navigation @@ -560,63 +675,123 @@ } if(tick){ // Executes once a second + tick=false; + headlights = (lastMsg[indexLastMsg[0x358]].data[1]&0x80)?true:false; // headlight/turn signal indicator accV=floor(mon12V*scale12V*10+0.5)/10; //Round to nearest 10th accOn=(accV>5)?true:false; + moving=(mph[0]>0.1); + charging=!moving&&(kW[0]<-1); // not moving and generating energy so must be charging if(laccOn&&!accOn){ // Car turned off + if (repeatPoll) { // Log on shutdown if autopoll enabled + tripLog(); // Write trip log on powerdown + } //write efficiency history data - cfile = fopen("/local/ehist.cny", "w"); - if (cfile!=NULL){ // found a efficiency history file + hfile = fopen("/local/ehist.cny", "w"); + if (hfile!=NULL){ // found a efficiency history file for(i=0;i<39;i++){ - fprintf(cfile,"%f %f\r\n",mph[i],kW[i]); + fprintf(hfile,"%f %f\r\n",mph[i],kW[i]); } - fclose(cfile); + fclose(hfile); + } + } + if(!laccOn&&accOn){ // Car turned on + miles_trip[0]=0; + kWh_trip[0]=0; + wait5secs=5; + if(showHealth){ + saveDmode=dMode[0]; + dMode[0]=healthScreen; } } laccOn=accOn; - if(!accOn&&!logEn&&userIdle&&!playbackEn){ - //sprintf(sTemp,"Display Off %4.2f\n",accV); - //logMsg(sTemp); - dled = 0; // turn off display if car off and logging disabled and no user activity + if(!accOn&&!logEn&&userIdle&&!playbackEn){ // Car off and logging disabled and no user activity + dled = 0; }else if(!headlights){ dled = ledHi; - }else{ + } else { dled = ledLo; } - + if(wait5secs>0){ // Wait a few seconds after poweron to give BMS time to measure CP's + wait5secs-=1; + if (repeatPoll&&(wait5secs==0)) { // Poll on startup if autopoll enabled + logOnce=true; + reqMsgCnt=0; + msgReq.attach(&sendReq,0.015); + } + } + if(moving&&(saveDmode<99)&&(wait5secs==0)){ + dMode[0]=saveDmode; + saveDmode=99; + } + //compute historic efficiency if(numSsamples>0){ // Avoid div0 - mph[0]=((float) motorRPM)/numSsamples/215; // Empirically derived - may change car to car - }else{ + mph[0]=((float) motorRPM)/numSsamples/220; // Empirically derived with MXV4s - may change with different wheels&tires + } else { mph[0]=0; } if(mph[0]>99){ mph[0]=0; } - mpkWh[0]=mph[0]; + numSsamples=0; + if(numWsamples>0){ // Avoid div0 + mpkWh[0]=mph[0]; kW[0]=((float) mWs_x4)/numWsamples/4e3; mpkWh[0]/=kW[0]; if (mpkWh[0]<0) { mpkWh[0]=99;// negative means inf. } - }else{ + } else { kW[0]=0; mpkWh[0]=0; } - //mpkWh[0]=floor(mpkWh[0]*10+0.5)/10; // Round to nearest 10th + numWsamples=0; + + if (!charging){ + miles_trip[0]+=mph[0]/3600; + miles_trip[1]+=mph[0]/3600; + miles_trip[2]+=mph[0]/3600; + kWh_trip[0]+=kW[0]/3600; + kWh_trip[1]+=kW[0]/3600; + kWh_trip[2]+=kW[0]/3600; + } + motorRPM=0; - numSsamples=0; mWs_x4=0; - numWsamples=0; - if(accOn||playbackEn){ + + // Compute ESR + if((Imax-Imin)<40){ // do nothing - insufficient delta_I to measure + unloadedV_x2 = (curRmax+curRmin)/2; + }else if ((redRmax-redRmin)<(curRmax-curRmin)) { + Resr-=0.001; + unloadedV_x2 = (redRmax+redRmin)/2; + } else if ((incRmax-incRmin)<(curRmax-curRmin)) { + Resr+=0.001; + unloadedV_x2 = (incRmax+incRmin)/2; + } else { + unloadedV_x2 = (curRmax+curRmin)/2; + } + curRmin=1000; + curRmax=0; + incRmin=1000; + incRmax=0; + redRmin=1000; + redRmax=0; + Imax=-1000; + Imin=1000; + + if((accOn||playbackEn)&&!charging){ for(i=1;i<39;i++){ average=mph[i]/timeConstant[i]; mph[i]-=average; mph[i]+=mph[0]; mpkWh[i]=average; average=kW[i]/timeConstant[i]; - kW[i]-=average; - kW[i]+=kW[0]; + if(!charging){ //Not charging - so include in efficiency data + kW[i]-=average; + kW[i]+=kW[0]; + } mpkWh[i]/=average; if (mpkWh[i]<0) { mpkWh[i]=99;// negative means inf. @@ -624,31 +799,33 @@ //mpkWh[i]=floor(mpkWh[i]*10+0.5)/10; // Round to nearest 10th } } - updateDTE=true; - if(logCP) - logPackVoltages(); // Turbo3 - tick=false; - } + if(logCP&&usbEn){ + if(logOnce){ + tripLog(); + logOnce=false; + } + logPackVoltages(); // Turbo3, only call + } + if(!usbEn&&!waitasec){ + usbEn=detectUSB(); // Keep looking if none found + } + waitasec=false; // work around to avoid hang when USB tries to init immediately + tock=true; + } // tick display=display<1?display+1:0; // toggle display updateDisplay(display); - - if(pollCP){ // We do this inside main loop instead of ticker so CAN RX will not be blocked - sendCPreq(); // send cellpair data request. - wait_ms(16); - sendTreq(); //send temperature request - pollCP=false; - } if(step){ // playback if(playbackOpen&&playbackEn){ for(i=0;i<120;i++){ - if(!feof(file)){ - fscanf(file,"%5c%8c",&header,&data); - logCan(header[0],CANMessage(0x7ff&((header[4]<<8)+header[3]), data, 8)); - }else{ - fclose(file); // restart - file = fopen("/usb/playback.alc", "rb"); + if(!f_eof(&efile)){ + efr=f_read(&efile,&header,5,&bytesRW); + efr=f_read(&efile,&data,8,&bytesRW); + logCan(header[0],CANMessage(0x7ff&((header[4]<<8)+header[3]), data, 8)); // Playback + } else { + f_close(&efile); // restart + efr = f_open(&efile,"playback.alc",FA_READ|FA_OPEN_EXISTING); lastDMode[whichTouched]=99;//force refresh spkr.beep(2000,0.25); }