Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: YATTT sd_map_test cPong SnowDemo ... more
PokittoLib
Library for programming Pokitto hardware
How to Use
- Import this library to online compiler (see button "import" on the right hand side
- DO NOT import mbed-src anymore, a better version is now included inside PokittoLib
- Change My_settings.h according to your project
- Start coding!
Revision 20:fa6899411a24, committed 2017-10-22
- 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
--- /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
+ *****************************************************************************/
+