spinal cord / PokittoLib

Dependents:   Sensitive

Fork of PokittoLib by Jonne Valola

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 "PokittoCore.h "
00038 #include "Pokitto_settings.h "
00039 #include "PokittoConsole.h "
00040 #include "PokittoFonts.h "
00041 #include "PokittoTimer.h "
00042 #include "PokittoLogos.h "
00043 #include <stdlib.h>
00044 #ifndef DISABLEAVRMIN
00045 #define max(a,b) ((a)>(b)?(a):(b))
00046 #endif // DISABLEAVRMIN
00047 
00048 char selectedfile[25];
00049 
00050 //#define F 
00051 #ifdef __ARMCC_VERSION
00052 typedef void (*func_t)(void);
00053 #endif 
00054 
00055 #ifndef POK_SIM
00056 /** start the user application
00057 * https://community.nxp.com/thread/417695
00058 *
00059 */
00060 void start_application(unsigned long app_link_location){
00061     //asm(" ldr sp, [r0,#0]");
00062     //asm(" ldr pc, [r0,#4]");
00063     //This code is not valid for the Cortex-m0+ instruction set.
00064     // The equivalent for this (as used by the KL26) is
00065 __disable_irq();// Start by disabling interrupts, before changing interrupt vectors
00066 
00067 // delete buttons
00068 //pokDeleteButtons();
00069 
00070 // completely kill button interrupts in preparation for reset
00071 LPC_PINT->IENR = 0;
00072 LPC_PINT->IENF = 0;
00073 
00074 SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk & ~(SysTick_CTRL_ENABLE_Msk); //disable systick
00075 LPC_SYSCON->PDRUNCFG     |=  (1 << 10);       /* Power-down USB PHY         */
00076 LPC_SYSCON->PDRUNCFG     |=  (1 <<  8);       /* Power-down USB PLL         */
00077 
00078 // reset clock source to IRC
00079 LPC_SYSCON->MAINCLKUEN    = 0x01;             /* Update MCLK Clock Source   */
00080 LPC_SYSCON->MAINCLKUEN    = 0x00;             /* Toggle Update Register     */
00081 while (LPC_SYSCON->MAINCLKUEN & 0x01);     /* Wait Until Updated         */
00082 // switch clock selection to IRC
00083 LPC_SYSCON->MAINCLKSEL    = 0;             /* Select Clock Source        */
00084 LPC_SYSCON->MAINCLKUEN    = 0x01;             /* Update MCLK Clock Source   */
00085 LPC_SYSCON->MAINCLKUEN    = 0x00;             /* Toggle Update Register     */
00086 while (LPC_SYSCON->MAINCLKUEN & 0x01);     /* Wait Until Updated         */
00087 //disable PLL clock output
00088 LPC_SYSCON->SYSPLLCLKUEN = 0;
00089 while (LPC_SYSCON->SYSPLLCLKUEN & 0x00);
00090 LPC_SYSCON->SYSPLLCTRL = 0;
00091 
00092 //kill peripherals
00093 LPC_SYSCON->MAINCLKSEL = 0;
00094 LPC_SYSCON->PRESETCTRL = 0; //disable all peripherals
00095 
00096 //power down PLL
00097 volatile uint32_t tmp;
00098 tmp = (LPC_SYSCON->PDRUNCFG & 0x000025FFL);
00099 tmp |= ((1<<7) & 0x000025FFL);
00100 LPC_SYSCON->PDRUNCFG = (tmp | 0x0000C800L); /* Power-down SYSPLL          */
00101 
00102 //Chip_Clock_SetMainClockSource(SYSCTL_MAINCLKSRC_IRC); //switch to IRC
00103 
00104 // clear all gpio states
00105 LPC_GPIO_PORT->PIN[0] = 0;
00106 LPC_GPIO_PORT->PIN[1] = 0;
00107 LPC_GPIO_PORT->PIN[2] = 0;
00108 
00109 SCB->VTOR = app_link_location;//APPL_ADDRESS; /* Change vector table address */
00110 #ifndef __ARMCC_VERSION
00111 asm(" mov r0, %[address]"::[address] "r" (app_link_location));
00112 asm(" ldr r1, [r0,#0]"); // get the stack pointer value from the program's reset vector
00113 asm(" mov sp, r1");      // copy the value to the stack pointer
00114 asm(" ldr r0, [r0,#4]"); // get the program counter value from the program's reset vector
00115 asm(" blx r0");          // jump to the' start address
00116 #else
00117 uint32_t *app_loc = (uint32_t*)app_link_location;
00118 __set_MSP (app_loc[0]);
00119 ((func_t)(app_loc[1]))();
00120 #endif
00121 }
00122 #endif
00123 
00124 // returns a random integar between 0 and maxVal
00125 int random(int maxVal)
00126 {
00127   return random( 0, maxVal);
00128 }
00129 
00130 // returns a random integar between minVal and maxVal
00131 int random(int minVal, int maxVal)
00132 {
00133   // int rand(void); included by default from newlib
00134   return rand() % (maxVal-minVal+1) + minVal;
00135 }
00136 
00137 using namespace Pokitto;
00138 
00139 bool Core::run_state; // this definition needed
00140 
00141 /** Components */
00142 Backlight Core::backlight;
00143 Buttons Core::buttons;
00144 Battery Core::battery;
00145 #if POK_ENABLE_SOUND > 0
00146 Sound Core::sound;
00147 #endif
00148 Display Core::display;
00149 
00150 //GB Related
00151 uint8_t Core::startMenuTimer;
00152 uint8_t Core::timePerFrame;
00153 uint32_t Core::nextFrameMillis;
00154 uint32_t Core::frameCount;
00155 const char* Core::popupText;
00156 uint8_t Core::popupTimeLeft;
00157 uint16_t Core::frameDurationMicros;
00158 uint32_t Core::frameStartMicros, Core::frameEndMicros;
00159 uint8_t Core::volbar_visible=0;
00160 
00161 
00162 Core::Core() {
00163 
00164 }
00165 
00166 void Core::showWarning() {
00167     display.enableDirectPrinting(true);
00168     display.directbgcolor = COLOR_BLACK;
00169     display.clearLCD();
00170     display.directcolor = COLOR_RED;
00171     display.setFont(fntC64UIGfx);
00172     display.adjustCharStep = 0;
00173     display.adjustLineStep = 0;
00174     display.setCursor(10*8,9);
00175     display.print("WARNING!");
00176     display.directcolor = COLOR_WHITE;
00177     display.setCursor(5*8,4*9);
00178     display.print("LOUD SOUND THROUGH");
00179     display.setCursor(2*8,5*9);
00180     display.print("HEADPHONES COULD DAMAGE");
00181     display.setCursor(7*8,6*9);
00182     display.print("YOUR HEARING.");
00183     display.setCursor(5*8,8*9);
00184     display.print("USE "); display.directcolor = COLOR_GREEN;
00185     display.print("0-100% VOLUME");
00186     display.directcolor = COLOR_WHITE;
00187     display.setCursor(5*8,9*9);
00188     display.print("FOR LISTENING WITH");
00189     display.setCursor(8*8,10*9);
00190     display.print("HEADPHONES");
00191     display.setCursor(5*8,12*9);
00192     display.print("USE "); display.directcolor = COLOR_RED;
00193     display.print("> 100% VOLUME"); display.directcolor = COLOR_GREEN;
00194     display.directcolor = COLOR_WHITE;
00195     display.setCursor(1*8,13*9);
00196     display.print("ONLY FOR LISTENING VIA THE");
00197     display.setCursor(5*8,14*9);
00198     display.print("BUILT-IN SPEAKER");
00199     display.setCursor(5*8,17*9);
00200     display.print("PRESS ");display.directcolor = COLOR_GREEN;
00201     display.print("C ");display.directcolor = COLOR_WHITE;
00202     display.print("TO ACCEPT");
00203     while (!buttons.cBtn()) {
00204         wait(100);
00205     }
00206     display.clearLCD();
00207     display.enableDirectPrinting(false);
00208 }
00209 
00210 void Core::jumpToLoader() {
00211     display.fontSize=1;
00212     display.directbgcolor=COLOR_BLACK;
00213     display.directcolor=COLOR_GREEN;
00214     display.setCursor(0,0);
00215     display.enableDirectPrinting(true);
00216     #ifdef POK_SIM
00217     display.println("LOADER IS NOT AVAILABLE ON THE SIMULATOR. PRESS A TO RETURN.");
00218     #else
00219     uint32_t* bootinfo;
00220     bootinfo = (uint32_t*)0x3FE04;
00221     if (*bootinfo != 0xB007AB1E) display.println("NO LOADER CONNECTED!");
00222     else start_application(*(bootinfo+2)); //never returns
00223     //display.println((unsigned int)(*(bootinfo+2)),16); 
00224     #endif // POK_SIM
00225     while (!buttons.aBtn()) {
00226         buttons.pollButtons();
00227         if (buttons.aBtn()) {
00228             while (buttons.aBtn()) {
00229                 buttons.pollButtons();
00230             }
00231             return;
00232         }
00233     }
00234 }
00235 
00236 void Core::askLoader() {
00237     display.enableDirectPrinting(true);
00238     display.directbgcolor = COLOR_BLACK;
00239     display.clearLCD();
00240     display.directcolor = COLOR_RED;
00241     display.setFont(fntC64UIGfx);
00242     display.fontSize=1;
00243     display.adjustCharStep = 0;
00244     display.adjustLineStep = 0;
00245     display.directcolor=COLOR_GREEN;
00246     display.set_cursor(12*8,6*8);
00247     display.print("ijkl");
00248     display.set_cursor(12*8,7*8);
00249     display.print("mnop");
00250     display.set_cursor(12*8,8*8);
00251     display.print("qrst");
00252     display.set_cursor(12*8,9*8);
00253     display.print("uvwx");
00254     display.set_cursor(5*8,12*8);
00255     display.print("PRESS");
00256     display.directcolor=COLOR_WHITE;
00257     display.print(" C ");
00258     display.directcolor=COLOR_GREEN;
00259     display.print("FOR LOADER");
00260     display.directcolor=COLOR_WHITE;
00261     display.fontSize=2;
00262     int countd=POK_LOADER_COUNTDOWN; uint16_t c2 = getTime();
00263     while (countd) {
00264         buttons.pollButtons();
00265         display.set_cursor(13*8,15*8);
00266         display.print(countd);
00267         if (getTime()>c2+1000) {
00268             c2=getTime();
00269             countd--;
00270         }
00271         if (cBtn()) {while (cBtn()) buttons.pollButtons();jumpToLoader();countd=0;}
00272         if (aBtn()) {while (aBtn()) buttons.pollButtons();countd=0;}
00273         if (bBtn()) {while (bBtn()) buttons.pollButtons();countd=0;}
00274     }
00275     display.fontSize=1;
00276     display.clearLCD();
00277     display.enableDirectPrinting(false);
00278 }
00279 
00280 
00281 void Core::drawvolbar(int x, int y, int level, bool text) {
00282     uint16_t oldcol = display.directcolor;
00283     if (text) display.directRectangle(0,0,50,50,COLOR_BLACK);
00284     display.directcolor = COLOR_GREEN;
00285     if (text) {
00286             bool temp = display.isDirectPrintingEnabled();
00287             display.enableDirectPrinting(true);
00288             display.print(x-1,y-20,(int)sound.getVolume());
00289             display.print("  ");
00290             display.enableDirectPrinting(temp);
00291     }
00292     if (level<12) display.directcolor = COLOR_GRAY_80;
00293     display.directBitmap(x,y,Pokitto_volumebar,1,1);
00294     if (level<24) display.directcolor = COLOR_GRAY_80;
00295     display.directBitmap(x+8,y,Pokitto_volumebar,1,1);
00296     display.directBitmap(x+8,y-4,Pokitto_volumebar,1,1);
00297     display.directcolor = COLOR_RED;
00298     if (level<48) display.directcolor = COLOR_GRAY_80;
00299     display.directBitmap(x+16,y,Pokitto_volumebar,1,1);
00300     display.directBitmap(x+16,y-4,Pokitto_volumebar,1,1);
00301     display.directBitmap(x+16,y-8,Pokitto_volumebar,1,1);
00302 
00303     if (level<96) {
00304             display.directcolor = COLOR_GRAY_80;
00305     }
00306     display.directBitmap(x+24,y,Pokitto_volumebar,1,1);
00307     display.directBitmap(x+24,y-4,Pokitto_volumebar,1,1);
00308     display.directBitmap(x+24,y-8,Pokitto_volumebar,1,1);
00309     display.directBitmap(x+24,y-12,Pokitto_volumebar,1,1);
00310     if (level<160) {
00311             display.directcolor = COLOR_GRAY_80;
00312     }
00313     display.directBitmap(x+32,y,Pokitto_volumebar,1,1);
00314     display.directBitmap(x+32,y-4,Pokitto_volumebar,1,1);
00315     display.directBitmap(x+32,y-8,Pokitto_volumebar,1,1);
00316     display.directBitmap(x+32,y-12,Pokitto_volumebar,1,1);
00317     display.directBitmap(x+32,y-16,Pokitto_volumebar,1,1);
00318     display.directcolor = oldcol;
00319 }
00320 
00321 
00322 #ifdef POK_SIM
00323 #define VINCMULT 1
00324 #else
00325 #define VINCMULT 50
00326 #endif //POK_SIM
00327 void Core::setVolLimit() {
00328     display.enableDirectPrinting(true);
00329     display.adjustCharStep = 0;
00330     sound.setMaxVol(VOLUME_HEADPHONE_MAX);
00331     int dstate=1;
00332     bool wipe = true;
00333     float vol = sound.getVolume(); float tvol;
00334     volbar_visible=0;
00335     while (core.isRunning() && dstate){
00336         switch (dstate) {
00337         case 1:
00338             //redraw
00339             if (wipe) {
00340             display.clearLCD();
00341             display.directcolor = COLOR_WHITE;
00342             display.setCursor(4*8,2*8);
00343             display.print("SELECT VOLUME LIMIT");
00344             display.setCursor(5*8,17*9);
00345             display.print("PRESS ");
00346             display.directcolor = COLOR_GREEN;
00347             display.print("A");
00348             display.directcolor = COLOR_WHITE;
00349             display.print(" TO ACCEPT");
00350             display.directcolor = COLOR_GREEN;
00351             // draw frame below first
00352             display.setCursor(0,11*8);
00353             display.println(" abbbbbbbbbbbbbbbbbbbbbbbc");
00354             display.println(" |                       |");
00355             display.println(" |                       |");
00356             display.println(" |                       |");
00357             display.println(" |                       |");
00358             display.println(" dbbbbbbbbbbbbbbbbbbbbbbbe");
00359             } // wipe = true
00360             display.setCursor(6*8,17*9);
00361             if (sound.getVolume()-5<=VOLUME_HEADPHONE_MAX) display.directcolor = COLOR_WHITE;
00362             else display.directcolor = COLOR_RED;
00363             display.directBitmap(21*8-4,6*8,Pokitto_headphones,1,2);
00364             display.setCursor(3*8,6*8+6);
00365             display.print("HEADPHONES");
00366             display.setCursor(3*8,8*8+2);
00367             if (sound.getVolume()-8>VOLUME_HEADPHONE_MAX) display.print("TOO LOUD!");
00368             else display.print("OK        ");
00369             display.directcolor = COLOR_GREEN;
00370             display.directBitmap(21*8-4,12*8,Pokitto_speaker,1,2);
00371             display.setCursor(3*8,12*8+6);
00372             display.print("VOLUME MAX");
00373             display.setCursor(3*8,14*8+2);
00374             tvol = (vol/float(VOLUME_HEADPHONE_MAX))*100;
00375             if (tvol > 100 && tvol < 120) tvol=100;
00376             if (sound.getVolume()-5>VOLUME_HEADPHONE_MAX) { display.directcolor=COLOR_RED;}
00377             else display.directcolor=COLOR_GREEN;
00378             display.print(int(sound.getVolume()));
00379             //display.print(int(tvol));
00380             display.print("  ");
00381             display.directcolor=COLOR_GREEN;
00382             drawvolbar(14*8,14*8+4+2,sound.getVolume(),false);
00383             //display.setCursor(1,10);
00384             //display.print(vol);
00385             dstate=2; break;
00386         case 2:
00387             buttons.pollButtons();
00388             if (aBtn()) {dstate=0;while(aBtn()){buttons.pollButtons();};break;}
00389             if (rightBtn()) {
00390                     if (vol >= VOLUME_HEADPHONE_MAX && vol < VOLUME_HEADPHONE_MAX+1 ) vol += 0.00025f*VINCMULT;
00391                     else if (vol >= VOLUME_HEADPHONE_MAX) vol += 0.025f*VINCMULT;
00392                     else vol += 0.05f*VINCMULT;
00393                     if (vol > VOLUME_HEADPHONE_MAX + 20) {
00394                             sound.setMaxVol(VOLUME_SPEAKER_MAX);
00395                     }
00396                     if (vol > VOLUME_SPEAKER_MAX) vol=VOLUME_SPEAKER_MAX;
00397                     sound.setVolume(vol);
00398                     dstate=1; wipe=false;
00399                     break;
00400                     }
00401             if (leftBtn()) {
00402                     vol -= 0.025f*VINCMULT;
00403                     if (vol <= VOLUME_HEADPHONE_MAX) sound.setMaxVol(VOLUME_HEADPHONE_MAX);
00404                     if (vol < 0) vol=0;
00405                     sound.setVolume(vol);
00406                     dstate=1; wipe=false;
00407                     break;
00408                     }
00409             break;
00410         }
00411     }
00412 }
00413 
00414 void Core::begin() {
00415 
00416     init(); // original functions
00417     timePerFrame = POK_FRAMEDURATION;
00418     //nextFrameMillis = 0;
00419     //frameCount = 0;
00420     frameEndMicros = 1;
00421     startMenuTimer = 255;
00422     //read default settings from flash memory (set using settings.hex)
00423     readSettings();
00424     //init everything
00425     backlight.begin();
00426     backlight.set(BACKLIGHT_MAX);
00427     buttons.begin();
00428     buttons.update();
00429     battery.begin();
00430     display.begin();
00431     #if POK_DISPLAYLOGO
00432         showLogo();
00433     #endif // POK_DISPLAYLOGO
00434     display.enableDirectPrinting(true);
00435     display.directbgcolor = COLOR_BLACK;
00436     display.clearLCD();
00437     display.setFont(fntC64UIGfx);
00438     askLoader();
00439     #ifndef DISABLE_SOUND_WARNING
00440     //showWarning();
00441     setVolLimit();
00442     //sound.setVolume(sound.getVolume());//make sure we're at set volume before continue
00443     sound.volumeUp();
00444     #endif
00445     display.enableDirectPrinting(false);
00446     display.adjustCharStep=1;
00447     display.adjustLineStep=1;
00448     display.fontSize=1;
00449     display.textWrap=true;
00450     #if POK_GAMEBUINO_SUPPORT > 0
00451     display.setFont(font5x7);
00452     #else
00453     display.setFont(fontC64);
00454     #endif
00455     
00456     #if POK_ENABLE_SOUND > 0
00457         sound.begin();
00458     
00459     //mute when B is held during start up or if battery is low
00460     battery.update();
00461     
00462     if(buttons.pressed(BTN_B) || (battery.level == 0)){
00463         sound.setVolume(0);
00464     }
00465     else{ //play the startup sound on each channel for it to be louder
00466         #if POK_GBSOUND > 0
00467         #if(NUM_CHANNELS > 0)
00468             sound.playPattern(startupSound, 0);
00469         #endif
00470         #if(NUM_CHANNELS > 1)
00471             sound.playPattern(startupSound, 1);
00472         #endif
00473         #if(NUM_CHANNELS > 2)
00474             sound.playPattern(startupSound, 2);
00475         #endif
00476         #if(NUM_CHANNELS > 3)
00477             sound.playPattern(startupSound, 3);
00478         #endif
00479         #endif // POK_GBSOUND
00480     }
00481     #endif // POK ENABLE_SOUND
00482 }
00483 
00484 void Core::init() {
00485     run_state = true;
00486     display.enableDirectPrinting(false);
00487     display.setFont(DEFAULT_FONT);
00488     initClock();
00489     initGPIO();
00490     initButtons();
00491     initRandom();
00492     //initAudio();
00493     //initDisplay();
00494 }
00495 
00496 void Core::init(uint8_t switches) {
00497     run_state = true;
00498     display.enableDirectPrinting(false);
00499     display.setFont(DEFAULT_FONT);
00500     initClock();
00501     initGPIO();
00502     initButtons();
00503     initRandom();
00504     //initAudio();
00505     //initDisplay();
00506 }
00507 
00508 void Core::initButtons() {
00509     #ifndef POK_SIM
00510     Pokitto::initButtons();
00511     #endif
00512 }
00513 
00514 bool Core::isRunning() {
00515     #ifdef POK_SIM
00516     run_state = simulator.isRunning();
00517     #endif // POK_SIM
00518     return run_state;
00519 }
00520 
00521 void Core::initDisplay() {
00522     #if POK_DISPLAYLOGO > 0
00523         showLogo();
00524     #endif
00525     #if POK_USE_CONSOLE > 0
00526         console.AddMessage(MSOURCE_LCD,MSG_INIT_OK);
00527     #endif
00528 }
00529 
00530 void Core::showLogo() {
00531     uint32_t now;
00532     uint8_t state=0; //jump directly to logo, bypass teeth
00533     uint16_t i=0;
00534     uint16_t sc;
00535     while (state < 255/6) {
00536     now=getTime();
00537     if (now>refreshtime) {
00538             refreshtime=now+30;
00539             switch (state) {
00540             case 0:
00541                 /** POKITTO CLEAN **/
00542                 display.directbgcolor = COLOR_BLACK;
00543                 display.fillLCD(display.directbgcolor);
00544                 sc = COLOR_BLACK;
00545                 state++;
00546                 break;
00547             case 1:
00548                 /** POKITTO FADE IN **/
00549                 display.directcolor = display.interpolateColor(sc, COLOR_GREEN, i);
00550                 display.directBitmap(POK_LCD_W/2 - (*Pokitto_logo/2),POK_LCD_H/2-(*(Pokitto_logo+1)/2),Pokitto_logo,1,1);
00551                 i += 28;
00552                 if (i>=0xFF) { state++; i=0;}
00553                 break;
00554             case 2:
00555                 /** POKITTO WAIT **/
00556                 display.directcolor = COLOR_GREEN;
00557                 display.directBitmap(POK_LCD_W/2 - (*Pokitto_logo/2),POK_LCD_H/2-(*(Pokitto_logo+1)/2),Pokitto_logo,1,1);
00558                 i+= 0x3F;
00559                 if (i>0x3FF) state = 255;
00560                 break;
00561             }
00562             if(buttons.aBtn()) state=255;
00563     }
00564     }
00565 }
00566 
00567 void Core::readSettings() {
00568     // ToDo
00569         /*display.contrast = SCR_CONTRAST;
00570         backlight.backlightMin = BACKLIGHT_MIN;
00571         backlight.backlightMax = BACKLIGHT_MAX;
00572         backlight.ambientLightMin = AMBIENTLIGHT_MIN;
00573         backlight.ambientLightMax = AMBIENTLIGHT_MAX;
00574 */
00575         sound.setMaxVol(VOLUME_HEADPHONE_MAX);
00576         sound.globalVolume = VOLUME_STARTUP;
00577 
00578         startMenuTimer = START_MENU_TIMER;
00579 /*
00580         battery.thresolds[0] = BAT_LVL_CRITIC;
00581         battery.thresolds[1] = BAT_LVL_LOW;
00582         battery.thresolds[2] = BAT_LVL_MED;
00583         battery.thresolds[3] = BAT_LVL_FULL;*/
00584 }
00585 
00586 void Core::titleScreen(const char* name){
00587     titleScreen(name, 0);
00588 }
00589 
00590 void Core::titleScreen(const uint8_t* logo){
00591     titleScreen((""), logo);
00592 }
00593 
00594 void Core::titleScreen(){
00595     titleScreen((""));
00596 }
00597 
00598 void Core::titleScreen(const char*  name, const uint8_t *logo){
00599     display.setFont(font5x7);
00600     if(startMenuTimer){
00601         display.fontSize = 1;
00602         display.textWrap = false;
00603         display.persistence = false;
00604         battery.show = false;
00605         display.setColor(BLACK);
00606         while(isRunning()){
00607             if(update()){
00608                 uint8_t logoOffset = name[0]?display.fontHeight:0; //add an offset the logo when there is a name to display
00609                 //draw graphics
00610                 display.setColorDepth(1);
00611                 display.setColor(3);
00612                 //display.drawBitmap(0,0, gamebuinoLogo);
00613                 display.setColor(1);
00614                 if(logo){
00615                     display.drawBitmap(0, 12+logoOffset, logo);
00616                 }
00617                 display.cursorX = 0;
00618                 display.cursorY = 12;
00619                 display.print(name);
00620 
00621                 //A button
00622                 display.cursorX = LCDWIDTH - display.fontWidth*3 -1;
00623                 display.cursorY = LCDHEIGHT - display.fontHeight*3 - 3;
00624                 if((frameCount/16)%2)
00625                   display.println(("\25 \20"));
00626                 else
00627                   display.println(("\25\20 "));
00628                 //B button
00629                 display.cursorX = LCDWIDTH - display.fontWidth*3 - 1;
00630                 display.cursorY++;
00631                 if(sound.globalVolume)
00632                     display.println(("\26\23\24"));
00633                 else
00634                     display.println(("\26\23x"));
00635                 //C button
00636                 display.cursorX = LCDWIDTH - display.fontWidth*3 - 1;
00637                 display.cursorY++;
00638                 //display.println(F("\27SD"));
00639 
00640                 //toggle volume when B is pressed
00641                 if(buttons.pressed(BTN_B)){
00642                     sound.setVolume(sound.getVolume() + 1);
00643                     sound.playTick();
00644                 }
00645                 //leave the menu
00646                 if(buttons.pressed(BTN_A) || ((frameCount>=startMenuTimer)&&(startMenuTimer != 255))){
00647                     startMenuTimer = 255; //don't automatically skip the title screen next time it's displayed
00648                     sound.stopPattern(0);
00649                     sound.playOK();
00650                     break;
00651                 }
00652                 //flash the loader
00653                 //if(buttons.pressed(BTN_C))
00654                     // ToDo changeGame();
00655             }
00656         }
00657         battery.show = true;
00658     }
00659 }
00660 
00661 bool Core::update(bool useDirectMode) {
00662 #if POK_STREAMING_MUSIC
00663         sound.updateStream();
00664     #endif
00665 
00666     if ((((nextFrameMillis - getTime())) > timePerFrame) && frameEndMicros) { //if time to render a new frame is reached and the frame end has ran once
00667         nextFrameMillis = getTime() + timePerFrame;
00668         frameCount++;
00669 
00670         frameEndMicros = 0;
00671         backlight.update();
00672         buttons.update();
00673         battery.update();
00674 
00675         return true;
00676 
00677     } else {
00678         if (!frameEndMicros) { //runs once at the end of the frame
00679             #if POK_ENABLE_SOUND > 0
00680             sound.updateTrack();
00681             sound.updatePattern();
00682             sound.updateNote();
00683             #endif
00684             updatePopup();
00685             displayBattery();
00686 
00687             if(!useDirectMode)
00688                 display.update(); //send the buffer to the screen
00689 
00690             frameEndMicros = 1; //jonne
00691 
00692         }
00693         return false;
00694     }
00695 }
00696 
00697 void Core::displayBattery(){
00698 #if (ENABLE_BATTERY > 0)
00699     //display.setColor(BLACK, WHITE);
00700     uint8_t ox,oy;
00701     ox=display.cursorX;
00702     oy=display.cursorY;
00703     display.cursorX = LCDWIDTH-display.fontWidth+1;
00704     display.cursorY = 0;
00705     switch(battery.level){
00706     case 0://battery critic, power down
00707         sound.stopPattern();
00708         backlight.set(0);
00709         display.clear();
00710         display.fontSize = 1;
00711         display.print(("LOW BATTERY\n"));
00712         display.print(battery.voltage);
00713         display.print(("mV\n\nPLEASE\nTURN OFF"));
00714         display.update();
00715         break;
00716     case 1: //empty battery
00717         if((frameCount % 16) < 8) display.print('\7'); //blinking battery
00718         else display.print('x');
00719         break;
00720     case 2://low battery
00721     case 3://full battery
00722     case 4://full battery
00723         if(battery.show){
00724             display.print(char(5+battery.level));
00725         }
00726         break;
00727     default:
00728         if(battery.show){
00729             display.print('/');
00730         }
00731         break;
00732     }
00733 display.cursorX = ox;
00734 display.cursorY = oy;
00735 #endif
00736 }
00737 
00738 char* Core::filemenu(char *ext) {
00739     display.persistence = false;
00740     uint16_t oldpal0=display.palette[0];
00741     uint16_t oldpal1=display.palette[1];
00742     uint16_t oldpal2=display.palette[2];
00743     display.palette[2]=COLOR_GREEN;
00744     display.palette[1]=COLOR_WHITE;
00745     display.palette[0]=COLOR_BLACK;
00746     uint8_t oldbg=display.bgcolor;
00747     uint8_t oldfg=display.color;
00748     display.color=1;
00749     display.bgcolor=0;
00750 
00751     int8_t activeItem = 0;
00752     int16_t currentY = 100;
00753     int16_t targetY = 0, rowh = display.fontHeight + 2;
00754     boolean exit = false;
00755 
00756     char* txt;
00757 
00758 
00759     while (isRunning()) {
00760         if (update()) {
00761             getFirstFile(ext);
00762             if (buttons.pressed(BTN_A) || buttons.pressed(BTN_B) || buttons.pressed(BTN_C)) {
00763                 exit = true; //time to exit menu !
00764                 targetY = - display.fontHeight * 10 - 2; //send the menu out of the screen
00765                 if (buttons.pressed(BTN_A)) {
00766                     //answer = activeItem;
00767                     sound.playOK();
00768                 } else {
00769                     sound.playCancel();
00770                 }
00771             }
00772             if (exit == false) {
00773                 if (buttons.repeat(BTN_DOWN,4)) {
00774                     activeItem++;
00775                     sound.playTick();
00776                 }
00777                 if (buttons.repeat(BTN_UP,4)) {
00778                     activeItem--;
00779                     sound.playTick();
00780                 }
00781                 //don't go out of the menu
00782                 //if (activeItem == length) activeItem = 0;
00783                 //if (activeItem < 0) activeItem = length - 1;
00784                 if (currentY>targetY) currentY-=16;
00785                 if (currentY<targetY) currentY=targetY;
00786                 //targetY = -rowh * activeItem + (rowh+4); //center the menu on the active item
00787             } else { //exit :
00788                 if (currentY>targetY) currentY-=16;
00789                 if (currentY<targetY) currentY=targetY;
00790                 if ((currentY - targetY) <= 1)
00791                 {
00792                     display.bgcolor=oldbg;
00793                     display.color=oldfg;
00794                     display.palette[0] = oldpal0;
00795                     display.palette[1] = oldpal1;
00796                     display.palette[2] = oldpal2;
00797                     return selectedfile;
00798                 }
00799 
00800             }
00801             //draw a fancy menu
00802             //currentY = 0;//(currentY + targetY) / 2 + 5;
00803             display.cursorX = 0;
00804             display.cursorY = currentY;
00805             display.textWrap = false;
00806             //getFirstFile(ext);
00807             for (int i = 0; i<20; i++) {
00808                 display.invisiblecolor=255;
00809                 display.cursorY = currentY + rowh * i;
00810                 if (i==3) display.color=1;
00811                 if (i == activeItem){
00812                     display.cursorX = 3;
00813 
00814                     //display.fillRoundRect(0, currentY + display.fontHeight * activeItem - 2, LCDWIDTH, (display.fontHeight+3), 3);
00815                     display.color=2;
00816                     display.fillRect(0, currentY + rowh * activeItem - 2, LCDWIDTH, (rowh));
00817                     display.setColor(0,2);
00818                 } else display.setColor(1,0);
00819                 //display.println((char*)*(const unsigned int*)(items+i));
00820                 //display.println((int)i);
00821                 txt = getNextFile(ext);
00822                 if (txt) {
00823                         display.println(txt);
00824                         if (i == activeItem) {
00825                             strcpy(selectedfile,txt);
00826                         }
00827                 } else i--;
00828                 display.setColor(1,0);
00829             } // draw menu loop
00830         } // update
00831     }
00832     return 0;
00833 }
00834 
00835 char* Core::filemenu() {
00836     return filemenu("");
00837 }
00838 
00839 int8_t Core::menu(const char* const* items, uint8_t length) {
00840 #if (ENABLE_GUI > 0)
00841     display.persistence = false;
00842     int8_t activeItem = 0;
00843     int16_t currentY = display.height;
00844     int16_t targetY = 0, rowh = display.fontHeight + 2;
00845     boolean exit = false;
00846     int8_t answer = -1;
00847     while (isRunning()) {
00848         if (update()) {
00849             if (buttons.pressed(BTN_A) || buttons.pressed(BTN_B) || buttons.pressed(BTN_C)) {
00850                 exit = true; //time to exit menu !
00851                 targetY = - display.fontHeight * length - 2; //send the menu out of the screen
00852                 if (buttons.pressed(BTN_A)) {
00853                     answer = activeItem;
00854                     sound.playOK();
00855                 } else {
00856                     sound.playCancel();
00857                 }
00858             }
00859             if (exit == false) {
00860                 if (buttons.repeat(BTN_DOWN,4)) {
00861                     activeItem++;
00862                     sound.playTick();
00863                 }
00864                 if (buttons.repeat(BTN_UP,4)) {
00865                     activeItem--;
00866                     sound.playTick();
00867                 }
00868                 //don't go out of the menu
00869                 if (activeItem == length) activeItem = 0;
00870                 if (activeItem < 0) activeItem = length - 1;
00871 
00872                 targetY = -rowh * activeItem + (rowh+4); //center the menu on the active item
00873             } else { //exit :
00874                 if ((currentY - targetY) <= 1)
00875                 return (answer);
00876             }
00877             //draw a fancy menu
00878             currentY = (currentY + targetY) / 2;
00879             display.cursorX = 0;
00880             display.cursorY = currentY;
00881             display.textWrap = false;
00882             uint16_t fc,bc;
00883             fc = display.color;
00884             bc = display.bgcolor;
00885             for (byte i = 0; i < length; i++) {
00886                 display.cursorY = currentY + rowh * i;
00887                 if (i == activeItem){
00888                     display.cursorX = 3;
00889 
00890                     //display.fillRoundRect(0, currentY + display.fontHeight * activeItem - 2, LCDWIDTH, (display.fontHeight+3), 3);
00891                     display.fillRect(0, currentY + rowh * activeItem - 2, LCDWIDTH, (rowh));
00892                     display.setColor(bc,fc);
00893                 } else display.setColor(fc,bc);
00894 
00895                 display.println((char*)*(const unsigned int*)(items+i));
00896                 display.setColor(fc,bc);
00897             }
00898 
00899         }
00900     }
00901 #else
00902     return 0;
00903 #endif
00904     return 0;
00905 }
00906 
00907 void Core::keyboard(char* text, uint8_t length) {
00908 #if (ENABLE_GUI > 0)
00909     display.persistence = false;
00910     //memset(text, 0, length); //clear the text
00911     text[length-1] = '\0';
00912     //active character in the typing area
00913     int8_t activeChar = 0;
00914     //selected char on the keyboard
00915     int8_t activeX = 0;
00916     int8_t activeY = 2;
00917     //position of the keyboard on the screen
00918     int8_t currentX = LCDWIDTH;
00919     int8_t currentY = LCDHEIGHT;
00920     int8_t targetX = 0;
00921     int8_t targetY = 0;
00922 
00923     while (1) {
00924         if (update()) {
00925             //move the character selector
00926             if (buttons.repeat(BTN_DOWN, 4)) {
00927                 activeY++;
00928                 sound.playTick();
00929             }
00930             if (buttons.repeat(BTN_UP, 4)) {
00931                 activeY--;
00932                 sound.playTick();
00933             }
00934             if (buttons.repeat(BTN_RIGHT, 4)) {
00935                 activeX++;
00936                 sound.playTick();
00937             }
00938             if (buttons.repeat(BTN_LEFT, 4)) {
00939                 activeX--;
00940                 sound.playTick();
00941             }
00942             //don't go out of the keyboard
00943             if (activeX == KEYBOARD_W) activeX = 0;
00944             if (activeX < 0) activeX = KEYBOARD_W - 1;
00945             if (activeY == KEYBOARD_H) activeY = 0;
00946             if (activeY < 0) activeY = KEYBOARD_H - 1;
00947             //set the keyboard position on screen
00948             targetX = -(display.fontWidth+1) * activeX + LCDWIDTH / 2 - 3;
00949             targetY = -(display.fontHeight+1) * activeY + LCDHEIGHT / 2 - 4 - display.fontHeight;
00950             //smooth the keyboard displacement
00951             currentX = (targetX + currentX) / 2;
00952             currentY = (targetY + currentY) / 2;
00953             //type character
00954             if (buttons.pressed(BTN_A)) {
00955                 if (activeChar < (length-1)) {
00956                     byte thisChar = activeX + KEYBOARD_W * activeY;
00957                     if((thisChar == 0)||(thisChar == 10)||(thisChar == 13)) //avoid line feed and carriage return
00958                     continue;
00959                     text[activeChar] = thisChar;
00960                     text[activeChar+1] = '\0';
00961                 }
00962                 activeChar++;
00963                 sound.playOK();
00964                 if (activeChar > length)
00965                 activeChar = length;
00966             }
00967             //erase character
00968             if (buttons.pressed(BTN_B)) {
00969                 activeChar--;
00970                 sound.playCancel();
00971                 if (activeChar >= 0)
00972                 text[activeChar] = 0;
00973                 else
00974                 activeChar = 0;
00975             }
00976             //leave menu
00977             if (buttons.pressed(BTN_C)) {
00978                 sound.playOK();
00979                 while (1) {
00980                     if (update()) {
00981                         //display.setCursor(0,0);
00982                         display.println(("You entered\n"));
00983                         display.print(text);
00984                         display.println(("\n\n\n\x15:okay \x16:edit"));
00985                         if(buttons.pressed(BTN_A)){
00986                             sound.playOK();
00987                             return;
00988                         }
00989                         if(buttons.pressed(BTN_B)){
00990                             sound.playCancel();
00991                             break;
00992                         }
00993                     }
00994                 }
00995             }
00996             //draw the keyboard
00997             for (int8_t y = 0; y < KEYBOARD_H; y++) {
00998                 for (int8_t x = 0; x < KEYBOARD_W; x++) {
00999                     display.drawChar(currentX + x * (display.fontWidth+1), currentY + y * (display.fontHeight+1), x + y * KEYBOARD_W, 1);
01000                 }
01001             }
01002             //draw instruction
01003             display.cursorX = currentX-display.fontWidth*6-2;
01004             display.cursorY = currentY+1*(display.fontHeight+1);
01005             display.print(("\25type"));
01006 
01007             display.cursorX = currentX-display.fontWidth*6-2;
01008             display.cursorY = currentY+2*(display.fontHeight+1);
01009             display.print(("\26back"));
01010 
01011             display.cursorX = currentX-display.fontWidth*6-2;
01012             display.cursorY = currentY+3*(display.fontHeight+1);
01013             display.print(("\27save"));
01014 
01015             //erase some pixels around the selected character
01016             display.setColor(WHITE);
01017             display.drawFastHLine(currentX + activeX * (display.fontWidth+1) - 1, currentY + activeY * (display.fontHeight+1) - 2, 7);
01018             //draw the selection rectangle
01019             display.setColor(BLACK);
01020             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);
01021             //draw keyboard outline
01022             //display.drawRoundRect(currentX - 6, currentY - 6, KEYBOARD_W * (display.fontWidth+1) + 12, KEYBOARD_H * (display.fontHeight+1) + 12, 8, BLACK);
01023             //text field
01024             display.drawFastHLine(0, LCDHEIGHT-display.fontHeight-2, LCDWIDTH);
01025             display.setColor(WHITE);
01026             display.fillRect(0, LCDHEIGHT-display.fontHeight-1, LCDWIDTH, display.fontHeight+1);
01027             //typed text
01028             display.cursorX = 0;
01029             display.cursorY = LCDHEIGHT-display.fontHeight;
01030             display.setColor(BLACK);
01031             display.print(text);
01032             //blinking cursor
01033             if (((frameCount % 8) < 4) && (activeChar < (length-1)))
01034             display.drawChar(display.fontWidth * activeChar, LCDHEIGHT-display.fontHeight, '_',1);
01035         }
01036     }
01037 #endif
01038 }
01039 
01040 void Core::popup(const char* text, uint8_t duration){
01041 #if (ENABLE_GUI > 0)
01042     popupText = text;
01043     popupTimeLeft = duration+12;
01044 #endif
01045 }
01046 
01047 void Core::updatePopup(){
01048 #if (ENABLE_GUI > 0)
01049     if (popupTimeLeft){
01050         uint8_t yOffset = 0;
01051         if(popupTimeLeft<12){
01052             yOffset = 12-popupTimeLeft;
01053         }
01054         display.fontSize = 1;
01055         display.setColor(WHITE);
01056         display.fillRoundRect(0,LCDHEIGHT-display.fontHeight+yOffset-3,84,display.fontHeight+3,3);
01057         display.setColor(BLACK);
01058         display.drawRoundRect(0,LCDHEIGHT-display.fontHeight+yOffset-3,84,display.fontHeight+3,3);
01059         display.cursorX = 4;
01060         display.cursorY = LCDHEIGHT-display.fontHeight+yOffset-1;
01061         display.print(popupText);
01062         popupTimeLeft--;
01063     }
01064 #endif
01065 }
01066 
01067 void Core::setFrameRate(uint8_t fps) {
01068     timePerFrame = 1000 / fps;
01069     sound.prescaler = fps / 20;
01070     sound.prescaler = __avrmax(1, sound.prescaler);
01071 }
01072 
01073 void Core::pickRandomSeed(){
01074         initRandom();
01075 }
01076 
01077 bool Core::collidePointRect(int16_t x1, int16_t y1 ,int16_t x2 ,int16_t y2, int16_t w, int16_t h){
01078     if((x1>=x2)&&(x1<x2+w))
01079     if((y1>=y2)&&(y1<y2+h))
01080     return true;
01081     return false;
01082 }
01083 
01084 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){
01085   return !( x2     >=  x1+w1  ||
01086             x2+w2  <=  x1     ||
01087             y2     >=  y1+h1  ||
01088             y2+h2  <=  y1     );
01089 }
01090 
01091 bool Core::collideBitmapBitmap(int16_t x1, int16_t y1, const uint8_t* b1, int16_t x2, int16_t y2, const uint8_t* b2){
01092   int16_t w1 = pgm_read_byte(b1);
01093   int16_t h1 = pgm_read_byte(b1 + 1);
01094   int16_t w2 = pgm_read_byte(b2);
01095   int16_t h2 = pgm_read_byte(b2 + 1);
01096 
01097   if(collideRectRect(x1, y1, w1, h1, x2, y2, w2, h2) == false){
01098     return false;
01099   }
01100 
01101   int16_t xmin = (x1>=x2)? 0 : x2-x1;
01102   int16_t ymin = (y1>=y2)? 0 : y2-y1;
01103   int16_t xmax = (x1+w1>=x2+w2)? x2+w2-x1 : w1;
01104   int16_t ymax = (y1+h1>=y2+h2)? y2+h2-y1 : h1;
01105   for(uint8_t y = ymin; y < ymax; y++){
01106     for(uint8_t x = xmin; x < xmax; x++){
01107       if(display.getBitmapPixel(b1, x, y) && display.getBitmapPixel(b2, x1+x-x2, y1+y-y2)){
01108         return true;
01109       }
01110     }
01111   }
01112   return false;
01113 }
01114 
01115 
01116 //** EOF **//
01117 
01118 
01119 
01120 
01121 
01122 
01123 
01124