PokittoLib is the library needed for programming the Pokitto DIY game console (www.pokitto.com)
Embed:
(wiki syntax)
Show/hide line numbers
PokittoCore.cpp
Go to the documentation of this file.
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 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()>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 00469 display.enableDirectPrinting(true); 00470 display.adjustCharStep = 0; 00471 //sound.setMaxVol(VOLUME_HEADPHONE_MAX); 00472 int dstate=1; 00473 bool wipe = true; 00474 float vol = sound.getVolume(); 00475 #ifndef POK_SIM 00476 vol=eeprom_read_byte((uint16_t*)EESETTINGS_VOL); 00477 Pokitto::Sound::globalVolume=vol; 00478 #endif 00479 if (vol>VOLUME_HEADPHONE_MAX) sound.setMaxVol(VOLUME_SPEAKER_MAX); 00480 else sound.setMaxVol(VOLUME_HEADPHONE_MAX); 00481 #ifdef PRODUCTIONTESTING 00482 vol=170; 00483 sound.setMaxVol(VOLUME_SPEAKER_MAX); 00484 #endif 00485 //sound.setVolume(0); 00486 //if (vol) { 00487 //for (uint8_t t=0;t<=vol;t++) sound.setVolume(t); 00488 //} 00489 discrete_vol = ((int)vol>>5); //get rid of 0 vol number 00490 sound.setVolume(vol); 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()>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 #if POK_DISPLAYLOGO 00621 #if PROJ_DEVELOPER_MODE != 1 00622 showLogo(); 00623 #endif // PROJ_DEVELOPER_MODE 00624 #endif // POK_DISPLAYLOGO 00625 00626 display.enableDirectPrinting(true); 00627 display.directbgcolor = COLOR_BLACK; 00628 display.clearLCD(); 00629 display.setFont(fntC64UIGfx); 00630 00631 display.enableDirectPrinting(true); 00632 display.directbgcolor = COLOR_BLACK; 00633 display.directcolor = COLOR_GREEN; 00634 display.clearLCD(); 00635 display.setFont(fntC64UIGfx); 00636 display.adjustCharStep=0; 00637 display.adjustLineStep=1; 00638 #ifdef JUSTLOAD 00639 jumpToLoader(); 00640 #endif 00641 00642 #ifndef DISABLE_LOADER 00643 #if PROJ_DEVELOPER_MODE != 1 00644 askLoader(); 00645 #endif // PROJ_DEVELOPER_MODE 00646 #endif 00647 00648 #if PROJ_DEVELOPER_MODE==1 00649 sound.setMaxVol(VOLUME_SPEAKER_MAX); 00650 sound.setVolume(VOLUME_SPEAKER_MAX); 00651 #else 00652 //showWarning(); 00653 setVolLimit(); 00654 display.clear(); 00655 display.update(); 00656 00657 while(buttons.states[BTN_A]) 00658 { 00659 buttons.update(); 00660 } 00661 00662 //sound.setVolume(sound.getVolume());//make sure we're at set volume before continue 00663 #endif 00664 display.enableDirectPrinting(false); 00665 display.adjustCharStep=1; 00666 display.adjustLineStep=1; 00667 display.fontSize=1; 00668 display.textWrap=true; 00669 #if POK_GAMEBUINO_SUPPORT > 0 00670 display.setFont(font5x7); 00671 #else 00672 display.setFont(fontC64); 00673 #endif 00674 #if POK_ENABLE_SOUND > 0 00675 sound.begin(); 00676 00677 //mute when B is held during start up or if battery is low 00678 battery.update(); 00679 if(buttons.pressed(BTN_B)){ 00680 sound.setVolume(0); 00681 } 00682 else{ //play the startup sound on each channel for it to be louder 00683 #if POK_GBSOUND > 0 00684 #if(NUM_CHANNELS > 0) 00685 sound.playPattern(startupSound, 0); 00686 #endif 00687 #if(NUM_CHANNELS > 1) 00688 sound.playPattern(startupSound, 1); 00689 #endif 00690 #if(NUM_CHANNELS > 2) 00691 sound.playPattern(startupSound, 2); 00692 #endif 00693 #if(NUM_CHANNELS > 3) 00694 sound.playPattern(startupSound, 3); 00695 #endif 00696 #endif // POK_GBSOUND 00697 } 00698 #endif // POK ENABLE_SOUND 00699 } 00700 00701 void Core::init() { 00702 run_state = true; 00703 display.enableDirectPrinting(false); 00704 display.setFont(DEFAULT_FONT); 00705 initClock(); 00706 initGPIO(); 00707 initButtons(); 00708 initRandom(); 00709 //initAudio(); 00710 //initDisplay(); 00711 } 00712 00713 void Core::init(uint8_t switches) { 00714 run_state = true; 00715 display.enableDirectPrinting(false); 00716 display.setFont(DEFAULT_FONT); 00717 initClock(); 00718 initGPIO(); 00719 initButtons(); 00720 initRandom(); 00721 //initAudio(); 00722 //initDisplay(); 00723 } 00724 00725 void Core::initButtons() { 00726 #ifndef POK_SIM 00727 Pokitto::initButtons(); 00728 #endif 00729 } 00730 00731 bool Core::isRunning() { 00732 #ifdef POK_SIM 00733 run_state = simulator.isRunning(); 00734 #endif // POK_SIM 00735 return run_state; 00736 } 00737 00738 void Core::initDisplay() { 00739 #if POK_DISPLAYLOGO > 0 00740 showLogo(); 00741 #endif 00742 #if POK_USE_CONSOLE > 0 00743 console.AddMessage(MSOURCE_LCD,MSG_INIT_OK); 00744 #endif 00745 } 00746 00747 void Core::showLogo() { 00748 uint32_t now; 00749 uint8_t state=0; //jump directly to logo, bypass teeth 00750 uint16_t i=0; 00751 uint16_t sc; 00752 while (state < 255/6) { 00753 now=getTime(); 00754 if (now>refreshtime) { 00755 refreshtime=now+30; 00756 switch (state) { 00757 case 0: 00758 /** POKITTO CLEAN **/ 00759 display.directbgcolor = COLOR_BLACK; 00760 display.fillLCD(display.directbgcolor); 00761 sc = COLOR_BLACK; 00762 state++; 00763 break; 00764 case 1: 00765 /** POKITTO FADE IN **/ 00766 display.directcolor = display.interpolateColor(sc, COLOR_GREEN, i); 00767 display.directBitmap(POK_LCD_W/2 - (*Pokitto_logo/2),POK_LCD_H/2-(*(Pokitto_logo+1)/2),Pokitto_logo,1,1); 00768 i += 28; 00769 if (i>=0xFF) { state++; i=0;} 00770 break; 00771 case 2: 00772 /** POKITTO WAIT **/ 00773 display.directcolor = COLOR_GREEN; 00774 display.directBitmap(POK_LCD_W/2 - (*Pokitto_logo/2),POK_LCD_H/2-(*(Pokitto_logo+1)/2),Pokitto_logo,1,1); 00775 i+= 0x3F; 00776 if (i>0x3FF) state = 255; 00777 break; 00778 } 00779 if(buttons.aBtn()) state=255; 00780 } 00781 } 00782 } 00783 00784 void Core::readSettings() { 00785 // ToDo 00786 /*display.contrast = SCR_CONTRAST; 00787 backlight.backlightMin = BACKLIGHT_MIN; 00788 backlight.backlightMax = BACKLIGHT_MAX; 00789 backlight.ambientLightMin = AMBIENTLIGHT_MIN; 00790 backlight.ambientLightMax = AMBIENTLIGHT_MAX; 00791 */ 00792 sound.setMaxVol(VOLUME_HEADPHONE_MAX); 00793 sound.globalVolume = VOLUME_STARTUP; 00794 00795 startMenuTimer = START_MENU_TIMER; 00796 /* 00797 battery.thresolds[0] = BAT_LVL_CRITIC; 00798 battery.thresolds[1] = BAT_LVL_LOW; 00799 battery.thresolds[2] = BAT_LVL_MED; 00800 battery.thresolds[3] = BAT_LVL_FULL;*/ 00801 } 00802 00803 void Core::titleScreen(const char* name){ 00804 titleScreen(name, 0); 00805 } 00806 00807 void Core::titleScreen(const uint8_t* logo){ 00808 titleScreen((""), logo); 00809 } 00810 00811 void Core::titleScreen(){ 00812 titleScreen(("")); 00813 } 00814 00815 void Core::titleScreen(const char* name, const uint8_t *logo){ 00816 display.setFont(font5x7); 00817 while(buttons.aBtn()) wait(10); //don't accidentally skip menu 00818 if(startMenuTimer){ 00819 display.fontSize = 1; 00820 display.textWrap = false; 00821 display.persistence = false; 00822 battery.show = false; 00823 display.setColor(BLACK); 00824 while(isRunning()){ 00825 if(update()){ 00826 uint8_t logoOffset = name[0]?display.fontHeight:0; //add an offset the logo when there is a name to display 00827 //draw graphics 00828 display.setColorDepth(1); 00829 display.setColor(3); 00830 //display.drawBitmap(0,0, gamebuinoLogo); 00831 display.setColor(1); 00832 if(logo){ 00833 display.drawBitmap(0, 12+logoOffset, logo); 00834 } 00835 display.cursorX = 0; 00836 display.cursorY = 12; 00837 display.print(name); 00838 00839 //A button 00840 display.cursorX = LCDWIDTH - display.fontWidth*3 -1; 00841 display.cursorY = LCDHEIGHT - display.fontHeight*3 - 3; 00842 if((frameCount/16)%2) 00843 display.println(("\25 \20")); 00844 else 00845 display.println(("\25\20 ")); 00846 //B button 00847 display.cursorX = LCDWIDTH - display.fontWidth*3 - 1; 00848 display.cursorY++; 00849 if(sound.globalVolume) 00850 display.println(("\26\23\24")); 00851 else 00852 display.println(("\26\23x")); 00853 //C button 00854 display.cursorX = LCDWIDTH - display.fontWidth*3 - 1; 00855 display.cursorY++; 00856 //display.println(F("\27SD")); 00857 00858 //toggle volume when B is pressed 00859 if(buttons.pressed(BTN_B)){ 00860 sound.setVolume(sound.getVolume() + 1); 00861 sound.playTick(); 00862 } 00863 //leave the menu 00864 if(buttons.pressed(BTN_A) || ((frameCount>=startMenuTimer)&&(startMenuTimer != 255))){ 00865 startMenuTimer = 255; //don't automatically skip the title screen next time it's displayed 00866 sound.stopPattern(0); 00867 sound.playOK(); 00868 break; 00869 } 00870 //flash the loader 00871 //if(buttons.pressed(BTN_C)) 00872 // ToDo changeGame(); 00873 } 00874 } 00875 battery.show = true; 00876 } 00877 } 00878 00879 /** 00880 * Update all the subsystems, like graphics, audio, events, etc. 00881 * Note: the update rect is used for drawing only part of the screen buffer to LCD. Because of speed optimizations, 00882 * the x, y, and width of the update rect must be dividable by 4 pixels, and the height must be dividable by 8 pixels. 00883 * The update rect is currently used for 220x176, 4 colors, screen mode only. 00884 * @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. 00885 * @param updRectX The update rect. 00886 * @param updRectY The update rect. 00887 * @param updRectW The update rect. 00888 * @param updRectH The update rect. 00889 */ 00890 bool Core::update(bool useDirectMode, uint8_t updRectX, uint8_t updRectY, uint8_t updRectW, uint8_t updRectH) { 00891 00892 #if POK_STREAMING_MUSIC 00893 sound.updateStream(); 00894 #endif 00895 00896 uint32_t now = getTime(); 00897 if ((((nextFrameMillis - now)) > timePerFrame) && frameEndMicros) { //if time to render a new frame is reached and the frame end has ran once 00898 nextFrameMillis = now + timePerFrame; 00899 frameCount++; 00900 00901 frameEndMicros = 0; 00902 backlight.update(); 00903 buttons.update(); 00904 battery.update(); 00905 00906 // FPS counter 00907 #if defined(PROJ_USE_FPS_COUNTER) || defined(PROJ_SHOW_FPS_COUNTER) 00908 const uint32_t fpsInterval_ms = 1000*3; 00909 00910 fps_frameCount++; 00911 if (now > fps_refreshtime) { 00912 fps_counter = (1000*fps_frameCount) / (now - fps_refreshtime + fpsInterval_ms); 00913 fps_refreshtime = now + fpsInterval_ms; 00914 fps_frameCount = 0; 00915 fps_counter_updated = true; 00916 } 00917 #endif 00918 00919 return true; 00920 00921 } else { 00922 if (!frameEndMicros) { //runs once at the end of the frame 00923 #if POK_ENABLE_SOUND > 0 00924 sound.updateTrack(); 00925 sound.updatePattern(); 00926 sound.updateNote(); 00927 #endif 00928 updatePopup(); 00929 displayBattery(); 00930 00931 display.update(useDirectMode, updRectX, updRectY, updRectW, updRectH); //send the buffer to the screen 00932 00933 frameEndMicros = 1; //jonne 00934 00935 } 00936 return false; 00937 } 00938 } 00939 00940 void Core::displayBattery(){ 00941 #if (ENABLE_BATTERY > 0) 00942 //display.setColor(BLACK, WHITE); 00943 uint8_t ox,oy; 00944 ox=display.cursorX; 00945 oy=display.cursorY; 00946 display.cursorX = LCDWIDTH-display.fontWidth+1; 00947 display.cursorY = 0; 00948 switch(battery.level){ 00949 case 0://battery critic, power down 00950 sound.stopPattern(); 00951 backlight.set(0); 00952 display.clear(); 00953 display.fontSize = 1; 00954 display.print(("LOW BATTERY\n")); 00955 display.print(battery.voltage); 00956 display.print(("mV\n\nPLEASE\nTURN OFF")); 00957 display.update(); 00958 break; 00959 case 1: //empty battery 00960 if((frameCount % 16) < 8) display.print('\7'); //blinking battery 00961 else display.print('x'); 00962 break; 00963 case 2://low battery 00964 case 3://full battery 00965 case 4://full battery 00966 if(battery.show){ 00967 display.print(char(5+battery.level)); 00968 } 00969 break; 00970 default: 00971 if(battery.show){ 00972 display.print('/'); 00973 } 00974 break; 00975 } 00976 display.cursorX = ox; 00977 display.cursorY = oy; 00978 #endif 00979 } 00980 00981 char* Core::filemenu(char *ext) { 00982 uint8_t oldPersistence = display.persistence; 00983 display.persistence = false; 00984 uint16_t oldpal0=display.palette[0]; 00985 uint16_t oldpal1=display.palette[1]; 00986 uint16_t oldpal2=display.palette[2]; 00987 display.palette[2]=COLOR_GREEN; 00988 display.palette[1]=COLOR_WHITE; 00989 display.palette[0]=COLOR_BLACK; 00990 uint8_t oldbg=display.bgcolor; 00991 uint8_t oldfg=display.color; 00992 display.color=1; 00993 display.bgcolor=0; 00994 00995 int16_t rowh = display.fontHeight + 2; 00996 int8_t activeItem = 0; 00997 int16_t currentTopItem = 0; 00998 int16_t itemsPerScreen = (display.height+1) / rowh; 00999 int16_t numOfItemsFound = 0; 01000 boolean exit = false; 01001 01002 char* txt; 01003 01004 pokInitSD(); 01005 01006 bool updated = true; 01007 while (isRunning()) { 01008 if (update(true)) { 01009 if (buttons.pressed(BTN_A) || buttons.pressed(BTN_B) || buttons.pressed(BTN_C)) { 01010 exit = true; //time to exit menu ! 01011 if (buttons.pressed(BTN_A)) { 01012 sound.playOK(); 01013 } else { 01014 *selectedfile = 0; 01015 sound.playCancel(); 01016 } 01017 updated = true; // update screen 01018 } 01019 if (exit == false) { 01020 if (buttons.repeat(BTN_DOWN,4)) { 01021 if( ++activeItem >= numOfItemsFound ) activeItem = numOfItemsFound - 1; 01022 if( activeItem >= currentTopItem + itemsPerScreen) currentTopItem += itemsPerScreen; // next page 01023 sound.playTick(); 01024 updated = true; // update screen 01025 } 01026 if (buttons.repeat(BTN_UP,4)) { 01027 if( --activeItem < 0 ) activeItem = 0; 01028 if( activeItem < currentTopItem) currentTopItem -= itemsPerScreen; // previous page 01029 sound.playTick(); 01030 updated = true; // update screen 01031 } 01032 01033 } else { //exit : 01034 display.bgcolor=oldbg; 01035 display.color=oldfg; 01036 display.palette[0] = oldpal0; 01037 display.palette[1] = oldpal1; 01038 display.palette[2] = oldpal2; 01039 display.persistence = oldPersistence; 01040 return selectedfile; 01041 } 01042 01043 //draw a fancy menu 01044 display.textWrap = false; 01045 //uint16_t fc,bc; 01046 //fc = display.color; 01047 //bc = display.bgcolor; 01048 if( updated ) { // update screen? 01049 #if POK_SIM 01050 getFirstFile(ext); 01051 #else 01052 bool isFirstFile = true; 01053 #endif 01054 for (int i = 0; ; i++) { 01055 display.cursorX = 0; 01056 display.invisiblecolor=255; 01057 display.cursorY = (i - currentTopItem ) * rowh; 01058 01059 // read the file name from SD 01060 #ifndef POK_SIM 01061 if(isFirstFile) { 01062 txt = getFirstFile(ext); 01063 isFirstFile = false; 01064 } 01065 else 01066 #endif 01067 01068 txt = getNextFile(ext); 01069 01070 if (txt) { 01071 01072 numOfItemsFound = i+1; 01073 01074 // Draw active line with diffrent backgtound and char color 01075 if (i == activeItem){ 01076 display.cursorX = 3; 01077 display.color=2; 01078 display.fillRect(0, display.cursorY - 2, LCDWIDTH, rowh); 01079 display.setColor(0,2); 01080 } else display.setColor(1,0); 01081 01082 // break loop if going out of screen 01083 if(i >= currentTopItem + itemsPerScreen ) { 01084 break; 01085 } 01086 01087 // Display only if the file is on the current page 01088 if( i >= currentTopItem) { 01089 display.print(display.cursorX, display.cursorY, txt); 01090 if (i == activeItem) 01091 strcpy(selectedfile,txt); 01092 } 01093 } else 01094 break; // break loop as no more files found 01095 01096 display.setColor(1,0); 01097 } // end for 01098 01099 display.update(); 01100 } 01101 updated = false; 01102 } // update 01103 01104 display.setColor(1,0); 01105 } 01106 return 0; 01107 } 01108 01109 char* Core::filemenu() { 01110 return filemenu(""); 01111 } 01112 01113 int8_t Core::menu(const char* const* items, uint8_t length) { 01114 if (display.color>3) display.color=1; 01115 #if (ENABLE_GUI > 0) 01116 display.persistence = false; 01117 int8_t activeItem = 0; 01118 int16_t currentY = display.height; 01119 int16_t targetY = 0, rowh = display.fontHeight + 2; 01120 boolean exit = false; 01121 int8_t answer = -1; 01122 while (isRunning()) { 01123 if (update()) { 01124 if (buttons.pressed(BTN_A) || buttons.pressed(BTN_B) || buttons.pressed(BTN_C)) { 01125 exit = true; //time to exit menu ! 01126 targetY = - display.fontHeight * length - 2; //send the menu out of the screen 01127 if (buttons.pressed(BTN_A)) { 01128 answer = activeItem; 01129 sound.playOK(); 01130 } else { 01131 sound.playCancel(); 01132 } 01133 } 01134 if (exit == false) { 01135 if (buttons.repeat(BTN_DOWN,4)) { 01136 activeItem++; 01137 sound.playTick(); 01138 } 01139 if (buttons.repeat(BTN_UP,4)) { 01140 activeItem--; 01141 sound.playTick(); 01142 } 01143 //don't go out of the menu 01144 if (activeItem == length) activeItem = 0; 01145 if (activeItem < 0) activeItem = length - 1; 01146 01147 targetY = -rowh * activeItem + (rowh+4); //center the menu on the active item 01148 } else { //exit : 01149 if ((currentY - targetY) <= 1) 01150 return (answer); 01151 } 01152 //draw a fancy menu 01153 currentY = (currentY + targetY) / 2; 01154 display.cursorX = 0; 01155 display.cursorY = currentY; 01156 display.textWrap = false; 01157 uint16_t fc,bc; 01158 fc = display.color; 01159 bc = display.bgcolor; 01160 for (byte i = 0; i < length; i++) { 01161 display.cursorY = currentY + rowh * i; 01162 if (i == activeItem){ 01163 display.cursorX = 3; 01164 01165 //display.fillRoundRect(0, currentY + display.fontHeight * activeItem - 2, LCDWIDTH, (display.fontHeight+3), 3); 01166 display.fillRect(0, currentY + rowh * activeItem - 2, LCDWIDTH, (rowh)); 01167 display.setColor(bc,fc); 01168 } else display.setColor(fc,bc); 01169 01170 display.println((char*)*(const unsigned int*)(items+i)); 01171 display.setColor(fc,bc); 01172 } 01173 01174 } 01175 } 01176 #else 01177 return 0; 01178 #endif 01179 return 0; 01180 } 01181 01182 void Core::keyboard(char* text, uint8_t length) { 01183 #if (ENABLE_GUI > 0) 01184 display.persistence = false; 01185 //memset(text, 0, length); //clear the text 01186 text[length-1] = '\0'; 01187 //active character in the typing area 01188 int8_t activeChar = 0; 01189 //selected char on the keyboard 01190 int8_t activeX = 0; 01191 int8_t activeY = 2; 01192 //position of the keyboard on the screen 01193 int8_t currentX = LCDWIDTH; 01194 int8_t currentY = LCDHEIGHT; 01195 int8_t targetX = 0; 01196 int8_t targetY = 0; 01197 01198 while (1) { 01199 if (update()) { 01200 //move the character selector 01201 if (buttons.repeat(BTN_DOWN, 4)) { 01202 activeY++; 01203 sound.playTick(); 01204 } 01205 if (buttons.repeat(BTN_UP, 4)) { 01206 activeY--; 01207 sound.playTick(); 01208 } 01209 if (buttons.repeat(BTN_RIGHT, 4)) { 01210 activeX++; 01211 sound.playTick(); 01212 } 01213 if (buttons.repeat(BTN_LEFT, 4)) { 01214 activeX--; 01215 sound.playTick(); 01216 } 01217 //don't go out of the keyboard 01218 if (activeX == KEYBOARD_W) activeX = 0; 01219 if (activeX < 0) activeX = KEYBOARD_W - 1; 01220 if (activeY == KEYBOARD_H) activeY = 0; 01221 if (activeY < 0) activeY = KEYBOARD_H - 1; 01222 //set the keyboard position on screen 01223 targetX = -(display.fontWidth+1) * activeX + LCDWIDTH / 2 - 3; 01224 targetY = -(display.fontHeight+1) * activeY + LCDHEIGHT / 2 - 4 - display.fontHeight; 01225 //smooth the keyboard displacement 01226 currentX = (targetX + currentX) / 2; 01227 currentY = (targetY + currentY) / 2; 01228 //type character 01229 if (buttons.pressed(BTN_A)) { 01230 if (activeChar < (length-1)) { 01231 byte thisChar = activeX + KEYBOARD_W * activeY; 01232 if((thisChar == 0)||(thisChar == 10)||(thisChar == 13)) //avoid line feed and carriage return 01233 continue; 01234 text[activeChar] = thisChar; 01235 text[activeChar+1] = '\0'; 01236 } 01237 activeChar++; 01238 sound.playOK(); 01239 if (activeChar > length) 01240 activeChar = length; 01241 } 01242 //erase character 01243 if (buttons.pressed(BTN_B)) { 01244 activeChar--; 01245 sound.playCancel(); 01246 if (activeChar >= 0) 01247 text[activeChar] = 0; 01248 else 01249 activeChar = 0; 01250 } 01251 //leave menu 01252 if (buttons.pressed(BTN_C)) { 01253 sound.playOK(); 01254 while (1) { 01255 if (update()) { 01256 //display.setCursor(0,0); 01257 display.println(("You entered\n")); 01258 display.print(text); 01259 display.println(("\n\n\n\x15:okay \x16:edit")); 01260 if(buttons.pressed(BTN_A)){ 01261 sound.playOK(); 01262 return; 01263 } 01264 if(buttons.pressed(BTN_B)){ 01265 sound.playCancel(); 01266 break; 01267 } 01268 } 01269 } 01270 } 01271 //draw the keyboard 01272 for (int8_t y = 0; y < KEYBOARD_H; y++) { 01273 for (int8_t x = 0; x < KEYBOARD_W; x++) { 01274 display.drawChar(currentX + x * (display.fontWidth+1), currentY + y * (display.fontHeight+1), x + y * KEYBOARD_W, 1); 01275 } 01276 } 01277 //draw instruction 01278 display.cursorX = currentX-display.fontWidth*6-2; 01279 display.cursorY = currentY+1*(display.fontHeight+1); 01280 display.print(("\25type")); 01281 01282 display.cursorX = currentX-display.fontWidth*6-2; 01283 display.cursorY = currentY+2*(display.fontHeight+1); 01284 display.print(("\26back")); 01285 01286 display.cursorX = currentX-display.fontWidth*6-2; 01287 display.cursorY = currentY+3*(display.fontHeight+1); 01288 display.print(("\27save")); 01289 01290 //erase some pixels around the selected character 01291 display.setColor(WHITE); 01292 display.drawFastHLine(currentX + activeX * (display.fontWidth+1) - 1, currentY + activeY * (display.fontHeight+1) - 2, 7); 01293 //draw the selection rectangle 01294 display.setColor(BLACK); 01295 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); 01296 //draw keyboard outline 01297 //display.drawRoundRect(currentX - 6, currentY - 6, KEYBOARD_W * (display.fontWidth+1) + 12, KEYBOARD_H * (display.fontHeight+1) + 12, 8, BLACK); 01298 //text field 01299 display.drawFastHLine(0, LCDHEIGHT-display.fontHeight-2, LCDWIDTH); 01300 display.setColor(WHITE); 01301 display.fillRect(0, LCDHEIGHT-display.fontHeight-1, LCDWIDTH, display.fontHeight+1); 01302 //typed text 01303 display.cursorX = 0; 01304 display.cursorY = LCDHEIGHT-display.fontHeight; 01305 display.setColor(BLACK); 01306 display.print(text); 01307 //blinking cursor 01308 if (((frameCount % 8) < 4) && (activeChar < (length-1))) 01309 display.drawChar(display.fontWidth * activeChar, LCDHEIGHT-display.fontHeight, '_',1); 01310 } 01311 } 01312 #endif 01313 } 01314 01315 void Core::popup(const char* text, uint8_t duration){ 01316 #if (ENABLE_GUI > 0) 01317 popupText = text; 01318 popupTimeLeft = duration+12; 01319 #endif 01320 } 01321 01322 void Core::updatePopup(){ 01323 #if (ENABLE_GUI > 0) 01324 if (popupTimeLeft){ 01325 uint8_t yOffset = 0; 01326 if(popupTimeLeft<12){ 01327 yOffset = 12-popupTimeLeft; 01328 } 01329 display.fontSize = 1; 01330 display.setColor(WHITE); 01331 display.fillRoundRect(0,LCDHEIGHT-display.fontHeight+yOffset-3,84,display.fontHeight+3,3); 01332 display.setColor(BLACK); 01333 display.drawRoundRect(0,LCDHEIGHT-display.fontHeight+yOffset-3,84,display.fontHeight+3,3); 01334 display.cursorX = 4; 01335 display.cursorY = LCDHEIGHT-display.fontHeight+yOffset-1; 01336 display.print(popupText); 01337 popupTimeLeft--; 01338 } 01339 #endif 01340 } 01341 01342 void Core::setFrameRate(uint8_t fps) { 01343 timePerFrame = 1000 / fps; 01344 sound.prescaler = fps / 20; 01345 sound.prescaler = __avrmax(1, sound.prescaler); 01346 } 01347 01348 void Core::pickRandomSeed(){ 01349 initRandom(); 01350 } 01351 01352 bool Core::collidePointRect(int16_t x1, int16_t y1 ,int16_t x2 ,int16_t y2, int16_t w, int16_t h){ 01353 if((x1>=x2)&&(x1<x2+w)) 01354 if((y1>=y2)&&(y1<y2+h)) 01355 return true; 01356 return false; 01357 } 01358 01359 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){ 01360 return !( x2 >= x1+w1 || 01361 x2+w2 <= x1 || 01362 y2 >= y1+h1 || 01363 y2+h2 <= y1 ); 01364 } 01365 01366 bool Core::collideBitmapBitmap(int16_t x1, int16_t y1, const uint8_t* b1, int16_t x2, int16_t y2, const uint8_t* b2){ 01367 int16_t w1 = pgm_read_byte(b1); 01368 int16_t h1 = pgm_read_byte(b1 + 1); 01369 int16_t w2 = pgm_read_byte(b2); 01370 int16_t h2 = pgm_read_byte(b2 + 1); 01371 01372 if(collideRectRect(x1, y1, w1, h1, x2, y2, w2, h2) == false){ 01373 return false; 01374 } 01375 01376 int16_t xmin = (x1>=x2)? 0 : x2-x1; 01377 int16_t ymin = (y1>=y2)? 0 : y2-y1; 01378 int16_t xmax = (x1+w1>=x2+w2)? x2+w2-x1 : w1; 01379 int16_t ymax = (y1+h1>=y2+h2)? y2+h2-y1 : h1; 01380 for(uint8_t y = ymin; y < ymax; y++){ 01381 for(uint8_t x = xmin; x < xmax; x++){ 01382 if(display.getBitmapPixel(b1, x, y) && display.getBitmapPixel(b2, x1+x-x2, y1+y-y2)){ 01383 return true; 01384 } 01385 } 01386 } 01387 return false; 01388 } 01389 01390 01391 //** EOF **// 01392 01393 01394 01395 01396 01397 01398 01399 01400
Generated on Tue Jul 12 2022 21:03:51 by 1.7.2