Tick Tock / Mbed 2 deprecated CANary_9341_test

Dependencies:   SPI_TFTx2 SPI_TFTx2_ILI9341 TFT_fonts TOUCH_TFTx2 mbed

Fork of CANary_9341 by Tick Tock

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers utility.cpp Source File

utility.cpp

00001 // utility.cpp
00002 #include "utility.h"
00003 unsigned long brkMonRate = 378947;
00004 unsigned short brkMonThr = 1895;
00005 Timeout beepOff;
00006 unsigned char bCount = 2;
00007 float bFreq[2] = { 1000, 1000 };
00008 float bTime[2] = { 0.1, 0.1 };
00009 
00010 void mbed_reset();
00011 
00012 void RTC_IRQHandler() {
00013     timer.reset(); // zero ms at the-seconds-tic
00014     carCanIdle=(++secsNoCarCanMsg>canTimeout)?true:false;
00015     evCanIdle=(++secsNoEvCanMsg>canTimeout)?true:false;
00016     userIdle=(++secsNoTouch>userTimeout)?true:false;
00017     LPC_RTC->ILR |= (1<<0); // clear interrupt to prepare for next
00018     tick=true;
00019     // will use this to generate a logTP() just before the next Message received.
00020     if( (time(NULL) % 60) == 0) ZeroSecTick = true; // gg - at 0-second of each minute
00021 }
00022 
00023 void RTC_Init (void) {
00024     LPC_RTC->ILR=0x00; // set up the RTC interrupts
00025     LPC_RTC->CIIR=0x01; // interrupts each second
00026     LPC_RTC->CCR = 0x01;  // Clock enable
00027     //NVIC_SetPriority( RTC_IRQn, 10 );
00028     NVIC_EnableIRQ( RTC_IRQn );
00029 }
00030 
00031 void printMsg (char *msg) {
00032     strcpy(displayLog[displayLoc],msg);
00033     displayLoc=displayLoc>17?0:displayLoc+1;
00034 }
00035 
00036 void touch_ISR(){
00037     //LPC_GPIOINT->IO2IntClr = (LPC_GPIOINT->IO2IntStatR | LPC_GPIOINT->IO2IntStatF); // seems to work without so maybe not necessary (performed in InterruptIn handler?)
00038     touched=true; // just set flag - touch screen algorythm is long and we don't want to block other interrupts
00039 }
00040 
00041 unsigned short getTimeStamp() {
00042     unsigned short msec = timer.read_ms() ; // read ms from the timer
00043     unsigned long secs = time(NULL); // seconds past 12:00:00 AM 1 Jan 1900
00044     unsigned short isecs = secs%60 ; // modulo 60 for 0-59 seconds from RTC
00045     return ((isecs<<10)+msec) ; // return the two byte time stamp
00046 }
00047 
00048 void logCan (char mType, CANMessage canRXmsg) {
00049 
00050     static unsigned char ii = 0;
00051     static unsigned char lasti = 0; // indexindex
00052     static unsigned char bdi=0;
00053     static signed short imotorRPM = 0;
00054     static unsigned short nLost = 0; // gg - overrun
00055  
00056     char sTemp[40];    
00057     unsigned char changed;
00058     unsigned short i,j,k;
00059     signed short packV_x2;
00060     signed short packA_x2;
00061     signed long imWs_x4;
00062     unsigned short ts;
00063 
00064     if(debugMode||(skin==ggSkin)){ 
00065         // code to insert actual number of dropped frames for overrun debug - skipped in normal mode to keep logcan short
00066         if(logOpen){
00067             // check to see if buffer is already full (read - write) = 1
00068             // actually the last buffer location cannot be used because then 
00069             //   the buffer would look empty after writePointer++
00070             
00071             //if (((writePointer+maxBufLen-readPointer)%maxBufLen)>(maxBufLen/16)) // modulo is slow?
00072  
00073             // pointers are 0 through maxBufLen-1
00074             if( (readPointer - writePointer) == 1 || (writePointer - readPointer) == (maxBufLen - 1)) {
00075                 // the buffer is "full", so Lose this message
00076                 
00077                 // point to the last-stored message
00078                 int tempWritePointer = writePointer - 1 ;
00079                 if( tempWritePointer < 0 ) tempWritePointer = maxBufLen - 1;
00080                 char strLost[9] ;
00081  
00082                 if( nLost == 0 ) {
00083                     // this is the first message lost 
00084                     //   and we must overwrite the last message with an FFE comment message
00085                     // So, there will be two messages lost as the comment message is laid in.
00086                     nLost = 2;
00087                     sprintf(strLost,"%s","Lost0002"); // indicate two messages lost
00088                     
00089                     // overlay the last message with a "Lost0002" comment
00090                     writeBuffer[tempWritePointer][0]=0;
00091                     // leave the ts of the overlaid message
00092                     //writeBuffer[tempWritePointer][1]=(ts&0xff00)>>8; // Time Stamp (2 bytes_
00093                     //writeBuffer[tempWritePointer][2]=(ts&0x00ff);
00094                     // force the MsgID to an Event Message 
00095                     writeBuffer[tempWritePointer][3]=0xfe; // MsgID, low byte
00096                     writeBuffer[tempWritePointer][4]=0xff; // Len nibble, and MsgID high nibble
00097                     // lay in the "Lost0002" text
00098                     for(i=5;i<13;i++){ 
00099                         writeBuffer[tempWritePointer][i]= strLost[i-5];
00100                     }
00101                 } else {
00102                     // at least one message was previously lost
00103                     // increment the loat counter
00104                     nLost += 1;
00105                     
00106                     // lay the new count into the comment
00107                     sprintf(strLost,"%04d",nLost);
00108                     for(i=9;i<13;i++){ 
00109                         writeBuffer[tempWritePointer][i]= strLost[i-9];
00110                     }
00111                 }
00112             } else {
00113                 // there is room to insert the message
00114                 // get it inserted quickly
00115                 ts=getTimeStamp(); 
00116                 writeBuffer[writePointer][0]=mType;
00117                 writeBuffer[writePointer][1]=(ts&0xff00)>>8; // Time Stamp (2 bytes_
00118                 writeBuffer[writePointer][2]=(ts&0x00ff);
00119                 writeBuffer[writePointer][3]=canRXmsg.id&0xff; // MsgID, low byte
00120                 char sLen = canRXmsg.len ;
00121                 writeBuffer[writePointer][4]=(canRXmsg.id>>8)+(sLen<<4); // Len nibble, and MsgID high nibble
00122                 for(i=0;i<8;i++){ // Is there a better way to do this? (writeBuffer[writePointer][i]=canRXmsg.data?)
00123                     if(i<sLen) 
00124                         writeBuffer[writePointer][i+5]=canRXmsg.data[i];
00125                     else // i>=sLen
00126                         // force unused data bytes to FF for CAN-Do compatibility
00127                         writeBuffer[writePointer][i+5]=0xFF;
00128                 }
00129                 
00130                 //--------------
00131                 // Note, this is not protected from the interrupt.
00132                 // Due to the nLost code above, this no longer
00133                 //    overflows to writePointer = readPointer
00134                 //    which would make the buffer look empty
00135                 if (++writePointer >= maxBufLen) {
00136                     writePointer = 0;
00137                     led3 = !led3;
00138                 }
00139                 //--------------
00140                 // log a local message if we had lost messages. gg - logcan
00141                 if( nLost > 0 ) {
00142                     // We previously lost messages that did not get into the buffer
00143                     sprintf(sTemp,"-- Lost %d Messages.\n", nLost);
00144                     printMsg(sTemp); // write buffer overrun
00145                     beep(500,0.25);
00146                     
00147                     nLost = 0 ;
00148                 }
00149                 //--------------
00150             }
00151         }
00152     }else{ // not debugMode - keep code short
00153         if(logOpen){
00154             NVIC_DisableIRQ(CAN_IRQn); // Block interrupts until write pointer assigned
00155             int localWritePointer = writePointer++; // create local copy to make logCan reentrant
00156             // note that the static variables do not prevent safe reentry
00157             // since they are only used for msgId<0x800 which will never interrupt
00158             // another msgId<0x800 (both CANbusses are same priority)
00159             if (writePointer >= maxBufLen) {
00160                 writePointer = 0;
00161                 led3 = !led3;
00162             }
00163             NVIC_EnableIRQ(CAN_IRQn); // Unblock interrupts once local pointer set and global pointer incremented
00164             ts=getTimeStamp();
00165             writeBuffer[localWritePointer][0]=mType;
00166             writeBuffer[localWritePointer][1]=(ts&0xff00)>>8;
00167             writeBuffer[localWritePointer][2]=(ts&0x00ff);
00168             writeBuffer[localWritePointer][3]=canRXmsg.id&0xff;
00169             writeBuffer[localWritePointer][4]=(canRXmsg.id>>8)+(canRXmsg.len<<4);
00170             for(i=5;i<13;i++){ // Is there a better way to do this?
00171                 writeBuffer[localWritePointer][i]=canRXmsg.data[i-5];
00172             }
00173             if (writePointer==readPointer) {
00174                 // Just caught up to read pointer
00175                 printMsg("Write buffer overrun.\n"); // write buffer overrun
00176                 //beep(500,0.25);
00177             }
00178         }
00179     }
00180 
00181     if(canRXmsg.id<0x800){ // Block FFE and FFF messages
00182         if(indexLastMsg[canRXmsg.id]==0) { //Check if no entry
00183             if(ii<99) {
00184                 indexLastMsg[canRXmsg.id]=++ii; //Create entry for first MsgID occurance
00185                 // ii max is 99 here
00186             } else {
00187                 // the ii array is full, more than 100 MsgIDs found
00188                 if(ii==99) {
00189                     ii++; // step to 100 to log only one error
00190                     printMsg("msgID buffer overrun.\n");
00191                     beep3(500,0.25,1000,0.5,500,0.25); //Alert driver to check log
00192                 }
00193             }
00194         }
00195         lastMsg[indexLastMsg[canRXmsg.id]]=canRXmsg; //Store data in table at assigned index
00196         
00197         //----------------
00198         if(dMode[0]==changedScreen||dMode[1]==changedScreen){// Skip if not using (for execution speed)
00199             changed=msgChanged[indexLastMsg[canRXmsg.id]];
00200             // This is cleared in the main loop when reset button is touched
00201             for(i=0;i<8;i++){
00202                 if(lastMsg[indexLastMsg[canRXmsg.id]].data[i]!=canRXmsg.data[i]){
00203                     changed |= 1<<i;
00204                 }
00205             }
00206             msgChanged[indexLastMsg[canRXmsg.id]]=changed;
00207         }
00208         
00209         //-------------------
00210         //Miscellaneous on-recieve operations below
00211         if((mType==1)&&(canRXmsg.id==0x7bb)){ // is battery data?  Need to store all responses
00212             if(canRXmsg.data[0]<0x20){
00213                 if(canRXmsg.data[3]==1){//Group 1 data
00214                     bdi=BatDataBaseG1; // index offset for Group 1 data
00215                     if(debugMode){
00216                         printMsg("  Getting Group 1 data\n");
00217                     }
00218                     
00219                 }else if(canRXmsg.data[3]==2){//Group 2 = cellpair data
00220                     bdi=BatDataBaseG2; // index offset for CP data
00221                     if(debugMode){
00222                         printMsg("  Getting cell pair data\n");
00223                     }
00224                     
00225                 }else if(canRXmsg.data[3]==3){//Group 3 data
00226                     bdi=BatDataBaseG3; // index offset for Group 3 data
00227                     if(debugMode){
00228                         printMsg("  Getting Group 3 data\n");
00229                     }
00230                     
00231                 }else if(canRXmsg.data[3]==4){//Group 4 = temperature data
00232                     bdi=BatDataBaseG4; // index offset for Temperature data
00233                     if(debugMode){
00234                         printMsg("  Getting temperature data\n");
00235                     }
00236                     
00237                 }else if(canRXmsg.data[3]==5){//Group 5 data
00238                     bdi=BatDataBaseG5; // index offset for Group 5 data
00239                     if(debugMode){
00240                         printMsg("  Getting Group 5 data\n");
00241                     }
00242                     
00243                 }else if(canRXmsg.data[3]==6){//Group 6 data = shunt data
00244                     bdi=BatDataBaseG6; // index offset for Group 6 data
00245                     if(debugMode){
00246                         printMsg("  Getting Group 6 data\n");
00247                     }
00248                     
00249                 }else bdi=0xff; // ignore other messages (for now)
00250                 lasti=0;
00251             }
00252             
00253             if(bdi<0xff){
00254                 i=canRXmsg.data[0]&0x0f; //lower nibble of D0 is index
00255                 if(lasti>i){ //detect rollover and offset index appropriately
00256                     bdi += 0x10; // for CP data
00257                 }
00258                 lasti=i; //remember the msb to detect rollover next time around
00259                 i+=bdi;
00260                 //-------
00261                 //-------
00262                 i*=7;
00263                 if(i+6 < BatDataBufMax) {
00264                     battData[i+0]=canRXmsg.data[1];
00265                     battData[i+1]=canRXmsg.data[2];
00266                     battData[i+2]=canRXmsg.data[3];
00267                     battData[i+3]=canRXmsg.data[4];
00268                     battData[i+4]=canRXmsg.data[5];
00269                     battData[i+5]=canRXmsg.data[6];
00270                     battData[i+6]=canRXmsg.data[7];
00271                 }
00272                 if(i==(BatDataBaseG6+3)*7){ // All data loaded
00273                     logCP=yesBattLog; // Only log if logging enabled
00274                     showCP=true; // Always show
00275                     
00276                     // Find hottest temperature by finding smallest ADC value
00277                     // 2013 models only have three sensors
00278                     k=battData[(BatDataBaseG4*7)+3]*0x100+battData[(BatDataBaseG4*7)+4];
00279                     j=battData[(BatDataBaseG4*7)+6]*0x100+battData[(BatDataBaseG4*7)+7];
00280                     if(j<k)k=j;
00281                     j=battData[(BatDataBaseG4*7)+9]*0x100+battData[(BatDataBaseG4*7)+10];
00282                     if(j<k)k=j;
00283                     j=battData[(BatDataBaseG4*7)+12]*0x100+battData[(BatDataBaseG4*7)+13];
00284                     if(j<k)k=j;
00285                     //interpolate from lookup table
00286                     unsigned short temp_adc[10] = {1000,720,690,589,487,401,365,340,309,000};
00287                     float            temp_C[10] = { -27,  0,  3, 13, 23, 32, 36, 39, 43, 76};
00288                     char ii=0;
00289                     while(k<=temp_adc[++ii]) { } // Find section in table
00290                     maxTemp=(float)(k-temp_adc[ii]);
00291                     maxTemp/=(float)(temp_adc[ii-1]-temp_adc[ii]);
00292                     maxTemp*=(temp_C[ii-1]-temp_C[ii]);
00293                     maxTemp+=temp_C[ii];
00294 
00295                     // Get state of health
00296                     SOH2_x100=battData[(BatDataBaseG1*7)+29]*0x100+battData[(BatDataBaseG1*7)+30];
00297                     Ah_x10000=battData[(BatDataBaseG1*7)+36]*0x10000+battData[(BatDataBaseG1*7)+37]*0x100+battData[(BatDataBaseG1*7)+38];
00298                     SOC_x10000=battData[(BatDataBaseG1*7)+32]*0x10000+battData[(BatDataBaseG1*7)+33]*0x100+battData[(BatDataBaseG1*7)+34];
00299                     accV2=(float)battData[(BatDataBaseG1*7)+23]/4+(float)battData[(BatDataBaseG1*7)+24]/1024;
00300                     
00301                     // Save shunt data
00302                     for(j=0; j<24; j++){
00303                         shunt[j*4+0]=battData[BatDataBaseG6*7+j+3]&0x08;
00304                         shunt[j*4+1]=battData[BatDataBaseG6*7+j+3]&0x04;
00305                         shunt[j*4+2]=battData[BatDataBaseG6*7+j+3]&0x02;
00306                         shunt[j*4+3]=battData[BatDataBaseG6*7+j+3]&0x01;
00307                     }
00308                 }
00309             }
00310         }else if((mType==1)&&(canRXmsg.id==0x1db)){ //Battery Volts and Amps
00311             packV_x2=((canRXmsg.data[2]<<2)|(canRXmsg.data[3]>>6)); // 1 LSB = 0.5V
00312             packA_x2=((canRXmsg.data[0]<<3)|(canRXmsg.data[1]>>5)); // 1 LSB = 0.5A
00313             if(packA_x2>0x03ff){
00314                 packA_x2|=0xf800;//extend sign;
00315             }
00316             packA_x2 -= 2; //Slight correction to value required (unique to my Leaf?)
00317             if (-packA_x2<Imin){
00318                 Imin=-packA_x2;
00319             } else if (-packA_x2>Imax){
00320                 Imax=-packA_x2;
00321             }
00322             imWs_x4 = packV_x2; // Volts*milliSeconds*2
00323             imWs_x4 *= -packA_x2; // milliWattseconds*4
00324             mWs_x4 += imWs_x4; // total mWs_x4
00325             float temp;
00326             temp = Resr;
00327             temp *= (float) -packA_x2;
00328             temp += (float) packV_x2;
00329             if(temp>curRmax){
00330                 curRmax=temp;
00331             } else if(temp<curRmin){
00332                 curRmin=temp;
00333             }
00334             temp = Resr-0.001;
00335             temp *= (float) -packA_x2;
00336             temp += (float) packV_x2;
00337             if(temp>redRmax){
00338                 redRmax=temp;
00339             } else if(temp<redRmin){
00340                 redRmin=temp;
00341             }
00342             temp = Resr+0.001;
00343             temp *= (float) -packA_x2;
00344             temp += (float) packV_x2;
00345             if(temp>incRmax){
00346                 incRmax=temp;
00347             } else if(temp<incRmin){
00348                 incRmin=temp;
00349             }
00350             numWsamples++;
00351         }else if((mType==2)&&(canRXmsg.id==0x176)){ //Motor Speed
00352             imotorRPM=((canRXmsg.data[2]<<8)|(canRXmsg.data[3]));
00353             motorRPM+=imotorRPM;
00354             numSsamples++;
00355 //        }else if((mType==1)&&(canRXmsg.id==0x1da)){ //Motor Speed
00356 //            imotorRPM_x2=((canRXmsg.data[4]<<8)|(canRXmsg.data[5]));
00357 //            if(imotorRPM_x2<0){ // take absolute value
00358 //                imotorRPM_x2=-imotorRPM_x2;
00359 //            }
00360 //            motorRPM_x2+=imotorRPM_x2;
00361 //            numSsamples++;
00362 //        }else if((mType==2)&&(canRXmsg.id==0x1ca)){ //Brake Pressure
00363         }else if((mType==2)&&(canRXmsg.id==0x292)){ //Brake Pressure
00364             if(brakeMon){
00365                 if(canRXmsg.data[0]<0xff){
00366                     if((canRXmsg.data[6]*imotorRPM)<brkMonThr){ // brkMonThr = 3.6/.0019 = 1895 --> squelch threshold 1Wh/sec
00367                         chirpInt=0;
00368                     }else{ // imotorRPM*data[6]*.0019=kW; 3.6/kW = seconds until 1Wh;
00369                         chirpInt=brkMonRate/imotorRPM; // brkMonRate=3.6/.0019/.02=94736.8 --> 1 chirp per Wh
00370                         chirpInt/=canRXmsg.data[6];
00371                     }
00372                 }
00373             }
00374         }
00375     }
00376 }
00377 
00378 //-----------------------------
00379 void logTS () {
00380     CANMessage tsMsg;
00381     unsigned long secs = time(NULL); // seconds past 12:00:00 AM 1 Jan 1900
00382     // NOTE: In Mbed, I believe that this is seconds past start of 1970, not 1900
00383     //   but this is good, since seconds past 1970 is what CAN-Do expects. GG - Date Time
00384     tsMsg.id=0xfff;
00385     tsMsg.len=0xf;
00386     tsMsg.data[0]=secs&0xff; 
00387     tsMsg.data[1]=(secs>>8)&0xff;
00388     tsMsg.data[2]=(secs>>16)&0xff;
00389     tsMsg.data[3]=(secs>>24)&0xff;
00390     tsMsg.data[4]=0; // 0xff; gg - Date Time
00391     tsMsg.data[5]=0; // 0xff; for CAN-Do
00392     tsMsg.data[6]=0; // 0xff;
00393     tsMsg.data[7]=0xff;
00394     logCan(0,tsMsg); // Date-Time
00395 }
00396 
00397 void logEvent (char * errMsg) {
00398     // log CAN-Do 8-character Pseudo Message
00399     CANMessage tsMsg;
00400     tsMsg.id=0xffe; // pseudo Message to CAN-Do log
00401     tsMsg.len=0xf;
00402     int iMsgLen = strlen(errMsg);
00403     // 8 character message compatible with CAN-Do
00404     for(int i=0; i<8; i++){
00405       tsMsg.data[i]=' '; 
00406       if( i < iMsgLen ) tsMsg.data[i]=errMsg[i];
00407     }
00408     logCan(0,tsMsg); // FFE Comment Message
00409 }
00410 
00411 void sendReq() {
00412     static char data[8] = {0x02, 0x21, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff};
00413     if(reqMsgCnt<99){
00414         switch (reqMsgCnt){
00415             case BatDataBaseG1:
00416                 can2.monitor(false); // set to active mode
00417                 can2SleepMode = 0; // enable TX
00418                 data[0]=0x02; //change to request group 1
00419                 data[1]=0x21;
00420                 data[2]=0x01;
00421                 break;
00422             case BatDataBaseG2: // group 1 has 6 frames
00423                 data[0]=0x02; //change to request group 2 (cp data)
00424                 data[1]=0x21;
00425                 data[2]=0x02;
00426                 break;
00427             case BatDataBaseG3: // group 2 has 29 frames
00428                 data[0]=0x02; //change to request group 3
00429                 data[1]=0x21;
00430                 data[2]=0x03;
00431                 break;
00432             case BatDataBaseG4: // group 3 has 5 frames
00433                 data[0]=0x02; //change to request group 4 (temperature)
00434                 data[1]=0x21;
00435                 data[2]=0x04;
00436                 break;
00437             case BatDataBaseG5: // group 4 has 3 frames
00438                 data[0]=0x02; //change to request group 5
00439                 data[1]=0x21;
00440                 data[2]=0x05;
00441                 break;
00442             case BatDataBaseG6: // group 4 has 3 frames
00443                 data[0]=0x02; //change to request group 5
00444                 data[1]=0x21;
00445                 data[2]=0x06;
00446                 break;
00447             case BatDataBaseG7: // group 5 has 11 frames
00448                 reqMsgCnt = 99;
00449                 can2SleepMode = VP230Sleep; // disable TX
00450                 can2.monitor(true); // set to snoop mode
00451                 msgReq.detach(); // stop ticker
00452             default:
00453                 data[0]=0x30; //change to request next line message
00454                 data[1]=0x01;
00455                 data[2]=0x00;
00456         }
00457         can2.write(CANMessage(0x79b, data, 8));
00458         reqMsgCnt++;
00459     }
00460 }
00461 
00462 void sendTempReq(){
00463     //Requests ambient and cabin temperature
00464     char data[8] = {0x03, 0x22, 0x11, 0x5d, 0xff, 0xff, 0xff, 0xff};
00465     can2.monitor(false); // set to active mode
00466     can2SleepMode = 0; // enable TX
00467     can2.write(CANMessage(0x797, data, 8));
00468     can2SleepMode = VP230Sleep; // disable TX
00469 }
00470 
00471 void autoPollISR(){
00472     //sendTempReq();
00473     reqMsgCnt = 0; //reset message counter
00474     msgReq.attach(&sendReq,0.015);
00475 }
00476 
00477 void playbackISR() { //Used for autoplayback
00478     step=true;
00479 }
00480 
00481 void recieve1() {
00482     CANMessage msg1;
00483     can1.read(msg1);
00484     
00485     secsNoEvCanMsg=0; // reset deadman switch
00486     if( ZeroSecTick ) { ZeroSecTick = false; logTS(); } // gg - 0-second EV bus
00487     if(msg1.id>0) {
00488         logCan(1, msg1); // EVcan Message Received
00489         led1 = !led1;
00490     }
00491 }
00492 
00493 void recieve2() {
00494     CANMessage msg2;
00495     can2.read(msg2);
00496     
00497     secsNoCarCanMsg=0; // reset deadman switch
00498     if( ZeroSecTick ) { ZeroSecTick = false; logTS(); } // gg - 0-second CAR bus    
00499     if(msg2.id>0) {
00500         logCan(2, msg2); // CARcan Message Received
00501         led2 = !led2;
00502     }
00503 }
00504 
00505 unsigned char buttonX(unsigned short X, unsigned char columns) {
00506     unsigned char val = X*columns/320;
00507     return val;
00508 }
00509 
00510 unsigned char buttonY(unsigned short Y, unsigned char rows) {
00511     unsigned short val = Y*rows/240;
00512     return val;
00513 }
00514 
00515 void saveConfig(){
00516     FILE *cfile;
00517     FIL efile; // external usb file
00518     FRESULT sfr; // external file access flags
00519     unsigned int bytesRW;
00520     const int bufSize = 2048;
00521     char buffer[bufSize];
00522     char sTemp[16];
00523 
00524     tt.set_font((unsigned char*) Arial12x12);
00525     tt.background(Blue);
00526     tt.foreground(Yellow);
00527     tt.locate(0,10);
00528     tt.cls();
00529 
00530     printMsg("Saving local config file.\n");
00531     printf("Saving local config file.\n");
00532     cfile = fopen("/local/config.txt", "w");    
00533     fprintf(cfile,"format 11\r\n");
00534     fprintf(cfile,"x0_off %d\r\n",tt.x0_off);
00535     fprintf(cfile,"y0_off %d\r\n",tt.y0_off);
00536     fprintf(cfile,"x0_pp %d\r\n",tt.x0_pp);
00537     fprintf(cfile,"y0_pp %d\r\n",tt.y0_pp);
00538     fprintf(cfile,"x1_off %d\r\n",tt.x1_off);
00539     fprintf(cfile,"y1_off %d\r\n",tt.y1_off);
00540     fprintf(cfile,"x1_pp %d\r\n",tt.x1_pp);
00541     fprintf(cfile,"y1_pp %d\r\n",tt.y1_pp);
00542     fprintf(cfile,"x_mid %d\r\n",tt.x_mid);
00543     if ((dMode[0]==configScreen)||(dMode[0]==config2Screen))
00544         fprintf(cfile,"dMode0 %d\r\n",mainScreen);
00545     else
00546         fprintf(cfile,"dMode0 %d\r\n",dMode[0]);
00547     if ((dMode[1]==configScreen)||(dMode[1]==config2Screen))
00548         fprintf(cfile,"dMode1 %d\r\n",mainScreen);
00549     else
00550         fprintf(cfile,"dMode1 %d\r\n",dMode[1]);
00551     fprintf(cfile,"ledHi %4.3f\r\n",ledHi);
00552     fprintf(cfile,"ledLo %4.3f\r\n",ledLo);
00553     fprintf(cfile,"pollInt %d\r\n",pollInt);
00554     fprintf(cfile,"scale12V %4.2f\r\n",scale12V);
00555     fprintf(cfile,"skin %d\r\n",skin);
00556     fprintf(cfile,"dtePeriod %d\r\n",dtePeriod);
00557     fprintf(cfile,"DebugMode %d\r\n",(debugMode?1:0));
00558     fprintf(cfile,"metric %d\r\n",(metric?1:0));
00559     fprintf(cfile, "firmware %d\r\n", fwCount );            
00560     fprintf(cfile,"showHealth %d\r\n",(showHealth?1:0));
00561     fprintf(cfile,"brakeMon %d\r\n",(heaterMon?4:0)+(brakeMon?2:0)+(regenMon?1:0));
00562     fprintf(cfile,"brkMonRate %2.1f\r\n", (float) brkMonRate/94737 );            
00563     fprintf(cfile,"brkMonThr %2.1f\r\n", (float) brkMonThr/1895);            
00564     for(char i=0;i<8;i++){
00565         sprintf(sTemp,"usrMsgId %04x",uMsgId[i]);
00566         fprintf(cfile,"%s\r\n", sTemp );
00567     }
00568     fprintf(cfile,"modelYear %d\r\n",modelYear);
00569     fprintf(cfile,"autoSync %d\r\n",(autoSync?1:0));
00570     fprintf(cfile,"kWperGid %4.3f\r\n",kWperGid);
00571     fclose(cfile);
00572     
00573     // Make copy of CONFIG.TXT
00574     printMsg("Saving CONFIG.BAK.\n");
00575     cfile = fopen("/local/CONFIG.TXT", "r");
00576     sfr = f_open(&efile,"CONFIG.BAK",FA_WRITE|FA_CREATE_NEW);    
00577     if((cfile != NULL)&&(sfr == FR_OK)){
00578         printf("Copy config file to USB\n");
00579         while (!feof(cfile))
00580         {
00581             bytesRW=fread(buffer, 1, bufSize, cfile);
00582             sfr=f_write(&efile,&buffer,bytesRW,&bytesRW);
00583         }
00584         fflush(cfile);
00585         fclose(cfile);
00586         f_close(&efile);
00587     }
00588 
00589     // Make copy of ehist.cny
00590     printMsg("Saving ehist.bak.\n");
00591     cfile = fopen("/local/ehist.cny", "r");
00592     sfr = f_open(&efile,"ehist.bak",FA_WRITE|FA_CREATE_NEW);    
00593     if((cfile != NULL)&&(sfr == FR_OK)){
00594         printf("Copy ehist file to USB\n");
00595         while (!feof(cfile))
00596         {
00597             bytesRW=fread(buffer, 1, bufSize, cfile);
00598             sfr=f_write(&efile,&buffer,bytesRW,&bytesRW);
00599         }
00600         fflush(cfile);
00601         fclose(cfile);
00602         f_close(&efile);
00603     }
00604     wait(3);
00605 }
00606 
00607 void readConfig(){
00608     FILE *cfile;
00609     int ff,readHex,readBool;
00610     char sTemp[16];
00611     float readFloat;
00612 
00613     cfile = fopen("/local/config.txt", "r");
00614     if (cfile==NULL){ // if doesn't exist --> create
00615         printMsg("No config file found.\n"); // no config file
00616         printMsg("Calibrating touch screen.\n"); // calibrating
00617         //tt.setcal(5570, 34030, 80, 108, 33700, 5780, 82, 108, 32500);// bypass calibration using my values
00618         tt.calibrate();   // run touchscreen calibration routine
00619         // NOTE: calibrates screen 1 first, then screen 0.
00620         saveConfig();
00621     } else {
00622         ledHi = 0.8;
00623         ledLo = 0.3;
00624         pollInt = 60;
00625         scale12V = 16.2;
00626         kWperGid=0.080;
00627         skin = ttSkin;
00628         fscanf(cfile, "format %d\r\n", &ff );
00629         fscanf(cfile, "x0_off %d\r\n", &tt.x0_off );
00630         fscanf(cfile, "y0_off %d\r\n", &tt.y0_off );
00631         fscanf(cfile, "x0_pp %d\r\n", &tt.x0_pp );
00632         fscanf(cfile, "y0_pp %d\r\n", &tt.y0_pp );
00633         fscanf(cfile, "x1_off %d\r\n", &tt.x1_off );
00634         fscanf(cfile, "y1_off %d\r\n", &tt.y1_off );
00635         fscanf(cfile, "x1_pp %d\r\n", &tt.x1_pp );
00636         fscanf(cfile, "y1_pp %d\r\n", &tt.y1_pp );
00637         fscanf(cfile, "x_mid %d\r\n", &tt.x_mid );
00638         fscanf(cfile, "dMode0 %d\r\n", &dMode[0] );
00639         fscanf(cfile, "dMode1 %d\r\n", &dMode[1] );
00640         if(ff>1){
00641             fscanf(cfile, "ledHi %f\r\n", &ledHi );
00642             fscanf(cfile, "ledLo %f\r\n", &ledLo );
00643             fscanf(cfile, "pollInt %d\r\n", &pollInt );
00644             fscanf(cfile, "scale12V %f\r\n", &scale12V );
00645         }
00646         if(ff>2){
00647             fscanf(cfile, "skin %d\r\n", &skin );
00648             fscanf(cfile, "dtePeriod %d\r\n", &dtePeriod );
00649         }
00650         if(ff>3){
00651             fscanf(cfile, "DebugMode %d\r\n", &readBool );            
00652             debugMode = (bool)readBool;
00653         }
00654         if(ff>4) {
00655             fscanf(cfile, "metric %d\r\n", &readBool );            
00656             metric = (bool)readBool; // This will get re-assigned based on dash selection
00657             fscanf(cfile, "firmware %d\r\n", &fwCount );
00658         }
00659         if(ff>5){
00660             fscanf(cfile, "showHealth %d\r\n", &readBool );            
00661             showHealth = (bool)readBool;
00662         }
00663         if(ff>6){
00664             fscanf(cfile, "brakeMon %d\r\n", &readBool );
00665             brakeMon = (bool)(readBool&1);
00666             regenMon = (bool)(readBool&2);
00667             heaterMon = (bool)(readBool&4);
00668             if(ff>10){
00669                 fscanf(cfile, "brkMonRate %f\r\n", &readFloat );
00670                 brkMonRate = 94737 * readFloat;
00671                 fscanf(cfile, "brkMonThr %f\r\n", &readFloat );
00672                 brkMonThr = 1895 * readFloat;
00673             }else{
00674                 fscanf(cfile, "brkMonRate %d\r\n", &brkMonRate );
00675                 fscanf(cfile, "brkMonThr %d\r\n", &brkMonThr);
00676                 brkMonRate = 378948;
00677                 brkMonThr = 1895;
00678             }
00679         }
00680         if(ff>7){
00681             for(char i=0;i<8;i++){
00682                 fscanf(cfile, "usrMsgId %s\r\n", &sTemp );
00683                 sscanf(sTemp,"%x", &readHex);
00684                 uMsgId[i]=readHex;
00685             }
00686         }
00687         if(ff>8){
00688             fscanf(cfile, "modelYear %d\r\n", &modelYear);            
00689             fscanf(cfile, "autoSync %d\r\n", &readBool);            
00690             autoSync = (bool)readBool;
00691         }
00692         if(ff>9){
00693             fscanf(cfile, "kWperGid %f\r\n", &kWperGid );
00694             }
00695         fclose(cfile);
00696         if((ff>11)||(ff<1)||(ledHi<0.1)||(scale12V<10)||(tt.x_mid<16000)||(ledHi>1)||(ledLo>1)||(dMode[0]>maxScreens)||(dMode[1]>maxScreens)){ //Sanity check a few things
00697             //Something wrong. Load defaults
00698             printMsg("Invalid config file.  Loading defaults.\n");
00699             wait(3);
00700             ff=11;
00701             tt.x0_off=5732;
00702             tt.y0_off=34009;
00703             tt.x0_pp=77;
00704             tt.y0_pp=106;
00705             tt.x1_off=33955;
00706             tt.y1_off=6310;
00707             tt.x1_pp=80;
00708             tt.y1_pp=104;
00709             tt.x_mid=31986;
00710             dMode[0]=2;
00711             dMode[1]=4;
00712             ledHi=0.800;
00713             ledLo=0.300;
00714             pollInt=300;
00715             scale12V=16.20;
00716             skin=0;
00717             dtePeriod=14;
00718             debugMode=false;
00719             metric=false;
00720             fwCount=1;
00721             showHealth=true;
00722             brakeMon=true;
00723             regenMon=true;
00724             heaterMon=true;
00725             brkMonRate=378947; // 4Wh per chirp
00726             brkMonThr=1895; // 1Wh per second
00727             uMsgId[0]=0x5103;
00728             uMsgId[1]=0x50a3;
00729             uMsgId[2]=0x54a4;
00730             uMsgId[3]=0x54b4;
00731             uMsgId[4]=0x54c0;
00732             uMsgId[5]=0x55b4;
00733             uMsgId[6]=0x0000;
00734             uMsgId[7]=0x0000;
00735             modelYear=2011;
00736             autoSync=false;
00737             kWperGid=0.080;
00738             }
00739         if(ff<11){//If not latest format, save as latest format
00740             saveConfig();
00741             printMsg("Config file format updated.\n"); // config format updates
00742         }
00743         printMsg("Config file loaded.\n"); // config file loaded
00744     }
00745 }
00746 
00747 void upDate(unsigned char field, bool upDownBar){
00748     struct tm t; // pointer to a static tm structure
00749     time_t seconds ;
00750     seconds = time(NULL);
00751     t = *localtime(&seconds) ;
00752     switch(field){
00753         case 0: // year
00754             if (upDownBar) {
00755                 t.tm_year = t.tm_year+1;
00756             } else {
00757                 t.tm_year = t.tm_year-1;
00758             }
00759             break;
00760         case 1: // month
00761             if (upDownBar) {
00762                 t.tm_mon = (t.tm_mon<11)?t.tm_mon+1:0;
00763             } else {
00764                 t.tm_mon = (t.tm_mon>0)?t.tm_mon-1:11;
00765             }
00766             break;
00767         case 2: // day
00768             if (upDownBar) {
00769                 t.tm_mday = (t.tm_mday<31)?t.tm_mday+1:1;
00770             } else {
00771                 t.tm_mday = (t.tm_mday>1)?t.tm_mday-1:31;
00772             }
00773             break;
00774         case 3: // hour
00775             if (upDownBar) {
00776                 t.tm_hour = (t.tm_hour<23)?t.tm_hour+1:0;
00777             } else {
00778                 t.tm_hour = (t.tm_hour>0)?t.tm_hour-1:23;
00779             }
00780             break;
00781         case 4: // minute
00782             if (upDownBar) {
00783                 t.tm_min = (t.tm_min<59)?t.tm_min+1:0;
00784             } else {
00785                 t.tm_min = (t.tm_min>0)?t.tm_min-1:59;
00786             }
00787             break;
00788         case 5: // second
00789             if (upDownBar) {
00790                 t.tm_sec = (t.tm_sec<59)?t.tm_sec+1:0;
00791             } else {
00792                 t.tm_sec = (t.tm_sec>0)?t.tm_sec-1:59;
00793             }
00794             break;
00795         default:
00796             break;
00797     }
00798     set_time(mktime(&t));
00799 }
00800 
00801 bool syncDateTime(){ // doesn't work on MY2013
00802     struct tm t; // pointer to a static tm structure
00803     time_t seconds ;
00804     CANMessage msg;
00805     static unsigned char lastHour, numMatched;
00806     seconds = time(NULL);
00807     t = *localtime(&seconds);
00808     if(modelYear<2013){ //MY2011,2012
00809         msg = lastMsg[indexLastMsg[0x5fa]];
00810         t.tm_mon = (msg.data[5]>>4)-1;
00811         t.tm_mday = msg.data[2]>>3;
00812         msg = lastMsg[indexLastMsg[0x5fb]];
00813         //t.tm_year = msg.data[1]; // Have not figured out where the year is
00814         msg = lastMsg[indexLastMsg[0x5fc]];
00815         t.tm_hour = msg.data[0]>>3;
00816         t.tm_min = (msg.data[1]<<4&0x30)+(msg.data[2]>>4);
00817         t.tm_sec = msg.data[1]>>2;
00818     }else{ // model year 2013 or higher
00819         msg = lastMsg[indexLastMsg[0x5f9]];
00820         t.tm_hour = msg.data[5]>>3;
00821         t.tm_min = msg.data[4];
00822         msg = lastMsg[indexLastMsg[0x509]];
00823         t.tm_sec = msg.data[2]>>2;
00824     }
00825     if(t.tm_hour==lastHour){ //filter
00826         numMatched++;
00827     }else{
00828         numMatched=0;
00829     }
00830     lastHour=t.tm_hour;
00831     if((numMatched>5)&&(t.tm_mon>=0)&&(t.tm_mon<12)&&(t.tm_mday>0)&&(t.tm_mday<32)&&(t.tm_hour>=0)&&(t.tm_hour<24)&&(t.tm_min>=0)&&(t.tm_min<60)&&(t.tm_sec>=0)&&(t.tm_sec<60)){ // sanity check result before using
00832         set_time(mktime(&t));
00833         numMatched=0;
00834         return(true);
00835     }else{
00836         return(false);
00837     }
00838 
00839 }
00840 
00841 void logPackVoltages() { // Turbo3 - routine to dump CP values to text file
00842     char sTemp[40];
00843     struct tm t; // pointer to a static tm structure
00844     short unsigned max, min, jv, i, bd;
00845     unsigned avg;
00846     unsigned short gids, SOC, packV_x2;
00847     unsigned long odo;
00848     signed short packA_x2;
00849     time_t seconds ;
00850     
00851     CANMessage msg;
00852     
00853     seconds = time(NULL); // Turbo3
00854     t = *localtime(&seconds) ; // Turbo3 
00855     
00856     msg = lastMsg[indexLastMsg[0x5bc]]; //Get gids
00857     gids = (msg.data[0]<<2)+(msg.data[1]>>6);
00858     msg = lastMsg[indexLastMsg[0x5c5]]; //Get odometer
00859     odo = (msg.data[1]<16)+(msg.data[2]<<8)+msg.data[3];
00860     msg = lastMsg[indexLastMsg[0x55b]]; //Get SOC
00861     SOC = (msg.data[0]<<2)+(msg.data[1]>>6);
00862     msg = lastMsg[indexLastMsg[0x1db]]; //Get pack volts
00863     packV_x2 = (msg.data[2]<<2)+(msg.data[3]>>6);
00864     packA_x2 = (msg.data[0]<<3)+(msg.data[1]>>5);
00865     if (packA_x2 & 0x400) packA_x2 |= 0xf800;
00866     
00867     max=0;
00868     min=9999;
00869     avg=0;
00870     for(i=0; i<96; i++) {
00871         bd=(battData[BatDataBaseG2*7+i*2+3]<<8)+battData[BatDataBaseG2*7+i*2+4];
00872         avg+=bd;
00873         if(bd>max) max=bd;
00874         if(bd<min) min=bd;
00875     }
00876     avg /= 96;
00877     if(min<3713) {
00878         jv=avg-(max-avg)*1.5;
00879     } else { // Only compute judgement value if min cellpair meets <= 3712mV requirement
00880         jv=0;
00881     }
00882     
00883     FIL bfile;
00884     FRESULT bfr;
00885     bfr = f_open(&bfile,"batvolt.txt",FA_WRITE|FA_OPEN_ALWAYS);
00886     if(bfr==FR_OK) {
00887         f_lseek(&bfile,0xffffffff); // go to end of file to append
00888         strftime(sTemp, 40, "%a %m/%d/%Y %X", &t);
00889         f_printf(&bfile,"%s,",sTemp);
00890         sprintf(sTemp,"%d,%d,%5.1f%%,%5.1f,%5.1f,%d,%d,%d,%d,%d",odo,gids,(float)SOC/10,(float)packV_x2/2,(float)packA_x2/2,max,min,avg,max-min,jv);
00891         f_printf(&bfile,"%s,",sTemp);           
00892         f_printf(&bfile,"%d,%d,%d,%d,",(battData[(BatDataBaseG4*7)+ 3]<<8)+battData[(BatDataBaseG4*7)+ 4],battData[(BatDataBaseG4*7)+ 5],(battData[(BatDataBaseG4*7)+ 6]<<8)+battData[(BatDataBaseG4*7)+ 7],battData[(BatDataBaseG4*7)+ 8]);
00893         f_printf(&bfile,"%d,%d,%d,%d", (battData[(BatDataBaseG4*7)+ 9]<<8)+battData[(BatDataBaseG4*7)+10],battData[(BatDataBaseG4*7)+11],(battData[(BatDataBaseG4*7)+12]<<8)+battData[(BatDataBaseG4*7)+13],battData[(BatDataBaseG4*7)+14]);
00894         for(i=0; i<96; i++) {
00895             bd=(battData[BatDataBaseG2*7+i*2+3]<<8)+battData[BatDataBaseG2*7+i*2+4];
00896             f_printf(&bfile,",%d",bd);
00897         }
00898         f_printf(&bfile,"\r\n");
00899         f_close(&bfile);
00900     }
00901     logCP=false;
00902     showCP=true;
00903 }
00904 
00905 void tripLog() { // Daily log
00906     char sTemp[40];
00907     unsigned char ambient;
00908     struct tm t; // pointer to a static tm structure
00909     short unsigned max, min, jv, i, bd;
00910     unsigned avg;
00911     unsigned short gids, SOC, packV_x2;
00912     unsigned long odo;
00913     signed short packA_x2;
00914     time_t seconds ;
00915     
00916     CANMessage msg;
00917     
00918     seconds = time(NULL); // Turbo3
00919     t = *localtime(&seconds) ; // Turbo3 
00920     
00921     msg = lastMsg[indexLastMsg[0x54c]]; //Get ambient
00922     ambient = msg.data[6]-56;
00923     msg = lastMsg[indexLastMsg[0x5bc]]; //Get gids
00924     gids = (msg.data[0]<<2)+(msg.data[1]>>6);
00925     msg = lastMsg[indexLastMsg[0x5c5]]; //Get odometer
00926     odo = (msg.data[1]<16)+(msg.data[2]<<8)+msg.data[3];
00927     msg = lastMsg[indexLastMsg[0x55b]]; //Get SOC
00928     SOC = (msg.data[0]<<2)+(msg.data[1]>>6);
00929     msg = lastMsg[indexLastMsg[0x1db]]; //Get pack volts
00930     packV_x2 = (msg.data[2]<<2)+(msg.data[3]>>6);
00931     packA_x2 = (msg.data[0]<<3)+(msg.data[1]>>5);
00932     if (packA_x2 & 0x400) packA_x2 |= 0xf800;
00933     
00934     max=0;
00935     min=9999;
00936     avg=0;
00937     for(i=0; i<96; i++) {
00938         bd=(battData[BatDataBaseG2*7+i*2+3]<<8)+battData[BatDataBaseG2*7+i*2+4];
00939         avg+=bd;
00940         if(bd>max) max=bd;
00941         if(bd<min) min=bd;
00942     }
00943     avg /= 96;
00944     if(min<3713) {
00945         jv=avg-(max-avg)*1.5;
00946     } else { // Only compute judgement value if min cellpair meets <= 3712mV requirement
00947         jv=0;
00948     }
00949     
00950     FIL bfile;
00951     FRESULT bfr;
00952     bfr = f_open(&bfile,"triplog.txt",FA_WRITE|FA_OPEN_ALWAYS);
00953     if(bfr==FR_OK) {
00954         f_lseek(&bfile,0xffffffff); // go to end of file to append
00955         // timestamp, odometer, accV, gids, SOC, SOH2, Ah, Vbatt, Ibatt, Rest, maxCP, minCP, avgCO, maxCP-minCP, CVLI_jv, miles_trip, kWh_trip, CCkWh_trip, ambient, T1raw, T1, T2raw, T2, T3raw, T3, T4raw, T4, CP1, CP2, ... , CP96
00956         strftime(sTemp, 40, "%a %m/%d/%Y %X", &t);
00957         f_printf(&bfile,"%s,",sTemp);
00958         sprintf(sTemp,"%d,%3.1f,%d,%5.1f%%,%5.1f%%,%4.2f,%5.1f,%4.1f,%4.3f,%d,%d,%d,%d,%d,%4.1f,%4.2f,%4.2f",odo,accV,gids,(float)SOC/10, (float)SOH2_x100/100,(float)Ah_x10000/10000,(float)packV_x2/2,(float)packA_x2/2,Resr,max,min,avg,max-min,jv,miles_trip[0],kWh_trip[0],CCkWh_trip[0]);
00959         f_printf(&bfile,"%s,%d,",sTemp,ambient);           
00960         f_printf(&bfile,"%d,%d,%d,%d,",(battData[(BatDataBaseG4*7)+ 3]<<8)+battData[(BatDataBaseG4*7)+ 4],battData[(BatDataBaseG4*7)+ 5],(battData[(BatDataBaseG4*7)+ 6]<<8)+battData[(BatDataBaseG4*7)+ 7],battData[(BatDataBaseG4*7)+ 8]);
00961         f_printf(&bfile,"%d,%d,%d,%d", (battData[(BatDataBaseG4*7)+ 9]<<8)+battData[(BatDataBaseG4*7)+10],battData[(BatDataBaseG4*7)+11],(battData[(BatDataBaseG4*7)+12]<<8)+battData[(BatDataBaseG4*7)+13],battData[(BatDataBaseG4*7)+14]);
00962         for(i=0; i<96; i++) {
00963             bd=(battData[BatDataBaseG2*7+i*2+3]<<8)+battData[BatDataBaseG2*7+i*2+4];
00964             f_printf(&bfile,",%d",bd);
00965         }
00966         f_printf(&bfile,"\r\n");
00967         f_close(&bfile);
00968     }
00969 }
00970 
00971 //LM - updates firmware off a usb key, eliminating the need to plug
00972 //the CANary into a computer for updates.
00973 void updateFirmware()
00974 {
00975     FIL efile; // external usb file
00976     FRESULT sfr; // external file access flags
00977     unsigned int bytesRW;
00978     char sTemp[40];
00979     const int bufSize = 2048;
00980     char buffer[bufSize];
00981     FILE *lfile;    
00982 
00983     tt.set_font((unsigned char*) Arial12x12);
00984     tt.background(Blue);
00985     tt.foreground(Yellow);
00986     tt.locate(0,10);
00987     tt.cls();
00988 
00989     sfr = f_open(&efile,"firmware.bin",FA_READ|FA_OPEN_EXISTING);    
00990     if(sfr != FR_OK)
00991     {        
00992         printf("Couldn't find firmware.bin\n");
00993         wait(3);
00994         lastDMode[whichTouched]=99;//force refresh
00995         return;
00996     }
00997     fwCount ++;
00998     printf("Saving config.\n");
00999     saveConfig();
01000     //delete all bin files in /local
01001     DIR *dir;
01002     struct dirent *ent;
01003     printf("Starting update.\n");
01004     printf("Deleting old firmware files.\n");
01005     if ((dir = opendir ("/local/")) != NULL) {
01006       // print all the files and directories within directory
01007       while ((ent = readdir (dir)) != NULL) {
01008             //printf("FILE: %s\n",ent->d_name);
01009             char dest[4] = "";
01010             strncat(dest, &ent->d_name[strlen(ent->d_name)-3],3);            
01011             dest[0] = tolower(dest[0]);
01012             dest[1] = tolower(dest[1]);
01013             dest[2] = tolower(dest[2]);                        
01014             if(strcmp(dest,"bin")==0)
01015             {                            
01016                 sprintf(sTemp,"/local/%s",ent->d_name);
01017                 int result = remove(sTemp);       
01018                 printf("deleted: %s\n",ent->d_name);
01019             }
01020       }
01021       closedir (dir);
01022     } else {
01023       //could not open directory
01024         printf("Couldn't open folder.\n");
01025         wait(3);
01026         return;
01027     }        
01028     printf("Copying new firmware.\n");
01029     //Copy the new firmware from usb->local
01030     //The newest bin file is the one that is used by the mbed  
01031     sprintf(sTemp,"/local/fw%d.bin",fwCount);
01032     printf("Writing %s.\n",sTemp);
01033     //wait(2);
01034     lfile = fopen(sTemp, "wb");
01035     if(lfile == NULL)
01036     {
01037         printf("Couldn't open destination.\n");
01038         wait(3);
01039         return;
01040     }
01041 
01042     while (!f_eof(&efile))
01043     {
01044         sfr=f_read(&efile,&buffer,bufSize,&bytesRW);
01045         fwrite(buffer, 1, bytesRW, lfile);
01046     }
01047 
01048     fflush(lfile);
01049     fclose(lfile);
01050     f_close(&efile);
01051     printf("Succesful.\n\n");
01052     printf("Rebooting in 5 seconds.\n");
01053     wait(5);
01054     //Now run new firmware
01055     mbed_reset();
01056 }
01057 
01058 void updateConfig()
01059 {
01060     FIL efile; // external usb file
01061     FRESULT sfr; // external file access flags
01062     unsigned int bytesRW;
01063     const int bufSize = 2048;
01064     char buffer[bufSize];
01065     FILE *lfile;    
01066 
01067     tt.set_font((unsigned char*) Arial12x12);
01068     tt.background(Blue);
01069     tt.foreground(Yellow);
01070     tt.locate(0,10);
01071     tt.cls();
01072     
01073     printMsg("Copy config file from USB\n");
01074     // Check for config file on USB drive
01075     sfr = f_open(&efile,"CONFIG.TXT",FA_READ|FA_OPEN_EXISTING);    
01076     if(sfr == FR_OK){        
01077         printf("Copy config file from USB\n");
01078         lfile = fopen("/local/CONFIG.TXT", "w");
01079         if(lfile != NULL) {
01080             while (!f_eof(&efile)){
01081                 sfr=f_read(&efile,&buffer,bufSize,&bytesRW);
01082                 fwrite(buffer, 1, bytesRW, lfile);
01083             }
01084             fflush(lfile);
01085             fclose(lfile);
01086         }
01087         f_close(&efile);
01088         int fwc_tmp = fwCount;
01089         readConfig();
01090         fwCount = fwc_tmp; // Do no overwrite fwcount when loading new config
01091     }
01092 
01093     // Check for history file on USB drive
01094     printMsg("Copy ehist file from USB\n");
01095     sfr = f_open(&efile,"ehist.cny",FA_READ|FA_OPEN_EXISTING);    
01096     if(sfr == FR_OK){        
01097         printf("Copy ehist file from USB\n");
01098         lfile = fopen("/local/ehist.cny", "w");
01099         if(lfile != NULL) {
01100             while (!f_eof(&efile)){
01101                 sfr=f_read(&efile,&buffer,bufSize,&bytesRW);
01102                 fwrite(buffer, 1, bytesRW, lfile);
01103             }
01104             fflush(lfile);
01105             fclose(lfile);
01106         }
01107         f_close(&efile);
01108     }
01109     printf("Succesful.\n\n");
01110     wait(5);
01111 }
01112 
01113 bool detectUSB(void){
01114     FIL tfile; // external usb file
01115     bool usbEn = (f_open(&tfile,"usb.det",FA_WRITE|FA_OPEN_ALWAYS)==FR_OK);
01116     if(usbEn){
01117         f_close(&tfile);
01118         f_unlink("usb.det");
01119     }
01120     return(usbEn);
01121 }
01122 
01123 void spkrOff(void){
01124     if(bCount<2){
01125         spkr.period(1.0/bFreq[bCount]);
01126         beepOff.attach(&spkrOff, bTime[bCount++]);   
01127     }else{
01128         spkr=0;
01129         dled.period(.001);
01130     }
01131 }
01132 
01133 void beep(float freq, float time){
01134     if (enableSound) {
01135         spkr.period(1.0/freq);
01136         spkr=0.5;
01137         if(!headlights){ //restore LCD pwm output (Beep pwm interferes with display pwm)
01138                 dled = ledHi;
01139             } else {
01140                 dled = ledLo;
01141             }
01142         beepOff.attach(&spkrOff, time);
01143     }
01144 }
01145 
01146 void beep3(float freq1, float time1, float freq2, float time2, float freq3, float time3){
01147     bFreq[0]=freq2;
01148     bTime[0]=time2;
01149     bFreq[1]=freq3;
01150     bTime[1]=time3;
01151     bCount=0;
01152     beep(freq1, time1);
01153 }
01154 
01155 void chirp(void){
01156     static unsigned short counter=0;
01157     
01158     if(chirpInt>0){
01159         if(++counter>chirpInt){
01160             beep(1600,0.015);
01161             counter=0;
01162         }
01163     }else{
01164         counter=0;
01165     }
01166 }
01167 
01168 //Sample CONFIG.TXT
01169 /*
01170 format 11
01171 x0_off 5732
01172 y0_off 34009
01173 x0_pp 77
01174 y0_pp 106
01175 x1_off 33955
01176 y1_off 6310
01177 x1_pp 80
01178 y1_pp 104
01179 x_mid 31986
01180 dMode0 4
01181 dMode1 2
01182 ledHi 0.800
01183 ledLo 0.300
01184 pollInt 300
01185 scale12V 16.20
01186 skin 0
01187 dtePeriod 14
01188 DebugMode 0
01189 metric 0
01190 firmware 1
01191 showHealth 1
01192 brakeMon 1
01193 brkMonRate 4.0
01194 brkMonThr 1.0
01195 usrMsgId 5103
01196 usrMsgId 50a3
01197 usrMsgId 54a4
01198 usrMsgId 54b4
01199 usrMsgId 54c0
01200 usrMsgId 55b4
01201 usrMsgId 0000
01202 usrMsgId 0000
01203 modelYear 2011
01204 autoSync 1
01205 kWperGid 0.075
01206 */