PokittoLib is the library needed for programming the Pokitto DIY game console (www.pokitto.com)

Dependents:   YATTT sd_map_test cPong SnowDemo ... more

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers PokittoCore.cpp Source File

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 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