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 46:e7e438368e16, committed 2018-05-21
- Comitter:
- Pokitto
- Date:
- Mon May 21 18:03:14 2018 +0000
- Parent:
- 45:bbfc6002118c
- Child:
- 47:8f962908f6a7
- Commit message:
- Fixes to sound;
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/POKITTO_CORE/PokittoCore.cpp Mon May 21 18:03:14 2018 +0000
@@ -0,0 +1,1390 @@
+/**************************************************************************/
+/*!
+ @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 "Pokitto_settings.h"
+#include "PokittoCore.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;
+
+uint32_t Core::fps_counter;
+bool Core::fps_counter_updated;
+uint32_t Core::fps_refreshtime;
+uint32_t Core::fps_frameCount;
+
+Core::Core() {
+
+}
+
+
+int Core::updateLoader (uint32_t version, uint32_t jumpaddress) {
+ #ifndef POK_SIM
+ 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(".");
+ }
+ }
+ #endif // POK_SIM
+ 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 = 0;
+ #ifndef POK_SIM
+ //read countdown time from settings
+ countd = eeprom_read_byte((uint16_t*)EESETTINGS_LOADERWAIT);
+ #endif
+ if (countd==0 || countd > 5) countd=3;
+ 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;
+ level = level >> 5;
+ if (text) display.directRectangle(0,0,50,50,COLOR_BLACK);
+ if (level<4) display.directcolor = COLOR_GREEN;
+ if (level==4) display.directcolor = COLOR_YELLOW;
+ if (level>4) display.directcolor = COLOR_RED;
+
+ 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<1) display.directcolor = COLOR_GRAY_80;
+ display.directBitmap(x,y,Pokitto_volumebar,1,1);
+ if (level<2) display.directcolor = COLOR_GRAY_80;
+ display.directBitmap(x+8,y,Pokitto_volumebar,1,1);
+ display.directBitmap(x+8,y-4,Pokitto_volumebar,1,1);
+ if (level<3) 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<4) {
+ 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<5) {
+ 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);
+
+ if (level<6) {
+ display.directcolor = COLOR_GRAY_80;
+ }
+ display.directBitmap(x+40,y,Pokitto_volumebar,1,1);
+ display.directBitmap(x+40,y-4,Pokitto_volumebar,1,1);
+ display.directBitmap(x+40,y-8,Pokitto_volumebar,1,1);
+ display.directBitmap(x+40,y-12,Pokitto_volumebar,1,1);
+ display.directBitmap(x+40,y-16,Pokitto_volumebar,1,1);
+ display.directBitmap(x+40,y-20,Pokitto_volumebar,1,1);
+ display.directcolor = oldcol;
+}
+
+
+#ifdef POK_SIM
+#define VINCMULT 0.9f
+#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;
+ #ifndef POK_SIM
+ vol=eeprom_read_byte((uint16_t*)EESETTINGS_VOL);
+ Pokitto::Sound::globalVolume=vol;
+ #endif
+ if (vol>VOLUME_HEADPHONE_MAX) sound.setMaxVol(VOLUME_SPEAKER_MAX);
+ else sound.setMaxVol(VOLUME_HEADPHONE_MAX);
+ #ifdef PRODUCTIONTESTING
+ vol=170;
+ sound.setMaxVol(VOLUME_SPEAKER_MAX);
+ #endif
+ for (uint8_t t=0;t<=vol;t++) {
+ sound.setVolume(t);
+ }
+ volbar_visible=0;
+ int countd=0;
+ #ifndef POK_SIM
+ //read countdown time from settings
+ countd = eeprom_read_byte((uint16_t*)EESETTINGS_VOLWAIT);
+ #endif
+ if (countd==0 || countd > 10) countd=0xFFFF;
+ #ifdef PRODUCTIONTESTING
+ countd=2;
+ #endif
+ uint16_t c2 = getTime();
+ while (core.isRunning() && dstate && countd){
+ if (getTime()>c2+1000) {
+ c2=getTime();
+ if (countd<0xFFFF) countd--;
+ }
+ 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 (discrete_vol<4) 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 (discrete_vol>3) 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;}
+ if ((sound.getVolume()>>5)>3) { display.directcolor=COLOR_RED;}
+ else display.directcolor=COLOR_GREEN;
+ if (discrete_vol==4) display.directcolor=COLOR_YELLOW;
+ if (discrete_vol==7) discrete_vol=6;
+ display.print((int)discrete_vol);
+ //display.print(int(tvol));
+ display.print(" ");
+ display.directcolor=COLOR_GREEN;
+ drawvolbar(14*8,14*8+4+3,sound.getVolume(),false);
+ //display.setCursor(1,10);
+ //display.print(vol);
+ dstate=2; break;
+ case 2:
+ #ifndef POK_SIM
+ buttons.pollButtons();
+ #endif // POK_SIM
+ buttons.update();
+ if (aBtn()) {dstate=0;break;}
+ if (buttons.pressed(BTN_RIGHT)) {
+ countd=0xFFFF; //disable countdown
+ /*if (vol >= VOLUME_HEADPHONE_MAX && vol < VOLUME_HEADPHONE_MAX+1 ) vol += 0.00025f*VINCMULT;
+ else if (vol >= VOLUME_HEADPHONE_MAX) vol += 0.25f*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);*/
+ sound.volumeUp();
+ dstate=1; wipe=false;
+ break;
+ }
+ if (buttons.pressed(BTN_LEFT)) {
+ countd=0xFFFF; //disable countdown
+ /*if (vol >= VOLUME_HEADPHONE_MAX) vol -= 0.25f*VINCMULT;
+ else vol -= 0.05f*VINCMULT;
+ if (vol <= VOLUME_HEADPHONE_MAX) sound.setMaxVol(VOLUME_HEADPHONE_MAX);
+ if (vol < 0) vol=0;
+ sound.setVolume(vol);*/
+ sound.volumeDown();
+ dstate=1; wipe=false;
+ break;
+ }
+ break;
+ }
+ }
+ vol = sound.getVolume();
+ #ifndef POK_SIM
+ if (vol != eeprom_read_byte((uint16_t*)EESETTINGS_VOL)) eeprom_write_byte((uint16_t*)EESETTINGS_VOL,(uint8_t)vol);
+ #endif
+ sound.setVolume(vol);
+ //sound.volumeUp();
+ display.setCursor(0,0);
+}
+
+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
+ #if PROJ_DEVELOPER_MODE != 1
+ showLogo();
+ #endif // PROJ_DEVELOPER_MODE
+ #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
+ #if PROJ_DEVELOPER_MODE != 1
+ askLoader();
+ #endif // PROJ_DEVELOPER_MODE
+ #endif
+
+ #if PROJ_DEVELOPER_MODE==1
+ sound.setMaxVol(VOLUME_SPEAKER_MAX);
+ sound.setVolume(VOLUME_SPEAKER_MAX);
+ #else
+ //showWarning();
+ setVolLimit();
+ display.clear();
+ display.update();
+
+ while(buttons.states[BTN_A])
+ {
+ buttons.update();
+ }
+
+ //sound.setVolume(sound.getVolume());//make sure we're at set volume before continue
+ #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)){
+ 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;
+ }
+}
+
+/**
+ * Update all the subsystems, like graphics, audio, events, etc.
+ * Note: the update rect is used for drawing only part of the screen buffer to LCD. Because of speed optimizations,
+ * the x, y, and width of the update rect must be dividable by 4 pixels, and the height must be dividable by 8 pixels.
+ * The update rect is currently used for 220x176, 4 colors, screen mode only.
+ * @param useDirectMode True, if only direct screen drawing is used. False, if the screen buffer is drawn. Note: If sprites are enabled, they are drawn in both modes.
+ * @param updRectX The update rect.
+ * @param updRectY The update rect.
+ * @param updRectW The update rect.
+ * @param updRectH The update rect.
+ */
+bool Core::update(bool useDirectMode, uint8_t updRectX, uint8_t updRectY, uint8_t updRectW, uint8_t updRectH) {
+
+ #if POK_STREAMING_MUSIC
+ sound.updateStream();
+ #endif
+
+ uint32_t now = getTime();
+ if ((((nextFrameMillis - now)) > timePerFrame) && frameEndMicros) { //if time to render a new frame is reached and the frame end has ran once
+ nextFrameMillis = now + timePerFrame;
+ frameCount++;
+
+ frameEndMicros = 0;
+ backlight.update();
+ buttons.update();
+ battery.update();
+
+ // FPS counter
+ #if defined(PROJ_USE_FPS_COUNTER) || defined(PROJ_SHOW_FPS_COUNTER)
+ const uint32_t fpsInterval_ms = 1000*3;
+
+ fps_frameCount++;
+ if (now > fps_refreshtime) {
+ fps_counter = (1000*fps_frameCount) / (now - fps_refreshtime + fpsInterval_ms);
+ fps_refreshtime = now + fpsInterval_ms;
+ fps_frameCount = 0;
+ fps_counter_updated = true;
+ }
+ #endif
+
+ 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();
+
+ display.update(useDirectMode, updRectX, updRectY, updRectW, updRectH); //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) {
+ uint8_t oldPersistence = display.persistence;
+ 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;
+
+ int16_t rowh = display.fontHeight + 2;
+ int8_t activeItem = 0;
+ int16_t currentTopItem = 0;
+ int16_t itemsPerScreen = (display.height+1) / rowh;
+ int16_t numOfItemsFound = 0;
+ boolean exit = false;
+
+ char* txt;
+
+ pokInitSD();
+
+ bool updated = true;
+ while (isRunning()) {
+ if (update(true)) {
+ if (buttons.pressed(BTN_A) || buttons.pressed(BTN_B) || buttons.pressed(BTN_C)) {
+ exit = true; //time to exit menu !
+ if (buttons.pressed(BTN_A)) {
+ sound.playOK();
+ } else {
+ *selectedfile = 0;
+ sound.playCancel();
+ }
+ updated = true; // update screen
+ }
+ if (exit == false) {
+ if (buttons.repeat(BTN_DOWN,4)) {
+ if( ++activeItem >= numOfItemsFound ) activeItem = numOfItemsFound - 1;
+ if( activeItem >= currentTopItem + itemsPerScreen) currentTopItem += itemsPerScreen; // next page
+ sound.playTick();
+ updated = true; // update screen
+ }
+ if (buttons.repeat(BTN_UP,4)) {
+ if( --activeItem < 0 ) activeItem = 0;
+ if( activeItem < currentTopItem) currentTopItem -= itemsPerScreen; // previous page
+ sound.playTick();
+ updated = true; // update screen
+ }
+
+ } else { //exit :
+ display.bgcolor=oldbg;
+ display.color=oldfg;
+ display.palette[0] = oldpal0;
+ display.palette[1] = oldpal1;
+ display.palette[2] = oldpal2;
+ display.persistence = oldPersistence;
+ return selectedfile;
+ }
+
+ //draw a fancy menu
+ display.textWrap = false;
+ uint16_t fc,bc;
+ fc = display.color;
+ bc = display.bgcolor;
+ if( updated ) { // update screen?
+ #if POK_SIM
+ getFirstFile(ext);
+ #else
+ bool isFirstFile = true;
+ #endif
+ for (int i = 0; ; i++) {
+ display.cursorX = 0;
+ display.invisiblecolor=255;
+ display.cursorY = (i - currentTopItem ) * rowh;
+
+ // read the file name from SD
+ #ifndef POK_SIM
+ if(isFirstFile) {
+ txt = getFirstFile(ext);
+ isFirstFile = false;
+ }
+ else
+ #endif
+
+ txt = getNextFile(ext);
+
+ if (txt) {
+
+ numOfItemsFound = i+1;
+
+ // Draw active line with diffrent backgtound and char color
+ if (i == activeItem){
+ display.cursorX = 3;
+ display.color=2;
+ display.fillRect(0, display.cursorY - 2, LCDWIDTH, rowh);
+ display.setColor(0,2);
+ } else display.setColor(1,0);
+
+ // break loop if going out of screen
+ if(i >= currentTopItem + itemsPerScreen ) {
+ break;
+ }
+
+ // Display only if the file is on the current page
+ if( i >= currentTopItem) {
+ display.print(display.cursorX, display.cursorY, txt);
+ if (i == activeItem)
+ strcpy(selectedfile,txt);
+ }
+ } else
+ break; // break loop as no more files found
+
+ display.setColor(1,0);
+ } // end for
+
+ display.update();
+ }
+ updated = false;
+ } // update
+
+ display.setColor(1,0);
+ }
+ 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/PokittoSound.cpp Mon May 21 18:03:14 2018 +0000
@@ -0,0 +1,942 @@
+/**************************************************************************/
+/*!
+ @file PokittoSound.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.
+*/
+/**************************************************************************/
+
+/*
+ * NOTE:
+ * API of the Pokitto Sound library is partially identical to the Gamebuino Sound API.
+ * Due to the difference in architecture (ARM Cortex-M0+ in mbed environment vs. 8-bit AVR)
+ * large parts are not identical. Most functions were rewritten, with only API remaining.
+ * We want to give attribution to the original author's project:
+ *
+ * License for Gamebuino-identical code:
+ *
+ * (C) Copyright 2014 Aurélien Rodot. All rights reserved.
+ *
+ * This file is part of the Gamebuino Library (http://gamebuino.com)
+ *
+ * The Gamebuino Library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ */
+
+#include "PokittoSound.h"
+#include "Pokitto_settings.h"
+#include "PokittoCore.h"
+#include "Synth.h"
+
+#ifndef POK_SIM
+#include "HWSound.h"
+#else
+#include "SimSound.h"
+#include "PokittoSimulator.h"
+#endif
+
+typedef uint8_t byte;
+
+using namespace Pokitto;
+
+/** discrete hardware volume control **/
+
+uint8_t Pokitto::discrete_vol = 0;
+uint8_t const Pokitto::discrete_vol_levels[8] {0,32,64,96,128,160,192,224};
+uint8_t const Pokitto::discrete_vol_hw_levels[8] {0,27,64,96,36,117,127,127};
+uint8_t const Pokitto::discrete_vol_multipliers[8] {0,127,127,127,192,192,255,255};
+
+Pokitto::Core _soundc;
+
+uint8_t Sound::prescaler;
+uint16_t Sound::globalVolume;
+uint16_t Sound::volumeMax = VOLUME_HEADPHONE_MAX;
+uint8_t Sound::headPhoneLevel=1;
+
+bool Sound::trackIsPlaying[NUM_CHANNELS];
+bool Sound::patternIsPlaying[NUM_CHANNELS];
+uint8_t Sound::outputPitch[NUM_CHANNELS];
+int8_t Sound::outputVolume[NUM_CHANNELS];
+
+uint16_t *Sound::trackData[NUM_CHANNELS];
+uint8_t Sound::trackCursor[NUM_CHANNELS];
+uint16_t **Sound::patternSet[NUM_CHANNELS];
+int8_t Sound::patternPitch[NUM_CHANNELS];
+
+// pattern data
+uint16_t *Sound::patternData[NUM_CHANNELS];
+uint16_t **Sound::instrumentSet[NUM_CHANNELS];
+bool Sound::patternLooping[NUM_CHANNELS];
+uint16_t Sound::patternCursor[NUM_CHANNELS];
+
+// note data
+uint8_t Sound::notePitch[NUM_CHANNELS];
+uint8_t Sound::noteDuration[NUM_CHANNELS];
+int8_t Sound::noteVolume[NUM_CHANNELS];
+bool Sound::notePlaying[NUM_CHANNELS];
+
+// commands data
+int8_t Sound::commandsCounter[NUM_CHANNELS];
+int8_t Sound::volumeSlideStepDuration[NUM_CHANNELS];
+int8_t Sound::volumeSlideStepSize[NUM_CHANNELS];
+uint8_t Sound::arpeggioStepDuration[NUM_CHANNELS];
+int8_t Sound::arpeggioStepSize[NUM_CHANNELS];
+uint8_t Sound::tremoloStepDuration[NUM_CHANNELS];
+int8_t Sound::tremoloStepSize[NUM_CHANNELS];
+
+// instrument data
+uint16_t *Sound::instrumentData[NUM_CHANNELS];
+uint8_t Sound::instrumentLength[NUM_CHANNELS]; //number of steps in the instrument
+uint8_t Sound::instrumentLooping[NUM_CHANNELS]; //how many steps to loop on when the last step of the instrument is reached
+uint16_t Sound::instrumentCursor[NUM_CHANNELS]; //which step is being played
+uint8_t Sound::instrumentNextChange[NUM_CHANNELS]; //how many frames before the next step
+
+//current step data
+int8_t Sound::stepVolume[NUM_CHANNELS];
+uint8_t Sound::stepPitch[NUM_CHANNELS];
+uint8_t Sound::chanVolumes[NUM_CHANNELS];
+
+#if (POK_ENABLE_SOUND < 1)
+ #define NUM_CHANNELS 0
+#endif
+
+#if(NUM_CHANNELS > 0)
+ #ifndef POK_SIM
+ uint32_t sbyte;
+ #else
+ uint32_t sbyte;
+ float pwm1;
+ #endif // POK_SIM
+
+//declare these variables globally for faster access
+uint8_t _rand = 1;
+uint8_t _chanCount[NUM_CHANNELS]; //counts until the next change of the waveform
+bool _chanState[NUM_CHANNELS]; //if the waveform is currently high or low
+uint8_t _chanHalfPeriod[NUM_CHANNELS]; //duration of half the period of the waveform
+uint8_t _chanOutputVolume[NUM_CHANNELS]; //amplitude of the outputted waveform
+uint8_t _chanOutput[NUM_CHANNELS]; //current value of the outputted waveform
+bool _chanNoise[NUM_CHANNELS]; //if a random value should be added to the waveform to generate noise
+
+#if POK_GBSOUND > 0
+const uint16_t squareWaveInstrument[] = {0x0101, 0x03F7};
+const uint16_t noiseInstrument[] = {0x0101, 0x03FF};
+const uint16_t* const defaultInstruments[] = {squareWaveInstrument,noiseInstrument};
+
+const uint16_t playOKPattern[] = {0x0005,0x138,0x168,0x0000};
+const uint16_t playCancelPattern[] = {0x0005,0x168,0x138,0x0000};
+const uint16_t playTickP[] = {0x0045,0x168,0x0000};
+#endif
+#if(EXTENDED_NOTE_RANGE > 0)
+//extended note range
+#define NUM_PITCH 59
+const uint8_t _halfPeriods[NUM_PITCH] = {246,232,219,207,195,184,174,164,155,146,138,130,123,116,110,104,98,92,87,82,78,73,69,65,62,58,55,52,49,46,44,41,39,37,35,33,31,29,28,26,25,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6};
+#else
+//regular note range
+#define NUM_PITCH 36
+const uint8_t _halfPeriods[NUM_PITCH] = {246,232,219,207,195,184,174,164,155,146,138,130,123,116,110,104,98,92,87,82,78,73,69,65,62,58,55,52,49,46,44,41,39,37,35,33};
+#endif
+
+#endif
+
+void Pokitto::audio_IRQ() {
+ #if POK_STREAMING_MUSIC > 0
+ #if POK_STREAMFREQ_HALVE > 0
+ streamstep = 1-streamstep;
+ #else
+ streamstep=1;
+ #endif
+
+ streamstep &= streamon; //check if stream is on
+
+ if(streamvol && streamstep) {
+ uint8_t output = (*currentPtr++);
+ sbyte = output;
+ } else {
+ sbyte = 0; // duty cycle
+ }
+
+ if (currentPtr >= endPtr)
+ {
+ currentBuffer++;
+ if (currentBuffer==4) currentBuffer=0;
+ currentPtr = buffers[currentBuffer];
+ endPtr = currentPtr + BUFFER_SIZE;
+ }
+
+ #endif // POK_STREAMING_MUSIC
+ #if (NUM_CHANNELS > 0)
+ Sound::generateOutput();
+ #endif
+}
+
+void Sound::volumeUp() {
+ Pokitto::discrete_vol++;
+ if (discrete_vol>7) discrete_vol=7;
+ globalVolume = discrete_vol_levels[discrete_vol];
+ setVolume(globalVolume);
+ //if (globalVolume>VOLUME_HEADPHONE_MAX) setVolume(getVolume()+VOLUME_STEP*2);
+ //else setVolume(getVolume()+VOLUME_STEP);
+}
+
+void Sound::volumeDown() {
+ if (discrete_vol) Pokitto::discrete_vol--;
+ globalVolume = discrete_vol_levels[discrete_vol];
+ setVolume(globalVolume);
+ //if (globalVolume>VOLUME_HEADPHONE_MAX) setVolume(getVolume()-VOLUME_STEP*4);
+ //else setVolume(getVolume()-VOLUME_STEP);
+}
+
+
+void Sound::setMaxVol(int16_t v) {
+ if (v < 0) v = 0; //prevent nasty wraparound
+ if (v > VOLUME_SPEAKER_MAX) {
+ v = VOLUME_SPEAKER_MAX;
+ }
+ volumeMax = v;
+ setVolume(globalVolume);
+}
+
+uint16_t Sound::getMaxVol() {
+ return volumeMax;
+}
+
+void Sound::updateStream() {
+ #if POK_STREAMING_MUSIC
+ if (oldBuffer != currentBuffer) {
+ if (currentBuffer==0) fileReadBytes(&buffers[3][0],BUFFER_SIZE);
+ else if (currentBuffer==1) fileReadBytes(&buffers[0][0],BUFFER_SIZE);
+ else if (currentBuffer==2) fileReadBytes(&buffers[1][0],BUFFER_SIZE);
+ else fileReadBytes(&buffers[2][0],BUFFER_SIZE);
+ oldBuffer = currentBuffer;
+ streamcounter += BUFFER_SIZE;
+ }
+
+ #ifndef POK_SIM
+ if ( streamcounter > fs.fsize - (BUFFER_SIZE)) {
+ #else
+ if ( streamcounter > getFileLength() - (BUFFER_SIZE)) {
+ #endif
+ streamcounter=0;
+ #if POK_STREAM_LOOP > 0
+ fileRewind();
+ #else
+ #ifndef POK_SIM
+ streamon=0;
+ #endif // POK_SIM
+ #endif // POK_STREAM_LOOP
+ }
+ #endif
+}
+
+void Sound::begin() {
+#if POK_ENABLE_SOUND > 0
+soundInit();
+ampEnable(true);
+#endif
+#if (NUM_CHANNELS > 0)
+#if POK_ENABLE_SOUND > 0
+#if POK_GBSOUND > 0
+ prescaler = 1;
+ for(byte i=0; i<NUM_CHANNELS; i++){
+ chanVolumes[i] = VOLUME_CHANNEL_MAX;
+ changeInstrumentSet(defaultInstruments, i); //load default instruments. #0:square wave, #1: noise
+ command(CMD_INSTRUMENT, 0, 0, i); //set the default instrument to square wave
+ }
+#endif // POK_GBSOUND
+#endif //POK_ENABLE_SOUND
+#endif
+}
+
+void Sound::playTrack(const uint16_t* track, uint8_t channel){
+#if(NUM_CHANNELS > 0)
+ if(channel>=NUM_CHANNELS)
+ return;
+ stopTrack(channel);
+ trackCursor[channel] = 0;
+ trackData[channel] = (uint16_t*)track;
+ trackIsPlaying[channel] = true;
+#endif
+}
+
+void Sound::stopTrack(uint8_t channel){
+#if(NUM_CHANNELS > 0)
+ if(channel>=NUM_CHANNELS)
+ return;
+ trackIsPlaying[channel] = false;
+ stopPattern(channel);
+#endif
+}
+
+void Sound::stopTrack(){
+#if(NUM_CHANNELS > 0)
+ for(uint8_t i=0; i<NUM_CHANNELS; i++){
+ stopTrack(i);
+ }
+#endif
+}
+
+void Sound::updateTrack(uint8_t channel){
+#if(NUM_CHANNELS > 0)
+ if(channel>=NUM_CHANNELS)
+ return;
+ if(trackIsPlaying[channel] && !patternIsPlaying[channel]){
+ uint16_t data = pgm_read_word(trackData[channel] + trackCursor[channel]);
+ if(data == 0xFFFF){ //en of the track
+ trackIsPlaying[channel] = false;
+ return;
+ }
+ uint8_t patternID = data & 0xFF;
+ data >>= 8;
+ patternPitch[channel] = data;
+ playPattern((const uint16_t*)pgm_read_word(&(patternSet[channel][patternID])), channel);
+ trackCursor[channel] ++;
+ }
+#endif
+}
+
+void Sound::updateTrack(){
+#if(NUM_CHANNELS > 0)
+ for (uint8_t i=0; i<NUM_CHANNELS; i++){
+ updateTrack(i);
+ }
+#endif
+}
+
+void Sound::changePatternSet(const uint16_t* const* patterns, uint8_t channel){
+#if(NUM_CHANNELS > 0)
+ if(channel>=NUM_CHANNELS)
+ return;
+ patternSet[channel] = (uint16_t**)patterns;
+#endif
+}
+
+void Sound::playPattern(const uint16_t* pattern, uint8_t channel){
+#if(NUM_CHANNELS > 0)
+ if(channel>=NUM_CHANNELS)
+ return;
+ stopPattern(channel);
+ patternData[channel] = (uint16_t*)pattern;
+ patternCursor[channel] = 0;
+ patternIsPlaying[channel] = true;
+ noteVolume[channel] = 9;
+ //reinit commands
+ volumeSlideStepDuration[channel] = 0;
+ arpeggioStepDuration[channel] = 0;
+ tremoloStepDuration[channel] = 0;
+#endif
+}
+
+void Sound::updatePattern(){
+#if(NUM_CHANNELS > 0)
+ for (uint8_t i=0; i<NUM_CHANNELS; i++){
+ updatePattern(i);
+ }
+#endif
+}
+
+void Sound::changeInstrumentSet(const uint16_t* const* instruments, uint8_t channel){
+#if(NUM_CHANNELS > 0)
+ if(channel>=NUM_CHANNELS)
+ return;
+ instrumentSet[channel] = (uint16_t**)instruments;
+#endif
+}
+
+void Sound::updatePattern(uint8_t i){
+#if(NUM_CHANNELS > 0)
+ if(i>=NUM_CHANNELS)
+ return;
+ if(patternIsPlaying[i]){
+ if(noteDuration[i]==0){//if the end of the previous note is reached
+
+ uint16_t data = pgm_read_word(patternCursor[i] + patternData[i]);
+
+ if(data == 0){ //end of the pattern reached
+ if(patternLooping[i] == true){
+ patternCursor[i] = 0;
+ data = pgm_read_word(patternCursor[i] + patternData[i]);
+ }
+ else{
+ patternIsPlaying[i] = false;
+ if(trackIsPlaying[i]){ //if this pattern is part of a track, get the next pattern
+ updateTrack(i);
+ data = pgm_read_word(patternCursor[i] + patternData[i]);
+ } else {
+ stopNote(i);
+ //Serial.print("pattern end\n");
+ return;
+ }
+ }
+ }
+
+ while (data & 0x0001){ //read all commands and instrument changes
+ data >>= 2;
+ //Serial.print("\ncmd\t");
+ uint8_t cmd = data & 0x0F;
+ data >>= 4;
+ uint8_t X = data & 0x1F;
+ data >>= 5;
+ int8_t Y = data - 16;
+ command(cmd,X,Y,i);
+ patternCursor[i]++;
+ data = pgm_read_word(patternCursor[i] + patternData[i]);
+ }
+ data >>= 2;
+
+ uint8_t pitch = data & 0x003F;
+ data >>= 6;
+
+ uint8_t duration = data;
+ if(pitch != 63){
+ }
+
+ playNote(pitch, duration, i);
+
+ patternCursor[i]++;
+ }
+ }
+#endif
+}
+
+void Sound::stopPattern(uint8_t channel){
+#if(NUM_CHANNELS > 0)
+ if(channel>=NUM_CHANNELS)
+ return;
+ stopNote(channel);
+ patternIsPlaying[channel] = false;
+#endif
+}
+
+void Sound::stopPattern(){
+#if(NUM_CHANNELS > 0)
+ for(uint8_t i=0; i<NUM_CHANNELS; i++){
+ stopPattern(i);
+ }
+#endif
+}
+
+void Sound::command(uint8_t cmd, uint8_t X, int8_t Y, uint8_t i){
+#if(NUM_CHANNELS > 0)
+ if(i>=NUM_CHANNELS)
+ return;
+ switch(cmd){
+ case CMD_VOLUME: //volume
+ X = constrain((int8_t)X, 0, 10);
+ noteVolume[i] = X;
+ break;
+ case CMD_INSTRUMENT: //instrument
+ instrumentData[i] = (uint16_t*)pgm_read_word(&(instrumentSet[i][X]));
+ instrumentLength[i] = pgm_read_word(&(instrumentData[i][0])) & 0x00FF; //8 LSB
+ instrumentLength[i] *= prescaler;
+ instrumentLooping[i] = min2((pgm_read_word(&(instrumentData[i][0])) >> 8), instrumentLength[i]); //8 MSB - check that the loop is shorter than the instrument length
+ instrumentLooping[i] *= prescaler;
+ break;
+ case CMD_SLIDE: //volume slide
+ volumeSlideStepDuration[i] = X * prescaler;
+ volumeSlideStepSize[i] = Y;
+ break;
+ case CMD_ARPEGGIO:
+ arpeggioStepDuration[i] = X * prescaler;
+ arpeggioStepSize[i] = Y;
+ break;
+ case CMD_TREMOLO:
+ tremoloStepDuration[i] = X * prescaler;
+ tremoloStepSize[i] = Y;
+ break;
+ default:
+ break;
+ }
+#endif
+}
+
+void Sound::playNote(uint8_t pitch, uint8_t duration, uint8_t channel){
+#if(NUM_CHANNELS > 0)
+ if(channel>=NUM_CHANNELS)
+ return;
+ //set note
+ notePitch[channel] = pitch;
+ noteDuration[channel] = duration * prescaler;
+ //reinit vars
+ instrumentNextChange[channel] = 0;
+ instrumentCursor[channel] = 0;
+ notePlaying[channel] = true;
+ _chanState[channel] = true;
+ commandsCounter[channel] = 0;
+#endif
+}
+
+void Sound::stopNote(uint8_t channel) {
+#if(NUM_CHANNELS > 0)
+ if(channel>=NUM_CHANNELS)
+ return;
+ notePlaying[channel] = false;
+ //counters
+ noteDuration[channel] = 0;
+ instrumentCursor[channel] = 0;
+ commandsCounter[channel] = 0;
+ //output
+ _chanOutput[channel] = 0;
+ _chanOutputVolume[channel] = 0;
+ _chanState[channel] = false;
+ updateOutput();
+#endif
+}
+
+void Sound::stopNote() {
+#if(NUM_CHANNELS > 0)
+ for (uint8_t channel = 0; channel < NUM_CHANNELS; channel++) {
+ stopNote(channel);
+ }
+#endif
+}
+
+void Sound::updateNote() {
+#if(NUM_CHANNELS > 0)
+ for (uint8_t i = 0; i < NUM_CHANNELS; i++) {
+ updateNote(i);
+ }
+#endif
+}
+
+void Sound::updateNote(uint8_t i) {
+#if(NUM_CHANNELS > 0)
+ if(i>=NUM_CHANNELS)
+ return;
+ if (notePlaying[i]) {
+
+ if(noteDuration[i] == 0){
+ stopNote(i);
+ //Serial.println("note end");
+ return;
+ } else {
+ noteDuration[i]--;
+ }
+
+ if (instrumentNextChange[i] == 0) {
+
+ //read the step data from the progmem and decode it
+ uint16_t thisStep = pgm_read_word(&(instrumentData[i][1 + instrumentCursor[i]]));
+
+ stepVolume[i] = thisStep & 0x0007;
+ thisStep >>= 3;
+
+ uint8_t stepNoise = thisStep & 0x0001;
+ thisStep >>= 1;
+
+ uint8_t stepDuration = thisStep & 0x003F;
+ thisStep >>= 6;
+
+ stepPitch[i] = thisStep;
+
+ //apply the step settings
+ instrumentNextChange[i] = stepDuration * prescaler;
+
+ _chanNoise[i] = stepNoise;
+
+
+ instrumentCursor[i]++;
+
+ if (instrumentCursor[i] >= instrumentLength[i]) {
+ if (instrumentLooping[i]) {
+ instrumentCursor[i] = instrumentLength[i] - instrumentLooping[i];
+ } else {
+ stopNote(i);
+ }
+ }
+ }
+ instrumentNextChange[i]--;
+
+ commandsCounter[i]++;
+
+ //UPDATE VALUES
+ //pitch
+ outputPitch[i] = notePitch[i] + stepPitch[i] + patternPitch[i];
+ if(arpeggioStepDuration[i]){
+ outputPitch[i] += commandsCounter[i] / arpeggioStepDuration[i] * arpeggioStepSize[i];
+ }
+ outputPitch[i] = (outputPitch[i] + NUM_PITCH) % NUM_PITCH; //wrap
+ //volume
+ outputVolume[i] = noteVolume[i];
+ if(volumeSlideStepDuration[i]){
+ outputVolume[i] += commandsCounter[i] / volumeSlideStepDuration[i] * volumeSlideStepSize[i];
+ }
+ if(tremoloStepDuration[i]){
+ outputVolume[i] += ((commandsCounter[i]/tremoloStepDuration[i]) % 2) * tremoloStepSize[i];
+ }
+ outputVolume[i] = constrain(outputVolume[i], 0, 9);
+ if(notePitch[i] == 63){
+ outputVolume[i] = 0;
+ }
+ // jonnehw noInterrupts();
+ _chanHalfPeriod[i] = pgm_read_byte(_halfPeriods + outputPitch[i]);
+ _chanOutput[i] = _chanOutputVolume[i] = outputVolume[i] * (globalVolume>>GLOBVOL_SHIFT) * chanVolumes[i] * stepVolume[i];
+ //Serial.println(outputVolume[i]);
+ // jonnehw interrupts();
+ }
+#endif
+}
+
+void Sound::setChannelHalfPeriod(uint8_t channel, uint8_t halfPeriod) {
+#if(NUM_CHANNELS > 0)
+ if(channel>=NUM_CHANNELS)
+ return;
+ _chanHalfPeriod[channel] = halfPeriod;
+ _chanState[channel] = false;
+ _chanCount[channel] = 0;
+ updateOutput();
+#endif
+}
+
+
+void Sound::generateOutput() {
+#if(NUM_CHANNELS > 0)
+ bool outputChanged = false;
+ //no for loop here, for the performance sake (this function runs 15 000 times per second...)
+ //CHANNEL 0
+ if (_chanOutputVolume[0]) {
+ _chanCount[0]++;
+ if (_chanCount[0] >= _chanHalfPeriod[0]) {
+ outputChanged = true;
+ _chanState[0] = !_chanState[0];
+ _chanCount[0] = 0;
+ if (_chanNoise[0]) {
+ _rand = 67 * _rand + 71;
+ _chanOutput[0] = _rand % _chanOutputVolume[0];
+ }
+ }
+ }
+
+
+ //CHANNEL 1
+ #if (NUM_CHANNELS > 1)
+ if (_chanOutputVolume[1]) {
+ _chanCount[1]++;
+ if (_chanCount[1] >= _chanHalfPeriod[1]) {
+ outputChanged = true;
+ _chanState[1] = !_chanState[1];
+ _chanCount[1] = 0;
+ if (_chanNoise[1]) {
+ _rand = 67 * _rand + 71;
+ _chanOutput[1] = _rand % _chanOutputVolume[1];
+ }
+ }
+ }
+ #endif
+
+ //CHANNEL 2
+ #if (NUM_CHANNELS > 2)
+ if (_chanOutputVolume[2]) {
+ _chanCount[2]++;
+ if (_chanCount[2] >= _chanHalfPeriod[2]) {
+ outputChanged = true;
+ _chanState[2] = !_chanState[2];
+ _chanCount[2] = 0;
+ if (_chanNoise[2]) {
+ _rand = 67 * _rand + 71;
+ _chanOutput[2] = _rand % _chanOutputVolume[2];
+ }
+ }
+ }
+ #endif
+
+ //CHANNEL 3
+ #if (NUM_CHANNELS > 3)
+ if (_chanOutputVolume[3]) {
+ _chanCount[3]++;
+ if (_chanCount[3] >= _chanHalfPeriod[3]) {
+ outputChanged = true;
+ _chanState[3] = !_chanState[3];
+ _chanCount[3] = 0;
+ if (_chanNoise[3]) {
+ _rand = 67 * _rand + 71;
+ _chanOutput[3] = _rand % _chanOutputVolume[3];
+ }
+ }
+ }
+ #endif
+
+ #if POK_STREAMING_MUSIC
+ if (streamstep) {
+ outputChanged=true;
+ }
+ #endif
+
+ if (outputChanged) {
+ updateOutput();
+ }
+#endif
+}
+
+void Sound::updateOutput() {
+#if(NUM_CHANNELS > 0)
+ uint32_t output = 0;
+
+ //CHANNEL 0
+ if (_chanState[0]) {
+ output += _chanOutput[0];
+ }
+
+ //CHANNEL 1
+ #if (NUM_CHANNELS > 1)
+ if (_chanState[1]) {
+ output += _chanOutput[1];
+ }
+ #endif
+
+ //CHANNEL 2
+ #if (NUM_CHANNELS > 2)
+ if (_chanState[2]) {
+ output += _chanOutput[2];
+ }
+ #endif
+
+ //CHANNEL 3
+ #if (NUM_CHANNELS > 3)
+ if (_chanState[3]) {
+ output += _chanOutput[3];
+ }
+ #endif
+
+ #ifndef POK_SIM
+ #if POK_ENABLE_SOUND
+ /** HARDWARE **/
+
+ #if POK_STREAMING_MUSIC
+ if (streamstep) {
+ //pwmout_write(&audiopwm,(float)(sbyte>>headPhoneLevel)/(float)255);
+ sbyte *= discrete_vol_multipliers[discrete_vol];
+ sbyte >>= 8;
+ pwmout_write(&audiopwm,(float)(sbyte)/(float)255);
+ }
+ #endif
+ output *= discrete_vol_multipliers[discrete_vol];
+ output >>= 8;
+ dac_write((uint8_t)output); //direct hardware mixing baby !
+ soundbyte = output;
+ #endif //POK_ENABLE_SOUND
+ #else
+ /** SIMULATOR **/
+ #if POK_STREAMING_MUSIC
+ if (streamstep) {
+ uint16_t o = output + sbyte;
+ output = (o/2);//>>headPhoneLevel;
+ }
+ #endif
+ soundbyte = output;//<<headPhoneLevel;
+ #endif // POK_SIM
+#endif
+}
+
+void Sound::setPatternLooping(bool loop, uint8_t channel) {
+#if(NUM_CHANNELS > 0)
+ if(channel>=NUM_CHANNELS)
+ return;
+ patternLooping[channel] = loop;
+#endif
+}
+
+void Sound::playOK(){
+ #if POK_GBSOUND
+#if(NUM_CHANNELS > 0)
+ playPattern(playOKPattern,0);
+#endif
+#endif // POK_GBSOUND
+}
+
+void Sound::playCancel(){
+#if POK_GBSOUND
+#if(NUM_CHANNELS > 0)
+ playPattern(playCancelPattern,0);
+#endif
+#endif
+}
+
+void Sound::playTick(){
+#if POK_GBSOUND
+#if(NUM_CHANNELS > 0)
+ playPattern(playTickP,0);
+#endif
+#endif // POK_GBSOUND
+}
+
+void Sound::setVolume(int16_t volume) {
+//#if NUM_CHANNELS > 0
+ if (volume<0) volume = 0;
+ //if (volume>volumeMax) volume = volumeMax;
+ globalVolume = volume;
+ #if POK_ENABLE_SOUND > 0
+ discrete_vol = (volume>>5);
+ #ifndef POK_SIM
+ setHWvolume(discrete_vol_hw_levels[discrete_vol]); //boost volume if headphonelevel
+ #endif
+ #endif
+ #if POK_SHOW_VOLUME > 0
+ _soundc.volbar_visible = VOLUMEBAR_TIMEOUT;
+ #endif
+//#endif
+}
+
+uint16_t Sound::getVolume() {
+//#if NUM_CHANNELS > 0
+ return globalVolume;
+//#else
+// return 0;
+//#endif
+}
+
+void Sound::setVolume(int8_t volume, uint8_t channel) {
+#if(NUM_CHANNELS > 0)
+ if(channel>=NUM_CHANNELS)
+ return;
+ volume = (volume > VOLUME_CHANNEL_MAX) ? VOLUME_CHANNEL_MAX : volume;
+ volume = (volume < 0) ? 0 : volume;
+ chanVolumes[channel] = volume;
+#endif
+}
+
+uint8_t Sound::getVolume(uint8_t channel) {
+#if(NUM_CHANNELS > 0)
+ if(channel>=NUM_CHANNELS)
+ return 255;
+ return (chanVolumes[channel]);
+#else
+ return 0;
+#endif
+}
+
+void Sound::playTone(uint8_t os, int frq, uint8_t amp, uint8_t wav,uint8_t arpmode)
+{
+ if (wav>5) wav=0;
+ if (arpmode>MAX_ARPMODE) arpmode=MAX_ARPMODE;
+ if (os==1) setOSC(&osc1,1,wav,1,0,0,frq,amp,0,0,0,0,0,0,arpmode,0,0);
+ else if (os==2) setOSC(&osc2,1,wav,1,0,0,frq,amp,0,0,0,0,0,0,arpmode,0,0);
+ else if (os==3) setOSC(&osc3,1,wav,1,0,0,frq,amp,0,0,0,0,0,0,arpmode,0,0);
+}
+
+void Sound::playTone(uint8_t os, uint16_t frq, uint8_t volume, uint32_t duration)
+{
+ if (os==1) setOSC(&osc1,1,WSQUARE,frq,volume,duration);
+ else if (os==2) setOSC(&osc2,1,WTRI,frq,volume,duration);
+ else if (os==3) setOSC(&osc3,1,WTRI,frq,volume,duration);
+}
+
+uint8_t Sound::ampIsOn()
+{
+ #ifdef POK_SIM
+ return core.ampIsOn();
+ #else
+ #if POK_ENABLE_SOUND > 0
+ return Pokitto::ampIsOn();
+ #endif
+ #endif // POK_SIM
+ return 0;
+}
+
+void Sound::ampEnable(uint8_t v) {
+ #ifdef POK_SIM
+ core.ampEnable(v);
+ #else
+ #if POK_ENABLE_SOUND > 0
+ Pokitto::ampEnable(v);
+ #endif
+ #endif // POK_SIM
+
+}
+
+int Sound::playMusicStream(char* filename)
+{
+ return playMusicStream(filename,FILE_MODE_READONLY | FILE_MODE_BINARY);
+}
+
+int Sound::playMusicStream()
+{
+ #if POK_STREAMING_MUSIC >0
+ if (currentPtr) {
+ pokPlayStream();
+ return 1;
+ } else return 0; //no stream
+ #endif // POK_STREAMING_MUSIC
+}
+
+void Sound::pauseMusicStream() {
+ #if POK_ENABLE_SOUND > 0
+ pokPauseStream();
+ #endif
+}
+
+int Sound::playMusicStream(char* filename, uint8_t options)
+{
+ #if POK_STREAMING_MUSIC
+ uint8_t result;
+ result = pokInitSD();
+ if (!isThisFileOpen(filename)) {
+ fileClose(); // close any open files
+ result = fileOpen(filename,FILE_MODE_READONLY | FILE_MODE_BINARY);
+ }
+
+ if (result) {
+ currentPtr = 0; // mark that no stream is available
+ return 0; // opening music file failed
+ }
+
+ fileReadBytes(&buffers[0][0],BUFFER_SIZE);
+ fileReadBytes(&buffers[1][0],BUFFER_SIZE);
+ fileReadBytes(&buffers[2][0],BUFFER_SIZE);
+ fileReadBytes(&buffers[3][0],BUFFER_SIZE);
+ currentBuffer = 0;
+ currentPtr = buffers[currentBuffer];
+ endPtr = currentPtr + BUFFER_SIZE;
+
+ //streaming = STR_PLAYING|options;
+
+ if (!options) pokPlayStream(); // activate stream
+ #endif //POK_STREAMING_MUSIC
+ return 1; // opening music file succeeded
+}
+
+uint32_t Sound::getMusicStreamElapsedSec() {
+ return streamcounter/POK_AUD_FREQ;
+}
+
+uint32_t Sound::getMusicStreamElapsedMilliSec() {
+ return streamcounter/(POK_AUD_FREQ/1000);
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/POKITTO_CORE/PokittoSound.h Mon May 21 18:03:14 2018 +0000
@@ -0,0 +1,229 @@
+/**************************************************************************/
+/*!
+ @file PokittoSound.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 POKITTOSOUND_H
+#define POKITTOSOUND_H
+
+#include <stdint.h>
+#include "Pokitto_settings.h"
+#include "GBcompatibility.h"
+#include "PokittoFakeavr.h"
+#include "PokittoGlobs.h"
+
+extern void pokPauseStream();
+extern void pokPlayStream();
+extern uint8_t pokStreamPaused();
+
+//volume levels
+#define GLOBVOL_SHIFT 5 //shift global volume to allow for finer increments
+
+
+#ifndef MAX_VOL_TEST
+ #define VOLUME_SPEAKER_MAX 255 //((8<<GLOBVOL_SHIFT)-1)
+ #define VOLUME_HEADPHONE_MAX 127
+ #define VOLUME_STARTUP VOLUME_HEADPHONE_MAX
+#else
+ #define VOLUME_SPEAKER_MAX 255
+ #define VOLUME_HEADPHONE_MAX VOLUME_SPEAKER_MAX
+ #define VOLUME_STARTUP VOLUME_SPEAKER_MAX
+#endif // MAXVOLTEST
+
+#ifdef POK_SIM
+#define VOLUME_STEP 1
+#else
+#define VOLUME_STEP 8
+#endif
+
+
+//commands
+#define CMD_VOLUME 0
+#define CMD_INSTRUMENT 1
+#define CMD_SLIDE 2
+#define CMD_ARPEGGIO 3
+#define CMD_TREMOLO 4
+
+#define STR_PLAYING 0x1
+#define STR_VISUALIZER 0x2
+#define STR_LOOP 0x4
+#define STR_PAUSED 0x8
+
+namespace Pokitto {
+
+/** Sound class.
+ * The Sound class is an API-compatible version of the Gamebuino Sound API by Aurelien Rodot.
+ * Because it is a class consisting of only static members, there is only 1 instance running,
+ * no matter how many Sound classes are declared (see example below). This means sound can
+ * be used through a simple Sound class object or as a member of the Core class.
+ *
+ */
+
+/** discrete_vol* are needed for more accurate volume control levels on hardware **/
+extern uint8_t discrete_vol;
+extern const uint8_t discrete_vol_levels[];
+extern const uint8_t discrete_vol_hw_levels[];
+extern const uint8_t discrete_vol_multipliers[];
+
+extern void audio_IRQ(); // audio interrupt
+
+class Sound {
+private:
+ static uint16_t volumeMax;
+
+public:
+ static void begin();
+
+ // Headphonemode
+ static uint8_t headPhoneLevel; // a workaround to disappearing sound at low volume
+ static void setMaxVol(int16_t);
+ static uint16_t getMaxVol();
+ static void volumeUp();
+ static void volumeDown();
+
+ // Original functions
+ static void updateStream();
+ static void playTone(uint8_t os, int frq, uint8_t amp, uint8_t wav,uint8_t arpmode);
+ static void playTone(uint8_t os, uint16_t freq, uint8_t volume, uint32_t duration);
+ static uint8_t ampIsOn();
+ static void ampEnable(uint8_t);
+ static int playMusicStream(char* filename, uint8_t options);
+ static int playMusicStream(char* filename);
+ static int playMusicStream();
+ static void pauseMusicStream();
+ static uint32_t getMusicStreamElapsedSec();
+ static uint32_t getMusicStreamElapsedMilliSec();
+
+ // GB compatibility functions
+ static void playTrack(const uint16_t* track, uint8_t channel);
+ static void updateTrack(uint8_t channel);
+ static void updateTrack();
+ static void stopTrack(uint8_t channel);
+ static void stopTrack();
+ static void changePatternSet(const uint16_t* const* patterns, uint8_t channel);
+ static bool trackIsPlaying[NUM_CHANNELS];
+
+ static void playPattern(const uint16_t* pattern, uint8_t channel);
+ static void changeInstrumentSet(const uint16_t* const* instruments, uint8_t channel);
+ static void updatePattern(uint8_t i);
+ static void updatePattern();
+ static void setPatternLooping(bool loop, uint8_t channel);
+ static void stopPattern(uint8_t channel);
+ static void stopPattern();
+ static bool patternIsPlaying[NUM_CHANNELS];
+
+ static void command(uint8_t cmd, uint8_t X, int8_t Y, uint8_t i);
+ static void playNote(uint8_t pitch, uint8_t duration, uint8_t channel);
+ static void updateNote();
+ static void updateNote(uint8_t i);
+ static void stopNote(uint8_t channel);
+ static void stopNote();
+
+ static uint8_t outputPitch[NUM_CHANNELS];
+ static int8_t outputVolume[NUM_CHANNELS];
+
+ static void setMasterVolume(uint8_t);
+ static uint8_t GetMasterVolume();
+ static void setVolume(int16_t volume);
+ static uint16_t getVolume();
+ static void setVolume(int8_t volume, uint8_t channel);
+ static uint8_t getVolume(uint8_t channel);
+
+ static void playOK();
+ static void playCancel();
+ static void playTick();
+
+ static uint8_t prescaler;
+
+ static void setChannelHalfPeriod(uint8_t channel, uint8_t halfPeriod);
+
+ static void generateOutput(); //!\\ DO NOT USE
+ static uint16_t globalVolume;
+
+
+#if (NUM_CHANNELS > 0)
+ //tracks data
+ static uint16_t *trackData[NUM_CHANNELS];
+ static uint8_t trackCursor[NUM_CHANNELS];
+ static uint16_t **patternSet[NUM_CHANNELS];
+ static int8_t patternPitch[NUM_CHANNELS];
+
+ // pattern data
+ static uint16_t *patternData[NUM_CHANNELS];
+ static uint16_t **instrumentSet[NUM_CHANNELS];
+ static bool patternLooping[NUM_CHANNELS];
+ static uint16_t patternCursor[NUM_CHANNELS];
+
+ // note data
+ static uint8_t notePitch[NUM_CHANNELS];
+ static uint8_t noteDuration[NUM_CHANNELS];
+ static int8_t noteVolume[NUM_CHANNELS];
+ static bool notePlaying[NUM_CHANNELS];
+
+ // commands data
+ static int8_t commandsCounter[NUM_CHANNELS];
+ static int8_t volumeSlideStepDuration[NUM_CHANNELS];
+ static int8_t volumeSlideStepSize[NUM_CHANNELS];
+ static uint8_t arpeggioStepDuration[NUM_CHANNELS];
+ static int8_t arpeggioStepSize[NUM_CHANNELS];
+ static uint8_t tremoloStepDuration[NUM_CHANNELS];
+ static int8_t tremoloStepSize[NUM_CHANNELS];
+
+
+ // instrument data
+ static uint16_t *instrumentData[NUM_CHANNELS];
+ static uint8_t instrumentLength[NUM_CHANNELS]; //number of steps in the instrument
+ static uint8_t instrumentLooping[NUM_CHANNELS]; //how many steps to loop on when the last step of the instrument is reached
+ static uint16_t instrumentCursor[NUM_CHANNELS]; //which step is being played
+ static uint8_t instrumentNextChange[NUM_CHANNELS]; //how many frames before the next step
+
+ //current step data
+ static int8_t stepVolume[NUM_CHANNELS];
+ static uint8_t stepPitch[NUM_CHANNELS];
+
+ static uint8_t chanVolumes[NUM_CHANNELS];
+#endif
+ static void updateOutput();
+};
+
+}
+
+#endif // POKITTOSOUND_H
+
+
+
+
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/POKITTO_HW/HWLCD.cpp Mon May 21 18:03:14 2018 +0000
@@ -0,0 +1,1921 @@
+/**************************************************************************/
+/*!
+ @file HWLCD.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 "HWLCD.h" //HWLCD.h" #include "HWLCD.h"
+#include "Pokitto_settings.h"
+
+#ifndef DISABLEAVRMIN
+#define max(a,b) ((a)>(b)?(a):(b))
+#define min(a,b) ((a)<(b)?(a):(b))
+#endif // DISABLEAVRMIN
+
+#ifdef DISABLEAVRMIN
+#include <algorithm>
+using std::min;
+using std::max;
+#endif // DISABLEAVRMIN
+
+#define AB_JUMP 1024 // jump one 1-bit Arduboy screen forward to get next color bit
+#define GB_JUMP 504 // jump one 1-bit Gamebuino screen forward to get next color bit
+
+using namespace Pokitto;
+
+uint16_t prevdata=0; // if data does not change, do not adjust LCD bus lines
+
+#if POK_BOARDREV == 2
+ pwmout_t backlightpwm;
+#endif
+
+
+/**************************************************************************/
+/*!
+ @brief set up the 16-bit bus
+*/
+/**************************************************************************/
+
+static inline void setup_data_16(uint16_t data)
+{
+ //uint32_t p2=0;
+
+ //if (data != prevdata) {
+ //
+ //prevdata=data;
+
+ /** D0...D16 = P2_3 ... P2_18 **/
+ //p2 = data << 3;
+
+ //__disable_irq(); // Disable Interrupts
+ SET_MASK_P2;
+ LPC_GPIO_PORT->MPIN[2] = (data<<3); // write bits to port
+ CLR_MASK_P2;
+ //__enable_irq(); // Enable Interrupts
+ //}
+}
+
+
+/**************************************************************************/
+/*!
+ @brief Write a command to the lcd, 16-bit bus
+*/
+/**************************************************************************/
+inline void write_command_16(uint16_t data)
+{
+ CLR_CS; // select lcd
+ CLR_CD; // clear CD = command
+ SET_RD; // RD high, do not read
+ setup_data_16(data); // function that inputs the data into the relevant bus lines
+ CLR_WR_SLOW; // WR low
+ SET_WR; // WR low, then high = write strobe
+ SET_CS; // de-select lcd
+}
+
+/**************************************************************************/
+/*!
+ @brief Write data to the lcd, 16-bit bus
+*/
+/**************************************************************************/
+inline void write_data_16(uint16_t data)
+{
+ CLR_CS;
+ SET_CD;
+ SET_RD;
+ setup_data_16(data);
+ CLR_WR;
+ SET_WR;
+ SET_CS;
+}
+
+/**************************************************************************/
+/*!
+ @brief Pump data to the lcd, 16-bit bus, public function
+*/
+/**************************************************************************/
+void Pokitto::pumpDRAMdata(uint16_t* data,uint16_t counter)
+{
+ while (counter--) {
+ CLR_CS;
+ SET_CD;
+ SET_RD;
+ setup_data_16(*data++);
+ CLR_WR;
+ SET_WR;
+ SET_CS;
+ }
+}
+
+
+/**************************************************************************/
+/*!
+ @brief Point to a (x,y) location in the LCD DRAM
+*/
+/**************************************************************************/
+static inline void setDRAMptr(uint8_t xptr, uint8_t yoffset)
+{
+ write_command(0x20); // Vertical DRAM Address
+ write_data(yoffset);
+ write_command(0x21); // Horizontal DRAM Address
+ write_data(xptr); //
+ write_command(0x22); // write data to DRAM
+ CLR_CS_SET_CD_RD_WR;
+}
+
+/**************************************************************************/
+/*!
+ @brief Point to a (x,y) location in the LCD DRAM, public function
+*/
+/**************************************************************************/
+void Pokitto::setDRAMpoint(uint8_t xptr, uint8_t yoffset)
+{
+ write_command(0x20); // Vertical DRAM Address
+ write_data(yoffset);
+ write_command(0x21); // Horizontal DRAM Address
+ write_data(xptr); //
+ write_command(0x22); // write data to DRAM
+ CLR_CS_SET_CD_RD_WR;
+}
+
+void Pokitto::initBacklight() {
+ #if POK_BOARDREV == 2
+ pwmout_init(&backlightpwm,POK_BACKLIGHT_PIN);
+ pwmout_period_us(&backlightpwm,5);
+ pwmout_write(&backlightpwm,POK_BACKLIGHT_INITIALVALUE);
+ #endif
+}
+
+void Pokitto::setBacklight(float value) {
+ if (value>0.999f) value = 0.999f;
+ pwmout_write(&backlightpwm,value);
+}
+
+void Pokitto::lcdInit() {
+ initBacklight();
+
+ SET_RESET;
+ wait_ms(10);
+ CLR_RESET;
+ wait_ms(10);
+ SET_RESET;
+ wait_ms(10);
+ //************* Start Initial Sequence **********//
+ write_command(0x01); // driver output control, this also affects direction
+ write_data(0x11C); // originally: 0x11C 100011100 SS,NL4,NL3,NL2
+ // NL4...0 is the number of scan lines to drive the screen !!!
+ // so 11100 is 1c = 220 lines, correct
+ // test 1: 0x1C 11100 SS=0,NL4,NL3,NL2 -> no effect
+ // test 2: 0x31C 1100011100 GS=1,SS=1,NL4,NL3,NL2 -> no effect
+ // test 3: 0x51C 10100011100 SM=1,GS=0,SS=1,NL4,NL3,NL2 -> no effect
+ // test 4: 0x71C SM=1,GS=1,SS=1,NL4,NL3,NL2
+ // test 5: 0x
+ // seems to have no effect... is this perhaps only for RGB mode ?
+
+ write_command(0x02); // LCD driving control
+ write_data(0x0100); // INV = 1
+
+ write_command(0x03); // Entry mode... lets try if this affects the direction
+ write_data(0x1030); // originally 0x1030 1000000110000 BGR,ID1,ID0
+ // test 1: 0x1038 1000000111000 BGR,ID1,ID0,AM=1 ->drawing DRAM horizontally
+ // test 4: am=1, id0=0, id1=0, 1000000001000,0x1008 -> same as above, but flipped on long
+ // test 2: am=0, id0=0, 1000000100000, 0x1020 -> flipped on long axis
+ // test 3: am=0, id1=0, 1000000010000, 0x1010 -> picture flowed over back to screen
+
+
+ write_command(0x08); // Display control 2
+ write_data(0x0808); // 100000001000 FP2,BP2
+
+ write_command(0x0C); // RGB display interface
+ write_data(0x0000); // all off
+
+ write_command(0x0F); // Frame marker position
+ write_data(0x0001); // OSC_EN
+
+ write_command(0x20); // Horizontal DRAM Address
+ write_data(0x0000); // 0
+
+ write_command(0x21); // Vertical DRAM Address
+ write_data(0x0000); // 0
+
+ //*************Power On sequence ****************//
+ write_command(0x10);
+ write_data(0x0000);
+
+ write_command(0x11);
+ write_data(0x1000);
+ wait_ms(10);
+//------------------------ Set GRAM area --------------------------------//
+ write_command(0x30); // Gate scan position
+ write_data(0x0000); // if GS=0, 00h=G1, else 00h=G220
+
+ write_command(0x31); // Vertical scroll control
+ write_data(0x00DB); // scroll start line 11011011 = 219
+
+ write_command(0x32); // Vertical scroll control
+ write_data(0x0000); // scroll end line 0
+
+ write_command(0x33); // Vertical scroll control
+ write_data(0x0000); // 0=vertical scroll disabled
+
+ write_command(0x34); // Partial screen driving control
+ write_data(0x00DB); // db = full screen (end)
+
+ write_command(0x35); // partial screen
+ write_data(0x0000); // 0 = start
+
+ write_command(0x36); // Horizontal and vertical RAM position
+ write_data(0x00AF); //end address 175
+
+ write_command(0x37);
+ write_data(0x0000); // start address 0
+
+ write_command(0x38);
+ write_data(0x00DB); //end address 219
+
+ write_command(0x39); // start address 0
+ write_data(0x0000);
+ wait_ms(10);
+ write_command(0xff); // start gamma register control
+ write_data(0x0003);
+
+// ----------- Adjust the Gamma Curve ----------//
+ write_command(0x50);
+ write_data(0x0203);
+
+ write_command(0x051);
+ write_data(0x0A09);
+
+ write_command(0x52);
+ write_data(0x0005);
+
+ write_command(0x53);
+ write_data(0x1021);
+
+ write_command(0x54);
+ write_data(0x0602);
+
+ write_command(0x55);
+ write_data(0x0003);
+
+ write_command(0x56);
+ write_data(0x0703);
+
+ write_command(0x57);
+ write_data(0x0507);
+
+ write_command(0x58);
+ write_data(0x1021);
+
+ write_command(0x59);
+ write_data(0x0703);
+
+ write_command(0xB0);
+ write_data(0x2501);
+
+ write_command(0xFF);
+ write_data(0x0000);
+
+ write_command(0x07);
+ write_data(0x1017);
+ wait_ms(200);
+ write_command(0x22);
+
+ lcdClear();
+}
+
+void Pokitto::lcdSleep(void){
+ write_command(0xFF);
+ write_data(0x0000);
+
+ write_command(0x07);
+ write_data(0x0000);
+ wait_ms(50);
+ write_command(0x10);// Enter Standby mode
+ write_data(0x0003);
+ wait_ms(200);
+
+}
+
+void Pokitto::lcdWakeUp (void){
+
+ wait_ms(200);
+ write_command(0xFF);
+ write_data(0x0000);
+
+ write_command(0x10);// Exit Sleep/ Standby mode
+ write_data(0x0000);
+ wait_ms(50);
+ write_command(0x07);
+ write_data(0x0117);
+ wait_ms(200);
+ }
+
+void Pokitto::lcdFillSurface(uint16_t c) {
+ uint32_t i;
+ write_command(0x20); // Horizontal DRAM Address
+ write_data(0x0000); // 0
+ write_command(0x21); // Vertical DRAM Address
+ write_data(0);
+ write_command(0x22); // write data to DRAM
+ setup_data_16(c);
+ CLR_CS_SET_CD_RD_WR;
+ for(i=0;i<220*176;i++)
+ {
+ CLR_WR;
+ SET_WR;
+ }
+}
+
+void Pokitto::lcdClear() {
+ uint32_t i;
+ write_command(0x20); // Horizontal DRAM Address
+ write_data(0x0000); // 0
+ write_command(0x21); // Vertical DRAM Address
+ write_data(0);
+ write_command(0x22); // write data to DRAM
+ setup_data_16(0x0000);
+ CLR_CS_SET_CD_RD_WR;
+ for(i=0;i<220*176;i++)
+ {
+ CLR_WR;
+ SET_WR;
+ }
+}
+
+void Pokitto::lcdPixel(int16_t x, int16_t y, uint16_t color) {
+ if ((x < 0) || (x >= POK_LCD_W) || (y < 0) || (y >= POK_LCD_H))
+ return;
+ write_command(0x20); // Horizontal DRAM Address
+ write_data(y); // 0
+ write_command(0x21); // Vertical DRAM Address
+ write_data(x);
+ write_command(0x22); // write data to DRAM
+ CLR_CS_SET_CD_RD_WR;
+ setup_data_16(color);
+ CLR_WR;SET_WR;
+}
+
+void Pokitto::setWindow(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2) {
+ write_command(0x37); write_data(x1);
+ write_command(0x36); write_data(x2);
+ write_command(0x39); write_data(y1);
+ write_command(0x38); write_data(y2);
+ write_command(0x20); write_data(x1);
+ write_command(0x21); write_data(y1);
+}
+
+void Pokitto::lcdTile(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t* gfx){
+ int width=x1-x0;
+ int height=y1-y0;
+ if (x0 > POK_LCD_W) return;
+ if (y0 > POK_LCD_H) return;
+ if (x0 < 0) x0=0;
+ if (y0 < 0) y0=0;
+
+ setWindow(y0, x0, y1-1, x1-1);
+ write_command(0x22);
+
+ for (int x=0; x<=width*height-1;x++) {
+ write_data(gfx[x]);
+ }
+ setWindow(0, 0, 175, 219);
+}
+
+
+void Pokitto::lcdRectangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t color) {
+ int16_t temp;
+ if (x0>x1) {temp=x0;x0=x1;x1=temp;}
+ if (y0>y1) {temp=y0;y0=y1;y1=temp;}
+ if (x0 > POK_LCD_W) return;
+ if (y0 > POK_LCD_H) return;
+ if (x1 > POK_LCD_W) x1=POK_LCD_W;
+ if (y1 > POK_LCD_H) y1=POK_LCD_H;
+ if (x0 < 0) x0=0;
+ if (y0 < 0) y0=0;
+
+ int16_t x,y;
+ for (x=x0; x<=x1;x++) {
+ write_command(0x20); // Horizontal DRAM Address (=y on pokitto screen)
+ write_data(y0);
+ write_command(0x21); // Vertical DRAM Address (=x on pokitto screen)
+ write_data(x);
+ write_command(0x22); // write data to DRAM
+
+ CLR_CS_SET_CD_RD_WR; // go to vram write mode
+
+
+ for (y=y0; y<y1;y++) {
+ setup_data_16(color); // setup the data (flat color = no change between pixels)
+ CLR_WR;SET_WR; //CLR_WR;SET_WR;//toggle writeline, pokitto screen writes a column up to down
+ }
+ }
+}
+
+/***
+ * Update the screen buffer of 220x176 pixels, 4 colors to LCD.
+ *
+ * The update rect is used for drawing only part of the screen buffer to LCD. Because of speed optimizations, the
+ * x, y, and width of the update rect must be dividable by 4 pixels, and the height must be dividable by 8 pixels.
+ * Note: The update rect is currently used for 220x176, 4 colors, screen mode only.
+ * @param scrbuf The screen buffer.
+ * @param updRectX The update rect.
+ * @param updRectY The update rect.
+ * @param updRectW The update rect.
+ * @param updRectH The update rect.
+ * @param paletteptr The screen palette.
+*/
+void Pokitto::lcdRefreshMode1(uint8_t * scrbuf, uint8_t updRectX, uint8_t updRectY, uint8_t updRectW, uint8_t updRectH, uint16_t* paletteptr) {
+
+ uint16_t x,y,xptr;
+ uint16_t scanline[4][176]; // read 4 half-nibbles = 4 pixels at a time
+ uint8_t *d, yoffset=0;
+
+ // If not the full screen is updated, check the validity of the update rect.
+ if ( updRectX != 0 || updRectY != 0 ||updRectW != LCDWIDTH ||updRectH != LCDHEIGHT ) {
+ uint8_t org_screenx = updRectX;
+ updRectX &= 0xfc; // Make the value dividable by 4.
+ updRectW += org_screenx - updRectX;
+ updRectW = (updRectW + 3) & 0xfc; // Make the value dividable by 4, round up.
+
+ uint8_t org_screeny = updRectY;
+ updRectY &= 0xfc; // Make the value dividable by 4.
+ updRectH += org_screeny - updRectY;
+ updRectH = (updRectH + 7) & 0xf8; // Make the value dividable by 8 (because of loop unroll optimization), round up.
+ }
+
+
+ #ifdef PROJ_SHOW_FPS_COUNTER
+ xptr = 8;
+ setDRAMptr(8, 0);
+ #else
+ xptr = 0;
+ setDRAMptr(0, 0);
+ #endif
+
+ for (x=updRectX; x<updRectX+updRectW; x+=4) {
+ d = scrbuf+(x>>2);// point to beginning of line in data
+
+ /** find colours in one scanline **/
+ uint8_t s=0;
+ d += (updRectY * 220/4);
+ for (y=updRectY; y<updRectY+updRectH; y++) {
+ uint8_t tdata = *d;
+ uint8_t t4 = tdata & 0x03; tdata >>= 2;// lowest half-nibble
+ uint8_t t3 = tdata & 0x03; tdata >>= 2;// second lowest half-nibble
+ uint8_t t2 = tdata & 0x03; tdata >>= 2;// second highest half-nibble
+ uint8_t t = tdata & 0x03;// highest half-nibble
+
+ /** put nibble values in the scanlines **/
+ scanline[0][y] = paletteptr[t];
+ scanline[1][y] = paletteptr[t2];
+ scanline[2][y] = paletteptr[t3];
+ scanline[3][y] = paletteptr[t4];
+
+ d += 220/4; // jump to read byte directly below in screenbuffer
+ }
+
+ #ifdef PROJ_SHOW_FPS_COUNTER
+ if (x>=8 ) {
+ #else
+ {
+
+ #endif
+
+ // Draw 8 vertical pixels at a time for performance reasons
+ setDRAMptr(x, updRectY);
+ for (uint8_t s=updRectY; s<updRectY+updRectH;) {
+ setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;
+ }
+ setDRAMptr(x+1, updRectY);
+ for (uint8_t s=updRectY; s<updRectY+updRectH;) {
+ setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;
+ }
+ setDRAMptr(x+2, updRectY);
+ for (uint8_t s=updRectY; s<updRectY+updRectH;) {
+ setup_data_16(scanline[2][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[2][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[2][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[2][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[2][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[2][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[2][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[2][s++]);CLR_WR;SET_WR;
+ }
+ setDRAMptr(x+3, updRectY);
+ for (uint8_t s=updRectY; s<updRectY+updRectH;) {
+ setup_data_16(scanline[3][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[3][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[3][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[3][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[3][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[3][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[3][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[3][s++]);CLR_WR;SET_WR;
+ }
+ }
+ }
+
+ #ifdef POK_SIM
+ simulator.refreshDisplay();
+ #endif
+}
+
+// Copy sprite pixels to the scanline
+#define SPRITE_2BPP_INNER_LOOP(n)\
+\
+ /* If the sprite is enabled and contained in this vertical scanline, copy 4 pixels. */\
+ if (sprScanlineAddr[(n)] &&\
+ y >= sprites[(n)].y && y < sprites[(n)].y + sprites[(n)].h ) {\
+\
+ int16_t sprx = sprites[(n)].x;\
+ uint16_t s_data16b = 0; /* sprite data, 2 bytes */\
+\
+ /* Get pixel block, 4 or 8 pixels horizontally. Use the predefined bitshift mode. */\
+ /* Note:it is cheapest to compare to 0 first. */\
+ if (sprScanlineBitshiftMode[(n)] == BITSHIFT_MODE_MIDDLE_BYTE) {\
+ s_data16b = *(sprScanlineAddr[(n)]);\
+ uint16_t leftByte = *(sprScanlineAddr[(n)]-1);\
+ s_data16b = (leftByte << 8) | s_data16b;\
+ }\
+ else if (sprScanlineBitshiftMode[(n)] == BITSHIFT_MODE_FIRST_BYTE) {\
+ s_data16b = *(sprScanlineAddr[(n)]);\
+ }\
+ else { /* BITSHIFT_MODE_LAST_BYTE */\
+ uint16_t leftByte = *(sprScanlineAddr[(n)]-1);\
+ s_data16b = (leftByte << 8) | s_data16b;\
+ }\
+\
+ /* Shift sprite pixels according to sprite x. After shifting we have only 4 pixels. */\
+ uint8_t shiftRight = (sprx&0x3) << 1;\
+ s_data16b = (s_data16b >> shiftRight);\
+\
+ /* Get individual pixels */\
+ uint8_t s_t4 = s_data16b & 0x03; s_data16b >>= 2; /* lowest half-nibble */\
+ uint8_t s_t3 = s_data16b & 0x03; s_data16b >>= 2; /* second lowest half-nibble */\
+ uint8_t s_t2 = s_data16b & 0x03; s_data16b >>= 2; /* second highest half-nibble */\
+ uint8_t s_t1 = s_data16b & 0x03; /* highest half-nibble */\
+\
+ /* Store pixels as 16-bit colors from the palette */\
+ if (s_t4 != transparentColor) p4 = sprites[(n)].palette[s_t4];\
+ if (s_t3 != transparentColor) p3 = sprites[(n)].palette[s_t3];\
+ if (s_t2 != transparentColor) p2 = sprites[(n)].palette[s_t2];\
+ if (s_t1 != transparentColor) p = sprites[(n)].palette[s_t1];\
+\
+ /* Advance scanline address */\
+ sprScanlineAddr[(n)] += (sprites[(n)].w >> 2);\
+ }
+
+// Loop unrolling macros
+#define UNROLLED_LOOP_1() SPRITE_2BPP_INNER_LOOP(0)
+#define UNROLLED_LOOP_2() UNROLLED_LOOP_1() SPRITE_2BPP_INNER_LOOP(1)
+#define UNROLLED_LOOP_3() UNROLLED_LOOP_2() SPRITE_2BPP_INNER_LOOP(2)
+#define UNROLLED_LOOP_4() UNROLLED_LOOP_3() SPRITE_2BPP_INNER_LOOP(3)
+#define UNROLLED_LOOP_5() UNROLLED_LOOP_4() SPRITE_2BPP_INNER_LOOP(4)
+#define UNROLLED_LOOP_6() UNROLLED_LOOP_5() SPRITE_2BPP_INNER_LOOP(5)
+#define UNROLLED_LOOP_7() UNROLLED_LOOP_6() SPRITE_2BPP_INNER_LOOP(6)
+#define UNROLLED_LOOP_8() UNROLLED_LOOP_7() SPRITE_2BPP_INNER_LOOP(7)
+#define UNROLLED_LOOP_9() UNROLLED_LOOP_8() SPRITE_2BPP_INNER_LOOP(8)
+#define UNROLLED_LOOP_10() UNROLLED_LOOP_9() SPRITE_2BPP_INNER_LOOP(9)
+#define UNROLLED_LOOP_11() UNROLLED_LOOP_10() SPRITE_2BPP_INNER_LOOP(10)
+#define UNROLLED_LOOP_12() UNROLLED_LOOP_11() SPRITE_2BPP_INNER_LOOP(11)
+#define UNROLLED_LOOP_13() UNROLLED_LOOP_12() SPRITE_2BPP_INNER_LOOP(12)
+#define UNROLLED_LOOP_14() UNROLLED_LOOP_13() SPRITE_2BPP_INNER_LOOP(13)
+#define UNROLLED_LOOP_15() UNROLLED_LOOP_14() SPRITE_2BPP_INNER_LOOP(14)
+#define UNROLLED_LOOP_16() UNROLLED_LOOP_15() SPRITE_2BPP_INNER_LOOP(15)
+#define UNROLLED_LOOP_N_(n) UNROLLED_LOOP_##n()
+#define UNROLLED_LOOP_N(n) UNROLLED_LOOP_N_(n)
+
+/***
+ * Update the screen buffer of 220x176 pixels, 4 colors and free size 4 color sprites to LCD.
+ *
+ * The update rect is used for drawing only part of the screen buffer to LCD. Because of speed optimizations, the
+ * x, y, and width of the update rect must be dividable by 4 pixels, and the height must be dividable by 8 pixels.
+ * Note: The update rect is currently used for 220x176, 4 colors, screen mode only.
+ * If drawSpritesOnly=true, only sprites are fully updated to LCD. However, the dirty rect of the screen buffer is
+ * drawn behind the sprite current and previous location.
+ * Note: Sprite is enabled if sprite.bitmapData is not NULL. Also all enabled sprites must be at the beginning of
+ * the sprites array. No gaps are allowed in the array.
+ * @param scrbuf The screen buffer.
+ * @param updRectX The update rect.
+ * @param updRectY The update rect.
+ * @param updRectW The update rect.
+ * @param updRectH The update rect.
+ * @param paletteptr The screen palette.
+ * @param sprites The sprite array.
+ * @param drawSpritesOnly True, if only sprites are drawn. False, if both sprites and the screen buffer are drawn.
+*/
+void Pokitto::lcdRefreshMode1Spr(
+ uint8_t * scrbuf, uint8_t updRectX, uint8_t updRectY, uint8_t updRectW, uint8_t updRectH, uint16_t* paletteptr,
+ SpriteInfo* sprites, bool drawSpritesOnly) {
+
+ // In direct mode draw only sprites and their dirty rects. Return now if there are no sprites
+ if (drawSpritesOnly && (sprites == NULL || sprites[0].bitmapData == NULL))
+ return;
+
+ uint16_t x,y;
+ uint16_t scanline[4][176]; // read 4 half-nibbles (= 4 pixels) at a time
+ const uint8_t transparentColor = 0; // fixed palette index 0 for transparency
+
+ // If not the full screen is updated, check the validity of the update rect.
+ if ( updRectX != 0 || updRectY != 0 ||updRectW != LCDWIDTH ||updRectH != LCDHEIGHT ) {
+ uint8_t org_screenx = updRectX;
+ updRectX &= 0xfc; // Make the value dividable by 4.
+ updRectW += org_screenx - updRectX;
+ updRectW = (updRectW + 3) & 0xfc; // Make the value dividable by 4, round up.
+
+ uint8_t org_screeny = updRectY;
+ updRectY &= 0xfc; // Make the value dividable by 4.
+ updRectH += org_screeny - updRectY;
+ updRectH = (updRectH + 7) & 0xf8; // Make the value dividable by 8 (because of loop unroll optimization), round up.
+ }
+
+ // Calculate the current amount of sprites
+ // Note: Sprites must be taken into use from index 0 upwards, because the first sprite with bitmapData==NULL is considered as the last sprite
+ uint8_t spriteCount = 0;
+ if (sprites != NULL)
+ for (;sprites[spriteCount].bitmapData != NULL && spriteCount < SPRITE_COUNT; spriteCount++);
+
+ // If drawing the screen buffer, set the start pos to LCD commands only here.
+ #ifdef PROJ_SHOW_FPS_COUNTER
+ if (!drawSpritesOnly) setDRAMptr(8, 0);
+ #else
+ if (!drawSpritesOnly) setDRAMptr(0, 0);
+ #endif
+
+ //*** GO THROUGH EACH VERTICAL GROUP OF 4 SCANLINES.***
+
+ for (x=0; x<LCDWIDTH; x+=4) {
+
+ uint8_t *screenBufScanlineAddr = scrbuf + (x>>2);// point to beginning of line in data
+
+ /*Prepare scanline start address for sprites that are visible in this vertical scanline. Sprite width cannot exceed the screen width*/
+ uint8_t *sprScanlineAddr[SPRITE_COUNT]; // Sprite start address for the scanline
+ uint8_t sprScanlineBitshiftMode[SPRITE_COUNT]; // Sprite bitshift mode for the scanline
+ const uint8_t BITSHIFT_MODE_MIDDLE_BYTE = 0;
+ const uint8_t BITSHIFT_MODE_FIRST_BYTE = 1;
+ const uint8_t BITSHIFT_MODE_LAST_BYTE = 2;
+ uint8_t scanlineMinY = 255; // Init to uninitialized value. Do not draw by default.
+ uint8_t scanlineMaxY = 0; // Init to uninitialized value. Do not draw by default.
+
+ //*** CALCULATE DIRTY RECTS AND RESOLVE WHICH SPRITES BELONG TO THIS SCANLINE GROUP ***
+
+ if (sprites != NULL) {
+
+ // Check all the sprites for this scanline. That is used for handling the given update rect
+ // Note that the last round is when (sprindex == spriteCount). That is used to add the screen buffer
+ // update rect to the dirty rect.
+ for (int sprindex = 0; sprindex <= spriteCount; sprindex++) {
+
+ int16_t sprx, spry, sprOldX, sprOldY;
+ uint8_t sprw, sprh;
+ bool isCurrentSpriteOutOfScreen = false;
+ bool isOldSpriteOutOfScreen = false;
+
+ if (sprindex < spriteCount) {
+
+ sprx = sprites[sprindex].x;
+ spry = sprites[sprindex].y;
+ sprw = sprites[sprindex].w;
+ sprh = sprites[sprindex].h;
+ sprOldX = sprites[sprindex].oldx;
+ sprOldY = sprites[sprindex].oldy;
+ }
+
+ // Handle the screen buffer update rect after all sprites
+ else if(!drawSpritesOnly){
+
+ sprx = updRectX;
+ spry = updRectY;
+ sprw = updRectW;
+ sprh = updRectH;
+ sprOldX = updRectX;
+ sprOldY = updRectY;
+ isCurrentSpriteOutOfScreen = false;
+ isOldSpriteOutOfScreen = false;
+ }
+
+ // Check for out-of-screen
+ if (sprx >= LCDWIDTH || spry >= LCDHEIGHT)
+ isCurrentSpriteOutOfScreen = true;
+ if (sprOldX >= LCDWIDTH || sprOldY >= LCDHEIGHT)
+ isOldSpriteOutOfScreen = true;
+
+ // Skip if current and old sprites are out-of-screen
+ if (isCurrentSpriteOutOfScreen && isOldSpriteOutOfScreen)
+ continue;
+
+ // Detect the dirty rect x-span by combining the previous and current sprite position.
+ int16_t sprDirtyXMin = min(sprx, sprOldX);
+ int16_t sprDirtyXMax = max(sprx, sprOldX);
+ if (isCurrentSpriteOutOfScreen)
+ sprDirtyXMax = sprOldX;
+ if (isOldSpriteOutOfScreen)
+ sprDirtyXMax = sprx;
+
+ // Is current x inside the sprite combined dirty rect ?
+ int16_t sprDirtyXMaxEnd = sprDirtyXMax + sprw - 1 + 4; // Add 4 pixels to dirty rect width (needed?)
+ if (sprDirtyXMin <= x+3 && x <= sprDirtyXMaxEnd) {
+
+ // *** COMBINE DIRTY RECTS FOR THIS SCANLINE GROUP ***
+
+ // Dirty rect
+ int sprDirtyYMin = std::min(spry, sprOldY);
+ sprDirtyYMin = std::max((int)sprDirtyYMin, 0);
+ int sprDirtyYMax = std::max(spry, sprOldY);
+ if (isCurrentSpriteOutOfScreen)
+ sprDirtyYMax = sprOldY;
+ if (isOldSpriteOutOfScreen)
+ sprDirtyYMax = spry;
+ int sprDirtyYMaxEnd = sprDirtyYMax + sprh - 1;
+ sprDirtyYMaxEnd = std::min(sprDirtyYMaxEnd, LCDHEIGHT - 1); // Should use LCDHEIGHT instead of screenH? Same with other screen* ?
+
+ // Get the scanline min and max y values for drawing
+ if (sprDirtyYMin < scanlineMinY)
+ scanlineMinY = sprDirtyYMin;
+ if (sprDirtyYMaxEnd > scanlineMaxY)
+ scanlineMaxY = sprDirtyYMaxEnd;
+
+ // *** PREPARE SPRITE FOR DRAWING ***
+
+ // Check if the sprite should be active for this vertical scanline group.
+ if (sprindex < spriteCount && // not for update rect
+ !isCurrentSpriteOutOfScreen && //out-of-screen
+ sprx <= x+3 && x < sprx + sprw) { // note: cover group of 4 pixels of the scanline (x+3)
+
+ // Find the byte number in the sprite data
+ int16_t byteNum = ((x+3) - sprx)>>2;
+
+ // Get the start addres of the spite data in this scanline.
+ sprScanlineAddr[sprindex] = const_cast<uint8_t*>(sprites[sprindex].bitmapData + byteNum);
+
+ // If the sprite goes over the top, it must be clipped from the top.
+ if(spry < 0)
+ sprScanlineAddr[sprindex] += (-spry) * (sprw >> 2);
+
+ // Select the bitshift mode for the blit algorithm
+ if (byteNum == 0)
+ sprScanlineBitshiftMode[sprindex] = BITSHIFT_MODE_FIRST_BYTE;
+ else if (byteNum >= (sprw >> 2))
+ sprScanlineBitshiftMode[sprindex] = BITSHIFT_MODE_LAST_BYTE;
+ else
+ sprScanlineBitshiftMode[sprindex] = BITSHIFT_MODE_MIDDLE_BYTE;
+ }
+ else
+ sprScanlineAddr[sprindex] = NULL; // Deactive sprite for this scanline
+ }
+ else
+ sprScanlineAddr[sprindex] = NULL; // Deactive sprite for this scanline
+ }
+ }
+
+ // *** ADJUST THE SCANLINE GROUP HEIGHT ***
+
+ // The height must dividable by 8. That is needed because later we copy 8 pixels at a time to the LCD.
+ if (scanlineMaxY - scanlineMinY + 1 > 0) {
+ uint8_t scanlineH = scanlineMaxY - scanlineMinY + 1;
+ uint8_t addW = 8 - (scanlineH & 0x7);
+
+ // if height is not dividable by 8, make it be.
+ if (addW != 0) {
+ if (scanlineMinY > addW )
+ scanlineMinY -= addW;
+ else if( scanlineMaxY + addW < updRectY+updRectH)
+ scanlineMaxY += addW;
+ else {
+ // Draw full height scanline
+ scanlineMinY = updRectY;
+ scanlineMaxY = updRectY+updRectH-1;
+ }
+ }
+ }
+
+ // *** COMBINE THE SCANLINE GROUP OF THE SCREEN BUFFER AND ALL SPRITES ***
+
+ // Find colours in this group of 4 scanlines
+ screenBufScanlineAddr += (scanlineMinY * 220/4);
+ for (y=scanlineMinY; y<=scanlineMaxY; y++)
+ {
+ // get the screen buffer data first
+ uint8_t tdata = *screenBufScanlineAddr;
+ uint8_t t4 = tdata & 0x03; tdata >>= 2;// lowest half-nibble
+ uint8_t t3 = tdata & 0x03; tdata >>= 2;// second lowest half-nibble
+ uint8_t t2 = tdata & 0x03; tdata >>= 2;// second highest half-nibble
+ uint8_t t = tdata & 0x03;// highest half-nibble
+
+ // Convert to 16-bit colors in palette
+ uint16_t p = paletteptr[t];
+ uint16_t p2 = paletteptr[t2];
+ uint16_t p3 = paletteptr[t3];
+ uint16_t p4 = paletteptr[t4];
+
+ #if 0
+ // Dirty rect visual test
+ p = COLOR_BLUE >> (Core::frameCount % 5);
+ p2 = COLOR_BLUE >> (Core::frameCount % 5);
+ p3 = COLOR_BLUE >> (Core::frameCount % 5);
+ p4 = COLOR_BLUE >> (Core::frameCount % 5);
+ #endif
+
+ // Add active sprite pixels
+ if (sprites != NULL) {
+
+ // Use loop unrolling for speed optimization
+ UNROLLED_LOOP_N(SPRITE_COUNT)
+ }
+
+ // put the result nibble values in the scanline
+ scanline[0][y] = p;
+ scanline[1][y] = p2;
+ scanline[2][y] = p3;
+ scanline[3][y] = p4;
+
+ screenBufScanlineAddr += 220>>2; // jump to read byte directly below in screenbuffer
+ }
+
+ // *** DRAW THE SCANLINE GROUP TO LCD
+
+#ifdef PROJ_SHOW_FPS_COUNTER
+ if (x>=8 && scanlineMaxY - scanlineMinY +1 > 0) {
+#else
+ if (scanlineMaxY - scanlineMinY +1 > 0) {
+#endif
+ // Draw 8 vertical pixels at a time for performance reasons
+
+ setDRAMptr(x, scanlineMinY);
+ for (uint8_t s=scanlineMinY;s<=scanlineMaxY;) {
+ setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;
+ }
+
+ setDRAMptr(x+1, scanlineMinY);
+ for (uint8_t s=scanlineMinY;s<=scanlineMaxY;) {
+ setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;
+ }
+
+ setDRAMptr(x+2, scanlineMinY);
+ for (uint8_t s=scanlineMinY;s<=scanlineMaxY;) {
+ setup_data_16(scanline[2][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[2][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[2][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[2][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[2][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[2][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[2][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[2][s++]);CLR_WR;SET_WR;
+ }
+
+ setDRAMptr(x+3, scanlineMinY);
+ for (uint8_t s=scanlineMinY;s<=scanlineMaxY;) {
+ setup_data_16(scanline[3][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[3][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[3][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[3][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[3][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[3][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[3][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[3][s++]);CLR_WR;SET_WR;
+ }
+ }
+ }
+
+ // Update old x and y for the sprites
+ if (sprites != NULL) {
+ for (int sprindex = 0; sprindex < spriteCount; sprindex++) {
+ sprites[sprindex].oldx = sprites[sprindex].x;
+ sprites[sprindex].oldy = sprites[sprindex].y;
+ }
+ }
+
+ #ifdef POK_SIM
+ simulator.refreshDisplay();
+ #endif
+}
+
+void Pokitto::lcdRefreshMode2(uint8_t * scrbuf, uint16_t* paletteptr) {
+uint16_t x,y;
+uint16_t scanline[2][88]; // read two nibbles = pixels at a time
+uint8_t *d;
+
+write_command(0x20); // Horizontal DRAM Address
+write_data(0); // 0
+write_command(0x21); // Vertical DRAM Address
+write_data(0);
+write_command(0x22); // write data to DRAM
+CLR_CS_SET_CD_RD_WR;
+
+for(x=0;x<110;x+=2)
+ {
+ d = scrbuf+(x>>1);// point to beginning of line in data
+ /** find colours in one scanline **/
+ uint8_t s=0;
+ for(y=0;y<88;y++)
+ {
+ uint8_t t = *d >> 4; // higher nibble
+ uint8_t t2 = *d & 0xF; // lower nibble
+ /** higher nibble = left pixel in pixel pair **/
+ scanline[0][s] = paletteptr[t];
+ scanline[1][s++] = paletteptr[t2];
+ /** testing only **/
+ //scanline[0][s] = 0xFFFF*(s&1);
+ //scanline[1][s] = 0xFFFF*(!(s&1));
+ //s++;
+ /** until here **/
+ d+=110/2; // jump to read byte directly below in screenbuffer
+ }
+ s=0;
+ /** draw scanlines **/
+ /** leftmost scanline twice**/
+
+ #ifdef PROJ_SHOW_FPS_COUNTER
+ if (x<4) continue;
+ setDRAMptr(x<<1, 0);
+ #endif
+
+ for (s=0;s<88;) {
+ setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
+ setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
+ setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
+ setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
+ setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
+ setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
+ setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
+ setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
+ }
+
+ for (s=0;s<88;) {
+ setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
+ setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
+ setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
+ setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
+ setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
+ setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
+ setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
+ setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
+ }
+ /** rightmost scanline twice**/
+ //setDRAMptr(xptr++,yoffset);
+ for (s=0;s<88;) {
+ setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
+ setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
+ setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
+ setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
+ setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
+ setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
+ setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
+ setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
+ }
+
+ for (s=0;s<88;) {
+ setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
+ setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
+ setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
+ setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
+ setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
+ setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
+ setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
+ setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
+ }
+ }
+}
+
+void Pokitto::lcdRefreshMode3(uint8_t * scrbuf, uint16_t* paletteptr) {
+uint16_t x,y;
+uint16_t scanline[2][176]; // read two nibbles = pixels at a time
+uint8_t *d;
+
+write_command(0x20); // Horizontal DRAM Address
+write_data(0); // 0
+write_command(0x21); // Vertical DRAM Address
+write_data(0);
+write_command(0x22); // write data to DRAM
+CLR_CS_SET_CD_RD_WR;
+
+for(x=0;x<220;x+=2)
+ {
+ d = scrbuf+(x>>1);// point to beginning of line in data
+ /** find colours in one scanline **/
+ uint8_t s=0;
+ for(y=0;y<176;y++)
+ {
+ uint8_t t = *d >> 4; // higher nibble
+ uint8_t t2 = *d & 0xF; // lower nibble
+ /** higher nibble = left pixel in pixel pair **/
+ scanline[0][s] = paletteptr[t];
+ scanline[1][s++] = paletteptr[t2];
+ /** testing only **/
+ //scanline[0][s] = 0xFFFF*(s&1);
+ //scanline[1][s] = 0xFFFF*(!(s&1));
+ //s++;
+ /** until here **/
+ d+=220/2; // jump to read byte directly below in screenbuffer
+ }
+ s=0;
+ /** draw scanlines **/
+ /** leftmost scanline**/
+
+ #ifdef PROJ_SHOW_FPS_COUNTER
+ if (x<8) continue;
+ setDRAMptr(x, 0);
+ #endif
+
+ for (s=0;s<176;) {
+ setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;
+ }
+
+ /** rightmost scanline**/
+ //setDRAMptr(xptr++,yoffset);
+ for (s=0;s<176;) {
+ setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;
+ }
+ }
+}
+
+void Pokitto::lcdRefreshGB(uint8_t * scrbuf, uint16_t* paletteptr) {
+uint16_t x,y;
+uint16_t scanline[48];
+uint8_t * d;
+
+#if POK_STRETCH
+//uint16_t xptr = 8;
+#else
+//xptr = 26;
+#endif
+
+write_command(0x20); // Horizontal DRAM Address
+write_data(0); // 0
+write_command(0x21); // Vertical DRAM Address
+write_data(0);
+write_command(0x22); // write data to DRAM
+CLR_CS_SET_CD_RD_WR;
+
+/** draw border **/
+ for (int s=0;s<5*176;) {
+ setup_data_16(COLOR_BLACK);CLR_WR;SET_WR;s++;
+ }
+
+for(x=0;x<84;x++)
+ {
+
+ d = scrbuf + x;// point to beginning of line in data
+
+ /** find colours in one scanline **/
+ uint8_t s=0;
+ for(y=0;y<6;y++)
+ {
+ uint8_t t = *d;
+ #if POK_COLORDEPTH > 1
+ uint8_t t2 = *(d+504);
+ #endif
+ #if POK_COLORDEPTH > 2
+ uint8_t t3 = *(d+504+504);
+ #endif
+ #if POK_COLORDEPTH > 3
+ uint8_t t4 = *(d+504+504+504);
+ #endif
+ uint8_t paletteindex = 0;
+
+ /** bit 1 **/
+ #if POK_COLORDEPTH == 1
+ paletteindex = (t & 0x1);
+ #elif POK_COLORDEPTH == 2
+ paletteindex = ((t & 0x1)) | ((t2 & 0x01)<<1);
+ #elif POK_COLORDEPTH == 3
+ paletteindex = (t & 0x1) | ((t2 & 0x1)<<1) | ((t3 & 0x1)<<2);
+ #elif POK_COLORDEPTH == 4
+ paletteindex = (t & 0x1) | ((t2 & 0x1)<<1) | ((t3 & 0x1)<<2) | ((t4 & 0x1)<<3);
+ #endif
+ scanline[s++] = paletteptr[paletteindex];
+
+ /** bit 2 **/
+ #if POK_COLORDEPTH == 1
+ paletteindex = (t & 0x2)>>1;
+ #elif POK_COLORDEPTH == 2
+ paletteindex = ((t & 0x2)>>1) | ((t2 & 0x02));
+ #elif POK_COLORDEPTH == 3
+ paletteindex = ((t & 0x2)>>1) | ((t2 & 0x2)) | ((t3 & 0x2)<<1);
+ #elif POK_COLORDEPTH == 4
+ paletteindex = ((t & 0x2)>>1) | ((t2 & 0x2)) | ((t3 & 0x2)<<1) | ((t4 & 0x2)<<2);
+ #endif
+ scanline[s++] = paletteptr[paletteindex];
+
+ /** bit 3 **/
+ #if POK_COLORDEPTH == 1
+ paletteindex = (t & 0x4)>>2;
+ #elif POK_COLORDEPTH == 2
+ paletteindex = ((t & 4)>>2) | ((t2 & 0x04)>>1);
+ #elif POK_COLORDEPTH == 3
+ paletteindex = ((t & 0x4)>>2) | ((t2 & 0x4)>>1) | (t3 & 0x4);
+ #elif POK_COLORDEPTH == 4
+ paletteindex = ((t & 0x4)>>2) | ((t2 & 0x4)>>1) | (t3 & 0x4) | ((t4 & 0x4)<<1);
+ #endif
+ scanline[s++] = paletteptr[paletteindex];
+
+ /** bit 4 **/
+ #if POK_COLORDEPTH == 1
+ paletteindex = (t & 0x8)>>3;
+ #elif POK_COLORDEPTH == 2
+ paletteindex = ((t & 0x8)>>3) | ((t2 & 0x08)>>2);
+ #elif POK_COLORDEPTH == 3
+ paletteindex = ((t & 0x8)>>3) | ((t2 & 0x8)>>2) | ((t3 & 0x8)>>1);
+ #elif POK_COLORDEPTH == 4
+ paletteindex = ((t & 0x8)>>3) | ((t2 & 0x8)>>2) | ((t3 & 0x8)>>1) | (t4 & 0x8);
+ #endif
+ scanline[s++] = paletteptr[paletteindex];
+
+ /** bit 5 **/
+ #if POK_COLORDEPTH == 1
+ paletteindex = (t & 0x10)>>4;
+ #elif POK_COLORDEPTH == 2
+ paletteindex = ((t & 0x10)>>4) | ((t2 & 0x10)>>3);
+ #elif POK_COLORDEPTH == 3
+ paletteindex = ((t & 0x10)>>4) | ((t2 & 0x10)>>3) | ((t3 & 0x10)>>2);
+ #elif POK_COLORDEPTH == 4
+ paletteindex = ((t & 0x10)>>4) | ((t2 & 0x10)>>3) | ((t3 & 0x10)>>2) | ((t4 & 0x10)>>1);
+ #endif
+ scanline[s++] = paletteptr[paletteindex];
+
+ /** bit 6 **/
+ #if POK_COLORDEPTH == 1
+ paletteindex = (t & 0x20)>>5;
+ #elif POK_COLORDEPTH == 2
+ paletteindex = ((t & 0x20)>>5) | ((t2 & 0x20)>>4);
+ #elif POK_COLORDEPTH == 3
+ paletteindex = ((t & 0x20)>>5) | ((t2 & 0x20)>>4) | ((t3 & 0x20)>>3);
+ #elif POK_COLORDEPTH == 4
+ paletteindex = ((t & 0x20)>>5) | ((t2 & 0x20)>>4) | ((t3 & 0x20)>>3) | ((t4 & 0x20)>>2);
+ #endif
+ scanline[s++] = paletteptr[paletteindex];
+
+ /** bit 7 **/
+ #if POK_COLORDEPTH == 1
+ paletteindex = (t & 0x40)>>6;
+ #elif POK_COLORDEPTH == 2
+ paletteindex = ((t & 0x40)>>6) | ((t2 & 0x40)>>5);
+ #elif POK_COLORDEPTH == 3
+ paletteindex = ((t & 0x40)>>6) | ((t2 & 0x40)>>5) | ((t3 & 0x40)>>4) ;
+ #elif POK_COLORDEPTH == 4
+ paletteindex = ((t & 0x40)>>6) | ((t2 & 0x40)>>5) | ((t3 & 0x40)>>4) | ((t4 & 0x40)>>3);
+ #endif
+ scanline[s++] = paletteptr[paletteindex];
+
+ /** bit 8 **/
+ #if POK_COLORDEPTH == 1
+ paletteindex = (t & 0x80)>>7;
+ #elif POK_COLORDEPTH == 2
+ paletteindex = ((t & 0x80)>>7) | ((t2 & 0x80)>>6);
+ #elif POK_COLORDEPTH == 3
+ paletteindex = ((t & 0x80)>>7) | ((t2 & 0x80)>>6) | ((t3 & 0x80)>>5);
+ #elif POK_COLORDEPTH == 4
+ paletteindex = ((t & 0x80)>>7) | ((t2 & 0x80)>>6) | ((t3 & 0x80)>>5) | ((t4 & 0x80)>>4);
+ #endif
+ scanline[s++] = paletteptr[paletteindex];
+
+ d+=84; // jump to byte directly below
+ }
+
+
+ /*write_command(0x20); // Horizontal DRAM Address
+ write_data(0x10); // 0
+ write_command(0x21); // Vertical DRAM Address
+ write_data(xptr++);
+ write_command(0x22); // write data to DRAM
+ CLR_CS_SET_CD_RD_WR;*/
+ /** draw border **/
+ setup_data_16(COLOR_BLACK);CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR; CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;
+
+ s=0;
+
+ /** draw scanlines **/
+ for (s=0;s<48;) {
+ setup_data_16(scanline[s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;
+ setup_data_16(scanline[s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;
+ setup_data_16(scanline[s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;
+ setup_data_16(scanline[s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;
+ setup_data_16(scanline[s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;
+ setup_data_16(scanline[s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;
+ setup_data_16(scanline[s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;
+ setup_data_16(scanline[s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;
+ }
+ /** draw border **/
+ setup_data_16(COLOR_BLACK);CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR; CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;
+
+
+ /*write_command(0x20); // Horizontal DRAM Address
+ write_data(0x10); // 0
+ write_command(0x21); // Vertical DRAM Address
+ write_data(xptr++);
+ write_command(0x22); // write data to DRAM
+ CLR_CS_SET_CD_RD_WR;*/
+ /** draw border **/
+ setup_data_16(COLOR_BLACK);CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR; CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;
+
+ for (s=0;s<48;) {
+ setup_data_16(scanline[s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;
+ setup_data_16(scanline[s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;
+ setup_data_16(scanline[s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;
+ setup_data_16(scanline[s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;
+ setup_data_16(scanline[s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;
+ setup_data_16(scanline[s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;
+ setup_data_16(scanline[s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;
+ setup_data_16(scanline[s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;
+ }
+
+ /** draw border **/
+ setup_data_16(COLOR_BLACK);CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR; CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;
+
+
+ #if POK_STRETCH
+ //if (x>16 && x<68)
+ if (x&2)// && x&2)
+ {
+ /*write_command(0x20); // Horizontal DRAM Address
+ write_data(0x10); // 0
+ write_command(0x21); // Vertical DRAM Address
+ write_data(xptr++);
+ write_command(0x22); // write data to DRAM
+ CLR_CS_SET_CD_RD_WR;*/
+ /** draw border **/
+ setup_data_16(COLOR_BLACK);CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR; CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;
+
+
+ for (s=0;s<48;) {
+ setup_data_16(scanline[s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;
+ setup_data_16(scanline[s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;
+ setup_data_16(scanline[s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;
+ setup_data_16(scanline[s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;
+ setup_data_16(scanline[s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;
+ setup_data_16(scanline[s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;
+ setup_data_16(scanline[s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;
+ setup_data_16(scanline[s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;
+ }
+
+ /** draw border **/
+ setup_data_16(COLOR_BLACK);CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR; CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;CLR_WR;SET_WR;
+
+ }
+ #endif
+ }
+ /** draw border **/
+ for (int s=0;s<5*176;) {
+ setup_data_16(COLOR_BLACK);CLR_WR;SET_WR;s++;
+ }
+}
+
+
+void Pokitto::lcdRefreshAB(uint8_t * scrbuf, uint16_t* paletteptr) {
+uint16_t x,y;
+uint16_t scanline[64];
+uint8_t *d;
+//lcdClear();
+#if POK_STRETCH
+uint16_t xptr = 14;
+uint8_t yoffset = 24;
+#else
+uint16_t xptr = 0;
+uint8_t yoffset = 0;
+#endif
+
+for(x=0;x<128;x++)
+ {
+ write_command(0x20); // Horizontal DRAM Address
+ write_data(yoffset); // 0
+ write_command(0x21); // Vertical DRAM Address
+ write_data(xptr++);
+ write_command(0x22); // write data to DRAM
+ CLR_CS_SET_CD_RD_WR;
+ //setDRAMptr(xptr++,yoffset);
+
+ d = scrbuf + x;// point to beginning of line in data
+
+ /** find colours in one scanline **/
+ uint8_t s=0;
+ for(y=0;y<8;y++)
+ {
+ uint8_t t = *d;
+ #if POK_COLORDEPTH > 1
+ uint8_t t2 = *(d+AB_JUMP);
+ #endif // POK_COLORDEPTH
+ #if POK_COLORDEPTH > 2
+ uint8_t t3 = *(d+AB_JUMP+AB_JUMP);
+ #endif // POK_COLORDEPTH
+ #if POK_COLORDEPTH > 3
+ uint8_t t4 = *(d+AB_JUMP+AB_JUMP+AB_JUMP);
+ #endif // POK_COLORDEPTH
+ uint8_t paletteindex = 0;
+
+ /** bit 1 **/
+ #if POK_COLORDEPTH == 1
+ paletteindex = (t & 0x1);
+ #elif POK_COLORDEPTH == 2
+ paletteindex = ((t & 0x1)) | ((t2 & 0x01)<<1);
+ #elif POK_COLORDEPTH == 3
+ paletteindex = (t & 0x1) | ((t2 & 0x1)<<1) | ((t3 & 0x1)<<2);
+ #elif POK_COLORDEPTH == 4
+ paletteindex = (t & 0x1) | ((t2 & 0x1)<<1) | ((t3 & 0x1)<<2) | ((t4 & 0x1)<<3);
+ #endif
+ scanline[s++] = paletteptr[paletteindex];
+
+ /** bit 2 **/
+ #if POK_COLORDEPTH == 1
+ paletteindex = (t & 0x2)>>1;
+ #elif POK_COLORDEPTH == 2
+ paletteindex = ((t & 0x2)>>1) | ((t2 & 0x02));
+ #elif POK_COLORDEPTH == 3
+ paletteindex = ((t & 0x2)>>1) | ((t2 & 0x2)) | ((t3 & 0x2)<<1);
+ #elif POK_COLORDEPTH == 4
+ paletteindex = ((t & 0x2)>>1) | ((t2 & 0x2)) | ((t3 & 0x2)<<1) | ((t4 & 0x2)<<2);
+ #endif
+ scanline[s++] = paletteptr[paletteindex];
+
+ /** bit 3 **/
+ #if POK_COLORDEPTH == 1
+ paletteindex = (t & 0x4)>>2;
+ #elif POK_COLORDEPTH == 2
+ paletteindex = ((t & 4)>>2) | ((t2 & 0x04)>>1);
+ #elif POK_COLORDEPTH == 3
+ paletteindex = ((t & 0x4)>>2) | ((t2 & 0x4)>>1) | (t3 & 0x4);
+ #elif POK_COLORDEPTH == 4
+ paletteindex = ((t & 0x4)>>2) | ((t2 & 0x4)>>1) | (t3 & 0x4) | ((t4 & 0x4)<<1);
+ #endif
+ scanline[s++] = paletteptr[paletteindex];
+
+ /** bit 4 **/
+ #if POK_COLORDEPTH == 1
+ paletteindex = (t & 0x8)>>3;
+ #elif POK_COLORDEPTH == 2
+ paletteindex = ((t & 0x8)>>3) | ((t2 & 0x08)>>2);
+ #elif POK_COLORDEPTH == 3
+ paletteindex = ((t & 0x8)>>3) | ((t2 & 0x8)>>2) | ((t3 & 0x8)>>1);
+ #elif POK_COLORDEPTH == 4
+ paletteindex = ((t & 0x8)>>3) | ((t2 & 0x8)>>2) | ((t3 & 0x8)>>1) | (t4 & 0x8);
+ #endif
+ scanline[s++] = paletteptr[paletteindex];
+
+ /** bit 5 **/
+ #if POK_COLORDEPTH == 1
+ paletteindex = (t & 0x10)>>4;
+ #elif POK_COLORDEPTH == 2
+ paletteindex = ((t & 0x10)>>4) | ((t2 & 0x10)>>3);
+ #elif POK_COLORDEPTH == 3
+ paletteindex = ((t & 0x10)>>4) | ((t2 & 0x10)>>3) | ((t3 & 0x10)>>2);
+ #elif POK_COLORDEPTH == 4
+ paletteindex = ((t & 0x10)>>4) | ((t2 & 0x10)>>3) | ((t3 & 0x10)>>2) | ((t4 & 0x10)>>1);
+ #endif
+ scanline[s++] = paletteptr[paletteindex];
+
+ /** bit 6 **/
+ #if POK_COLORDEPTH == 1
+ paletteindex = (t & 0x20)>>5;
+ #elif POK_COLORDEPTH == 2
+ paletteindex = ((t & 0x20)>>5) | ((t2 & 0x20)>>4);
+ #elif POK_COLORDEPTH == 3
+ paletteindex = ((t & 0x20)>>5) | ((t2 & 0x20)>>4) | ((t3 & 0x20)>>3);
+ #elif POK_COLORDEPTH == 4
+ paletteindex = ((t & 0x20)>>5) | ((t2 & 0x20)>>4) | ((t3 & 0x20)>>3) | ((t4 & 0x20)>>2);
+ #endif
+ scanline[s++] = paletteptr[paletteindex];
+
+ /** bit 7 **/
+ #if POK_COLORDEPTH == 1
+ paletteindex = (t & 0x40)>>6;
+ #elif POK_COLORDEPTH == 2
+ paletteindex = ((t & 0x40)>>6) | ((t2 & 0x40)>>5);
+ #elif POK_COLORDEPTH == 3
+ paletteindex = ((t & 0x40)>>6) | ((t2 & 0x40)>>5) | ((t3 & 0x40)>>4) ;
+ #elif POK_COLORDEPTH == 4
+ paletteindex = ((t & 0x40)>>6) | ((t2 & 0x40)>>5) | ((t3 & 0x40)>>4) | ((t4 & 0x40)>>3);
+ #endif
+ scanline[s++] = paletteptr[paletteindex];
+
+ /** bit 8 **/
+ #if POK_COLORDEPTH == 1
+ paletteindex = (t & 0x80)>>7;
+ #elif POK_COLORDEPTH == 2
+ paletteindex = ((t & 0x80)>>7) | ((t2 & 0x80)>>6);
+ #elif POK_COLORDEPTH == 3
+ paletteindex = ((t & 0x80)>>7) | ((t2 & 0x80)>>6) | ((t3 & 0x80)>>5);
+ #elif POK_COLORDEPTH == 4
+ paletteindex = ((t & 0x80)>>7) | ((t2 & 0x80)>>6) | ((t3 & 0x80)>>5) | ((t4 & 0x80)>>4);
+ #endif
+ scanline[s++] = paletteptr[paletteindex];
+
+ d+=128; // jump to byte directly below
+ }
+
+ s=0;
+
+ /** draw scanlines **/
+ for (s=0;s<64;) {
+ setup_data_16(scanline[s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
+ setup_data_16(scanline[s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
+ setup_data_16(scanline[s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
+ setup_data_16(scanline[s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
+ setup_data_16(scanline[s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
+ setup_data_16(scanline[s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
+ setup_data_16(scanline[s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
+ setup_data_16(scanline[s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
+ }
+
+ #if POK_STRETCH
+ if (x&1) {
+ write_command(0x20); // Horizontal DRAM Address
+ write_data(yoffset); // 0
+ write_command(0x21); // Vertical DRAM Address
+ write_data(xptr++);
+ write_command(0x22); // write data to DRAM
+ CLR_CS_SET_CD_RD_WR;
+ //setDRAMptr(xptr++,yoffset);
+
+ for (s=0;s<64;) {
+ setup_data_16(scanline[s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
+ setup_data_16(scanline[s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
+ setup_data_16(scanline[s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
+ setup_data_16(scanline[s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
+ setup_data_16(scanline[s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
+ setup_data_16(scanline[s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
+ setup_data_16(scanline[s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
+ setup_data_16(scanline[s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
+ }
+ }
+ #endif
+ }
+}
+
+void Pokitto::lcdRefreshModeGBC(uint8_t * scrbuf, uint16_t* paletteptr) {
+uint16_t x,y,xptr;
+uint16_t scanline[4][144]; // read 4 half-nibbles = 4 pixels at a time
+uint8_t *d, yoffset=0;
+
+xptr = 0;
+setDRAMptr(xptr,yoffset);
+
+
+for(x=0;x<160;x+=4)
+ {
+ d = scrbuf+(x>>2);// point to beginning of line in data
+ /** find colours in one scanline **/
+ uint8_t s=0;
+ for(y=0;y<144;y++)
+ {
+ uint8_t tdata = *d;
+ uint8_t t4 = tdata & 0x03; tdata >>= 2;// lowest half-nibble
+ uint8_t t3 = tdata & 0x03; tdata >>= 2;// second lowest half-nibble
+ uint8_t t2 = tdata & 0x03; tdata >>= 2;// second highest half-nibble
+ uint8_t t = tdata & 0x03;// highest half-nibble
+
+ /** put nibble values in the scanlines **/
+
+ scanline[0][s] = paletteptr[t];
+ scanline[1][s] = paletteptr[t2];
+ scanline[2][s] = paletteptr[t3];
+ scanline[3][s++] = paletteptr[t4];
+
+ d+=160/4; // jump to read byte directly below in screenbuffer
+ }
+
+ s=0;
+ /** draw scanlines **/
+ for (s=0;s<144;) {
+ setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;
+ }
+ setDRAMptr(++xptr,yoffset);
+ for (s=0;s<144;) {
+ setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;
+ }
+ setDRAMptr(++xptr,yoffset);
+ for (s=0;s<144;) {
+ setup_data_16(scanline[2][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[2][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[2][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[2][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[2][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[2][s++]);CLR_WR;SET_WR;
+ }
+ setDRAMptr(++xptr,yoffset);
+ for (s=0;s<144;) {
+ setup_data_16(scanline[3][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[3][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[3][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[3][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[3][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[3][s++]);CLR_WR;SET_WR;
+ }
+ setDRAMptr(++xptr,yoffset);
+ }
+}
+
+
+void Pokitto::lcdRefreshT1(uint8_t* tilebuf, uint8_t* tilecolorbuf, uint8_t* tileset, uint16_t* paletteptr) {
+#ifdef POK_TILEMODE
+uint16_t x,y,data,xptr;
+uint16_t scanline[176];
+uint8_t yoffset=0, tilebyte, tileindex, tilex=0, tiley=0,xcount;
+
+
+if (!tileset) return;
+
+#if LCDWIDTH < POK_LCD_W
+xptr = (POK_LCD_W-LCDWIDTH)/2;
+#else
+xptr = 0;
+#endif
+#if LCDHEIGHT < POK_LCD_H
+yoffset = (POK_LCD_H-LCDHEIGHT)/2;
+#else
+yoffset = 0;
+#endif
+
+for(x=0, xcount=0 ;x<LCDWIDTH;x++,xcount++) // loop through vertical columns
+ {
+ setDRAMptr(xptr++,yoffset); //point to VRAM
+
+ /** find colours in one scanline **/
+ uint8_t s=0, tiley=0;
+ //tileindex = tilebuf[tilex*POK_TILES_Y];
+ if (xcount==POK_TILE_W) {
+ tilex++;
+ xcount=0;
+ }
+
+ for(y=0;y<LCDHEIGHT;)
+ {
+ uint8_t tileval = tilebuf[tilex+tiley*POK_TILES_X]; //get tile number
+ uint16_t index = tileval*POK_TILE_W+xcount;
+ uint8_t tilebyte = tileset[index]; //get bitmap data
+ for (uint8_t ycount=0, bitcount=0; ycount<POK_TILE_H; ycount++, y++, bitcount++) {
+ if (bitcount==8) {
+ bitcount=0;
+ index += 176; //jump to byte below in the tileset bitmap
+ tilebyte = tileset[index]; //get bitmap data
+ }
+ //tilebyte = tile[(tileindex>>4)+*POK_TILE_W]; //tilemaps are 16x16
+ //uint8_t paletteindex = ((tilebyte>>(bitcount&0x7)) & 0x1);
+ if (!tileval) scanline[s++] = COLOR_MAGENTA*((tilebyte>>bitcount)&0x1);//paletteptr[paletteindex];
+ else scanline[s++] = paletteptr[((tilebyte>>bitcount)&0x1)*tileval];//paletteptr[paletteindex];
+ }
+ tiley++; //move to next tile
+ }
+ s=0;
+
+ /** draw scanlines **/
+ for (s=0;s<LCDHEIGHT;) {
+ setup_data_16(scanline[s++]);CLR_WR;SET_WR;
+ }
+ }
+ #endif
+}
+
+
+void Pokitto::lcdRefreshMode13(uint8_t * scrbuf, uint16_t* paletteptr, uint8_t offset){
+uint16_t x,y;
+uint16_t scanline[2][110]; // read two nibbles = pixels at a time
+uint8_t *d;
+
+write_command(0x20); write_data(0);
+write_command(0x21); write_data(0);
+write_command(0x22);
+CLR_CS_SET_CD_RD_WR;
+
+for(x=0;x<110;x+=2)
+ {
+ d = scrbuf+x;// point to beginning of line in data
+ uint8_t s=0;
+ for(y=0;y<88;y++)
+ {
+ uint8_t t = *d;
+ uint8_t t1 = *(d+1);
+ scanline[0][s] = paletteptr[(t+offset)&255];
+ scanline[1][s++] = paletteptr[(t1+offset)&255];
+ d+=110; // jump to read byte directly below in screenbuffer
+ }
+ s=0;
+ for (s=0;s<88;) {
+ setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
+ setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
+ setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
+ setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
+ setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
+ setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
+ setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
+ setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
+ }
+ for (s=0;s<88;) {
+ setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
+ setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
+ setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
+ setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
+ setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
+ setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
+ setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
+ setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
+ }
+ for (s=0;s<88;) {
+ setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
+ setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
+ setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
+ setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
+ setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
+ setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
+ setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
+ setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
+ }
+ for (s=0;s<88;) {
+ setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
+ setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
+ setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
+ setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
+ setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
+ setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
+ setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
+ setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;CLR_WR;SET_WR;
+ }
+ }
+
+}
+
+
+
+void Pokitto::lcdRefreshMode14(uint8_t * scrbuf, uint16_t* paletteptr) {
+uint16_t x,y,data,xptr;
+uint16_t scanline[176]; uint16_t* scptr;
+uint8_t *d;
+
+write_command(0x20); write_data(0);
+write_command(0x21); write_data(0);
+write_command(0x22);
+CLR_CS_SET_CD_RD_WR;
+
+for(x=0;x<220;x++)
+ {
+ d = scrbuf+x;
+ scptr = &scanline[0];
+
+ /** find colours in one scanline **/
+ /*for(y=0;y<22;y++)
+ {
+
+ uint16_t t = *d;
+ uint16_t t2 = *(d+POK_BITFRAME);
+ uint16_t t3 = *(d+POK_BITFRAME+POK_BITFRAME);
+
+ *scptr++ = (t & 0x1)*R_MASK | (t2 & 0x1)*G_MASK | (t3 & 0x1)*B_MASK; t >>= 1;t2 >>= 1;t3 >>= 1;
+ *scptr++ = (t & 0x1)*R_MASK | (t2 & 0x1)*G_MASK | (t3 & 0x1)*B_MASK; t >>= 1;t2 >>= 1;t3 >>= 1;
+ *scptr++ = (t & 0x1)*R_MASK | (t2 & 0x1)*G_MASK | (t3 & 0x1)*B_MASK; t >>= 1;t2 >>= 1;t3 >>= 1;
+ *scptr++ = (t & 0x1)*R_MASK | (t2 & 0x1)*G_MASK | (t3 & 0x1)*B_MASK; t >>= 1;t2 >>= 1;t3 >>= 1;
+
+ *scptr++ = (t & 0x1)*R_MASK | (t2 & 0x1)*G_MASK | (t3 & 0x1)*B_MASK; t >>= 1;t2 >>= 1;t3 >>= 1;
+ *scptr++ = (t & 0x1)*R_MASK | (t2 & 0x1)*G_MASK | (t3 & 0x1)*B_MASK; t >>= 1;t2 >>= 1;t3 >>= 1;
+ *scptr++ = (t & 0x1)*R_MASK | (t2 & 0x1)*G_MASK | (t3 & 0x1)*B_MASK; t >>= 1;t2 >>= 1;t3 >>= 1;
+ *scptr++ = (t & 0x1)*R_MASK | (t2 & 0x1)*G_MASK | (t3 & 0x1)*B_MASK; t >>= 1;t2 >>= 1;t3 >>= 1;
+
+
+ d+=220; // jump to word directly below
+ }
+ */
+ /** alternative way: go through one color at a time **/
+ scptr = &scanline[0]; // set to beginning of scanline
+ for(y=0;y<22;y++, d +=220)
+ {
+ uint16_t t = *d & 0xFF;
+
+ *scptr++ = R_MASK * (t&0x1); t >>= 1;
+ *scptr++ = R_MASK * (t&0x1); t >>= 1;
+ *scptr++ = R_MASK * (t&0x1); t >>= 1;
+ *scptr++ = R_MASK * (t&0x1); t >>= 1;
+ *scptr++ = R_MASK * (t&0x1); t >>= 1;
+ *scptr++ = R_MASK * (t&0x1); t >>= 1;
+ *scptr++ = R_MASK * (t&0x1); t >>= 1;
+ *scptr++ = R_MASK * (t&0x1);
+ }
+ scptr = &scanline[0]; // set to beginning of scanline
+ d = scrbuf+x+POK_BITFRAME;
+ for(y=0;y<22;y++, d +=220)
+ {
+ uint16_t t = *d & 0xFF;
+
+ *scptr++ |= G_MASK * (t&0x1); t >>= 1;
+ *scptr++ |= G_MASK * (t&0x1); t >>= 1;
+ *scptr++ |= G_MASK * (t&0x1); t >>= 1;
+ *scptr++ |= G_MASK * (t&0x1); t >>= 1;
+ *scptr++ |= G_MASK * (t&0x1); t >>= 1;
+ *scptr++ |= G_MASK * (t&0x1); t >>= 1;
+ *scptr++ |= G_MASK * (t&0x1); t >>= 1;
+ *scptr++ |= G_MASK * (t&0x1);
+ }
+ scptr = &scanline[0]; // set to beginning of scanline
+ d = scrbuf+x+POK_BITFRAME*2;
+ for(y=0;y<22;y++, d +=220)
+ {
+ uint16_t t = *d & 0xFF;
+
+ *scptr++ |= B_MASK * (t&0x1); t >>= 1;
+ *scptr++ |= B_MASK * (t&0x1); t >>= 1;
+ *scptr++ |= B_MASK * (t&0x1); t >>= 1;
+ *scptr++ |= B_MASK * (t&0x1); t >>= 1;
+ *scptr++ |= B_MASK * (t&0x1); t >>= 1;
+ *scptr++ |= B_MASK * (t&0x1); t >>= 1;
+ *scptr++ |= B_MASK * (t&0x1); t >>= 1;
+ *scptr++ |= B_MASK * (t&0x1);
+ }
+
+
+ #ifdef PROJ_SHOW_FPS_COUNTER
+ if (x<8) continue;
+ setDRAMptr(x, 0);
+ #endif
+
+ /** draw scanlines **/
+ for (int s=0;s<176;) {
+ setup_data_16(scanline[s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[s++]);CLR_WR;SET_WR;
+
+ }
+
+ }
+}
+
+//#define ADEKTOSMODE15
+
+#ifdef ADEKTOSMODE15
+void Pokitto::lcdRefreshMode15(uint16_t* pal, uint8_t* scrbuf){
+ write_command(0x03); write_data(0x1038); //realy only need to call this once
+ write_command(0x20); write_data(0);
+ write_command(0x21); write_data(0);
+
+ write_command(0x22);
+
+ #ifdef PROJ_SHOW_FPS_COUNTER
+ for (int x=0,xt=0; x<0x4BA0;x++,xt++) {
+ if (xt==110) xt=0;
+ if (xt<8) {
+ write_data(0);
+ write_data(0);
+ } else {
+ write_data(pal[(((scrbuf[x]) & 0xf0) >> 4)]);
+ write_data(pal[( (scrbuf[x]) & 0x0f)]);
+ }
+
+ }
+ #else
+ for (int x=0; x<0x4BA0;x++) {
+ write_data(pal[(((scrbuf[x]) & 0xf0) >> 4)]);
+ write_data(pal[( (scrbuf[x]) & 0x0f)]);
+ }
+ #endif //PROJ_SHOW_FPS_COUNTER
+}
+
+#else
+
+void Pokitto::lcdRefreshMode15(uint16_t* paletteptr, uint8_t* scrbuf){
+uint16_t x,y,xptr;
+uint16_t scanline[2][176]; // read two nibbles = pixels at a time
+uint8_t *d, yoffset=0;
+
+xptr = 0;
+//setDRAMptr(xptr,yoffset);
+
+write_command(0x20); write_data(0);
+write_command(0x21); write_data(0);
+write_command(0x22);
+CLR_CS_SET_CD_RD_WR;
+
+for(x=0;x<220;x+=2)
+ {
+ d = scrbuf+(x>>1);// point to beginning of line in data
+ // find colours in one scanline
+ uint8_t s=0;
+ for(y=0;y<176;y++)
+ {
+ uint8_t t = *d >> 4; // higher nibble
+ uint8_t t2 = *d & 0xF; // lower nibble
+ // higher nibble = left pixel in pixel pair
+ scanline[0][s] = paletteptr[t];
+ scanline[1][s++] = paletteptr[t2];
+
+ d+=220/2; // jump to read byte directly below in screenbuffer
+ }
+ s=0;
+ // draw scanlines
+
+ #ifdef PROJ_SHOW_FPS_COUNTER
+ if (x<8) continue;
+ setDRAMptr(x, 0);
+ #endif
+
+ for (s=0;s<176;) {
+ setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[0][s++]);CLR_WR;SET_WR;
+ }
+
+ for (s=0;s<176;) {
+ setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;
+ setup_data_16(scanline[1][s++]);CLR_WR;SET_WR;
+ }
+ }
+}
+#endif //ADEKTOSMODE15
+
+void Pokitto::blitWord(uint16_t c) {
+ setup_data_16(c);CLR_WR;SET_WR;
+}
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/POKITTO_HW/HWLCD.h Mon May 21 18:03:14 2018 +0000
@@ -0,0 +1,218 @@
+/**************************************************************************/
+/*!
+ @file HWLCD.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 __HWLCD_H__
+#define __HWLCD_H__
+
+#include "mbed.h"
+#include "gpio_api.h"
+#include "pinmap.h"
+
+#define write_command write_command_16
+#define write_data write_data_16
+
+namespace Pokitto {
+
+struct SpriteInfo {
+ const uint8_t* bitmapData;
+ int16_t x;
+ int16_t y;
+ int16_t oldx;
+ int16_t oldy;
+ uint8_t w;
+ uint8_t h;
+ uint16_t palette[4];
+};
+
+extern void setDRAMpoint(uint8_t, uint8_t);
+extern void pumpDRAMdata(uint16_t*, uint16_t);
+extern void initBacklight();
+extern void setBacklight(float);
+extern void lcdFillSurface(uint16_t);
+extern void lcdPixel(int16_t x, int16_t y, uint16_t c);
+extern void setWindow(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2);
+extern void lcdTile(int16_t x0, int16_t y0, int16_t width, int16_t height, uint16_t* gfx);
+extern void lcdRectangle(int16_t x, int16_t y,int16_t x2, int16_t y2, uint16_t color);
+extern void lcdInit();
+extern void lcdSleep();
+extern void lcdWakeUp();
+extern void lcdRefresh(uint8_t *, uint16_t*);
+extern void lcdRefreshAB(uint8_t *, uint16_t*);
+extern void lcdRefreshMode14(uint8_t *, uint16_t*);
+extern void lcdRefreshGB(uint8_t *, uint16_t*);
+extern void lcdRefreshMode1(uint8_t* scrbuf, uint8_t updRectX, uint8_t updRectY, uint8_t updRectW, uint8_t updRectH, uint16_t* paletteptr);
+extern void lcdRefreshMode1Spr(uint8_t * scrbuf, uint8_t screenx, uint8_t screeny, uint8_t screenw, uint8_t screenh, uint16_t* paletteptr, Pokitto::SpriteInfo* sprites, bool drawSpritesOnly);
+extern void lcdRefreshMode2(uint8_t *, uint16_t*);
+extern void lcdRefreshMode3(uint8_t *, uint16_t*);
+extern void lcdRefreshModeGBC(uint8_t *, uint16_t*);
+extern void lcdRefreshMode13(uint8_t *, uint16_t*, uint8_t);
+
+extern void lcdRefreshMode15(uint16_t*, uint8_t*);
+
+
+/** Update LCD from 1-bit tile mode */
+extern void lcdRefreshT1(uint8_t*, uint8_t*, uint8_t*, uint16_t*);
+extern void lcdClear();
+extern void lcdFill(uint16_t);
+/** Blit one word of data*/
+extern void blitWord(uint16_t);
+
+/**************************************************************************/
+/** PINS AND PORTS **/
+/**************************************************************************/
+
+#if POK_BOARDREV == 1
+/** 2-layer board version 1.3 **/
+ #define LCD_CD_PORT 0
+ #define LCD_CD_PIN 2
+ #define LCD_WR_PORT 1
+ #define LCD_WR_PIN 23
+ #define LCD_RD_PORT 1
+ #define LCD_RD_PIN 24
+ #define LCD_RES_PORT 1
+ #define LCD_RES_PIN 28
+#else
+/** 4-layer board version 2.1 **/
+ #define LCD_CD_PORT 0
+ #define LCD_CD_PIN 2
+ #define LCD_WR_PORT 1
+ #define LCD_WR_PIN 12
+ #define LCD_RD_PORT 1
+ #define LCD_RD_PIN 24
+ #define LCD_RES_PORT 1
+ #define LCD_RES_PIN 0
+#endif
+
+/**************************************************************************/
+/** LCD CONTROL MACROS **/
+/**************************************************************************/
+
+#define CLR_RESET LPC_GPIO_PORT->CLR[LCD_RES_PORT] = 1 << LCD_RES_PIN; //RST = (0); // Clear pin
+#define SET_RESET LPC_GPIO_PORT->SET[LCD_RES_PORT] = 1 << LCD_RES_PIN; // RST = (1); // Set pin
+
+#define CLR_CD { LPC_GPIO_PORT->CLR[LCD_CD_PORT] = 1 << LCD_CD_PIN; } // RS = (0); // Clear pin
+#define SET_CD { LPC_GPIO_PORT->SET[LCD_CD_PORT] = 1 << LCD_CD_PIN; }// RS = (1); // Set pin
+
+#define CLR_WR { LPC_GPIO_PORT->CLR[LCD_WR_PORT] = 1 << LCD_WR_PIN;__asm("nop");}//__asm("nop");}//WR = (0); // Clear pin
+#define CLR_WR_SLOW { LPC_GPIO_PORT->CLR[LCD_WR_PORT] = 1 << LCD_WR_PIN;__asm("nop");__asm("nop");}//WR = (0); // Clear pin
+#define SET_WR LPC_GPIO_PORT->SET[LCD_WR_PORT] = 1 << LCD_WR_PIN; //WR = (1); // Set pin
+
+#define CLR_RD LPC_GPIO_PORT->CLR[LCD_RD_PORT] = 1 << LCD_RD_PIN; //RD = (0); // Clear pin
+#define SET_RD LPC_GPIO_PORT->SET[LCD_RD_PORT] = 1 << LCD_RD_PIN; //RD = (1); // Set pin
+
+#define SET_CS //CS tied to ground
+#define CLR_CS
+
+#define CLR_CS_CD_SET_RD_WR {CLR_CD; SET_RD; SET_WR;}
+#define CLR_CS_SET_CD_RD_WR {SET_CD; SET_RD; SET_WR;}
+#define SET_CD_RD_WR {SET_CD; SET_RD; SET_WR;}
+#define SET_WR_CS SET_WR;
+
+#define SET_MASK_P2 LPC_GPIO_PORT->MASK[2] = ~(0x7FFF8); //mask P2_3 ...P2_18
+#define CLR_MASK_P2 LPC_GPIO_PORT->MASK[2] = 0; // all on
+
+
+
+/**************************************************************************/
+/** SETUP GPIO & DATA **/
+/**************************************************************************/
+
+static void setup_gpio()
+{
+ /** control lines **/
+ LPC_GPIO_PORT->DIR[LCD_CD_PORT] |= (1 << LCD_CD_PIN );
+ LPC_GPIO_PORT->DIR[LCD_WR_PORT] |= (1 << LCD_WR_PIN );
+ LPC_GPIO_PORT->DIR[LCD_RD_PORT] |= (1 << LCD_RD_PIN );
+ LPC_GPIO_PORT->DIR[LCD_RES_PORT] |= (1 << LCD_RES_PIN );
+ /** data lines **/
+ LPC_GPIO_PORT->DIR[2] |= (0xFFFF << 3); // P2_3...P2_18 as output
+
+ pin_mode(P2_3,PullNone); // turn off pull-up
+ pin_mode(P2_4,PullNone); // turn off pull-up
+ pin_mode(P2_5,PullNone); // turn off pull-up
+ pin_mode(P2_6,PullNone); // turn off pull-up
+
+ pin_mode(P2_7,PullNone); // turn off pull-up
+ pin_mode(P2_8,PullNone); // turn off pull-up
+ pin_mode(P2_9,PullNone); // turn off pull-up
+ pin_mode(P2_10,PullNone); // turn off pull-up
+
+ pin_mode(P2_11,PullNone); // turn off pull-up
+ pin_mode(P2_12,PullNone); // turn off pull-up
+ pin_mode(P2_13,PullNone); // turn off pull-up
+ pin_mode(P2_14,PullNone); // turn off pull-up
+
+ pin_mode(P2_15,PullNone); // turn off pull-up
+ pin_mode(P2_16,PullNone); // turn off pull-up
+ pin_mode(P2_17,PullNone); // turn off pull-up
+ pin_mode(P2_18,PullNone); // turn off pull-up
+}
+
+
+
+
+#define HI_BYTE(d) (LPC_GPIO->MPIN[1]= (d<<13)) //((d>>8)<<21))
+#define LO_BYTE(d) (LPC_GPIO->MPIN[1]= (d<<21)) //because of mask makes no difference
+
+// Macros to set data bus direction to input/output
+#define LCD_GPIO2DATA_SETINPUT GPIO_GPIO2DIR &= ~LCD_DATA_MASK
+#define LCD_GPIO2DATA_SETOUTPUT GPIO_GPIO2DIR |= LCD_DATA_MASK
+
+
+// Basic Color definitions
+#define COLOR_BLACK (uint16_t)(0x0000)
+#define COLOR_BLUE (uint16_t)(0x001F)
+#define COLOR_RED (uint16_t)(0xF800)
+#define COLOR_GREEN (uint16_t)(0x07E0)
+#define COLOR_CYAN (uint16_t)(0x07FF)
+#define COLOR_MAGENTA (uint16_t)(0xF81F)
+#define COLOR_YELLOW (uint16_t)(0xFFE0)
+#define COLOR_WHITE (uint16_t)(0xFFFF)
+
+// Grayscale Values
+#define COLOR_GRAY_15 (uint16_t)(0x0861) // 15 15 15
+#define COLOR_GRAY_30 (uint16_t)(0x18E3) // 30 30 30
+#define COLOR_GRAY_50 (uint16_t)(0x3186) // 50 50 50
+#define COLOR_GRAY_80 (uint16_t)(0x528A) // 80 80 80
+#define COLOR_GRAY_128 (uint16_t)(0x8410) // 128 128 128
+#define COLOR_GRAY_200 (uint16_t)(0xCE59) // 200 200 200
+#define COLOR_GRAY_225 (uint16_t)(0xE71C) // 225 225 225
+
+
+} // namespace pokitto
+#endif // __HWLCD_H_
+
+