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