Jonne Valola / PokittoLib Featured

Dependents:   YATTT sd_map_test cPong SnowDemo ... more

PokittoLib

Library for programming Pokitto hardware

How to Use

  1. Import this library to online compiler (see button "import" on the right hand side
  2. DO NOT import mbed-src anymore, a better version is now included inside PokittoLib
  3. Change My_settings.h according to your project
  4. Start coding!

Files at this revision

API Documentation at this revision

Comitter:
Pokitto
Date:
Sun Oct 22 19:02:56 2017 +0000
Parent:
19:d1cf5dff4c21
Child:
21:f8dc968e5739
Commit message:
BLv3 mechanism installed

Changed in this revision

POKITTO_CORE/PokittoCore.cpp Show annotated file Show diff for this revision Revisions of this file
POKITTO_CORE/PokittoCore.h Show annotated file Show diff for this revision Revisions of this file
POKITTO_CORE/PokittoDisk.cpp Show annotated file Show diff for this revision Revisions of this file
POKITTO_HW/iap.cpp Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/POKITTO_CORE/PokittoCore.cpp	Sun Oct 22 19:02:56 2017 +0000
@@ -0,0 +1,1252 @@
+/**************************************************************************/
+/*!
+    @file     PokittoCore.cpp
+    @author   Jonne Valola
+
+    @section LICENSE
+
+    Software License Agreement (BSD License)
+
+    Copyright (c) 2016, Jonne Valola
+    All rights reserved.
+
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions are met:
+    1. Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer.
+    2. Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in the
+    documentation and/or other materials provided with the distribution.
+    3. Neither the name of the copyright holders nor the
+    names of its contributors may be used to endorse or promote products
+    derived from this software without specific prior written permission.
+
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
+    EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
+    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/**************************************************************************/
+
+#include "PokittoCore.h"
+#include "Pokitto_settings.h"
+#include "PokittoConsole.h"
+#include "PokittoFonts.h"
+#include "PokittoTimer.h"
+#include "PokittoLogos.h"
+#include <stdlib.h>
+#ifndef DISABLEAVRMIN
+#define max(a,b) ((a)>(b)?(a):(b))
+#endif // DISABLEAVRMIN
+
+char selectedfile[25];
+
+//#define F
+#ifdef __ARMCC_VERSION
+typedef void (*func_t)(void);
+#endif
+
+#ifndef POK_SIM
+#include "iap.h"
+/** start the user application
+* https://community.nxp.com/thread/417695
+*
+*/
+void start_application(unsigned long app_link_location){
+    //asm(" ldr sp, [r0,#0]");
+    //asm(" ldr pc, [r0,#4]");
+    //This code is not valid for the Cortex-m0+ instruction set.
+    // The equivalent for this (as used by the KL26) is
+__disable_irq();// Start by disabling interrupts, before changing interrupt vectors
+
+// delete buttons
+//pokDeleteButtons();
+
+// completely kill button interrupts in preparation for reset
+LPC_PINT->IENR = 0;
+LPC_PINT->IENF = 0;
+
+SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk & ~(SysTick_CTRL_ENABLE_Msk); //disable systick
+LPC_SYSCON->PDRUNCFG     |=  (1 << 10);       /* Power-down USB PHY         */
+LPC_SYSCON->PDRUNCFG     |=  (1 <<  8);       /* Power-down USB PLL         */
+
+// reset clock source to IRC
+LPC_SYSCON->MAINCLKUEN    = 0x01;             /* Update MCLK Clock Source   */
+LPC_SYSCON->MAINCLKUEN    = 0x00;             /* Toggle Update Register     */
+while (LPC_SYSCON->MAINCLKUEN & 0x01);     /* Wait Until Updated         */
+// switch clock selection to IRC
+LPC_SYSCON->MAINCLKSEL    = 0;             /* Select Clock Source        */
+LPC_SYSCON->MAINCLKUEN    = 0x01;             /* Update MCLK Clock Source   */
+LPC_SYSCON->MAINCLKUEN    = 0x00;             /* Toggle Update Register     */
+while (LPC_SYSCON->MAINCLKUEN & 0x01);     /* Wait Until Updated         */
+//disable PLL clock output
+LPC_SYSCON->SYSPLLCLKUEN = 0;
+while (LPC_SYSCON->SYSPLLCLKUEN & 0x00);
+LPC_SYSCON->SYSPLLCTRL = 0;
+
+//kill peripherals
+LPC_SYSCON->MAINCLKSEL = 0;
+LPC_SYSCON->PRESETCTRL = 0; //disable all peripherals
+
+//power down PLL
+volatile uint32_t tmp;
+tmp = (LPC_SYSCON->PDRUNCFG & 0x000025FFL);
+tmp |= ((1<<7) & 0x000025FFL);
+LPC_SYSCON->PDRUNCFG = (tmp | 0x0000C800L); /* Power-down SYSPLL          */
+
+//Chip_Clock_SetMainClockSource(SYSCTL_MAINCLKSRC_IRC); //switch to IRC
+
+// clear all gpio states
+LPC_GPIO_PORT->PIN[0] = 0;
+LPC_GPIO_PORT->PIN[1] = 0;
+LPC_GPIO_PORT->PIN[2] = 0;
+
+SCB->VTOR = app_link_location;//APPL_ADDRESS; /* Change vector table address */
+#ifndef __ARMCC_VERSION
+asm(" mov r0, %[address]"::[address] "r" (app_link_location));
+asm(" ldr r1, [r0,#0]"); // get the stack pointer value from the program's reset vector
+asm(" mov sp, r1");      // copy the value to the stack pointer
+asm(" ldr r0, [r0,#4]"); // get the program counter value from the program's reset vector
+asm(" blx r0");          // jump to the' start address
+#else
+uint32_t *app_loc = (uint32_t*)app_link_location;
+__set_MSP (app_loc[0]);
+((func_t)(app_loc[1]))();
+#endif
+}
+#endif
+
+// returns a random integar between 0 and maxVal
+int random(int maxVal)
+{
+  return random( 0, maxVal);
+}
+
+// returns a random integar between minVal and maxVal
+int random(int minVal, int maxVal)
+{
+  // int rand(void); included by default from newlib
+  return rand() % (maxVal-minVal+1) + minVal;
+}
+
+using namespace Pokitto;
+
+bool Core::run_state; // this definition needed
+
+/** Components */
+Backlight Core::backlight;
+Buttons Core::buttons;
+Battery Core::battery;
+#if POK_ENABLE_SOUND > 0
+Sound Core::sound;
+#endif
+Display Core::display;
+
+//GB Related
+uint8_t Core::startMenuTimer;
+uint8_t Core::timePerFrame;
+uint32_t Core::nextFrameMillis;
+uint32_t Core::frameCount;
+const char* Core::popupText;
+uint8_t Core::popupTimeLeft;
+uint16_t Core::frameDurationMicros;
+uint32_t Core::frameStartMicros, Core::frameEndMicros;
+uint8_t Core::volbar_visible=0;
+
+
+Core::Core() {
+
+}
+
+
+int Core::updateLoader (uint32_t version, uint32_t jumpaddress) {
+    uint32_t counter=0;
+    uint8_t data[256];
+    /** prepare the flash writing **/
+    float progress=0;
+    int opg=-1;
+    uint32_t fsize=0;
+    fileEnd(); //
+    fsize = fileGetPosition();
+    if (fsize>0x40000-jumpaddress) fsize = 0x40000-jumpaddress; // shouldn't happen!!
+    fileRewind();
+    display.println("PLEASE WAIT");
+    while (1) {
+        //if (counter >= fsize-0x200) {
+        //    display.println("gotcha");
+        //}
+        if (counter >= fsize) {
+                break;
+        }
+        opg=progress;
+        if (fileReadBytes(&data[0],0x100)<0x100) {
+                if (fsize-counter>0x100) {
+                        display.println("ERROR READING LOA.DER FILE");
+                        return 1; // 1 means error
+                }
+        }
+        if (CopyPageToFlash(jumpaddress+counter,data)) {
+                    display.println("FLASH WRITE ERROR");
+                    return 1;
+        } else {
+            counter += 0x100;
+            display.print(".");
+        }
+        }
+    return 0; //success
+}
+
+void Core::showWarning() {
+    display.enableDirectPrinting(true);
+    display.directbgcolor = COLOR_BLACK;
+    display.clearLCD();
+    display.directcolor = COLOR_RED;
+    display.setFont(fntC64UIGfx);
+    display.adjustCharStep = 0;
+    display.adjustLineStep = 0;
+    display.setCursor(10*8,9);
+    display.print("WARNING!");
+    display.directcolor = COLOR_WHITE;
+    display.setCursor(5*8,4*9);
+    display.print("LOUD SOUND THROUGH");
+    display.setCursor(2*8,5*9);
+    display.print("HEADPHONES COULD DAMAGE");
+    display.setCursor(7*8,6*9);
+    display.print("YOUR HEARING.");
+    display.setCursor(5*8,8*9);
+    display.print("USE "); display.directcolor = COLOR_GREEN;
+    display.print("0-100% VOLUME");
+    display.directcolor = COLOR_WHITE;
+    display.setCursor(5*8,9*9);
+    display.print("FOR LISTENING WITH");
+    display.setCursor(8*8,10*9);
+    display.print("HEADPHONES");
+    display.setCursor(5*8,12*9);
+    display.print("USE "); display.directcolor = COLOR_RED;
+    display.print("> 100% VOLUME"); display.directcolor = COLOR_GREEN;
+    display.directcolor = COLOR_WHITE;
+    display.setCursor(1*8,13*9);
+    display.print("ONLY FOR LISTENING VIA THE");
+    display.setCursor(5*8,14*9);
+    display.print("BUILT-IN SPEAKER");
+    display.setCursor(5*8,17*9);
+    display.print("PRESS ");display.directcolor = COLOR_GREEN;
+    display.print("C ");display.directcolor = COLOR_WHITE;
+    display.print("TO ACCEPT");
+    while (!buttons.cBtn()) {
+        wait(100);
+    }
+    display.clearLCD();
+    display.enableDirectPrinting(false);
+}
+
+void Core::jumpToLoader() {
+    //display.setFont(font5x7);
+    //display.adjustCharStep=1;
+    //display.adjustLineStep=2;
+    display.fontSize=1;
+    display.directbgcolor=COLOR_BLACK;
+    display.directcolor=COLOR_GREEN;
+    display.clearLCD();
+    display.setCursor(0,0);
+    display.enableDirectPrinting(true);
+    #ifdef POK_SIM
+    display.println("LOADER IS NOT AVAILABLE ON THE SIMULATOR. PRESS A TO RETURN.");
+    #else
+    uint32_t* bootinfo;
+    uint32_t bootversion=0, sdversion=0, sdjump=0;
+    bool flashloader=false, checkforboot=true;
+    //check for loa.der on SD card
+    #if POK_ENABLE_LOADER_UPDATES > 0
+    pokInitSD();
+    if (fileOpen("LOA.DER", FILE_MODE_BINARY)==0) {
+        //LOA.DER found on SD
+        fileEnd(); // go to end
+        fileSeekRelative(-8); //rewind 8 bytes
+        uint32_t* tptr = &sdversion;
+        fileReadBytes((uint8_t*)tptr,4); //read version number of loader on SD card
+        tptr = &sdjump;
+        fileReadBytes((uint8_t*)tptr,4); //read jump address of loader on sd card
+        fileRewind();
+    }
+    #endif
+    //now start searching for bootkey
+    while (checkforboot)
+    {
+    checkforboot=false; flashloader=false;
+    bootinfo = (uint32_t*)0x3FFF4;
+    if (*bootinfo != 0xB007AB1E) bootinfo = (uint32_t*)0x3FF04; //allow couple of alternative locations
+    if (*bootinfo != 0xB007AB1E) bootinfo = (uint32_t*)0x3FE04; //allow couple of alternative locations
+    if (*bootinfo != 0xB007AB1E) bootinfo = (uint32_t*)0x3F004; //for futureproofing
+    if (*bootinfo != 0xB007AB1E) {
+        // no bootkey found at all
+        display.directcolor=COLOR_YELLOW;
+        display.println("NO LOADER INSTALLED");
+        if (sdversion==0 || sdjump < 0x38000) {
+                //file open of loader failed
+                display.println("NO VALID LOA.DER ON SD");
+                display.println("");
+                display.directcolor=COLOR_GREEN;
+                display.println("PUT LOA.DER ON SD & REBOOT");
+        } else flashloader=true;
+    } else {
+        //loader was found
+        //check if we should update the loader
+        display.directcolor=COLOR_CYAN;
+        display.print("LOADER V.");
+        display.directcolor=COLOR_WHITE;
+        display.println(*(bootinfo+1));
+        #if POK_ENABLE_LOADER_UPDATES
+        if (sdversion>(*(bootinfo+1))) flashloader=true;
+        else start_application(*(bootinfo+2)); //never returns
+        #else
+        start_application(*(bootinfo+2)); //never returns
+        #endif
+    }
+    // update loader if it was requested
+    if(flashloader) {
+            display.directcolor=COLOR_MAGENTA;
+            display.print("NEW LOADER ON SD V.");
+            display.directcolor=COLOR_WHITE;
+            display.println(sdversion);
+            display.directcolor=COLOR_GREEN;
+            display.println("UPDATE LOADER?\n(UP=YES, DOWN=CANCEL)");
+            while(1) {
+                    if (buttons.upBtn()) {
+                        if (updateLoader(sdversion,sdjump)) {
+                            display.println("PUT LOA.DER ON SD AND RETRY");
+                        } else {
+                        display.println("SUCCESS!!");
+                        checkforboot=true; //recheck
+                        }
+                    break;
+                    }
+                    if (buttons.downBtn()) return;
+            }
+    } // if flashloader
+    } // while checkforboot
+    #endif // POK_SIM
+    while (!buttons.aBtn()) {
+        buttons.pollButtons();
+        if (buttons.aBtn()) {
+            while (buttons.aBtn()) {
+                buttons.pollButtons();
+            }
+            return;
+        }
+    }
+}
+
+void Core::askLoader() {
+    display.enableDirectPrinting(true);
+    display.directbgcolor = COLOR_BLACK;
+    display.clearLCD();
+    display.directcolor = COLOR_RED;
+    display.setFont(fntC64UIGfx);
+    display.fontSize=1;
+    display.adjustCharStep = 0;
+    display.adjustLineStep = 0;
+    display.directcolor=COLOR_GREEN;
+    display.set_cursor(12*8,6*8);
+    display.print("ijkl");
+    display.set_cursor(12*8,7*8);
+    display.print("mnop");
+    display.set_cursor(12*8,8*8);
+    display.print("qrst");
+    display.set_cursor(12*8,9*8);
+    display.print("uvwx");
+    display.set_cursor(5*8,12*8);
+    display.print("PRESS");
+    display.directcolor=COLOR_WHITE;
+    display.print(" C ");
+    display.directcolor=COLOR_GREEN;
+    display.print("FOR LOADER");
+    display.directcolor=COLOR_WHITE;
+    display.fontSize=2;
+    int countd=POK_LOADER_COUNTDOWN; uint16_t c2 = getTime();
+    while (countd) {
+        buttons.pollButtons();
+        display.set_cursor(13*8,15*8);
+        display.print(countd);
+        if (getTime()>c2+1000) {
+            c2=getTime();
+            countd--;
+        }
+        if (cBtn()) {while (cBtn()) buttons.pollButtons();jumpToLoader();countd=0;}
+        if (aBtn()) {while (aBtn()) buttons.pollButtons();countd=0;}
+        if (bBtn()) {while (bBtn()) buttons.pollButtons();countd=0;}
+    }
+    display.fontSize=1;
+    display.clearLCD();
+    display.enableDirectPrinting(false);
+}
+
+
+void Core::drawvolbar(int x, int y, int level, bool text) {
+    uint16_t oldcol = display.directcolor;
+    if (text) display.directRectangle(0,0,50,50,COLOR_BLACK);
+    display.directcolor = COLOR_GREEN;
+    if (text) {
+            bool temp = display.isDirectPrintingEnabled();
+            display.enableDirectPrinting(true);
+            display.print(x-1,y-20,(int)sound.getVolume());
+            display.print("  ");
+            display.enableDirectPrinting(temp);
+    }
+    if (level<12) display.directcolor = COLOR_GRAY_80;
+    display.directBitmap(x,y,Pokitto_volumebar,1,1);
+    if (level<24) display.directcolor = COLOR_GRAY_80;
+    display.directBitmap(x+8,y,Pokitto_volumebar,1,1);
+    display.directBitmap(x+8,y-4,Pokitto_volumebar,1,1);
+    display.directcolor = COLOR_RED;
+    if (level<48) display.directcolor = COLOR_GRAY_80;
+    display.directBitmap(x+16,y,Pokitto_volumebar,1,1);
+    display.directBitmap(x+16,y-4,Pokitto_volumebar,1,1);
+    display.directBitmap(x+16,y-8,Pokitto_volumebar,1,1);
+
+    if (level<96) {
+            display.directcolor = COLOR_GRAY_80;
+    }
+    display.directBitmap(x+24,y,Pokitto_volumebar,1,1);
+    display.directBitmap(x+24,y-4,Pokitto_volumebar,1,1);
+    display.directBitmap(x+24,y-8,Pokitto_volumebar,1,1);
+    display.directBitmap(x+24,y-12,Pokitto_volumebar,1,1);
+    if (level<160) {
+            display.directcolor = COLOR_GRAY_80;
+    }
+    display.directBitmap(x+32,y,Pokitto_volumebar,1,1);
+    display.directBitmap(x+32,y-4,Pokitto_volumebar,1,1);
+    display.directBitmap(x+32,y-8,Pokitto_volumebar,1,1);
+    display.directBitmap(x+32,y-12,Pokitto_volumebar,1,1);
+    display.directBitmap(x+32,y-16,Pokitto_volumebar,1,1);
+    display.directcolor = oldcol;
+}
+
+
+#ifdef POK_SIM
+#define VINCMULT 1
+#else
+#define VINCMULT 50
+#endif //POK_SIM
+void Core::setVolLimit() {
+    display.enableDirectPrinting(true);
+    display.adjustCharStep = 0;
+    sound.setMaxVol(VOLUME_HEADPHONE_MAX);
+    int dstate=1;
+    bool wipe = true;
+    float vol = sound.getVolume(); float tvol;
+    volbar_visible=0;
+    while (core.isRunning() && dstate){
+        switch (dstate) {
+        case 1:
+            //redraw
+            if (wipe) {
+            display.clearLCD();
+            display.directcolor = COLOR_WHITE;
+            display.setCursor(4*8,2*8);
+            display.print("SELECT VOLUME LIMIT");
+            display.setCursor(5*8,17*9);
+            display.print("PRESS ");
+            display.directcolor = COLOR_GREEN;
+            display.print("A");
+            display.directcolor = COLOR_WHITE;
+            display.print(" TO ACCEPT");
+            display.directcolor = COLOR_GREEN;
+            // draw frame below first
+            display.setCursor(0,11*8);
+            display.println(" abbbbbbbbbbbbbbbbbbbbbbbc");
+            display.println(" |                       |");
+            display.println(" |                       |");
+            display.println(" |                       |");
+            display.println(" |                       |");
+            display.println(" dbbbbbbbbbbbbbbbbbbbbbbbe");
+            } // wipe = true
+            display.setCursor(6*8,17*9);
+            if (sound.getVolume()-5<=VOLUME_HEADPHONE_MAX) display.directcolor = COLOR_WHITE;
+            else display.directcolor = COLOR_RED;
+            display.directBitmap(21*8-4,6*8,Pokitto_headphones,1,2);
+            display.setCursor(3*8,6*8+6);
+            display.print("HEADPHONES");
+            display.setCursor(3*8,8*8+2);
+            if (sound.getVolume()-8>VOLUME_HEADPHONE_MAX) display.print("TOO LOUD!");
+            else display.print("OK        ");
+            display.directcolor = COLOR_GREEN;
+            display.directBitmap(21*8-4,12*8,Pokitto_speaker,1,2);
+            display.setCursor(3*8,12*8+6);
+            display.print("VOLUME MAX");
+            display.setCursor(3*8,14*8+2);
+            tvol = (vol/float(VOLUME_HEADPHONE_MAX))*100;
+            if (tvol > 100 && tvol < 120) tvol=100;
+            if (sound.getVolume()-5>VOLUME_HEADPHONE_MAX) { display.directcolor=COLOR_RED;}
+            else display.directcolor=COLOR_GREEN;
+            display.print(int(sound.getVolume()));
+            //display.print(int(tvol));
+            display.print("  ");
+            display.directcolor=COLOR_GREEN;
+            drawvolbar(14*8,14*8+4+2,sound.getVolume(),false);
+            //display.setCursor(1,10);
+            //display.print(vol);
+            dstate=2; break;
+        case 2:
+            buttons.pollButtons();
+            if (aBtn()) {dstate=0;while(aBtn()){buttons.pollButtons();};break;}
+            if (rightBtn()) {
+                    if (vol >= VOLUME_HEADPHONE_MAX && vol < VOLUME_HEADPHONE_MAX+1 ) vol += 0.00025f*VINCMULT;
+                    else if (vol >= VOLUME_HEADPHONE_MAX) vol += 0.025f*VINCMULT;
+                    else vol += 0.05f*VINCMULT;
+                    if (vol > VOLUME_HEADPHONE_MAX + 20) {
+                            sound.setMaxVol(VOLUME_SPEAKER_MAX);
+                    }
+                    if (vol > VOLUME_SPEAKER_MAX) vol=VOLUME_SPEAKER_MAX;
+                    sound.setVolume(vol);
+                    dstate=1; wipe=false;
+                    break;
+                    }
+            if (leftBtn()) {
+                    vol -= 0.025f*VINCMULT;
+                    if (vol <= VOLUME_HEADPHONE_MAX) sound.setMaxVol(VOLUME_HEADPHONE_MAX);
+                    if (vol < 0) vol=0;
+                    sound.setVolume(vol);
+                    dstate=1; wipe=false;
+                    break;
+                    }
+            break;
+        }
+    }
+}
+
+void Core::begin() {
+
+    init(); // original functions
+    timePerFrame = POK_FRAMEDURATION;
+	//nextFrameMillis = 0;
+	//frameCount = 0;
+	frameEndMicros = 1;
+	startMenuTimer = 255;
+	//read default settings from flash memory (set using settings.hex)
+	readSettings();
+	//init everything
+	backlight.begin();
+	backlight.set(BACKLIGHT_MAX);
+	buttons.begin();
+	buttons.update();
+	battery.begin();
+	display.begin();
+	#if POK_DISPLAYLOGO
+        showLogo();
+	#endif // POK_DISPLAYLOGO
+
+	display.enableDirectPrinting(true);
+    display.directbgcolor = COLOR_BLACK;
+    display.clearLCD();
+    display.setFont(fntC64UIGfx);
+
+    display.enableDirectPrinting(true);
+    display.directbgcolor = COLOR_BLACK;
+    display.directcolor = COLOR_GREEN;
+    display.clearLCD();
+    display.setFont(fntC64UIGfx);
+    display.adjustCharStep=0;
+    display.adjustLineStep=1;
+    #ifdef JUSTLOAD
+	jumpToLoader();
+	#endif
+
+    #ifndef DISABLE_LOADER
+    askLoader();
+    #endif
+
+	#ifndef DISABLE_SOUND_WARNING
+	//showWarning();
+	setVolLimit();
+	//sound.setVolume(sound.getVolume());//make sure we're at set volume before continue
+	sound.volumeUp();
+	#endif
+	display.enableDirectPrinting(false);
+	display.adjustCharStep=1;
+	display.adjustLineStep=1;
+	display.fontSize=1;
+	display.textWrap=true;
+	#if POK_GAMEBUINO_SUPPORT > 0
+	display.setFont(font5x7);
+	#else
+	display.setFont(fontC64);
+    #endif
+	#if POK_ENABLE_SOUND > 0
+        sound.begin();
+
+	//mute when B is held during start up or if battery is low
+	battery.update();
+	if(buttons.pressed(BTN_B) || (battery.level == 0)){
+		sound.setVolume(0);
+	}
+	else{ //play the startup sound on each channel for it to be louder
+		#if POK_GBSOUND > 0
+		#if(NUM_CHANNELS > 0)
+			sound.playPattern(startupSound, 0);
+		#endif
+		#if(NUM_CHANNELS > 1)
+			sound.playPattern(startupSound, 1);
+		#endif
+		#if(NUM_CHANNELS > 2)
+			sound.playPattern(startupSound, 2);
+		#endif
+		#if(NUM_CHANNELS > 3)
+			sound.playPattern(startupSound, 3);
+		#endif
+		#endif // POK_GBSOUND
+	}
+	#endif // POK ENABLE_SOUND
+}
+
+void Core::init() {
+    run_state = true;
+    display.enableDirectPrinting(false);
+    display.setFont(DEFAULT_FONT);
+    initClock();
+    initGPIO();
+    initButtons();
+    initRandom();
+    //initAudio();
+    //initDisplay();
+}
+
+void Core::init(uint8_t switches) {
+    run_state = true;
+    display.enableDirectPrinting(false);
+    display.setFont(DEFAULT_FONT);
+    initClock();
+    initGPIO();
+    initButtons();
+    initRandom();
+    //initAudio();
+    //initDisplay();
+}
+
+void Core::initButtons() {
+    #ifndef POK_SIM
+    Pokitto::initButtons();
+    #endif
+}
+
+bool Core::isRunning() {
+    #ifdef POK_SIM
+    run_state = simulator.isRunning();
+    #endif // POK_SIM
+    return run_state;
+}
+
+void Core::initDisplay() {
+    #if POK_DISPLAYLOGO > 0
+        showLogo();
+    #endif
+    #if POK_USE_CONSOLE > 0
+        console.AddMessage(MSOURCE_LCD,MSG_INIT_OK);
+    #endif
+}
+
+void Core::showLogo() {
+    uint32_t now;
+    uint8_t state=0; //jump directly to logo, bypass teeth
+    uint16_t counter=0, i=0;
+    uint16_t sc;
+    while (state < 255/6) {
+    now=getTime();
+    if (now>refreshtime) {
+            refreshtime=now+30;
+            switch (state) {
+            case 0:
+                /** POKITTO CLEAN **/
+                display.directbgcolor = COLOR_BLACK;
+                display.fillLCD(display.directbgcolor);
+                sc = COLOR_BLACK;
+                state++;
+                break;
+            case 1:
+                /** POKITTO FADE IN **/
+                display.directcolor = display.interpolateColor(sc, COLOR_GREEN, i);
+                display.directBitmap(POK_LCD_W/2 - (*Pokitto_logo/2),POK_LCD_H/2-(*(Pokitto_logo+1)/2),Pokitto_logo,1,1);
+                i += 28;
+                if (i>=0xFF) { state++; i=0;}
+                break;
+            case 2:
+                /** POKITTO WAIT **/
+                display.directcolor = COLOR_GREEN;
+                display.directBitmap(POK_LCD_W/2 - (*Pokitto_logo/2),POK_LCD_H/2-(*(Pokitto_logo+1)/2),Pokitto_logo,1,1);
+                i+= 0x3F;
+                if (i>0x3FF) state = 255;
+                break;
+            }
+            if(buttons.aBtn()) state=255;
+    }
+    }
+}
+
+void Core::readSettings() {
+    // ToDo
+        /*display.contrast = SCR_CONTRAST;
+		backlight.backlightMin = BACKLIGHT_MIN;
+		backlight.backlightMax = BACKLIGHT_MAX;
+		backlight.ambientLightMin = AMBIENTLIGHT_MIN;
+		backlight.ambientLightMax = AMBIENTLIGHT_MAX;
+*/
+		sound.setMaxVol(VOLUME_HEADPHONE_MAX);
+		sound.globalVolume = VOLUME_STARTUP;
+
+		startMenuTimer = START_MENU_TIMER;
+/*
+		battery.thresolds[0] = BAT_LVL_CRITIC;
+		battery.thresolds[1] = BAT_LVL_LOW;
+		battery.thresolds[2] = BAT_LVL_MED;
+		battery.thresolds[3] = BAT_LVL_FULL;*/
+}
+
+void Core::titleScreen(const char* name){
+	titleScreen(name, 0);
+}
+
+void Core::titleScreen(const uint8_t* logo){
+	titleScreen((""), logo);
+}
+
+void Core::titleScreen(){
+	titleScreen((""));
+}
+
+void Core::titleScreen(const char*  name, const uint8_t *logo){
+	display.setFont(font5x7);
+	if(startMenuTimer){
+		display.fontSize = 1;
+		display.textWrap = false;
+		display.persistence = false;
+		battery.show = false;
+		display.setColor(BLACK);
+		while(isRunning()){
+			if(update()){
+				uint8_t logoOffset = name[0]?display.fontHeight:0; //add an offset the logo when there is a name to display
+				//draw graphics
+				display.setColorDepth(1);
+				display.setColor(3);
+				//display.drawBitmap(0,0, gamebuinoLogo);
+				display.setColor(1);
+				if(logo){
+					display.drawBitmap(0, 12+logoOffset, logo);
+				}
+				display.cursorX = 0;
+				display.cursorY = 12;
+				display.print(name);
+
+				//A button
+				display.cursorX = LCDWIDTH - display.fontWidth*3 -1;
+				display.cursorY = LCDHEIGHT - display.fontHeight*3 - 3;
+				if((frameCount/16)%2)
+				  display.println(("\25 \20"));
+				else
+				  display.println(("\25\20 "));
+				//B button
+				display.cursorX = LCDWIDTH - display.fontWidth*3 - 1;
+				display.cursorY++;
+				if(sound.globalVolume)
+					display.println(("\26\23\24"));
+				else
+					display.println(("\26\23x"));
+				//C button
+				display.cursorX = LCDWIDTH - display.fontWidth*3 - 1;
+				display.cursorY++;
+				//display.println(F("\27SD"));
+
+				//toggle volume when B is pressed
+				if(buttons.pressed(BTN_B)){
+					sound.setVolume(sound.getVolume() + 1);
+					sound.playTick();
+				}
+				//leave the menu
+				if(buttons.pressed(BTN_A) || ((frameCount>=startMenuTimer)&&(startMenuTimer != 255))){
+					startMenuTimer = 255; //don't automatically skip the title screen next time it's displayed
+					sound.stopPattern(0);
+					sound.playOK();
+					break;
+				}
+				//flash the loader
+				//if(buttons.pressed(BTN_C))
+					// ToDo changeGame();
+			}
+		}
+		battery.show = true;
+	}
+}
+
+bool Core::update(bool useDirectMode) {
+#if POK_STREAMING_MUSIC
+        sound.updateStream();
+    #endif
+
+	if ((((nextFrameMillis - getTime())) > timePerFrame) && frameEndMicros) { //if time to render a new frame is reached and the frame end has ran once
+		nextFrameMillis = getTime() + timePerFrame;
+		frameCount++;
+
+		frameEndMicros = 0;
+		backlight.update();
+		buttons.update();
+		battery.update();
+
+		return true;
+
+	} else {
+		if (!frameEndMicros) { //runs once at the end of the frame
+			#if POK_ENABLE_SOUND > 0
+			sound.updateTrack();
+			sound.updatePattern();
+			sound.updateNote();
+			#endif
+			updatePopup();
+			displayBattery();
+
+			if(!useDirectMode)
+				display.update(); //send the buffer to the screen
+
+            frameEndMicros = 1; //jonne
+
+		}
+		return false;
+	}
+}
+
+void Core::displayBattery(){
+#if (ENABLE_BATTERY > 0)
+	//display.setColor(BLACK, WHITE);
+	uint8_t ox,oy;
+	ox=display.cursorX;
+	oy=display.cursorY;
+	display.cursorX = LCDWIDTH-display.fontWidth+1;
+	display.cursorY = 0;
+	switch(battery.level){
+	case 0://battery critic, power down
+		sound.stopPattern();
+		backlight.set(0);
+		display.clear();
+		display.fontSize = 1;
+		display.print(("LOW BATTERY\n"));
+		display.print(battery.voltage);
+		display.print(("mV\n\nPLEASE\nTURN OFF"));
+		display.update();
+		break;
+	case 1: //empty battery
+		if((frameCount % 16) < 8) display.print('\7'); //blinking battery
+		else display.print('x');
+		break;
+	case 2://low battery
+	case 3://full battery
+	case 4://full battery
+		if(battery.show){
+			display.print(char(5+battery.level));
+		}
+		break;
+	default:
+		if(battery.show){
+			display.print('/');
+		}
+		break;
+	}
+display.cursorX = ox;
+display.cursorY = oy;
+#endif
+}
+
+char* Core::filemenu(char *ext) {
+    display.persistence = false;
+    uint16_t oldpal0=display.palette[0];
+    uint16_t oldpal1=display.palette[1];
+    uint16_t oldpal2=display.palette[2];
+    display.palette[2]=COLOR_GREEN;
+    display.palette[1]=COLOR_WHITE;
+    display.palette[0]=COLOR_BLACK;
+    uint8_t oldbg=display.bgcolor;
+    uint8_t oldfg=display.color;
+    display.color=1;
+    display.bgcolor=0;
+
+    int8_t activeItem = 0;
+	int16_t currentY = 100;
+	int16_t targetY = 0, rowh = display.fontHeight + 2;
+	boolean exit = false;
+
+	char* txt;
+
+
+	while (isRunning()) {
+		if (update()) {
+            getFirstFile(ext);
+			if (buttons.pressed(BTN_A) || buttons.pressed(BTN_B) || buttons.pressed(BTN_C)) {
+				exit = true; //time to exit menu !
+				targetY = - display.fontHeight * 10 - 2; //send the menu out of the screen
+				if (buttons.pressed(BTN_A)) {
+					//answer = activeItem;
+					sound.playOK();
+				} else {
+					sound.playCancel();
+				}
+			}
+			if (exit == false) {
+				if (buttons.repeat(BTN_DOWN,4)) {
+					activeItem++;
+					sound.playTick();
+				}
+				if (buttons.repeat(BTN_UP,4)) {
+					activeItem--;
+					sound.playTick();
+				}
+				//don't go out of the menu
+				//if (activeItem == length) activeItem = 0;
+				//if (activeItem < 0) activeItem = length - 1;
+                if (currentY>targetY) currentY-=16;
+                if (currentY<targetY) currentY=targetY;
+				//targetY = -rowh * activeItem + (rowh+4); //center the menu on the active item
+			} else { //exit :
+			    if (currentY>targetY) currentY-=16;
+                if (currentY<targetY) currentY=targetY;
+				if ((currentY - targetY) <= 1)
+				{
+				    display.bgcolor=oldbg;
+				    display.color=oldfg;
+				    display.palette[0] = oldpal0;
+				    display.palette[1] = oldpal1;
+				    display.palette[2] = oldpal2;
+				    return selectedfile;
+				}
+
+			}
+			//draw a fancy menu
+			//currentY = 0;//(currentY + targetY) / 2 + 5;
+			display.cursorX = 0;
+			display.cursorY = currentY;
+			display.textWrap = false;
+			uint16_t fc,bc;
+			fc = display.color;
+            bc = display.bgcolor;
+            //getFirstFile(ext);
+			for (int i = 0; i<20; i++) {
+				display.invisiblecolor=255;
+				display.cursorY = currentY + rowh * i;
+				if (i==3) display.color=1;
+				if (i == activeItem){
+					display.cursorX = 3;
+
+                    //display.fillRoundRect(0, currentY + display.fontHeight * activeItem - 2, LCDWIDTH, (display.fontHeight+3), 3);
+                    display.color=2;
+                    display.fillRect(0, currentY + rowh * activeItem - 2, LCDWIDTH, (rowh));
+                    display.setColor(0,2);
+				} else display.setColor(1,0);
+				//display.println((char*)*(const unsigned int*)(items+i));
+				//display.println((int)i);
+                txt = getNextFile(ext);
+                if (txt) {
+                        display.println(txt);
+                        if (i == activeItem) {
+                            strcpy(selectedfile,txt);
+                        }
+                } else i--;
+                display.setColor(1,0);
+			} // draw menu loop
+		} // update
+	}
+	return 0;
+}
+
+char* Core::filemenu() {
+    return filemenu("");
+}
+
+int8_t Core::menu(const char* const* items, uint8_t length) {
+#if (ENABLE_GUI > 0)
+	display.persistence = false;
+	int8_t activeItem = 0;
+	int16_t currentY = display.height;
+	int16_t targetY = 0, rowh = display.fontHeight + 2;
+	boolean exit = false;
+	int8_t answer = -1;
+	while (isRunning()) {
+		if (update()) {
+			if (buttons.pressed(BTN_A) || buttons.pressed(BTN_B) || buttons.pressed(BTN_C)) {
+				exit = true; //time to exit menu !
+				targetY = - display.fontHeight * length - 2; //send the menu out of the screen
+				if (buttons.pressed(BTN_A)) {
+					answer = activeItem;
+					sound.playOK();
+				} else {
+					sound.playCancel();
+				}
+			}
+			if (exit == false) {
+				if (buttons.repeat(BTN_DOWN,4)) {
+					activeItem++;
+					sound.playTick();
+				}
+				if (buttons.repeat(BTN_UP,4)) {
+					activeItem--;
+					sound.playTick();
+				}
+				//don't go out of the menu
+				if (activeItem == length) activeItem = 0;
+				if (activeItem < 0) activeItem = length - 1;
+
+				targetY = -rowh * activeItem + (rowh+4); //center the menu on the active item
+			} else { //exit :
+				if ((currentY - targetY) <= 1)
+				return (answer);
+			}
+			//draw a fancy menu
+			currentY = (currentY + targetY) / 2;
+			display.cursorX = 0;
+			display.cursorY = currentY;
+			display.textWrap = false;
+			uint16_t fc,bc;
+			fc = display.color;
+            bc = display.bgcolor;
+			for (byte i = 0; i < length; i++) {
+				display.cursorY = currentY + rowh * i;
+				if (i == activeItem){
+					display.cursorX = 3;
+
+                    //display.fillRoundRect(0, currentY + display.fontHeight * activeItem - 2, LCDWIDTH, (display.fontHeight+3), 3);
+                    display.fillRect(0, currentY + rowh * activeItem - 2, LCDWIDTH, (rowh));
+                    display.setColor(bc,fc);
+				} else display.setColor(fc,bc);
+
+				display.println((char*)*(const unsigned int*)(items+i));
+				display.setColor(fc,bc);
+			}
+
+		}
+	}
+#else
+	return 0;
+#endif
+	return 0;
+}
+
+void Core::keyboard(char* text, uint8_t length) {
+#if (ENABLE_GUI > 0)
+	display.persistence = false;
+	//memset(text, 0, length); //clear the text
+	text[length-1] = '\0';
+	//active character in the typing area
+	int8_t activeChar = 0;
+	//selected char on the keyboard
+	int8_t activeX = 0;
+	int8_t activeY = 2;
+	//position of the keyboard on the screen
+	int8_t currentX = LCDWIDTH;
+	int8_t currentY = LCDHEIGHT;
+	int8_t targetX = 0;
+	int8_t targetY = 0;
+
+	while (1) {
+		if (update()) {
+			//move the character selector
+			if (buttons.repeat(BTN_DOWN, 4)) {
+				activeY++;
+				sound.playTick();
+			}
+			if (buttons.repeat(BTN_UP, 4)) {
+				activeY--;
+				sound.playTick();
+			}
+			if (buttons.repeat(BTN_RIGHT, 4)) {
+				activeX++;
+				sound.playTick();
+			}
+			if (buttons.repeat(BTN_LEFT, 4)) {
+				activeX--;
+				sound.playTick();
+			}
+			//don't go out of the keyboard
+			if (activeX == KEYBOARD_W) activeX = 0;
+			if (activeX < 0) activeX = KEYBOARD_W - 1;
+			if (activeY == KEYBOARD_H) activeY = 0;
+			if (activeY < 0) activeY = KEYBOARD_H - 1;
+			//set the keyboard position on screen
+			targetX = -(display.fontWidth+1) * activeX + LCDWIDTH / 2 - 3;
+			targetY = -(display.fontHeight+1) * activeY + LCDHEIGHT / 2 - 4 - display.fontHeight;
+			//smooth the keyboard displacement
+			currentX = (targetX + currentX) / 2;
+			currentY = (targetY + currentY) / 2;
+			//type character
+			if (buttons.pressed(BTN_A)) {
+				if (activeChar < (length-1)) {
+					byte thisChar = activeX + KEYBOARD_W * activeY;
+					if((thisChar == 0)||(thisChar == 10)||(thisChar == 13)) //avoid line feed and carriage return
+					continue;
+					text[activeChar] = thisChar;
+					text[activeChar+1] = '\0';
+				}
+				activeChar++;
+				sound.playOK();
+				if (activeChar > length)
+				activeChar = length;
+			}
+			//erase character
+			if (buttons.pressed(BTN_B)) {
+				activeChar--;
+				sound.playCancel();
+				if (activeChar >= 0)
+				text[activeChar] = 0;
+				else
+				activeChar = 0;
+			}
+			//leave menu
+			if (buttons.pressed(BTN_C)) {
+				sound.playOK();
+				while (1) {
+					if (update()) {
+						//display.setCursor(0,0);
+						display.println(("You entered\n"));
+						display.print(text);
+						display.println(("\n\n\n\x15:okay \x16:edit"));
+						if(buttons.pressed(BTN_A)){
+							sound.playOK();
+							return;
+						}
+						if(buttons.pressed(BTN_B)){
+							sound.playCancel();
+							break;
+						}
+					}
+				}
+			}
+			//draw the keyboard
+			for (int8_t y = 0; y < KEYBOARD_H; y++) {
+				for (int8_t x = 0; x < KEYBOARD_W; x++) {
+					display.drawChar(currentX + x * (display.fontWidth+1), currentY + y * (display.fontHeight+1), x + y * KEYBOARD_W, 1);
+				}
+			}
+			//draw instruction
+			display.cursorX = currentX-display.fontWidth*6-2;
+			display.cursorY = currentY+1*(display.fontHeight+1);
+			display.print(("\25type"));
+
+			display.cursorX = currentX-display.fontWidth*6-2;
+			display.cursorY = currentY+2*(display.fontHeight+1);
+			display.print(("\26back"));
+
+			display.cursorX = currentX-display.fontWidth*6-2;
+			display.cursorY = currentY+3*(display.fontHeight+1);
+			display.print(("\27save"));
+
+			//erase some pixels around the selected character
+			display.setColor(WHITE);
+			display.drawFastHLine(currentX + activeX * (display.fontWidth+1) - 1, currentY + activeY * (display.fontHeight+1) - 2, 7);
+			//draw the selection rectangle
+			display.setColor(BLACK);
+			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);
+			//draw keyboard outline
+			//display.drawRoundRect(currentX - 6, currentY - 6, KEYBOARD_W * (display.fontWidth+1) + 12, KEYBOARD_H * (display.fontHeight+1) + 12, 8, BLACK);
+			//text field
+			display.drawFastHLine(0, LCDHEIGHT-display.fontHeight-2, LCDWIDTH);
+			display.setColor(WHITE);
+			display.fillRect(0, LCDHEIGHT-display.fontHeight-1, LCDWIDTH, display.fontHeight+1);
+			//typed text
+			display.cursorX = 0;
+			display.cursorY = LCDHEIGHT-display.fontHeight;
+			display.setColor(BLACK);
+			display.print(text);
+			//blinking cursor
+			if (((frameCount % 8) < 4) && (activeChar < (length-1)))
+			display.drawChar(display.fontWidth * activeChar, LCDHEIGHT-display.fontHeight, '_',1);
+		}
+	}
+#endif
+}
+
+void Core::popup(const char* text, uint8_t duration){
+#if (ENABLE_GUI > 0)
+	popupText = text;
+	popupTimeLeft = duration+12;
+#endif
+}
+
+void Core::updatePopup(){
+#if (ENABLE_GUI > 0)
+	if (popupTimeLeft){
+		uint8_t yOffset = 0;
+		if(popupTimeLeft<12){
+			yOffset = 12-popupTimeLeft;
+		}
+		display.fontSize = 1;
+		display.setColor(WHITE);
+		display.fillRoundRect(0,LCDHEIGHT-display.fontHeight+yOffset-3,84,display.fontHeight+3,3);
+		display.setColor(BLACK);
+		display.drawRoundRect(0,LCDHEIGHT-display.fontHeight+yOffset-3,84,display.fontHeight+3,3);
+		display.cursorX = 4;
+		display.cursorY = LCDHEIGHT-display.fontHeight+yOffset-1;
+		display.print(popupText);
+		popupTimeLeft--;
+	}
+#endif
+}
+
+void Core::setFrameRate(uint8_t fps) {
+	timePerFrame = 1000 / fps;
+	sound.prescaler = fps / 20;
+	sound.prescaler = __avrmax(1, sound.prescaler);
+}
+
+void Core::pickRandomSeed(){
+        initRandom();
+}
+
+bool Core::collidePointRect(int16_t x1, int16_t y1 ,int16_t x2 ,int16_t y2, int16_t w, int16_t h){
+	if((x1>=x2)&&(x1<x2+w))
+	if((y1>=y2)&&(y1<y2+h))
+	return true;
+	return false;
+}
+
+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){
+  return !( x2     >=  x1+w1  ||
+            x2+w2  <=  x1     ||
+            y2     >=  y1+h1  ||
+            y2+h2  <=  y1     );
+}
+
+bool Core::collideBitmapBitmap(int16_t x1, int16_t y1, const uint8_t* b1, int16_t x2, int16_t y2, const uint8_t* b2){
+  int16_t w1 = pgm_read_byte(b1);
+  int16_t h1 = pgm_read_byte(b1 + 1);
+  int16_t w2 = pgm_read_byte(b2);
+  int16_t h2 = pgm_read_byte(b2 + 1);
+
+  if(collideRectRect(x1, y1, w1, h1, x2, y2, w2, h2) == false){
+    return false;
+  }
+
+  int16_t xmin = (x1>=x2)? 0 : x2-x1;
+  int16_t ymin = (y1>=y2)? 0 : y2-y1;
+  int16_t xmax = (x1+w1>=x2+w2)? x2+w2-x1 : w1;
+  int16_t ymax = (y1+h1>=y2+h2)? y2+h2-y1 : h1;
+  for(uint8_t y = ymin; y < ymax; y++){
+    for(uint8_t x = xmin; x < xmax; x++){
+      if(display.getBitmapPixel(b1, x, y) && display.getBitmapPixel(b2, x1+x-x2, y1+y-y2)){
+        return true;
+      }
+    }
+  }
+  return false;
+}
+
+
+//** EOF **//
+
+
+
+
+
+
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/POKITTO_CORE/PokittoCore.h	Sun Oct 22 19:02:56 2017 +0000
@@ -0,0 +1,263 @@
+/**************************************************************************/
+/*!
+    @file     PokittoCore.h
+    @author   Jonne Valola
+
+    @section LICENSE
+
+    Software License Agreement (BSD License)
+
+    Copyright (c) 2016, Jonne Valola
+    All rights reserved.
+
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions are met:
+    1. Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer.
+    2. Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in the
+    documentation and/or other materials provided with the distribution.
+    3. Neither the name of the copyright holders nor the
+    names of its contributors may be used to endorse or promote products
+    derived from this software without specific prior written permission.
+
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
+    EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
+    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/**************************************************************************/
+
+#ifndef POKITTOCORE_H
+#define POKITTOCORE_H
+
+#include <stdint.h>
+#include <math.h>
+#ifndef POK_SIM
+    #include "pwmout_api.h"
+    #include "HWButtons.h"
+#else
+    #include "PokittoSimulator.h"
+#endif
+#if POK_USE_CONSOLE > 0
+    #include "PokittoConsole.h"
+#endif // POK_USE_CONSOLE
+#if POK_ENABLE_SD > 0
+    #include "PokittoDisk.h"
+#endif
+
+#include "PokittoFonts.h"
+#include "PokittoPalettes.h"
+#include "PokittoDisplay.h"
+#include "PokittoButtons.h"
+#include "PokittoBattery.h"
+#include "PokittoBacklight.h"
+#include "PokittoSound.h"
+#include "PokittoFakeavr.h"
+
+#define PALETTE_SIZE 16
+#define PI 3.141592741f
+
+// For GB compatibility
+#if PROJ_GAMEBUINO > 0
+extern void setup();
+extern void loop();
+#endif // PROJ_GAMEBUINO
+
+extern uint32_t* ptimer; // re-directed tick counter
+
+namespace Pokitto {
+
+/** Core class.
+ *  The Core class is a class consisting of static data and methods.
+ *  It handles the lowlevel hardware functions of the Pokitto.
+ *  It is declared as static to prevent several instances running at same time.
+ * Example:
+ * @code
+ * // A simple "Hello World!" program with Pokitto
+ *
+ * #include "Pokitto.h"
+ *
+ * Pokitto::Core myApp;
+ *
+ * int main() {
+ *     myApp.begin(); // This starts up the console (the display, buttons etc.)
+ *     while(myApp.isRunning()) {
+ *         if(myApp.Update()) {
+ *             myApp.display.print("Hello World!");
+ *         }
+ *     }
+ * }
+ * @endcode
+ */
+
+class Core
+{
+public:
+  /** Create a Core runtime instance
+  */
+  Core();
+
+  /** Backlight component of the Core runtime */
+  static Backlight backlight;
+  /** Buttons component of the Core runtime */
+  static Buttons buttons;
+  /** Battery component of the Core runtime */
+  static Battery battery;
+  /** Sound component of the Core runtime */
+  static Sound sound;
+  /** Display component of the Core runtime */
+  static Display display;
+
+  // EXCECUTION CONTROL
+public:
+  /** Initialize runtime (use this one) */
+  static void begin();
+  /** Initialize runtime (deprecated, avoid) */
+  static void init();
+  /** Initialize runtime with options (deprecated, avoid) */
+  static void init(uint8_t);
+  /** Return run state (1 = running, 0 = shutting down) */
+  static bool isRunning();
+  /** Stop running */
+  static void quit();
+private:
+  /** run_state is true as long as program is running */
+  static bool run_state;
+
+public:
+  // INITIALIZATION
+  /** Initialize display */
+  static void initDisplay();
+  /** Initialize random generator */
+  static void initRandom();
+  /** Initialize GPIO */
+  static void initGPIO();
+  /** Initialize LCD */
+  static void initLCD();
+  /** Initialize Audio */
+  static void initAudio();
+
+
+  // DISPLAY
+public:
+  /** Initialize backlight */
+  static void initBacklight();
+
+private:
+  /** Backlight PWM pointer */
+  #ifndef POK_SIM
+  static pwmout_t backlightpwm;
+  #endif
+
+  // TIMEKEEPING
+public:
+  /** Initialize runtime clock */
+  static void initClock();
+  /** Get value of time elapsed during program in milliseconds */
+  static uint32_t getTime();
+  /** Wait for n milliseconds */
+  static void wait(uint16_t);
+private:
+  /** Time of next refresh */
+  static uint32_t refreshtime;
+
+  // DIRECT TO SCREEN
+public:
+  /** Display Pokitto logo */
+  static void showLogo();
+  static void showWarning();
+  static void setVolLimit();
+
+// BUTTON INPUT HANDLING
+private:
+  static uint8_t heldStates[];
+public:
+  static void initButtons();
+  static void pollButtons();
+  static uint8_t leftBtn();
+  static uint8_t rightBtn();
+  static uint8_t upBtn();
+  static uint8_t downBtn();
+  static uint8_t aBtn();
+  static uint8_t bBtn();
+  static uint8_t cBtn();
+  static uint8_t leftHeld();
+  static uint8_t rightHeld();
+  static uint8_t upHeld();
+  static uint8_t downHeld();
+  static uint8_t aHeld();
+  static uint8_t bHeld();
+  static uint8_t cHeld();
+
+  static uint8_t leftReleased();
+  static uint8_t rightReleased();
+  static uint8_t upReleased();
+  static uint8_t downReleased();
+  static uint8_t aReleased();
+  static uint8_t bReleased();
+  static uint8_t cReleased();
+
+  // AUDIO RELATED
+  static uint8_t ampIsOn();
+  static void ampEnable(uint8_t);
+  static uint8_t soundbyte;
+
+  // GB RELATED
+public:
+    static void readSettings();
+    static void titleScreen(const char* name, const uint8_t *logo);
+	static void titleScreen(const char* name);
+	static void titleScreen(const uint8_t* logo);
+    static void titleScreen();
+    static bool update(bool useDirectMode=false);
+    static uint32_t frameCount;
+    static int8_t menu(const char* const* items, uint8_t length);
+    static char* filemenu(char*);
+    static char* filemenu();
+    static void keyboard(char* text, uint8_t length);
+    static void popup(const char* text, uint8_t duration);
+    static void setFrameRate(uint8_t fps);
+	static void pickRandomSeed();
+
+	static uint8_t getCpuLoad();
+    static uint16_t getFreeRam();
+
+    static bool collidePointRect(int16_t x1, int16_t y1 ,int16_t x2 ,int16_t y2, int16_t w, int16_t h);
+	static bool 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);
+    static bool collideBitmapBitmap(int16_t x1, int16_t y1, const uint8_t* b1, int16_t x2, int16_t y2, const uint8_t* b2);
+
+private:
+    static uint8_t timePerFrame;
+    static uint32_t nextFrameMillis;
+    static void updatePopup();
+    static const char* popupText;
+    static uint8_t popupTimeLeft;
+    static void displayBattery();
+    static uint16_t frameDurationMicros;
+    static uint32_t frameStartMicros, frameEndMicros;
+    static uint8_t startMenuTimer;
+    static int updateLoader(uint32_t,uint32_t);
+public:
+    static uint8_t volbar_visible;
+    static void drawvolbar(int,int,int, bool);
+    static void askLoader();
+    static void jumpToLoader();
+};
+
+// this is the instance used by the system
+extern Core core;
+
+
+}
+
+#endif // POKITTOCORE_H
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/POKITTO_CORE/PokittoDisk.cpp	Sun Oct 22 19:02:56 2017 +0000
@@ -0,0 +1,294 @@
+/**************************************************************************/
+/*!
+    @file     Pokitto_disk.cpp
+    @author   Jonne Valola
+
+    @section LICENSE
+
+    Pokitto development stage library
+    Software License Agreement
+
+    Copyright (c) 2015, Jonne Valola ("Author")
+    All rights reserved.
+
+    This library is intended solely for the purpose of Pokitto development.
+
+    Redistribution and use in source and binary forms, with or without
+    modification requires written permission from Author.
+*/
+/**************************************************************************/
+
+#include "Pokitto.h"
+
+#define SD_MOSI_PORT   0
+#define SD_MISO_PORT   0
+#define SD_SCK_PORT    0
+#define SD_CS_PORT     0
+#define SD_MOSI_PIN   9
+#define SD_MISO_PIN   8
+#define SD_SCK_PIN    6
+#define SD_CS_PIN     7
+
+#if POK_ENABLE_SD > 0
+BYTE res;
+FATFS fs;            /* File system object */
+FATDIR dir;            /* Directory object */
+FILINFO fno;        /* File information */
+
+//static FATFS *FatFs;    /* Pointer to the file system object (logical drive) */
+
+bool diropened=false;
+
+#define SPEAKER 3
+//#define BUFFER_SIZE 256 // was 128
+#define SONGLENGTH 0x1BFBCD // 1072223
+#define FILESIZE 0x1BFBCD
+
+uint8_t filemode = FILE_MODE_UNINITIALIZED;
+char currentfile[15]; // holds current file's name
+
+SPI device(CONNECT_MOSI,CONNECT_MISO,CONNECT_SCK);
+//DigitalOut mmccs(CONNECT_CS);
+
+const char *get_filename_ext(const char *filename) {
+    const char *dot = strrchr(filename, '.');
+    if(!dot || dot == filename) return "";
+    return dot + 1;
+}
+
+__attribute__((section(".SD_Code"))) void initSDGPIO() {
+    LPC_GPIO_PORT->DIR[SD_MOSI_PORT] |= (1  << SD_MOSI_PIN );
+    LPC_GPIO_PORT->DIR[SD_MISO_PORT] |= (1  << SD_MISO_PIN );
+    LPC_GPIO_PORT->DIR[SD_SCK_PORT]  |= (1  << SD_SCK_PIN );
+    LPC_GPIO_PORT->DIR[SD_CS_PORT]   |= (1  << SD_CS_PIN );
+}
+
+__attribute__((section(".SD_Code"))) int pokInitSD() {
+    initSDGPIO();
+    res = disk_initialize();
+    res = (pf_mount(&fs));
+    res = pf_opendir(&dir,"");
+    if (res) diropened=false;
+    else diropened=true;
+    return res;
+}
+
+
+void emptyFname() {
+    for (int i=0; i<13; i++) fno.fname[i]=NULL;
+}
+
+/** PUBLIC FUNCTIONS **/
+
+char* getFirstDirEntry() {
+    res=0;
+    if (!diropened) {
+            pokInitSD();
+    }
+    res = pf_opendir(&dir,"");
+    emptyFname();
+    res = pf_readdir(&dir,&fno); //returns 0 if everything is OK
+    if (res) return 0;
+    while (res==0) { //while res is ok
+        if ((fno.fattrib & 0x02)==0) {
+                if (fno.fattrib & 0x10) {
+                    fno.fname[8]='.';
+                    fno.fname[9]='D';
+                    fno.fname[10]='I';
+                    fno.fname[11]='R';
+                    fno.fname[12]='\0';
+                }
+                return fno.fname;
+        }
+        emptyFname();
+        res = pf_readdir(&dir,&fno); //returns 0 if everything is OK
+        if (res==0 && dir.index==0) break;
+    }
+    return 0;
+}
+
+char* getNextDirEntry() {
+    if (!diropened) pokInitSD();
+    emptyFname();
+	res = pf_readdir(&dir,&fno); //returns 0 if everything is OK
+	if (res==0) {
+	        while (fno.fattrib & 0x02 && !res) {emptyFname(); res = pf_readdir(&dir,&fno);} //system/hidden file
+	        if (fno.fattrib & 0x10) {
+	                int a=12;
+                    while (a) {
+                            fno.fname[a] = fno.fname[a-1];
+                            a--;
+                    }
+                    if (fno.fname[0]) {
+                            fno.fname[0]='/';
+                            a=0;
+                            while (fno.fname[a]) a++;
+                            fno.fname[a]='/';
+                    }
+
+	                /*fno.fname[a++]='.';
+                    fno.fname[a++]='D';
+                    fno.fname[a++]='I';
+                    fno.fname[a++]='R';
+                    fno.fname[a]='\0';*/
+	        }
+	        return fno.fname;
+	}
+    return NULL;
+}
+
+char* getNextFile (char* ext){
+
+    if (!diropened) pokInitSD();
+	int a=1;
+	emptyFname();
+	res = pf_readdir(&dir,&fno); //returns 0 if everything is OK
+	while (res==0 || a) { //while there are entries and
+        if (dir.index==0) return 0; //end of list
+        a = strcmp((const char*)get_filename_ext(fno.fname),(const char*)ext); // returns 0 if strings are identical
+        if (strcmp(ext,"")==0 && (fno.fattrib & 0x10) == 0) a=0;
+        if (a == 0 && (fno.fattrib & 0x10) == 0) return fno.fname;
+        if (fno.fname[0]==NULL) return NULL; //end of files
+        //if (fno.fattrib&0x10) return NULL; //its a directory
+        emptyFname();
+        res = pf_readdir(&dir,&fno); //returns 0 if everything is OK
+	}
+return 0;
+}
+
+
+char* getNextFile() {
+    return getNextFile("");
+}
+
+char* getFirstFile(char* ext) {
+    res=0;
+    if (!diropened) {
+            pokInitSD();
+    }
+    res = pf_opendir(&dir,"");
+    emptyFname();
+    res = pf_readdir(&dir,&fno); //returns 0 if everything is OK
+    if (res) return 0;
+    while (res==0 || (fno.fattrib & 0x10) == 0) {
+        int a=0;
+        a = strcmp((const char*)get_filename_ext(fno.fname),(const char*)ext); // returns 0 if strings are identical
+        if (!strcmp(ext,"")) a=0;
+        if ( a == 0 && (fno.fattrib & 0x10) == 0) return fno.fname;
+        emptyFname();
+        res = pf_readdir(&dir,&fno); //returns 0 if everything is OK
+        if (fno.fname[0]==NULL) break; //end of directory reached, no files found
+        if (res==0 && dir.index==0) break;
+    }
+    return 0;
+}
+
+char* getFirstFile() {
+    return getFirstFile("");
+}
+
+int isThisFileOpen(char* buffer){
+    int a=0;
+    a = strcmp((const char*)buffer,(const char*)currentfile); // returns 0 if strings are identical
+    if ( a == 0 && filemode != FILE_MODE_FAILED) return 1;
+    return 0;
+}
+
+int fileOK() {
+    if (filemode != FILE_MODE_FAILED) return 1;
+    return 0;
+}
+
+uint8_t fileOpen(char* buffer, char fmode) {
+    int err;
+    if (filemode == FILE_MODE_UNINITIALIZED) {
+        int a = pf_mount(&fs);
+        if (a) return 1; // 1 means error in this context
+    }
+
+    filemode = fmode;
+    err = pf_open(buffer);
+    if (err==0) {
+            strcpy(currentfile,(const char*)buffer);
+            return 0; // 0 means all clear
+    }
+    // file open failed
+    filemode = FILE_MODE_FAILED;
+    return 1; // 1 means failed
+}
+
+void fileClose() {
+    filemode = FILE_MODE_UNINITIALIZED;
+    for (uint8_t i=0; i<15; i++) currentfile[i]=0;
+}
+
+int fileGetChar() {
+    BYTE buff[1];
+    WORD br;
+    int err = pf_read(buff, 1, &br);    /* Read data to the buff[] */
+    return buff[0];
+}
+
+void filePutChar(char c) {
+    WORD bw;
+    pf_write((const void*)&c, 1, &bw);
+    pf_write(0, 0, &bw);
+}
+
+void fileWriteBytes(uint8_t * b, uint16_t n) {
+    WORD bw;
+    pf_write((const void*)&b, n, &bw);
+    pf_write(0, 0, &bw);
+}
+
+uint16_t fileReadBytes(uint8_t * b, uint16_t n) {
+    WORD br;
+    pf_read(b, n, &br);    /* Read data to the buff[] */
+    return br;             /* Return number of bytes read */
+}
+
+void fileSeekAbsolute(long n) {
+    res = pf_lseek(n);
+}
+
+void fileSeekRelative(long n) {
+    if (n<0) if (fs.fptr < -n) n=-fs.fptr;
+    else if (n>0) if (fs.fptr+n > fs.fsize) n=fs.fsize-fs.fptr;
+    res = pf_lseek(fs.fptr + n);
+}
+
+void fileRewind() {
+  res = pf_lseek(0);
+}
+
+void fileEnd() {
+  res = pf_lseek(fs.fsize);
+}
+
+long int fileGetPosition() {
+    return fs.fptr;
+}
+
+uint8_t filePeek(long n) {
+    pf_lseek(n);
+    return fileGetChar();
+}
+
+void filePoke(long n, uint8_t c) {
+    pf_lseek(n);
+    filePutChar(c);
+}
+
+int dirOpen() {
+    return pf_opendir(&dir,"");
+}
+
+int dirUp() {
+
+return 0;
+}
+
+#endif // POK_ENABLE_SD
+
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/POKITTO_HW/iap.cpp	Sun Oct 22 19:02:56 2017 +0000
@@ -0,0 +1,729 @@
+#include <stdio.h>
+#include <stdint.h>
+#include <iap.h>
+#include "LPC11U6x.h"
+#include "PokittoDisk.h"
+
+#define TICKRATE_HZ (10)	/* 10 ticks per second */
+/* SystemTick Counter */
+static volatile uint32_t sysTick;
+
+/* LPC1347 IAP entry address */
+#define IAP_LOCATION 0x1fff1ff1
+
+#define last_sector_flash  0x00038000  //0x0000F000
+#define IAP_LAST_SECTOR 28 /* Page number 896 - 1023, 0x00038000 - 0x0003FFFF */
+#define IAP_NUM_BYTES_TO_WRITE 256
+#define WRITECOUNT (IAP_NUM_BYTES_TO_WRITE / 4) /* when data array is in uint32_t */
+
+#define IAP_PREWRRITE_CMD 50 /* Prepare sector for write operation command */
+#define IAP_WRISECTOR_CMD 51
+#define IAP_ERSSECTOR_CMD 52
+#define IAP_REPID_CMD 54
+
+/* IAP command variables */
+static unsigned int command[5], result[4];
+
+/* IAP entry function */
+typedef int (*IAP)(unsigned int[], unsigned int[]);
+IAP iap_entry = (IAP) IAP_LOCATION;
+
+int CopyPageToFlash (uint32_t address, uint8_t* data) {
+    IAP iap_call = (IAP) IAP_LOCATION;
+    uint32_t writecount=0;
+	__disable_irq();
+
+    unsigned int sector, page;
+    bool firstpage=false, erasepage=false;
+
+    //DEBUG//
+    //for (int i=0;i<256;i++) data[i]=0xBB;
+
+    /* Calculate sector based on address */
+    if (address < 0x18000) sector = address/0x1000; // sectors go in 4 k's
+    else if (address >= 0x38000) sector = 28;
+    else if (address >= 0x30000) sector = 27;
+    else if (address >= 0x28000) sector = 26;
+    else if (address >= 0x20000) sector = 25;
+    else sector = 24;
+
+    /* Check is it the first page in the sector */
+    if (sector<24) {
+        if (address == sector * 0x1000) firstpage = true;
+    } else {
+        if (address == (sector-24)*0x4000 + 0x18000) firstpage = true;
+    }
+
+	/* Prepare the sector for writing */
+	command[0] = IAP_PREWRRITE_CMD;						/* Prepare to write/erase command code */
+	command[1] = sector;         							/* Start Sector Number */
+	command[2] = sector;		        					/* End Sector Number */
+	iap_call(command, result);
+    if (result[0]) return 1;
+
+    /* wipe pages when writing the loader */
+    if (address==0x39000) {
+            erasepage=true;
+    }
+
+    /* do sector erase only when writing first page of given sector */
+    if (firstpage) {
+        /* Erase the last sector */
+        command[0] = IAP_ERSSECTOR_CMD;	   					/* Erase command code*/
+        command[1] = sector;             						/* Start Sector Number */
+        command[2] = sector;            						/* End Sector Number */
+        command[3] = SystemCoreClock / 1000UL;	/* Core clock frequency in kHz */
+        iap_call(command, result);
+        if (result[0]) return 1;
+        /* Prepare to write/erase the last sector, needs to be done again because succesful erase re-locks sectors */
+        command[0] = IAP_PREWRRITE_CMD;						/* Prepare to write/erase command code */
+        command[1] = sector;			            				/* Start Sector Number */
+        command[2] = sector;        							/* Start Sector Number */
+        iap_call(command, result);
+        if (result[0]) return 1;
+    }
+
+    /* page erase for bootloader area */
+    if (erasepage) {
+        command[0] = 59; //erase page command
+        command[1] = 896;
+        command[2] = 1023;
+        command[3] = SystemCoreClock / 1000UL;	/* Core clock frequency in kHz */
+        iap_call(command, result);
+        if (result[0]) return 1;
+        /* Prepare to write/erase the last sector, needs to be done again because succesful erase re-locks sectors */
+        command[0] = IAP_PREWRRITE_CMD;						/* Prepare to write/erase command code */
+        command[1] = sector;			            				/* Start Sector Number */
+        command[2] = sector;        							/* Start Sector Number */
+        iap_call(command, result);
+        if (result[0]) return 1;
+    }
+
+	/* Write data to the sectors */
+	command[0] = IAP_WRISECTOR_CMD;						/* Write command code */
+	command[1] = (uint32_t) (uint32_t*) address;              		    /* Destination Flash Address */
+	command[2] = (uint32_t) data;	    				/* Source RAM Address */
+	command[3] = 0x100;             					/* Number of Bytes to be written */
+	command[4] = SystemCoreClock / 1000;				/* System clock frequency */
+	iap_call(command, result);
+    if (result[0]) return 1;
+
+	/* Re-enable interrupt mode */
+	__enable_irq();
+
+    return 0; /*succesful write*/
+
+}
+
+__attribute__((section(".IAP_Code"))) int HelloFromIAP() {
+    static uint32_t array_data[WRITECOUNT];
+    int i;
+    /* Initialize the array data to be written to FLASH */
+	for (i = 0; i < WRITECOUNT; i++) {
+		array_data[i] = 0xB007AB1E;
+	}
+
+    IAP iap_call = (IAP) IAP_LOCATION;
+    uint8_t teahupoo;
+    //readEEPROM(0,&teahupoo,1);
+    teahupoo++;
+    //writeEEPROM(0,&teahupoo,1);
+
+    /** open file **/
+    pokInitSD();
+    char fn[20];
+    char* now;
+    now = (char*)last_sector_flash;
+    switch (now[0]) {
+case 0xAA:
+    fn[0]='B';fn[1]='B';fn[2]='.';fn[3]='B';fn[4]='I';fn[5]='N';fn[6]='\0';break;
+case 0xBB:
+    fn[0]='C';fn[1]='C';fn[2]='.';fn[3]='B';fn[4]='I';fn[5]='N';fn[6]='\0';break;
+default:
+    fn[0]='A';fn[1]='A';fn[2]='.';fn[3]='B';fn[4]='I';fn[5]='N';fn[6]='\0';
+    }
+    if(fileOpen(fn,FILE_MODE_BINARY)) {
+            return 1;
+    } else {
+     for (i = 0; i < WRITECOUNT; i++) {
+		fileReadBytes((uint8_t*)&array_data[i],4);
+	 }
+    }
+
+
+    /** write sector in flash **/
+    /* Read Part Identification Number*/
+	command[0] = IAP_REPID_CMD;								/* Read ID command code */
+	iap_call(command, result);
+
+	__disable_irq();
+
+	/* Prepare to write/erase the last sector */
+	command[0] = IAP_PREWRRITE_CMD;						/* Prepare to write/erase command code */
+	command[1] = IAP_LAST_SECTOR;							/* Start Sector Number */
+	command[2] = IAP_LAST_SECTOR;							/* End Sector Number */
+	iap_call(command, result);
+	/* Erase the last sector */
+	command[0] = IAP_ERSSECTOR_CMD;						/* Erase command code*/
+	command[1] = IAP_LAST_SECTOR;							/* Start Sector Number */
+	command[2] = IAP_LAST_SECTOR;							/* Start Sector Number */
+	command[3] = SystemCoreClock / 1000UL;	/* Core clock frequency in kHz */
+	iap_call(command, result);
+	/* Prepare to write/erase the last sector */
+	command[0] = IAP_PREWRRITE_CMD;						/* Prepare to write/erase command code */
+	command[1] = IAP_LAST_SECTOR;							/* Start Sector Number */
+	command[2] = IAP_LAST_SECTOR;							/* Start Sector Number */
+	iap_call(command, result);
+	/* Write to the last sector */
+	command[0] = IAP_WRISECTOR_CMD;								/* Write command code */
+	command[1] = (uint32_t) last_sector_flash;		        /* Destination Flash Address */
+	command[2] = (uint32_t) &array_data;					/* Source RAM Address */
+	command[3] = IAP_NUM_BYTES_TO_WRITE;					/* Number of Bytes to be written */
+	command[4] = SystemCoreClock / 1000;					/* System clock frequency */
+	iap_call(command, result);
+
+	/* Re-enable interrupt mode */
+	__enable_irq();
+
+
+    SCB->AIRCR = 0x05FA0004; //issue system reset
+    while(1); //should never come here
+    return teahupoo;
+}
+
+
+
+
+void IAPstacksave()
+{
+  /*need to save 32 top bytes of RAM to RAM1*/
+  #define RAM1_0 (*((volatile unsigned long *) 0x20000000))
+  #define RAM1_1 (*((volatile unsigned long *) 0x20000004))
+  #define RAM1_2 (*((volatile unsigned long *) 0x20000008))
+  #define RAM1_3 (*((volatile unsigned long *) 0x2000000C))
+  #define RAM1_4 (*((volatile unsigned long *) 0x20000010))
+  #define RAM1_5 (*((volatile unsigned long *) 0x20000014))
+  #define RAM1_6 (*((volatile unsigned long *) 0x20000018))
+  #define RAM1_7 (*((volatile unsigned long *) 0x2000001C))
+
+  uint32_t *saveloc = (uint32_t*)(0x10002000-0x20); // RAM top - 32 bytes
+  RAM1_0 = *saveloc++;
+  RAM1_1 = *saveloc++;
+  RAM1_2 = *saveloc++;
+  RAM1_3 = *saveloc++;
+  RAM1_4 = *saveloc++;
+  RAM1_5 = *saveloc++;
+  RAM1_6 = *saveloc++;
+  RAM1_7 = *saveloc;
+}
+
+
+char iaptest() {
+    static uint32_t array_data[WRITECOUNT];
+    int i;
+    /* Initialize the array data to be written to FLASH */
+	for (i = 0; i < WRITECOUNT; i++) {
+		array_data[i] = 0x11223340 + i;
+	}
+
+	/* Read Part Identification Number*/
+	command[0] = IAP_REPID_CMD;								/* Read ID command code */
+	iap_entry(command, result);
+
+	/* Reinvoke ISP mode so that reprogamming of Flash possible */
+	__disable_irq();
+
+	command[0] = IAP_REPID_CMD;
+	iap_entry(command, result);
+
+	/* Prepare to write/erase the last sector */
+	command[0] = IAP_PREWRRITE_CMD;						/* Prepare to write/erase command code */
+	command[1] = IAP_LAST_SECTOR;							/* Start Sector Number */
+	command[2] = IAP_LAST_SECTOR;							/* End Sector Number */
+	iap_entry(command, result);
+
+	/* Erase the last sector */
+	command[0] = IAP_ERSSECTOR_CMD;						/* Erase command code*/
+	command[1] = IAP_LAST_SECTOR;							/* Start Sector Number */
+	command[2] = IAP_LAST_SECTOR;							/* Start Sector Number */
+	iap_entry(command, result);
+
+	/* Prepare to write/erase the last sector */
+	command[0] = IAP_PREWRRITE_CMD;						/* Prepare to write/erase command code */
+	command[1] = IAP_LAST_SECTOR;							/* Start Sector Number */
+	command[2] = IAP_LAST_SECTOR;							/* Start Sector Number */
+	iap_entry(command, result);
+
+	/* Write to the last sector */
+	command[0] = IAP_WRISECTOR_CMD;								/* Write command code */
+	command[1] = (uint32_t) last_sector_flash;		/* Destination Flash Address */
+	command[2] = (uint32_t) &array_data;					/* Source RAM Address */
+	command[3] = IAP_NUM_BYTES_TO_WRITE;					/* Number of Bytes to be written */
+	command[4] = SystemCoreClock / 1000;					/* System clock frequency */
+	iap_entry(command, result);
+
+	/* Re-enable interrupt mode */
+	__enable_irq();
+
+	//while (1) {
+	//	__WFI();
+	//}
+
+	return 0;
+
+}
+
+
+//1) EEprom Write
+//
+//Command code: 61
+//Param0: eeprom address (byte, half-word or word aligned)
+//Param1: RAM address (byte, half-word or word aligned)
+//Param2: Number of bytes to be written ( Byte, Half-words write are ok)
+//Param3: System Clock Frequency (CCLK) in kHz
+//
+//Return Code CMD_SUCCESS | SRC_ADDR_NOT_MAPPED | DST_ADDR_NOT_MAPPED
+__attribute__((section(".IAP_Code"))) void writeEEPROM( uint8_t* eeAddress, uint8_t* buffAddress, uint32_t byteCount )
+{
+	unsigned int command[5], result[4];
+
+	command[0] = 61;
+	command[1] = (uint32_t) eeAddress;
+	command[2] = (uint32_t) buffAddress;
+	command[3] = byteCount;
+	command[4] = SystemCoreClock/1000;
+
+	/* Invoke IAP call...*/
+#if (EEPROM_PROFILE!=0)
+	LPC_CT32B0->TCR = 1;
+	__disable_irq();
+  	iap_entry(command, result);
+  	__enable_irq();
+	LPC_CT32B0->TCR = 0;
+#else
+    __disable_irq();
+	iap_entry(command, result);
+	__enable_irq();
+#endif
+	if (0 != result[0])
+	{
+		//Trap error
+		while(1);
+	}
+	return;
+}
+
+//2) EEprom Read
+//Command code: 62
+//Param0: eeprom address (byte, half-word or word aligned)
+//Param1: RAM address (byte, half-word or word aligned)
+//Param2: Number of bytes to be read ( Byte, Half-words read are ok)
+//Param3: System Clock Frequency (CCLK) in kHz
+//
+//Return Code CMD_SUCCESS | SRC_ADDR_NOT_MAPPED | DST_ADDR_NOT_MAPPED
+__attribute__((section(".IAP_Code"))) void readEEPROM( uint8_t* eeAddress, uint8_t* buffAddress, uint32_t byteCount )
+{
+	unsigned int command[5], result[4];
+
+	command[0] = 62;
+	command[1] = (uint32_t) eeAddress;
+	command[2] = (uint32_t) buffAddress;
+	command[3] = byteCount;
+	command[4] = SystemCoreClock/1000;
+
+	/* Invoke IAP call...*/
+	__disable_irq();
+  	iap_entry( command, result);
+  	__enable_irq();
+	if (0 != result[0])
+	{
+		//Trap error
+		while(1);
+	}
+	return;
+}
+
+__attribute__((section(".IAP_Code"))) void IAPreadPartId( uint8_t* eeAddress, uint8_t* buffAddress, uint32_t byteCount )
+{
+	unsigned int command[5], result[4];
+
+	command[0] = 62;
+	command[1] = (uint32_t) eeAddress;
+	command[2] = (uint32_t) buffAddress;
+	command[3] = byteCount;
+	command[4] = SystemCoreClock/1000;
+
+	/* Invoke IAP call...*/
+	__disable_irq();
+  	iap_entry( command, result);
+  	__enable_irq();
+	if (0 != result[0])
+	{
+		//Trap error
+		while(1);
+	}
+	return;
+}
+
+uint8_t eeprom_read_byte(uint8_t* index) {
+    uint8_t val;
+    readEEPROM(index,&val,1);
+    return val;
+}
+
+void eeprom_write_byte(uint8_t*index , uint8_t val) {
+    writeEEPROM(index,&val,1);
+}
+
+/*****************************************************************************
+ * $Id$
+ *
+ * Project: 	NXP LPC11U6x In Application Programming
+ *
+ * Description: Provides access to In-Application Programming (IAP) routines
+ * 			    contained within the bootROM sector of LPC11U6x devices.
+ *
+ * Copyright(C) 2010, NXP Semiconductor
+ * All rights reserved.
+ *
+ *****************************************************************************
+ * Software that is described herein is for illustrative purposes only
+ * which provides customers with programming information regarding the
+ * products. This software is supplied "AS IS" without any warranties.
+ * NXP Semiconductors assumes no responsibility or liability for the
+ * use of the software, conveys no license or title under any patent,
+ * copyright, or mask work right to the product. NXP Semiconductors
+ * reserves the right to make changes in the software without
+ * notification. NXP Semiconductors also make no representation or
+ * warranty that such application will be suitable for the specified
+ * use without further testing or modification.
+ *****************************************************************************/
+
+/* IAP Command Definitions */
+#define	IAP_CMD_PREPARE_SECTORS			  50
+#define	IAP_CMD_COPY_RAM_TO_FLASH		  51
+#define	IAP_CMD_ERASE_SECTORS			    52
+#define	IAP_CMD_BLANK_CHECK_SECTORS		53
+#define	IAP_CMD_READ_PART_ID			    54
+#define	IAP_CMD_READ_BOOT_ROM_VERSION	55
+#define	IAP_CMD_COMPARE					      56
+#define	IAP_CMD_REINVOKE_ISP			    57
+#define IAP_CMD_READ_UID              58
+
+#define IAP_CMD_ERASE_PAGE            59    //new
+
+/* IAP boot ROM location and access function */
+#define IAP_ROM_LOCATION				0x1FFF1FF1UL
+//#define IAP_EXECUTE_CMD(a, b)			((void (*)())(IAP_ROM_LOCATION))(a, b)
+
+__attribute__((section(".IAP_Code"))) void IAP_EXECUTE_CMD(uint32_t* a, uint32_t* b) {
+    void (*user_code_entry)(uint32_t*,uint32_t*);
+    uint32_t *p;
+    p = (uint32_t *)IAP_ROM_LOCATION;
+    user_code_entry = (void (*)(uint32_t*,uint32_t*))(*p);
+    user_code_entry(a, b);
+}
+
+
+/*****************************************************************************
+** Function name:	u32IAP_PrepareSectors
+**
+** Description:		Prepares sector(s) for erasing or write operations. This
+** 								command must be executed before executing the "Copy RAM to
+** 								Flash" or "Erase Sector(s)" commands.
+**
+** Parameters:		u32StartSector - Number of first sector to prepare.
+** 								u32EndSector - Number of last sector to prepare.
+**
+** Returned value:	Status code returned by IAP ROM function.
+**
+******************************************************************************/
+__attribute__((section(".IAP_Code"))) uint32_t u32IAP_PrepareSectors(uint32_t u32StartSector, uint32_t u32EndSector)
+{
+	uint32_t u32Status;
+	uint32_t au32Result[3];
+	uint32_t au32Command[5];
+
+	if (u32EndSector < u32StartSector)
+	{
+		u32Status = IAP_STA_INVALD_PARAM;
+	}
+	else
+	{
+		au32Command[0] = IAP_CMD_PREPARE_SECTORS;
+		au32Command[1] = u32StartSector;
+		au32Command[2] = u32EndSector;
+		__disable_irq();
+		IAP_EXECUTE_CMD(au32Command, au32Result);
+		__enable_irq();
+		u32Status = au32Result[0];
+	}
+	return u32Status;
+}
+
+/*****************************************************************************
+** Function name:	u32IAP_CopyRAMToFlash
+**
+** Description:		Program the flash memory with data stored in RAM.
+**
+** Parameters:	   	u32DstAddr - Destination Flash address, should be a 256
+**                               byte boundary.
+**			 		u32SrcAddr - Source RAM address, should be a word boundary
+**			 		u32Len     - Number of 8-bit bytes to write, must be a
+**			 					 multiple of 256.
+*
+** Returned value:	Status code returned by IAP ROM function.
+**
+******************************************************************************/
+__attribute__((section(".IAP_Code"))) uint32_t u32IAP_CopyRAMToFlash(uint32_t u32DstAddr, uint32_t u32SrcAddr, uint32_t u32Len)
+{
+	uint32_t au32Result[3];
+	uint32_t au32Command[5];
+
+	au32Command[0] = IAP_CMD_COPY_RAM_TO_FLASH;
+	au32Command[1] = u32DstAddr;
+	au32Command[2] = u32SrcAddr;
+	au32Command[3] = u32Len;
+	au32Command[4] = SystemCoreClock / 1000UL;	/* Core clock frequency in kHz */
+
+	IAP_EXECUTE_CMD(au32Command, au32Result);
+
+	return au32Result[0];
+}
+
+/*****************************************************************************
+** Function name:	u32IAP_EraseSectors
+**
+** Description:		Erase a sector or multiple sectors of on-chip Flash memory.
+**
+** Parameters:		u32StartSector - Number of first sector to erase.
+** 					u32EndSector - Number of last sector to erase.
+*
+** Returned value:	Status code returned by IAP ROM function.
+**
+******************************************************************************/
+__attribute__((section(".IAP_Code"))) uint32_t u32IAP_EraseSectors(uint32_t u32StartSector, uint32_t u32EndSector)
+{
+	uint32_t u32Status;
+	uint32_t au32Result[3];
+	uint32_t au32Command[5];
+
+	if (u32EndSector < u32StartSector)
+	{
+		u32Status = IAP_STA_INVALD_PARAM;
+	}
+	else
+	{
+		au32Command[0] = IAP_CMD_ERASE_SECTORS;
+		au32Command[1] = u32StartSector;
+		au32Command[2] = u32EndSector;
+		au32Command[3] = SystemCoreClock / 1000UL;	/* Core clock frequency in kHz */
+
+		IAP_EXECUTE_CMD(au32Command, au32Result);
+
+		u32Status = au32Result[0];
+	}
+	return u32Status;
+}
+
+/*****************************************************************************
+** Function name:	u32IAP_BlankCheckSectors
+**
+** Description:		Blank check a sector or multiple sectors of on-chip flash
+** 					memory.
+**
+** Parameters:		u32StartSector - Number of first sector to check.
+** 					u32EndSector - Number of last sector to check.
+** 					pu32Result[0] - Offset of the first non blank word location
+**                  if the Status Code is IAP_STA_SECTOR_NOT_BLANK.
+** 					pu32Result[1] - Contents of non blank word location.
+**
+** Returned value:	Status code returned by IAP ROM function.
+**
+******************************************************************************/
+__attribute__((section(".IAP_Code"))) uint32_t u32IAP_BlankCheckSectors(uint32_t u32StartSector, uint32_t u32EndSector, uint32_t *pu32Result)
+{
+	uint32_t u32Status;
+	uint32_t au32Result[3];
+	uint32_t au32Command[5];
+
+	if (u32EndSector < u32StartSector)
+	{
+		u32Status = IAP_STA_INVALD_PARAM;
+	}
+	else
+	{
+		au32Command[0] = IAP_CMD_BLANK_CHECK_SECTORS;
+		au32Command[1] = u32StartSector;
+		au32Command[2] = u32EndSector;
+
+		IAP_EXECUTE_CMD(au32Command, au32Result);
+
+		if (au32Result[0] == IAP_STA_SECTOR_NOT_BLANK)
+		{
+			*pu32Result       = au32Result[0];
+			*(pu32Result + 1) = au32Result[1];
+		}
+		u32Status = au32Result[0];
+	}
+	return u32Status;
+}
+
+/*****************************************************************************
+** Function name:	u32IAP_ReadPartID
+**
+** Description:		Read the part identification number.
+**
+** Parameters:		pu32PartID - Pointer to storage for part ID number.
+*
+** Returned value:	Status code returned by IAP ROM function.
+**
+******************************************************************************/
+__attribute__((section(".IAP_Code"))) uint32_t u32IAP_ReadPartID(uint32_t *pu32PartID)
+{
+	uint32_t au32Result[3];
+	uint32_t au32Command[5];
+
+	au32Command[0] = IAP_CMD_READ_PART_ID;
+	__disable_irq();
+	IAP_EXECUTE_CMD(au32Command, au32Result);
+	__enable_irq();
+	*pu32PartID = au32Result[1];
+
+	return au32Result[0];
+}
+
+/*****************************************************************************
+** Function name:	u32IAP_ReadBootVersion
+**
+** Description:		Read the boot code version number.
+**
+** Parameters:		pu32Major - Major version number in ASCII format.
+** 					pu32Minor - Minor version number in ASCII format.
+**
+** Returned value:	Status code returned by IAP ROM function.
+**
+******************************************************************************/
+__attribute__((section(".IAP_Code"))) uint32_t u32IAP_ReadBootVersion(uint32_t *pu32Major, uint32_t *pu32Minor)
+//uint32_t u32IAP_ReadBootVersion(uint32_t *pu32Major)
+{
+	uint32_t au32Result[3];
+	uint32_t au32Command[5];
+
+	au32Command[0] = IAP_CMD_READ_BOOT_ROM_VERSION;
+
+	IAP_EXECUTE_CMD(au32Command, au32Result);
+
+
+	*pu32Major = (au32Result[1] & 0x0000FF00UL) >> 8;
+	*pu32Minor = au32Result[1] & 0x000000FFUL;
+
+	return au32Result[0];
+}
+
+/*****************************************************************************
+** Function name:	u32IAP_Compare
+**
+** Description:		Compares the memory contents at two locations.
+**
+** Parameters:		u32Len - Number of bytes to compare, must be a multiple of 4.
+**					pu32Offset - Offset of the first mismatch if the Status Code is COMPARE_ERROR
+**
+** Returned value:	Status code returned by IAP ROM function.
+**
+******************************************************************************/
+__attribute__((section(".IAP_Code"))) uint32_t u32IAP_Compare(uint32_t u32DstAddr, uint32_t u32SrcAddr, uint32_t u32Len, uint32_t *pu32Offset)
+{
+	uint32_t au32Result[3];
+	uint32_t au32Command[5];
+
+	au32Command[0] = IAP_CMD_COMPARE;
+	au32Command[1] = u32DstAddr;
+	au32Command[2] = u32SrcAddr;
+	au32Command[3] = u32Len;
+
+	IAP_EXECUTE_CMD(au32Command, au32Result);
+
+	if (au32Result[0] == IAP_STA_COMPARE_ERROR)
+	{
+		if (pu32Offset != 0)
+		{
+			*pu32Offset = au32Result[1];
+		}
+	}
+	return au32Result[0];
+}
+
+/*****************************************************************************
+** Function name:	vIAP_ReinvokeISP
+**
+** Description:		Invoke the bootloader in ISP mode.
+**
+** Parameters:		None.
+*
+** Returned value:	None.
+**
+******************************************************************************/
+__attribute__((section(".IAP_Code"))) void vIAP_ReinvokeISP(void)
+{
+	uint32_t au32Result[3];
+	uint32_t au32Command[5];
+
+	au32Command[0] = IAP_CMD_REINVOKE_ISP;
+
+	IAP_EXECUTE_CMD(au32Command, au32Result);
+}
+
+// read UID
+__attribute__((section(".IAP_Code"))) uint32_t u32IAP_ReadUID(uint32_t * pu32UID)
+{
+	uint32_t au32Result[5];
+	uint32_t au32Command[5];
+
+	au32Command[0] = IAP_CMD_READ_UID;
+
+	IAP_EXECUTE_CMD(au32Command, au32Result);
+//	*pu32UID++ =  au32Result[1];
+//	*pu32UID++ =  au32Result[2];
+//	*pu32UID++ =  au32Result[3];
+//	*pu32UID =  au32Result[4];
+
+	*pu32UID =  au32Result[1];
+	*pu32UID++ =  au32Result[2];
+	*pu32UID++ =  au32Result[3];
+	*pu32UID++ =  au32Result[4];
+
+	return au32Result[0];
+
+}
+
+//IAP erase	Page  256B	 64K have 0-255 pages, page0-15 in sector 0,	32K have 0-127 pages, 128k have 0-511 pages,
+__attribute__((section(".IAP_Code"))) uint32_t u32IAP_ErasePage(uint32_t u32StartPage, uint32_t u32EndPage)
+{
+	uint32_t u32Status;
+	uint32_t au32Result[3];
+	uint32_t au32Command[5];
+
+	if (u32EndPage < u32StartPage)
+	{
+		u32Status = IAP_STA_INVALD_PARAM;
+	}
+	else
+	{
+		au32Command[0] = IAP_CMD_ERASE_PAGE;
+		au32Command[1] = u32StartPage;
+		au32Command[2] = u32EndPage;
+		au32Command[3] = SystemCoreClock / 1000UL;	/* Core clock frequency in kHz */
+
+		IAP_EXECUTE_CMD(au32Command, au32Result);
+
+		u32Status = au32Result[0];
+	}
+	return u32Status;
+}
+
+
+/*****************************************************************************
+ **                            End Of File
+ *****************************************************************************/
+