test fork

Dependencies:   SPI_TFTx2 SPI_TFTx2_ILI9341 TFT_fonts TOUCH_TFTx2 mbed

Fork of CANary_9341 by Tick Tock

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);
                     }