PokittoLib is the library needed for programming the Pokitto DIY game console (www.pokitto.com)
Dependents: YATTT sd_map_test cPong SnowDemo ... more
PokittoCore.cpp
00001 /**************************************************************************/ 00002 /*! 00003 @file PokittoCore.cpp 00004 @author Jonne Valola 00005 00006 @section LICENSE 00007 00008 Software License Agreement (BSD License) 00009 00010 Copyright (c) 2016, Jonne Valola 00011 All rights reserved. 00012 00013 Redistribution and use in source and binary forms, with or without 00014 modification, are permitted provided that the following conditions are met: 00015 1. Redistributions of source code must retain the above copyright 00016 notice, this list of conditions and the following disclaimer. 00017 2. Redistributions in binary form must reproduce the above copyright 00018 notice, this list of conditions and the following disclaimer in the 00019 documentation and/or other materials provided with the distribution. 00020 3. Neither the name of the copyright holders nor the 00021 names of its contributors may be used to endorse or promote products 00022 derived from this software without specific prior written permission. 00023 00024 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY 00025 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 00026 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 00027 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY 00028 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 00029 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 00030 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 00031 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 00032 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 00033 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00034 */ 00035 /**************************************************************************/ 00036 00037 #include "Pokitto_settings.h " 00038 #include "PokittoCore.h " 00039 #include "PokittoConsole.h " 00040 #include "PokittoFonts.h " 00041 #include "PokittoTimer.h " 00042 #include "PokittoLogos.h " 00043 #include <stdlib.h> 00044 00045 #ifndef DISABLEAVRMIN 00046 #define max(a,b) ((a)>(b)?(a):(b)) 00047 #endif // DISABLEAVRMIN 00048 00049 char selectedfile[25]; 00050 00051 //#define F 00052 #ifdef __ARMCC_VERSION 00053 typedef void (*func_t)(void); 00054 #endif 00055 00056 #ifndef POK_SIM 00057 #include "iap.h" 00058 /** start the user application 00059 * https://community.nxp.com/thread/417695 00060 * 00061 */ 00062 void start_application(unsigned long app_link_location){ 00063 //asm(" ldr sp, [r0,#0]"); 00064 //asm(" ldr pc, [r0,#4]"); 00065 //This code is not valid for the Cortex-m0+ instruction set. 00066 // The equivalent for this (as used by the KL26) is 00067 __disable_irq();// Start by disabling interrupts, before changing interrupt vectors 00068 00069 // delete buttons 00070 //pokDeleteButtons(); 00071 00072 // completely kill button interrupts in preparation for reset 00073 LPC_PINT->IENR = 0; 00074 LPC_PINT->IENF = 0; 00075 00076 SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk & ~(SysTick_CTRL_ENABLE_Msk); //disable systick 00077 LPC_SYSCON->PDRUNCFG |= (1 << 10); /* Power-down USB PHY */ 00078 LPC_SYSCON->PDRUNCFG |= (1 << 8); /* Power-down USB PLL */ 00079 00080 // reset clock source to IRC 00081 LPC_SYSCON->MAINCLKUEN = 0x01; /* Update MCLK Clock Source */ 00082 LPC_SYSCON->MAINCLKUEN = 0x00; /* Toggle Update Register */ 00083 while (LPC_SYSCON->MAINCLKUEN & 0x01); /* Wait Until Updated */ 00084 // switch clock selection to IRC 00085 LPC_SYSCON->MAINCLKSEL = 0; /* Select Clock Source */ 00086 LPC_SYSCON->MAINCLKUEN = 0x01; /* Update MCLK Clock Source */ 00087 LPC_SYSCON->MAINCLKUEN = 0x00; /* Toggle Update Register */ 00088 while (LPC_SYSCON->MAINCLKUEN & 0x01); /* Wait Until Updated */ 00089 //disable PLL clock output 00090 LPC_SYSCON->SYSPLLCLKUEN = 0; 00091 while (LPC_SYSCON->SYSPLLCLKUEN & 0x00); 00092 LPC_SYSCON->SYSPLLCTRL = 0; 00093 00094 //kill peripherals 00095 LPC_SYSCON->MAINCLKSEL = 0; 00096 LPC_SYSCON->PRESETCTRL = 0; //disable all peripherals 00097 00098 //power down PLL 00099 volatile uint32_t tmp; 00100 tmp = (LPC_SYSCON->PDRUNCFG & 0x000025FFL); 00101 tmp |= ((1<<7) & 0x000025FFL); 00102 LPC_SYSCON->PDRUNCFG = (tmp | 0x0000C800L); /* Power-down SYSPLL */ 00103 00104 //Chip_Clock_SetMainClockSource(SYSCTL_MAINCLKSRC_IRC); //switch to IRC 00105 00106 // clear all gpio states 00107 LPC_GPIO_PORT->PIN[0] = 0; 00108 LPC_GPIO_PORT->PIN[1] = 0; 00109 LPC_GPIO_PORT->PIN[2] = 0; 00110 00111 SCB->VTOR = app_link_location;//APPL_ADDRESS; /* Change vector table address */ 00112 #ifndef __ARMCC_VERSION 00113 asm(" mov r0, %[address]"::[address] "r" (app_link_location)); 00114 asm(" ldr r1, [r0,#0]"); // get the stack pointer value from the program's reset vector 00115 asm(" mov sp, r1"); // copy the value to the stack pointer 00116 asm(" ldr r0, [r0,#4]"); // get the program counter value from the program's reset vector 00117 asm(" blx r0"); // jump to the' start address 00118 #else 00119 uint32_t *app_loc = (uint32_t*)app_link_location; 00120 __set_MSP (app_loc[0]); 00121 ((func_t)(app_loc[1]))(); 00122 #endif 00123 } 00124 #endif 00125 00126 // returns a random integar between 0 and maxVal 00127 int random(int maxVal) 00128 { 00129 return random( 0, maxVal); 00130 } 00131 00132 // returns a random integar between minVal and maxVal 00133 int random(int minVal, int maxVal) 00134 { 00135 // int rand(void); included by default from newlib 00136 #ifdef OLDINCLUSIVERANDOM 00137 return rand() % (maxVal-minVal+1) + minVal; 00138 #else 00139 return rand() % (maxVal-minVal) + minVal; 00140 #endif 00141 } 00142 00143 using namespace Pokitto; 00144 00145 bool Core::run_state; // this definition needed 00146 00147 /** Components */ 00148 Backlight Core::backlight; 00149 Buttons Core::buttons; 00150 Battery Core::battery; 00151 #if POK_ENABLE_SOUND > 0 00152 Sound Core::sound; 00153 #endif 00154 Display Core::display; 00155 00156 //GB Related 00157 uint8_t Core::startMenuTimer; 00158 uint8_t Core::timePerFrame; 00159 uint32_t Core::nextFrameMillis; 00160 uint32_t Core::frameCount; 00161 const char* Core::popupText; 00162 uint8_t Core::popupTimeLeft; 00163 uint16_t Core::frameDurationMicros; 00164 uint32_t Core::frameStartMicros, Core::frameEndMicros; 00165 uint8_t Core::volbar_visible=0; 00166 00167 uint32_t Core::fps_counter; 00168 bool Core::fps_counter_updated; 00169 uint32_t Core::fps_refreshtime; 00170 uint32_t Core::fps_frameCount; 00171 00172 Core::Core() { 00173 00174 } 00175 00176 00177 int Core::updateLoader (uint32_t version, uint32_t jumpaddress) { 00178 #ifndef POK_SIM 00179 uint32_t counter=0; 00180 uint8_t data[256]; 00181 /** prepare the flash writing **/ 00182 float progress=0; 00183 int opg=-1; 00184 uint32_t fsize=0; 00185 fileEnd(); // 00186 fsize = fileGetPosition(); 00187 if (fsize>0x40000-jumpaddress) fsize = 0x40000-jumpaddress; // shouldn't happen!! 00188 fileRewind(); 00189 display.println("PLEASE WAIT"); 00190 while (1) { 00191 //if (counter >= fsize-0x200) { 00192 // display.println("gotcha"); 00193 //} 00194 if (counter >= fsize) { 00195 break; 00196 } 00197 opg=progress; 00198 if (fileReadBytes(&data[0],0x100)<0x100) { 00199 if (fsize-counter>0x100) { 00200 display.println("ERROR READING LOA.DER FILE"); 00201 return 1; // 1 means error 00202 } 00203 } 00204 if (CopyPageToFlash(jumpaddress+counter,data)) { 00205 display.println("FLASH WRITE ERROR"); 00206 return 1; 00207 } else { 00208 counter += 0x100; 00209 display.print("."); 00210 } 00211 } 00212 #endif // POK_SIM 00213 return 0; //success 00214 } 00215 00216 void Core::showWarning() { 00217 display.enableDirectPrinting(true); 00218 display.directbgcolor = COLOR_BLACK; 00219 display.clearLCD(); 00220 display.directcolor = COLOR_RED; 00221 display.setFont(fntC64UIGfx); 00222 display.adjustCharStep = 0; 00223 display.adjustLineStep = 0; 00224 display.setCursor(10*8,9); 00225 display.print("WARNING!"); 00226 display.directcolor = COLOR_WHITE; 00227 display.setCursor(5*8,4*9); 00228 display.print("LOUD SOUND THROUGH"); 00229 display.setCursor(2*8,5*9); 00230 display.print("HEADPHONES COULD DAMAGE"); 00231 display.setCursor(7*8,6*9); 00232 display.print("YOUR HEARING."); 00233 display.setCursor(5*8,8*9); 00234 display.print("USE "); display.directcolor = COLOR_GREEN; 00235 display.print("0-100% VOLUME"); 00236 display.directcolor = COLOR_WHITE; 00237 display.setCursor(5*8,9*9); 00238 display.print("FOR LISTENING WITH"); 00239 display.setCursor(8*8,10*9); 00240 display.print("HEADPHONES"); 00241 display.setCursor(5*8,12*9); 00242 display.print("USE "); display.directcolor = COLOR_RED; 00243 display.print("> 100% VOLUME"); display.directcolor = COLOR_GREEN; 00244 display.directcolor = COLOR_WHITE; 00245 display.setCursor(1*8,13*9); 00246 display.print("ONLY FOR LISTENING VIA THE"); 00247 display.setCursor(5*8,14*9); 00248 display.print("BUILT-IN SPEAKER"); 00249 display.setCursor(5*8,17*9); 00250 display.print("PRESS ");display.directcolor = COLOR_GREEN; 00251 display.print("C ");display.directcolor = COLOR_WHITE; 00252 display.print("TO ACCEPT"); 00253 while (!buttons.cBtn()) { 00254 wait(100); 00255 } 00256 display.clearLCD(); 00257 display.enableDirectPrinting(false); 00258 } 00259 00260 void Core::jumpToLoader() { 00261 //display.setFont(font5x7); 00262 //display.adjustCharStep=1; 00263 //display.adjustLineStep=2; 00264 display.fontSize=1; 00265 display.directbgcolor=COLOR_BLACK; 00266 display.directcolor=COLOR_GREEN; 00267 display.clearLCD(); 00268 display.setCursor(0,0); 00269 display.enableDirectPrinting(true); 00270 #ifdef POK_SIM 00271 display.println("LOADER IS NOT AVAILABLE ON THE SIMULATOR. PRESS A TO RETURN."); 00272 #else 00273 uint32_t* bootinfo; 00274 uint32_t bootversion=0, sdversion=0, sdjump=0; 00275 bool flashloader=false, checkforboot=true; 00276 //check for loa.der on SD card 00277 #if POK_ENABLE_LOADER_UPDATES > 0 00278 pokInitSD(); 00279 if (fileOpen("LOA.DER", FILE_MODE_BINARY)==0) { 00280 //LOA.DER found on SD 00281 fileEnd(); // go to end 00282 fileSeekRelative(-8); //rewind 8 bytes 00283 uint32_t* tptr = &sdversion; 00284 fileReadBytes((uint8_t*)tptr,4); //read version number of loader on SD card 00285 tptr = &sdjump; 00286 fileReadBytes((uint8_t*)tptr,4); //read jump address of loader on sd card 00287 fileRewind(); 00288 } 00289 #endif 00290 //now start searching for bootkey 00291 while (checkforboot) 00292 { 00293 checkforboot=false; flashloader=false; 00294 bootinfo = (uint32_t*)0x3FFF4; 00295 if (*bootinfo != 0xB007AB1E) bootinfo = (uint32_t*)0x3FF04; //allow couple of alternative locations 00296 if (*bootinfo != 0xB007AB1E) bootinfo = (uint32_t*)0x3FE04; //allow couple of alternative locations 00297 if (*bootinfo != 0xB007AB1E) bootinfo = (uint32_t*)0x3F004; //for futureproofing 00298 if (*bootinfo != 0xB007AB1E) { 00299 // no bootkey found at all 00300 display.directcolor=COLOR_YELLOW; 00301 display.println("NO LOADER INSTALLED"); 00302 if (sdversion==0 || sdjump < 0x38000) { 00303 //file open of loader failed 00304 display.println("NO VALID LOA.DER ON SD"); 00305 display.println(""); 00306 display.directcolor=COLOR_GREEN; 00307 display.println("PUT LOA.DER ON SD & REBOOT"); 00308 } else flashloader=true; 00309 } else { 00310 //loader was found 00311 //check if we should update the loader 00312 display.directcolor=COLOR_CYAN; 00313 display.print("LOADER V."); 00314 display.directcolor=COLOR_WHITE; 00315 display.println(*(bootinfo+1)); 00316 #if POK_ENABLE_LOADER_UPDATES 00317 if (sdversion>(*(bootinfo+1))) flashloader=true; 00318 else start_application(*(bootinfo+2)); //never returns 00319 #else 00320 start_application(*(bootinfo+2)); //never returns 00321 #endif 00322 } 00323 // update loader if it was requested 00324 if(flashloader) { 00325 display.directcolor=COLOR_MAGENTA; 00326 display.print("NEW LOADER ON SD V."); 00327 display.directcolor=COLOR_WHITE; 00328 display.println(sdversion); 00329 display.directcolor=COLOR_GREEN; 00330 display.println("UPDATE LOADER?\n(UP=YES, DOWN=CANCEL)"); 00331 while(1) { 00332 if (buttons.upBtn()) { 00333 if (updateLoader(sdversion,sdjump)) { 00334 display.println("PUT LOA.DER ON SD AND RETRY"); 00335 } else { 00336 display.println("SUCCESS!!"); 00337 checkforboot=true; //recheck 00338 } 00339 break; 00340 } 00341 if (buttons.downBtn()) return; 00342 } 00343 } // if flashloader 00344 } // while checkforboot 00345 #endif // POK_SIM 00346 while (!buttons.aBtn()) { 00347 buttons.pollButtons(); 00348 if (buttons.aBtn()) { 00349 while (buttons.aBtn()) { 00350 buttons.pollButtons(); 00351 } 00352 return; 00353 } 00354 } 00355 } 00356 00357 void Core::askLoader() { 00358 display.enableDirectPrinting(true); 00359 display.directbgcolor = COLOR_BLACK; 00360 display.clearLCD(); 00361 display.directcolor = COLOR_RED; 00362 display.setFont(fntC64UIGfx); 00363 display.fontSize=1; 00364 display.adjustCharStep = 0; 00365 display.adjustLineStep = 0; 00366 display.directcolor=COLOR_GREEN; 00367 display.set_cursor(12*8,6*8); 00368 display.print("ijkl"); 00369 display.set_cursor(12*8,7*8); 00370 display.print("mnop"); 00371 display.set_cursor(12*8,8*8); 00372 display.print("qrst"); 00373 display.set_cursor(12*8,9*8); 00374 display.print("uvwx"); 00375 display.set_cursor(5*8,12*8); 00376 display.print("PRESS"); 00377 display.directcolor=COLOR_WHITE; 00378 display.print(" C "); 00379 display.directcolor=COLOR_GREEN; 00380 display.print("FOR LOADER"); 00381 display.directcolor=COLOR_WHITE; 00382 display.fontSize=2; 00383 int countd = 0; 00384 //#ifndef POK_SIM 00385 //read countdown time from settings 00386 countd = eeprom_read_byte((uint16_t*)EESETTINGS_LOADERWAIT); 00387 //#endif 00388 if (countd<=0 || countd > 5) countd=3; 00389 uint16_t c2 = getTime(); 00390 while (countd) { 00391 buttons.pollButtons(); 00392 display.set_cursor(13*8,15*8); 00393 display.print(countd); 00394 if (getTime()>uint32_t(c2+1000)) { 00395 c2=getTime(); 00396 countd--; 00397 } 00398 if (cBtn()) {while (cBtn()) buttons.pollButtons();jumpToLoader();countd=0;} 00399 if (aBtn()) {while (aBtn()) buttons.pollButtons();countd=0;} 00400 if (bBtn()) {while (bBtn()) buttons.pollButtons();countd=0;} 00401 } 00402 display.fontSize=1; 00403 display.clearLCD(); 00404 display.enableDirectPrinting(false); 00405 } 00406 00407 00408 void Core::drawvolbar(int x, int y, int level, bool text) { 00409 uint16_t oldcol = display.directcolor; 00410 level = level >> 5; 00411 if (text) display.directRectangle(0,0,50,50,COLOR_BLACK); 00412 if (level<4) display.directcolor = COLOR_GREEN; 00413 if (level==4) display.directcolor = COLOR_YELLOW; 00414 if (level>4) display.directcolor = COLOR_RED; 00415 00416 if (text) { 00417 bool temp = display.isDirectPrintingEnabled(); 00418 display.enableDirectPrinting(true); 00419 display.print(x-1,y-20,(int)sound.getVolume()); 00420 display.print(" "); 00421 display.enableDirectPrinting(temp); 00422 } 00423 if (level<1) display.directcolor = COLOR_GRAY_80; 00424 display.directBitmap(x,y,Pokitto_volumebar,1,1); 00425 if (level<2) display.directcolor = COLOR_GRAY_80; 00426 display.directBitmap(x+8,y,Pokitto_volumebar,1,1); 00427 display.directBitmap(x+8,y-4,Pokitto_volumebar,1,1); 00428 if (level<3) display.directcolor = COLOR_GRAY_80; 00429 display.directBitmap(x+16,y,Pokitto_volumebar,1,1); 00430 display.directBitmap(x+16,y-4,Pokitto_volumebar,1,1); 00431 display.directBitmap(x+16,y-8,Pokitto_volumebar,1,1); 00432 if (level<4) { 00433 display.directcolor = COLOR_GRAY_80; 00434 } 00435 display.directBitmap(x+24,y,Pokitto_volumebar,1,1); 00436 display.directBitmap(x+24,y-4,Pokitto_volumebar,1,1); 00437 display.directBitmap(x+24,y-8,Pokitto_volumebar,1,1); 00438 display.directBitmap(x+24,y-12,Pokitto_volumebar,1,1); 00439 00440 if (level<5) { 00441 display.directcolor = COLOR_GRAY_80; 00442 } 00443 display.directBitmap(x+32,y,Pokitto_volumebar,1,1); 00444 display.directBitmap(x+32,y-4,Pokitto_volumebar,1,1); 00445 display.directBitmap(x+32,y-8,Pokitto_volumebar,1,1); 00446 display.directBitmap(x+32,y-12,Pokitto_volumebar,1,1); 00447 display.directBitmap(x+32,y-16,Pokitto_volumebar,1,1); 00448 00449 if (level<6) { 00450 display.directcolor = COLOR_GRAY_80; 00451 } 00452 display.directBitmap(x+40,y,Pokitto_volumebar,1,1); 00453 display.directBitmap(x+40,y-4,Pokitto_volumebar,1,1); 00454 display.directBitmap(x+40,y-8,Pokitto_volumebar,1,1); 00455 display.directBitmap(x+40,y-12,Pokitto_volumebar,1,1); 00456 display.directBitmap(x+40,y-16,Pokitto_volumebar,1,1); 00457 display.directBitmap(x+40,y-20,Pokitto_volumebar,1,1); 00458 display.directcolor = oldcol; 00459 } 00460 00461 00462 #ifdef POK_SIM 00463 #define VINCMULT 0.9f 00464 #else 00465 #define VINCMULT 50 00466 #endif //POK_SIM 00467 void Core::setVolLimit() { 00468 display.enableDirectPrinting(true); 00469 display.adjustCharStep = 0; 00470 //sound.setMaxVol(VOLUME_HEADPHONE_MAX); 00471 int dstate=1; 00472 bool wipe = true; 00473 float vol = sound.getVolume(); 00474 //#ifndef POK_SIM 00475 vol=eeprom_read_byte((uint16_t*)EESETTINGS_VOL); 00476 Pokitto::Sound::globalVolume=vol; 00477 //#endif 00478 if (vol>VOLUME_HEADPHONE_MAX) sound.setMaxVol(VOLUME_SPEAKER_MAX); 00479 else sound.setMaxVol(VOLUME_HEADPHONE_MAX); 00480 #ifdef PRODUCTIONTESTING 00481 vol=170; 00482 sound.setMaxVol(VOLUME_SPEAKER_MAX); 00483 #endif 00484 //for (uint8_t t=0;t<=vol;t++) { 00485 // sound.setVolume(t); 00486 //} 00487 sound.setVolume(vol/4); 00488 sound.setVolume(vol/2); 00489 sound.setVolume(vol); //prevent "crack" by gradually increasing volume 00490 discrete_vol = ((int)vol>>5); // fix "shows zero" in volume slider bug 00491 volbar_visible=0; 00492 int countd=0; 00493 //#ifndef POK_SIM 00494 //read countdown time from settings 00495 countd = eeprom_read_byte((uint16_t*)EESETTINGS_VOLWAIT); 00496 //#endif 00497 if (countd<=0 || countd > 10) countd=0xFFFF; 00498 #ifdef PRODUCTIONTESTING 00499 countd=2; 00500 #endif 00501 uint16_t c2 = getTime(); 00502 while (core.isRunning() && dstate && countd){ 00503 if (getTime()>uint32_t(c2+1000)) { 00504 c2=getTime(); 00505 if (countd<0xFFFF) countd--; 00506 } 00507 switch (dstate) { 00508 case 1: 00509 //redraw 00510 if (wipe) { 00511 display.clearLCD(); 00512 display.directcolor = COLOR_WHITE; 00513 display.setCursor(4*8,2*8); 00514 display.print("SELECT VOLUME LIMIT"); 00515 display.setCursor(5*8,17*9); 00516 display.print("PRESS "); 00517 display.directcolor = COLOR_GREEN; 00518 display.print("A"); 00519 display.directcolor = COLOR_WHITE; 00520 display.print(" TO ACCEPT"); 00521 display.directcolor = COLOR_GREEN; 00522 // draw frame below first 00523 display.setCursor(0,11*8); 00524 display.println(" abbbbbbbbbbbbbbbbbbbbbbbc"); 00525 display.println(" | |"); 00526 display.println(" | |"); 00527 display.println(" | |"); 00528 display.println(" | |"); 00529 display.println(" dbbbbbbbbbbbbbbbbbbbbbbbe"); 00530 } // wipe = true 00531 display.setCursor(6*8,17*9); 00532 if (discrete_vol<4) display.directcolor = COLOR_WHITE; 00533 else display.directcolor = COLOR_RED; 00534 display.directBitmap(21*8-4,6*8,Pokitto_headphones,1,2); 00535 display.setCursor(3*8,6*8+6); 00536 display.print("HEADPHONES"); 00537 display.setCursor(3*8,8*8+2); 00538 if (discrete_vol>3) display.print("TOO LOUD!"); 00539 else display.print("OK "); 00540 display.directcolor = COLOR_GREEN; 00541 display.directBitmap(21*8-4,12*8,Pokitto_speaker,1,2); 00542 display.setCursor(3*8,12*8+6); 00543 display.print("VOLUME MAX"); 00544 display.setCursor(3*8,14*8+2); 00545 //tvol = (vol/float(VOLUME_HEADPHONE_MAX))*100; 00546 //if (tvol > 100 && tvol < 120) tvol=100; 00547 //if (sound.getVolume()-5>VOLUME_HEADPHONE_MAX) { display.directcolor=COLOR_RED;} 00548 if ((sound.getVolume()>>5)>3) { display.directcolor=COLOR_RED;} 00549 else display.directcolor=COLOR_GREEN; 00550 if (discrete_vol==4) display.directcolor=COLOR_YELLOW; 00551 if (discrete_vol==7) discrete_vol=6; 00552 display.print((int)discrete_vol); 00553 //display.print(int(tvol)); 00554 display.print(" "); 00555 display.directcolor=COLOR_GREEN; 00556 drawvolbar(14*8,14*8+4+3,sound.getVolume(),false); 00557 //display.setCursor(1,10); 00558 //display.print(vol); 00559 dstate=2; break; 00560 case 2: 00561 #ifndef POK_SIM 00562 buttons.pollButtons(); 00563 #endif // POK_SIM 00564 buttons.update(); 00565 if (aBtn()) {dstate=0;break;} 00566 if (buttons.pressed(BTN_RIGHT)) { 00567 countd=0xFFFF; //disable countdown 00568 /*if (vol >= VOLUME_HEADPHONE_MAX && vol < VOLUME_HEADPHONE_MAX+1 ) vol += 0.00025f*VINCMULT; 00569 else if (vol >= VOLUME_HEADPHONE_MAX) vol += 0.25f*VINCMULT; 00570 else vol += 0.05f*VINCMULT; 00571 if (vol > VOLUME_HEADPHONE_MAX + 20) { 00572 sound.setMaxVol(VOLUME_SPEAKER_MAX); 00573 } 00574 if (vol > VOLUME_SPEAKER_MAX) vol=VOLUME_SPEAKER_MAX; 00575 sound.setVolume(vol);*/ 00576 sound.volumeUp(); 00577 dstate=1; wipe=false; 00578 break; 00579 } 00580 if (buttons.pressed(BTN_LEFT)) { 00581 countd=0xFFFF; //disable countdown 00582 /*if (vol >= VOLUME_HEADPHONE_MAX) vol -= 0.25f*VINCMULT; 00583 else vol -= 0.05f*VINCMULT; 00584 if (vol <= VOLUME_HEADPHONE_MAX) sound.setMaxVol(VOLUME_HEADPHONE_MAX); 00585 if (vol < 0) vol=0; 00586 sound.setVolume(vol);*/ 00587 sound.volumeDown(); 00588 dstate=1; wipe=false; 00589 break; 00590 } 00591 break; 00592 } 00593 } 00594 vol = sound.getVolume(); 00595 //#ifndef POK_SIM 00596 if (vol != eeprom_read_byte((uint16_t*)EESETTINGS_VOL)) eeprom_write_byte((uint16_t*)EESETTINGS_VOL,(uint8_t)vol); 00597 //#endif 00598 sound.setVolume(vol); 00599 //sound.volumeUp(); 00600 display.setCursor(0,0); 00601 } 00602 00603 void Core::begin() { 00604 00605 init(); // original functions 00606 timePerFrame = POK_FRAMEDURATION; 00607 //nextFrameMillis = 0; 00608 //frameCount = 0; 00609 frameEndMicros = 1; 00610 startMenuTimer = 255; 00611 //read default settings from flash memory (set using settings.hex) 00612 readSettings(); 00613 //init everything 00614 backlight.begin(); 00615 backlight.set(BACKLIGHT_MAX); 00616 buttons.begin(); 00617 buttons.update(); 00618 battery.begin(); 00619 display.begin(); 00620 00621 char logoFlag = eeprom_read_byte((uint16_t*)EESETTINGS_SKIPINTRO); 00622 if( logoFlag&2 ){ // toggle flag set, change value for next boot 00623 eeprom_write_byte((uint16_t*)EESETTINGS_SKIPINTRO, !(logoFlag&1)); 00624 } 00625 logoFlag &= 1; 00626 00627 #if POK_DISPLAYLOGO 00628 #if PROJ_DEVELOPER_MODE != 1 00629 if( logoFlag == 0 ){ 00630 showLogo(); 00631 } 00632 #endif // PROJ_DEVELOPER_MODE 00633 #endif // POK_DISPLAYLOGO 00634 00635 00636 display.enableDirectPrinting(true); 00637 display.directbgcolor = COLOR_BLACK; 00638 display.clearLCD(); 00639 display.setFont(fntC64UIGfx); 00640 00641 display.enableDirectPrinting(true); 00642 display.directbgcolor = COLOR_BLACK; 00643 display.directcolor = COLOR_GREEN; 00644 display.setFont(fntC64UIGfx); 00645 display.adjustCharStep=0; 00646 display.adjustLineStep=1; 00647 #ifdef JUSTLOAD 00648 jumpToLoader(); 00649 #endif 00650 00651 #ifndef DISABLE_LOADER 00652 #if PROJ_DEVELOPER_MODE != 1 00653 if( logoFlag == 0 ){ 00654 askLoader(); 00655 } 00656 #endif // PROJ_DEVELOPER_MODE 00657 #endif 00658 00659 #if PROJ_DEVELOPER_MODE==1 00660 sound.setMaxVol(VOLUME_SPEAKER_MAX); 00661 sound.setVolume(VOLUME_SPEAKER_MAX); 00662 #else 00663 if( logoFlag == 0 ){ 00664 //showWarning(); 00665 setVolLimit(); 00666 display.clear(); 00667 display.update(); 00668 00669 while(buttons.states[BTN_A]) 00670 { 00671 buttons.update(); 00672 } 00673 }else{ 00674 sound.setVolume(sound.getVolume());//make sure we're at set volume before continue 00675 } 00676 00677 #endif 00678 00679 display.enableDirectPrinting(false); 00680 display.adjustCharStep=1; 00681 display.adjustLineStep=1; 00682 display.fontSize=1; 00683 display.textWrap=true; 00684 #if POK_GAMEBUINO_SUPPORT > 0 00685 display.setFont(font5x7); 00686 #else 00687 display.setFont(fontC64); 00688 #endif 00689 #if POK_ENABLE_SOUND > 0 00690 sound.begin(); 00691 00692 //mute when B is held during start up or if battery is low 00693 battery.update(); 00694 if(buttons.pressed(BTN_B)){ 00695 sound.setVolume(0); 00696 } 00697 else{ //play the startup sound on each channel for it to be louder 00698 #if POK_GBSOUND > 0 00699 #if(NUM_CHANNELS > 0) 00700 sound.playPattern(startupSound, 0); 00701 #endif 00702 #if(NUM_CHANNELS > 1) 00703 sound.playPattern(startupSound, 1); 00704 #endif 00705 #if(NUM_CHANNELS > 2) 00706 sound.playPattern(startupSound, 2); 00707 #endif 00708 #if(NUM_CHANNELS > 3) 00709 sound.playPattern(startupSound, 3); 00710 #endif 00711 #endif // POK_GBSOUND 00712 } 00713 #endif // POK ENABLE_SOUND 00714 } 00715 00716 void Core::init() { 00717 run_state = true; 00718 display.enableDirectPrinting(false); 00719 display.setFont(DEFAULT_FONT); 00720 initClock(); 00721 initGPIO(); 00722 initButtons(); 00723 initRandom(); 00724 //initAudio(); 00725 //initDisplay(); 00726 } 00727 00728 void Core::init(uint8_t switches) { 00729 run_state = true; 00730 display.enableDirectPrinting(false); 00731 display.setFont(DEFAULT_FONT); 00732 initClock(); 00733 initGPIO(); 00734 initButtons(); 00735 initRandom(); 00736 //initAudio(); 00737 //initDisplay(); 00738 } 00739 00740 void Core::initButtons() { 00741 #ifndef POK_SIM 00742 Pokitto::initButtons(); 00743 #endif 00744 } 00745 00746 bool Core::isRunning() { 00747 #ifdef POK_SIM 00748 run_state = simulator.isRunning(); 00749 #endif // POK_SIM 00750 return run_state; 00751 } 00752 00753 void Core::initDisplay() { 00754 #if POK_DISPLAYLOGO > 0 00755 showLogo(); 00756 #endif 00757 #if POK_USE_CONSOLE > 0 00758 console.AddMessage(MSOURCE_LCD,MSG_INIT_OK); 00759 #endif 00760 } 00761 00762 void Core::showLogo() { 00763 uint32_t now; 00764 uint8_t state=0; //jump directly to logo, bypass teeth 00765 uint16_t i=0; 00766 uint16_t sc; 00767 while (state < 255/6) { 00768 now=getTime(); 00769 if (now>refreshtime) { 00770 refreshtime=now+30; 00771 switch (state) { 00772 case 0: 00773 /** POKITTO CLEAN **/ 00774 display.directbgcolor = COLOR_BLACK; 00775 display.fillLCD(display.directbgcolor); 00776 sc = COLOR_BLACK; 00777 state++; 00778 break; 00779 case 1: 00780 /** POKITTO FADE IN **/ 00781 display.directcolor = display.interpolateColor(sc, COLOR_GREEN, i); 00782 display.directBitmap(POK_LCD_W/2 - (*Pokitto_logo/2),POK_LCD_H/2-(*(Pokitto_logo+1)/2),Pokitto_logo,1,1); 00783 i += 28; 00784 if (i>=0xFF) { state++; i=0;} 00785 break; 00786 case 2: 00787 /** POKITTO WAIT **/ 00788 display.directcolor = COLOR_GREEN; 00789 display.directBitmap(POK_LCD_W/2 - (*Pokitto_logo/2),POK_LCD_H/2-(*(Pokitto_logo+1)/2),Pokitto_logo,1,1); 00790 i+= 0x3F; 00791 if (i>0x3FF) state = 255; 00792 break; 00793 } 00794 if(buttons.aBtn()) state=255; 00795 } 00796 } 00797 } 00798 00799 void Core::readSettings() { 00800 // ToDo 00801 /*display.contrast = SCR_CONTRAST; 00802 backlight.backlightMin = BACKLIGHT_MIN; 00803 backlight.backlightMax = BACKLIGHT_MAX; 00804 backlight.ambientLightMin = AMBIENTLIGHT_MIN; 00805 backlight.ambientLightMax = AMBIENTLIGHT_MAX; 00806 */ 00807 sound.setMaxVol(VOLUME_HEADPHONE_MAX); 00808 sound.globalVolume = VOLUME_STARTUP; 00809 00810 startMenuTimer = START_MENU_TIMER; 00811 /* 00812 battery.thresolds[0] = BAT_LVL_CRITIC; 00813 battery.thresolds[1] = BAT_LVL_LOW; 00814 battery.thresolds[2] = BAT_LVL_MED; 00815 battery.thresolds[3] = BAT_LVL_FULL;*/ 00816 } 00817 00818 void Core::titleScreen(const char* name){ 00819 titleScreen(name, 0); 00820 } 00821 00822 void Core::titleScreen(const uint8_t* logo){ 00823 titleScreen((""), logo); 00824 } 00825 00826 void Core::titleScreen(){ 00827 titleScreen(("")); 00828 } 00829 00830 void Core::titleScreen(const char* name, const uint8_t *logo){ 00831 display.setFont(font5x7); 00832 while(buttons.aBtn()) wait(10); //don't accidentally skip menu 00833 if(startMenuTimer){ 00834 display.fontSize = 1; 00835 display.textWrap = false; 00836 display.persistence = false; 00837 battery.show = false; 00838 display.setColor(BLACK); 00839 while(isRunning()){ 00840 if(update()){ 00841 uint8_t logoOffset = name[0]?display.fontHeight:0; //add an offset the logo when there is a name to display 00842 //draw graphics 00843 display.setColorDepth(1); 00844 display.setColor(3); 00845 //display.drawBitmap(0,0, gamebuinoLogo); 00846 display.setColor(1); 00847 if(logo){ 00848 display.drawBitmap(0, 12+logoOffset, logo); 00849 } 00850 display.cursorX = 0; 00851 display.cursorY = 12; 00852 display.print(name); 00853 00854 //A button 00855 display.cursorX = LCDWIDTH - display.fontWidth*3 -1; 00856 display.cursorY = LCDHEIGHT - display.fontHeight*3 - 3; 00857 if((frameCount/16)%2) 00858 display.println(("\25 \20")); 00859 else 00860 display.println(("\25\20 ")); 00861 //B button 00862 display.cursorX = LCDWIDTH - display.fontWidth*3 - 1; 00863 display.cursorY++; 00864 if(sound.globalVolume) 00865 display.println(("\26\23\24")); 00866 else 00867 display.println(("\26\23x")); 00868 //C button 00869 display.cursorX = LCDWIDTH - display.fontWidth*3 - 1; 00870 display.cursorY++; 00871 //display.println(F("\27SD")); 00872 00873 //toggle volume when B is pressed 00874 if(buttons.pressed(BTN_B)){ 00875 sound.setVolume(sound.getVolume() + 1); 00876 sound.playTick(); 00877 } 00878 //leave the menu 00879 if(buttons.pressed(BTN_A) || ((frameCount>=startMenuTimer)&&(startMenuTimer != 255))){ 00880 startMenuTimer = 255; //don't automatically skip the title screen next time it's displayed 00881 sound.stopPattern(0); 00882 sound.playOK(); 00883 break; 00884 } 00885 //flash the loader 00886 //if(buttons.pressed(BTN_C)) 00887 // ToDo changeGame(); 00888 } 00889 } 00890 battery.show = true; 00891 } 00892 } 00893 00894 /** 00895 * Update all the subsystems, like graphics, audio, events, etc. 00896 * Note: the update rect is used for drawing only part of the screen buffer to LCD. Because of speed optimizations, 00897 * the x, y, and width of the update rect must be dividable by 4 pixels, and the height must be dividable by 8 pixels. 00898 * The update rect is currently used for 220x176, 4 colors, screen mode only. 00899 * @param useDirectMode True, if only direct screen drawing is used. False, if the screen buffer is drawn. Note: If sprites are enabled, they are drawn in both modes. 00900 * @param updRectX The update rect. 00901 * @param updRectY The update rect. 00902 * @param updRectW The update rect. 00903 * @param updRectH The update rect. 00904 */ 00905 bool Core::update(bool useDirectMode, uint8_t updRectX, uint8_t updRectY, uint8_t updRectW, uint8_t updRectH) { 00906 00907 #if POK_STREAMING_MUSIC 00908 sound.updateStream(); 00909 #endif 00910 00911 #ifdef PROJ_BUTTONS_POLLING_ONLY 00912 buttons.pollButtons(); 00913 #endif 00914 00915 uint32_t now = getTime(); 00916 if ((((nextFrameMillis - now)) > timePerFrame) && frameEndMicros) { //if time to render a new frame is reached and the frame end has ran once 00917 nextFrameMillis = now + timePerFrame; 00918 frameCount++; 00919 00920 frameEndMicros = 0; 00921 backlight.update(); 00922 buttons.update(); 00923 battery.update(); 00924 00925 // FPS counter 00926 #if defined(PROJ_USE_FPS_COUNTER) || defined(PROJ_SHOW_FPS_COUNTER) 00927 const uint32_t fpsInterval_ms = 1000*3; 00928 00929 fps_frameCount++; 00930 if (now > fps_refreshtime) { 00931 fps_counter = (1000*fps_frameCount) / (now - fps_refreshtime + fpsInterval_ms); 00932 fps_refreshtime = now + fpsInterval_ms; 00933 fps_frameCount = 0; 00934 fps_counter_updated = true; 00935 } 00936 #endif 00937 00938 return true; 00939 00940 } else { 00941 if (!frameEndMicros) { //runs once at the end of the frame 00942 #if POK_ENABLE_SOUND > 0 00943 sound.updateTrack(); 00944 sound.updatePattern(); 00945 sound.updateNote(); 00946 #endif 00947 updatePopup(); 00948 displayBattery(); 00949 00950 display.update(useDirectMode, updRectX, updRectY, updRectW, updRectH); //send the buffer to the screen 00951 00952 frameEndMicros = 1; //jonne 00953 00954 } 00955 return false; 00956 } 00957 } 00958 00959 void Core::displayBattery(){ 00960 #if (ENABLE_BATTERY > 0) 00961 //display.setColor(BLACK, WHITE); 00962 uint8_t ox,oy; 00963 ox=display.cursorX; 00964 oy=display.cursorY; 00965 display.cursorX = LCDWIDTH-display.fontWidth+1; 00966 display.cursorY = 0; 00967 switch(battery.level){ 00968 case 0://battery critic, power down 00969 sound.stopPattern(); 00970 backlight.set(0); 00971 display.clear(); 00972 display.fontSize = 1; 00973 display.print(("LOW BATTERY\n")); 00974 display.print(battery.voltage); 00975 display.print(("mV\n\nPLEASE\nTURN OFF")); 00976 display.update(); 00977 break; 00978 case 1: //empty battery 00979 if((frameCount % 16) < 8) display.print('\7'); //blinking battery 00980 else display.print('x'); 00981 break; 00982 case 2://low battery 00983 case 3://full battery 00984 case 4://full battery 00985 if(battery.show){ 00986 display.print(char(5+battery.level)); 00987 } 00988 break; 00989 default: 00990 if(battery.show){ 00991 display.print('/'); 00992 } 00993 break; 00994 } 00995 display.cursorX = ox; 00996 display.cursorY = oy; 00997 #endif 00998 } 00999 01000 char* Core::filemenu(char *ext) { 01001 uint8_t oldPersistence = display.persistence; 01002 display.persistence = false; 01003 uint16_t oldpal0=display.palette[0]; 01004 uint16_t oldpal1=display.palette[1]; 01005 uint16_t oldpal2=display.palette[2]; 01006 display.palette[2]=COLOR_GREEN; 01007 display.palette[1]=COLOR_WHITE; 01008 display.palette[0]=COLOR_BLACK; 01009 uint8_t oldbg=display.bgcolor; 01010 uint8_t oldfg=display.color; 01011 display.color=1; 01012 display.bgcolor=0; 01013 01014 int16_t rowh = display.fontHeight + 2; 01015 int8_t activeItem = 0; 01016 int16_t currentTopItem = 0; 01017 int16_t itemsPerScreen = (display.height+1) / rowh; 01018 int16_t numOfItemsFound = 0; 01019 boolean exit = false; 01020 01021 char* txt; 01022 01023 pokInitSD(); 01024 01025 bool updated = true; 01026 while (isRunning()) { 01027 if (update(true)) { 01028 if (buttons.pressed(BTN_A) || buttons.pressed(BTN_B) || buttons.pressed(BTN_C)) { 01029 exit = true; //time to exit menu ! 01030 if (buttons.pressed(BTN_A)) { 01031 sound.playOK(); 01032 } else { 01033 *selectedfile = 0; 01034 sound.playCancel(); 01035 } 01036 updated = true; // update screen 01037 } 01038 if (exit == false) { 01039 if (buttons.repeat(BTN_DOWN,4)) { 01040 if( ++activeItem >= numOfItemsFound ) activeItem = numOfItemsFound - 1; 01041 if( activeItem >= currentTopItem + itemsPerScreen) currentTopItem += itemsPerScreen; // next page 01042 sound.playTick(); 01043 updated = true; // update screen 01044 } 01045 if (buttons.repeat(BTN_UP,4)) { 01046 if( --activeItem < 0 ) activeItem = 0; 01047 if( activeItem < currentTopItem) currentTopItem -= itemsPerScreen; // previous page 01048 sound.playTick(); 01049 updated = true; // update screen 01050 } 01051 01052 } else { //exit : 01053 display.bgcolor=oldbg; 01054 display.color=oldfg; 01055 display.palette[0] = oldpal0; 01056 display.palette[1] = oldpal1; 01057 display.palette[2] = oldpal2; 01058 display.persistence = oldPersistence; 01059 return selectedfile; 01060 } 01061 01062 //draw a fancy menu 01063 display.textWrap = false; 01064 if( updated ) { // update screen? 01065 #if POK_SIM 01066 getFirstFile(ext); 01067 #else 01068 bool isFirstFile = true; 01069 #endif 01070 for (int i = 0; ; i++) { 01071 display.cursorX = 0; 01072 display.invisiblecolor=255; 01073 display.cursorY = (i - currentTopItem ) * rowh; 01074 01075 // read the file name from SD 01076 #ifndef POK_SIM 01077 if(isFirstFile) { 01078 txt = getFirstFile(ext); 01079 isFirstFile = false; 01080 } 01081 else 01082 #endif 01083 01084 txt = getNextFile(ext); 01085 01086 if (txt) { 01087 01088 numOfItemsFound = i+1; 01089 01090 // Draw active line with diffrent backgtound and char color 01091 if (i == activeItem){ 01092 display.cursorX = 3; 01093 display.color=2; 01094 display.fillRect(0, display.cursorY - 2, LCDWIDTH, rowh); 01095 display.setColor(0,2); 01096 } else display.setColor(1,0); 01097 01098 // break loop if going out of screen 01099 if(i >= currentTopItem + itemsPerScreen ) { 01100 break; 01101 } 01102 01103 // Display only if the file is on the current page 01104 if( i >= currentTopItem) { 01105 display.print(display.cursorX, display.cursorY, txt); 01106 if (i == activeItem) 01107 strcpy(selectedfile,txt); 01108 } 01109 } else 01110 break; // break loop as no more files found 01111 01112 display.setColor(1,0); 01113 } // end for 01114 01115 display.update(); 01116 } 01117 updated = false; 01118 } // update 01119 01120 display.setColor(1,0); 01121 } 01122 01123 return 0; 01124 } 01125 01126 char* Core::filemenu() { 01127 return filemenu((char*)""); 01128 } 01129 01130 int8_t Core::menu(const char* const* items, uint8_t length) { 01131 if (display.color>3) display.color=1; 01132 #if (ENABLE_GUI > 0) 01133 display.persistence = false; 01134 int8_t activeItem = 0; 01135 int16_t currentY = display.height; 01136 int16_t targetY = 0, rowh = display.fontHeight + 2; 01137 boolean exit = false; 01138 int8_t answer = -1; 01139 while (isRunning()) { 01140 if (update()) { 01141 if (buttons.pressed(BTN_A) || buttons.pressed(BTN_B) || buttons.pressed(BTN_C)) { 01142 exit = true; //time to exit menu ! 01143 targetY = - display.fontHeight * length - 2; //send the menu out of the screen 01144 if (buttons.pressed(BTN_A)) { 01145 answer = activeItem; 01146 sound.playOK(); 01147 } else { 01148 sound.playCancel(); 01149 } 01150 } 01151 if (exit == false) { 01152 if (buttons.repeat(BTN_DOWN,4)) { 01153 activeItem++; 01154 sound.playTick(); 01155 } 01156 if (buttons.repeat(BTN_UP,4)) { 01157 activeItem--; 01158 sound.playTick(); 01159 } 01160 //don't go out of the menu 01161 if (activeItem == length) activeItem = 0; 01162 if (activeItem < 0) activeItem = length - 1; 01163 01164 targetY = -rowh * activeItem + (rowh+4); //center the menu on the active item 01165 } else { //exit : 01166 if ((currentY - targetY) <= 1) 01167 return (answer); 01168 } 01169 //draw a fancy menu 01170 currentY = (currentY + targetY) / 2; 01171 display.cursorX = 0; 01172 display.cursorY = currentY; 01173 display.textWrap = false; 01174 uint16_t fc,bc; 01175 fc = display.color; 01176 bc = display.bgcolor; 01177 for (byte i = 0; i < length; i++) { 01178 display.cursorY = currentY + rowh * i; 01179 if (i == activeItem){ 01180 display.cursorX = 3; 01181 01182 //display.fillRoundRect(0, currentY + display.fontHeight * activeItem - 2, LCDWIDTH, (display.fontHeight+3), 3); 01183 display.fillRect(0, currentY + rowh * activeItem - 2, LCDWIDTH, (rowh)); 01184 display.setColor(bc,fc); 01185 } else display.setColor(fc,bc); 01186 01187 display.println((char*)*(const unsigned int*)(items+i)); 01188 display.setColor(fc,bc); 01189 } 01190 01191 } 01192 } 01193 #else 01194 return 0; 01195 #endif 01196 return 0; 01197 } 01198 01199 void Core::keyboard(char* text, uint8_t length) { 01200 #if (ENABLE_GUI > 0) 01201 display.persistence = false; 01202 //memset(text, 0, length); //clear the text 01203 text[length-1] = '\0'; 01204 //active character in the typing area 01205 int8_t activeChar = 0; 01206 //selected char on the keyboard 01207 int8_t activeX = 0; 01208 int8_t activeY = 2; 01209 //position of the keyboard on the screen 01210 int8_t currentX = LCDWIDTH; 01211 int8_t currentY = LCDHEIGHT; 01212 int8_t targetX = 0; 01213 int8_t targetY = 0; 01214 01215 while (1) { 01216 if (update()) { 01217 //move the character selector 01218 if (buttons.repeat(BTN_DOWN, 4)) { 01219 activeY++; 01220 sound.playTick(); 01221 } 01222 if (buttons.repeat(BTN_UP, 4)) { 01223 activeY--; 01224 sound.playTick(); 01225 } 01226 if (buttons.repeat(BTN_RIGHT, 4)) { 01227 activeX++; 01228 sound.playTick(); 01229 } 01230 if (buttons.repeat(BTN_LEFT, 4)) { 01231 activeX--; 01232 sound.playTick(); 01233 } 01234 //don't go out of the keyboard 01235 if (activeX == KEYBOARD_W) activeX = 0; 01236 if (activeX < 0) activeX = KEYBOARD_W - 1; 01237 if (activeY == KEYBOARD_H) activeY = 0; 01238 if (activeY < 0) activeY = KEYBOARD_H - 1; 01239 //set the keyboard position on screen 01240 targetX = -(display.fontWidth+1) * activeX + LCDWIDTH / 2 - 3; 01241 targetY = -(display.fontHeight+1) * activeY + LCDHEIGHT / 2 - 4 - display.fontHeight; 01242 //smooth the keyboard displacement 01243 currentX = (targetX + currentX) / 2; 01244 currentY = (targetY + currentY) / 2; 01245 //type character 01246 if (buttons.pressed(BTN_A)) { 01247 if (activeChar < (length-1)) { 01248 byte thisChar = activeX + KEYBOARD_W * activeY; 01249 if((thisChar == 0)||(thisChar == 10)||(thisChar == 13)) //avoid line feed and carriage return 01250 continue; 01251 text[activeChar] = thisChar; 01252 text[activeChar+1] = '\0'; 01253 } 01254 activeChar++; 01255 sound.playOK(); 01256 if (activeChar > length) 01257 activeChar = length; 01258 } 01259 //erase character 01260 if (buttons.pressed(BTN_B)) { 01261 activeChar--; 01262 sound.playCancel(); 01263 if (activeChar >= 0) 01264 text[activeChar] = 0; 01265 else 01266 activeChar = 0; 01267 } 01268 //leave menu 01269 if (buttons.pressed(BTN_C)) { 01270 sound.playOK(); 01271 while (1) { 01272 if (update()) { 01273 //display.setCursor(0,0); 01274 display.println(("You entered\n")); 01275 display.print(text); 01276 display.println(("\n\n\n\x15:okay \x16:edit")); 01277 if(buttons.pressed(BTN_A)){ 01278 sound.playOK(); 01279 return; 01280 } 01281 if(buttons.pressed(BTN_B)){ 01282 sound.playCancel(); 01283 break; 01284 } 01285 } 01286 } 01287 } 01288 //draw the keyboard 01289 for (int8_t y = 0; y < KEYBOARD_H; y++) { 01290 for (int8_t x = 0; x < KEYBOARD_W; x++) { 01291 display.drawChar(currentX + x * (display.fontWidth+1), currentY + y * (display.fontHeight+1), x + y * KEYBOARD_W, 1); 01292 } 01293 } 01294 //draw instruction 01295 display.cursorX = currentX-display.fontWidth*6-2; 01296 display.cursorY = currentY+1*(display.fontHeight+1); 01297 display.print(("\25type")); 01298 01299 display.cursorX = currentX-display.fontWidth*6-2; 01300 display.cursorY = currentY+2*(display.fontHeight+1); 01301 display.print(("\26back")); 01302 01303 display.cursorX = currentX-display.fontWidth*6-2; 01304 display.cursorY = currentY+3*(display.fontHeight+1); 01305 display.print(("\27save")); 01306 01307 //erase some pixels around the selected character 01308 display.setColor(WHITE); 01309 display.drawFastHLine(currentX + activeX * (display.fontWidth+1) - 1, currentY + activeY * (display.fontHeight+1) - 2, 7); 01310 //draw the selection rectangle 01311 display.setColor(BLACK); 01312 display.drawRoundRect(currentX + activeX * (display.fontWidth+1) - 2, currentY + activeY * (display.fontHeight+1) - 3, (display.fontWidth+2)+(display.fontWidth-1)%2, (display.fontHeight+5), 3); 01313 //draw keyboard outline 01314 //display.drawRoundRect(currentX - 6, currentY - 6, KEYBOARD_W * (display.fontWidth+1) + 12, KEYBOARD_H * (display.fontHeight+1) + 12, 8, BLACK); 01315 //text field 01316 display.drawFastHLine(0, LCDHEIGHT-display.fontHeight-2, LCDWIDTH); 01317 display.setColor(WHITE); 01318 display.fillRect(0, LCDHEIGHT-display.fontHeight-1, LCDWIDTH, display.fontHeight+1); 01319 //typed text 01320 display.cursorX = 0; 01321 display.cursorY = LCDHEIGHT-display.fontHeight; 01322 display.setColor(BLACK); 01323 display.print(text); 01324 //blinking cursor 01325 if (((frameCount % 8) < 4) && (activeChar < (length-1))) 01326 display.drawChar(display.fontWidth * activeChar, LCDHEIGHT-display.fontHeight, '_',1); 01327 } 01328 } 01329 #endif 01330 } 01331 01332 void Core::popup(const char* text, uint8_t duration){ 01333 #if (ENABLE_GUI > 0) 01334 popupText = text; 01335 popupTimeLeft = duration+12; 01336 #endif 01337 } 01338 01339 void Core::updatePopup(){ 01340 #if (ENABLE_GUI > 0) 01341 if (popupTimeLeft){ 01342 uint8_t yOffset = 0; 01343 if(popupTimeLeft<12){ 01344 yOffset = 12-popupTimeLeft; 01345 } 01346 display.fontSize = 1; 01347 display.setColor(WHITE); 01348 display.fillRoundRect(0,LCDHEIGHT-display.fontHeight+yOffset-3,84,display.fontHeight+3,3); 01349 display.setColor(BLACK); 01350 display.drawRoundRect(0,LCDHEIGHT-display.fontHeight+yOffset-3,84,display.fontHeight+3,3); 01351 display.cursorX = 4; 01352 display.cursorY = LCDHEIGHT-display.fontHeight+yOffset-1; 01353 display.print(popupText); 01354 popupTimeLeft--; 01355 } 01356 #endif 01357 } 01358 01359 void Core::setFrameRate(uint8_t fps) { 01360 timePerFrame = 1000 / fps; 01361 sound.prescaler = fps / 20; 01362 sound.prescaler = __avrmax(1, sound.prescaler); 01363 } 01364 01365 uint8_t Core::getFrameRate() { 01366 return 1000 / timePerFrame; 01367 } 01368 01369 void Core::pickRandomSeed(){ 01370 initRandom(); 01371 } 01372 01373 bool Core::collidePointRect(int16_t x1, int16_t y1 ,int16_t x2 ,int16_t y2, int16_t w, int16_t h){ 01374 if((x1>=x2)&&(x1<x2+w)) 01375 if((y1>=y2)&&(y1<y2+h)) 01376 return true; 01377 return false; 01378 } 01379 01380 bool Core::collideRectRect(int16_t x1, int16_t y1, int16_t w1, int16_t h1 ,int16_t x2 ,int16_t y2, int16_t w2, int16_t h2){ 01381 return !( x2 >= x1+w1 || 01382 x2+w2 <= x1 || 01383 y2 >= y1+h1 || 01384 y2+h2 <= y1 ); 01385 } 01386 01387 bool Core::collideBitmapBitmap(int16_t x1, int16_t y1, const uint8_t* b1, int16_t x2, int16_t y2, const uint8_t* b2){ 01388 int16_t w1 = pgm_read_byte(b1); 01389 int16_t h1 = pgm_read_byte(b1 + 1); 01390 int16_t w2 = pgm_read_byte(b2); 01391 int16_t h2 = pgm_read_byte(b2 + 1); 01392 01393 if(collideRectRect(x1, y1, w1, h1, x2, y2, w2, h2) == false){ 01394 return false; 01395 } 01396 01397 int16_t xmin = (x1>=x2)? 0 : x2-x1; 01398 int16_t ymin = (y1>=y2)? 0 : y2-y1; 01399 int16_t xmax = (x1+w1>=x2+w2)? x2+w2-x1 : w1; 01400 int16_t ymax = (y1+h1>=y2+h2)? y2+h2-y1 : h1; 01401 for(uint8_t y = ymin; y < ymax; y++){ 01402 for(uint8_t x = xmin; x < xmax; x++){ 01403 if(display.getBitmapPixel(b1, x, y) && display.getBitmapPixel(b2, x1+x-x2, y1+y-y2)){ 01404 return true; 01405 } 01406 } 01407 } 01408 return false; 01409 } 01410 01411 01412 //** EOF **// 01413 01414 01415 01416 01417 01418 01419 01420 01421
Generated on Tue Jul 12 2022 11:20:36 by 1.7.2