├── LICENSE ├── Makefile ├── README.md ├── data ├── GameBoy.json ├── GameBoyAdvance.json ├── GameBoyColor.json ├── img │ ├── box_gb.png │ ├── box_gba.png │ ├── box_gbc.png │ ├── font.ttf │ ├── icon_abtn.png │ ├── icon_bbtn.png │ ├── icon_bluetooth.png │ ├── icon_cartridge.png │ ├── icon_catalog.png │ ├── icon_dpad.png │ ├── icon_left_arrow_shadow.png │ ├── icon_play.png │ ├── icon_power.png │ ├── icon_refresh.png │ ├── icon_right_arrow_shadow.png │ ├── icon_settings.png │ ├── icon_sync.png │ ├── icon_usbdown.png │ ├── icon_usbup.png │ ├── screen_gb.png │ ├── screen_gba.png │ ├── screen_gbc.png │ └── title.png ├── retroarch │ └── retroarch.cfg └── settings.txt └── source ├── CGameManager.cpp ├── CGameManager.h ├── CImageSceneNode.cpp ├── CImageSceneNode.h ├── CMenuManager.cpp ├── CMenuManager.h ├── COutlineSceneNode.cpp ├── COutlineSceneNode.h ├── CRectSceneNode.cpp ├── CRectSceneNode.h ├── CSceneManager.cpp ├── CSceneManager.h ├── CSceneNode.cpp ├── CSceneNode.h ├── CSettingsManager.cpp ├── CSettingsManager.h ├── CTextSceneNode.cpp ├── CTextSceneNode.h ├── Color.h ├── Vector.h ├── core ├── bt.c ├── bt.h ├── egpio.c ├── egpio.h ├── gba │ ├── gba.c │ ├── gba.h │ ├── gba_cart.c │ ├── gba_cart.h │ ├── gba_eeprom.c │ ├── gba_eeprom.h │ ├── gba_flash.c │ ├── gba_flash.h │ ├── gba_rom.c │ ├── gba_rom.h │ ├── gba_save.c │ ├── gba_save.h │ ├── gba_sram.c │ └── gba_sram.h ├── gbc │ ├── gbc.c │ ├── gbc.h │ ├── gbc_cart.c │ ├── gbc_cart.h │ ├── gbc_mbc1.c │ ├── gbc_mbc1.h │ ├── gbc_mbc2.c │ ├── gbc_mbc2.h │ ├── gbc_mbc3.c │ ├── gbc_mbc3.h │ ├── gbc_mbc5.c │ ├── gbc_mbc5.h │ ├── gbc_rom.c │ └── gbc_rom.h ├── gbx.c ├── gbx.h ├── inp.c ├── inp.h ├── nrf.c ├── nrf.h ├── spi.c ├── spi.h ├── usb.c ├── usb.h ├── vid.c ├── vid.h ├── vkey.c ├── vkey.h ├── wgc.c └── wgc.h └── main.cpp /Makefile: -------------------------------------------------------------------------------- 1 | # Target Name 2 | TARGET=GBConsole 3 | 4 | # Directories 5 | BUILDDIR=build 6 | SOURCEDIR=source 7 | BASEDIR=core 8 | 9 | # Objects to Build 10 | OBJECTSC=$(BUILDDIR)/vid.o $(BUILDDIR)/bt.o $(BUILDDIR)/usb.o $(BUILDDIR)/inp.o $(BUILDDIR)/vkey.o $(BUILDDIR)/wgc.o $(BUILDDIR)/nrf.o $(BUILDDIR)/spi.o $(BUILDDIR)/egpio.o $(BUILDDIR)/gbx.o \ 11 | $(BUILDDIR)/gbc.o $(BUILDDIR)/gbc_cart.o $(BUILDDIR)/gbc_rom.o $(BUILDDIR)/gbc_mbc1.o $(BUILDDIR)/gbc_mbc2.o $(BUILDDIR)/gbc_mbc3.o $(BUILDDIR)/gbc_mbc5.o \ 12 | $(BUILDDIR)/gba.o $(BUILDDIR)/gba_cart.o $(BUILDDIR)/gba_rom.o $(BUILDDIR)/gba_save.o $(BUILDDIR)/gba_sram.o $(BUILDDIR)/gba_flash.o $(BUILDDIR)/gba_eeprom.o 13 | OBJECTSCXX=$(BUILDDIR)/main.o $(BUILDDIR)/CSettingsManager.o $(BUILDDIR)/CSceneManager.o $(BUILDDIR)/CMenuManager.o $(BUILDDIR)/CGameManager.o \ 14 | $(BUILDDIR)/CSceneNode.o $(BUILDDIR)/CRectSceneNode.o $(BUILDDIR)/CImageSceneNode.o $(BUILDDIR)/CTextSceneNode.o $(BUILDDIR)/COutlineSceneNode.o 15 | 16 | # Libraries to Include 17 | SDLCONFIG=`sdl-config --cflags` `sdl-config --libs` 18 | LIBRARIES=-lSDL -lSDL_image -lSDL_gfx -lSDL_ttf -lcrypto -lpthread 19 | 20 | # Compiler 21 | CC=gcc 22 | CXX=g++ 23 | 24 | # Flags 25 | CFLAGS= 26 | CXXFLAGS=$(CFLAGS) 27 | 28 | #=============================================================================== 29 | 30 | $(TARGET): $(OBJECTSC) $(OBJECTSCXX) 31 | $(CXX) -o $@ $^ $(CXXFLAGS) $(SDLCONFIG) $(LIBRARIES) 32 | 33 | $(BUILDDIR)/%.o : $(SOURCEDIR)/$(BASEDIR)/%.c 34 | $(CXX) -I$(SOURCEDIR)/$(BASEDIR) $(CFLAGS) -c -o $@ $< 35 | 36 | $(BUILDDIR)/%.o : $(SOURCEDIR)/$(BASEDIR)/gba/%.c 37 | $(CXX) -I$(SOURCEDIR)/$(BASEDIR) $(CFLAGS) -c -o $@ $< 38 | 39 | $(BUILDDIR)/%.o : $(SOURCEDIR)/$(BASEDIR)/gbc/%.c 40 | $(CXX) -I$(SOURCEDIR)/$(BASEDIR) $(CFLAGS) -c -o $@ $< 41 | 42 | $(BUILDDIR)/%.o : $(SOURCEDIR)/%.cpp 43 | $(CXX) -I$(SOURCEDIR)/$(BASEDIR) $(CXXFLAGS) -c -o $@ $< 44 | 45 | $(shell mkdir -p $(BUILDDIR)) 46 | 47 | clean: 48 | rm -f $(TARGET) 49 | rm -f $(BUILDDIR)/*.o 50 | 51 | .PHONY: FORCE -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GameBoy Console 2 | The GameBoy Console is an emulator that plays physical GameBoy, GameBoy Color and GameBoy Advance cartridges on your TV! The goal of this project is to provide an inexpensive solution for revisiting beloved GameBoy games on the big screen and help preserve cartridge save data. 3 | 4 | 5 | 6 | ## Built Image 7 | If you wish to skip the manual installation process, you can use an already built [GBConsole(v1.1)](http://www.mediafire.com/file/1nio26ro8n0pnzi/GBConsole%2528v1_1%2529.zip/file) image. Refer to [this tutorial](https://www.raspberrypi.org/documentation/installation/installing-images/README.md) for how to install OS images on an SD card. Otherwise, continue with the following instructions to build from scratch. 8 | 9 | ## Software Setup 10 | Please follow these steps to install and setup the GameBoy Console on a Raspberry Pi Zero or Raspberry Pi Zero W (other Raspberry Pi versions not yet supported). You will need the appropriate hardware connected to the GPIO of the Raspberry Pi in order to read cartridges. Refer to the additional documentation [here](https://github.com/pixelcircuits/GBConsole_Documentation) for information on setting up the hardware. 11 | 12 | ### 1. Install and Setup Raspbian Lite 13 | a) The first thing to do is start with a fresh SD card with [Raspbian Lite](https://www.raspberrypi.org/downloads/raspbian/) loaded. Refer to [this tutorial](https://www.raspberrypi.org/documentation/installation/installing-images/README.md) for getting Raspbian up and running (last known working version is 2020-02-13) 14 | 15 | b) Boot up the Raspberry Pi and from the command line run the raspi configuration tool and set the following options 16 | ``` 17 | sudo raspi-config 18 | Network Options -> Wi-Fi (setup) 19 | Interfacing Options -> SPI (enable) 20 | Advanced Options -> Overscan (disable) 21 | Advanced Options -> Memory Split (256) 22 | ``` 23 | c) Reboot the Raspberry Pi and run the following commands to make sure the package manager is up to date 24 | ``` 25 | sudo apt-get update 26 | sudo apt-get dist-upgrade -y 27 | sudo apt-get install -y git 28 | ``` 29 | 30 | ### 2. Install Emulators from RetroPie 31 | a) Run the following commands to download the RetroPie seutp script 32 | ``` 33 | cd /home/pi 34 | git clone --depth=1 https://github.com/RetroPie/RetroPie-Setup.git 35 | ``` 36 | b) Run the RetroPie seutp script and install the following packages (be patient, this will take a while...) 37 | ``` 38 | cd /home/pi/RetroPie-Setup 39 | sudo ./retropie_setup.sh 40 | Manage packages -> Manage core packages -> retroarch -> Install from binary 41 | Manage packages -> Manage main packages -> lr-gambatte -> Install from binary 42 | Manage packages -> Manage main packages -> lr-gpsp -> Install from binary 43 | Manage packages -> Manage main packages -> lr-mgba -> Install from binary 44 | ``` 45 | 46 | ### 3. Build and Install GameBoy Console 47 | a) Run the following commands to install dependencies, download the source code and build the GameBoy Console 48 | ``` 49 | cd /home/pi 50 | sudo apt-get install -y libsdl1.2-dev libsdl-image1.2-dev libsdl-gfx1.2-dev libsdl-ttf2.0-dev libssl-dev 51 | git clone https://github.com/pixelcircuits/GBConsole.git 52 | cd GBConsole 53 | make 54 | ``` 55 | b) To have the application run on boot add the following lines before the exit line to rc.local by running the nano text editor (press ctrl+x to exit and make sure to save) 56 | ``` 57 | sudo nano /etc/rc.local 58 | cd /home/pi/GBConsole 59 | sudo ./GBConsole 60 | ``` 61 | 62 | ### 4. Download Box Art and Screen Captures 63 | a) Run the following commands to download box art and screen captures from the libretro repository used to enhance the UI (be patient, this will take a while...) 64 | ``` 65 | cd /home/pi 66 | mkdir libretro 67 | wget https://github.com/libretro-thumbnails/Nintendo_-_Game_Boy/archive/master.zip 68 | unzip master.zip 69 | mv /home/pi/Nintendo_-_Game_Boy-master /home/pi/libretro/gb 70 | rm master.zip 71 | wget https://github.com/libretro-thumbnails/Nintendo_-_Game_Boy_Color/archive/master.zip 72 | unzip master.zip 73 | mv /home/pi/Nintendo_-_Game_Boy_Color-master /home/pi/libretro/gbc 74 | rm master.zip 75 | wget https://github.com/libretro-thumbnails/Nintendo_-_Game_Boy_Advance/archive/master.zip 76 | unzip master.zip 77 | mv /home/pi/Nintendo_-_Game_Boy_Advance-master /home/pi/libretro/gba 78 | rm master.zip 79 | ``` 80 | 81 | ### 5. Troubleshooting 82 | If you find yourself having issues with any of the emulator cores you can install them from a previously known working binary. Run the following commands for the problem cores. 83 | ##### lr-mgba 84 | ``` 85 | wget https://raw.githubusercontent.com/pixelcircuits/GBConsole_Documentation/master/bin/lr-mgba.zip 86 | unzip lr-mgba.zip -d /home/pi/lr-mgba 87 | sudo rm -r /opt/retropie/libretrocores/lr-mgba 88 | sudo mv /home/pi/lr-mgba /opt/retropie/libretrocores/lr-mgba 89 | rm /home/pi/lr-mgba.zip 90 | ``` 91 | ##### lr-gpsp 92 | ``` 93 | wget https://raw.githubusercontent.com/pixelcircuits/GBConsole_Documentation/master/bin/lr-gpsp.zip 94 | unzip lr-gpsp.zip -d /home/pi/lr-gpsp 95 | sudo rm -r /opt/retropie/libretrocores/lr-gpsp 96 | sudo mv /home/pi/lr-gpsp /opt/retropie/libretrocores/lr-gpsp 97 | rm /home/pi/lr-gpsp.zip 98 | ``` 99 | ##### lr-gambatte 100 | ``` 101 | wget https://raw.githubusercontent.com/pixelcircuits/GBConsole_Documentation/master/bin/lr-gambatte.zip 102 | unzip lr-gambatte.zip -d /home/pi/lr-gambatte 103 | sudo rm -r /opt/retropie/libretrocores/lr-gambatte 104 | sudo mv /home/pi/lr-gambatte /opt/retropie/libretrocores/lr-gambatte 105 | rm /home/pi/lr-gambatte.zip 106 | ``` 107 | 108 | -------------------------------------------------------------------------------- /data/img/box_gb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pixelcircuits/GBConsole/0ea57981cc9833985ea17679838523af08fec5a4/data/img/box_gb.png -------------------------------------------------------------------------------- /data/img/box_gba.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pixelcircuits/GBConsole/0ea57981cc9833985ea17679838523af08fec5a4/data/img/box_gba.png -------------------------------------------------------------------------------- /data/img/box_gbc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pixelcircuits/GBConsole/0ea57981cc9833985ea17679838523af08fec5a4/data/img/box_gbc.png -------------------------------------------------------------------------------- /data/img/font.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pixelcircuits/GBConsole/0ea57981cc9833985ea17679838523af08fec5a4/data/img/font.ttf -------------------------------------------------------------------------------- /data/img/icon_abtn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pixelcircuits/GBConsole/0ea57981cc9833985ea17679838523af08fec5a4/data/img/icon_abtn.png -------------------------------------------------------------------------------- /data/img/icon_bbtn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pixelcircuits/GBConsole/0ea57981cc9833985ea17679838523af08fec5a4/data/img/icon_bbtn.png -------------------------------------------------------------------------------- /data/img/icon_bluetooth.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pixelcircuits/GBConsole/0ea57981cc9833985ea17679838523af08fec5a4/data/img/icon_bluetooth.png -------------------------------------------------------------------------------- /data/img/icon_cartridge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pixelcircuits/GBConsole/0ea57981cc9833985ea17679838523af08fec5a4/data/img/icon_cartridge.png -------------------------------------------------------------------------------- /data/img/icon_catalog.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pixelcircuits/GBConsole/0ea57981cc9833985ea17679838523af08fec5a4/data/img/icon_catalog.png -------------------------------------------------------------------------------- /data/img/icon_dpad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pixelcircuits/GBConsole/0ea57981cc9833985ea17679838523af08fec5a4/data/img/icon_dpad.png -------------------------------------------------------------------------------- /data/img/icon_left_arrow_shadow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pixelcircuits/GBConsole/0ea57981cc9833985ea17679838523af08fec5a4/data/img/icon_left_arrow_shadow.png -------------------------------------------------------------------------------- /data/img/icon_play.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pixelcircuits/GBConsole/0ea57981cc9833985ea17679838523af08fec5a4/data/img/icon_play.png -------------------------------------------------------------------------------- /data/img/icon_power.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pixelcircuits/GBConsole/0ea57981cc9833985ea17679838523af08fec5a4/data/img/icon_power.png -------------------------------------------------------------------------------- /data/img/icon_refresh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pixelcircuits/GBConsole/0ea57981cc9833985ea17679838523af08fec5a4/data/img/icon_refresh.png -------------------------------------------------------------------------------- /data/img/icon_right_arrow_shadow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pixelcircuits/GBConsole/0ea57981cc9833985ea17679838523af08fec5a4/data/img/icon_right_arrow_shadow.png -------------------------------------------------------------------------------- /data/img/icon_settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pixelcircuits/GBConsole/0ea57981cc9833985ea17679838523af08fec5a4/data/img/icon_settings.png -------------------------------------------------------------------------------- /data/img/icon_sync.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pixelcircuits/GBConsole/0ea57981cc9833985ea17679838523af08fec5a4/data/img/icon_sync.png -------------------------------------------------------------------------------- /data/img/icon_usbdown.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pixelcircuits/GBConsole/0ea57981cc9833985ea17679838523af08fec5a4/data/img/icon_usbdown.png -------------------------------------------------------------------------------- /data/img/icon_usbup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pixelcircuits/GBConsole/0ea57981cc9833985ea17679838523af08fec5a4/data/img/icon_usbup.png -------------------------------------------------------------------------------- /data/img/screen_gb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pixelcircuits/GBConsole/0ea57981cc9833985ea17679838523af08fec5a4/data/img/screen_gb.png -------------------------------------------------------------------------------- /data/img/screen_gba.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pixelcircuits/GBConsole/0ea57981cc9833985ea17679838523af08fec5a4/data/img/screen_gba.png -------------------------------------------------------------------------------- /data/img/screen_gbc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pixelcircuits/GBConsole/0ea57981cc9833985ea17679838523af08fec5a4/data/img/screen_gbc.png -------------------------------------------------------------------------------- /data/img/title.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pixelcircuits/GBConsole/0ea57981cc9833985ea17679838523af08fec5a4/data/img/title.png -------------------------------------------------------------------------------- /data/retroarch/retroarch.cfg: -------------------------------------------------------------------------------- 1 | # General Settings 2 | video_fullscreen_x = "1920" 3 | video_fullscreen_y = "1080" 4 | input_autodetect_enable = "false" 5 | 6 | # Keyboard Input 7 | input_player1_a = "x" 8 | input_player1_b = "z" 9 | input_player1_y = "a" 10 | input_player1_x = "s" 11 | input_player1_start = "enter" 12 | input_player1_select = "rshift" 13 | input_player1_l = "q" 14 | input_player1_r = "w" 15 | input_player1_left = "left" 16 | input_player1_right = "right" 17 | input_player1_up = "up" 18 | input_player1_down = "down" 19 | input_enable_hotkey = "home" 20 | input_exit_emulator = "escape" 21 | input_state_slot_increase = "f7" 22 | input_state_slot_decrease = "f6" 23 | input_save_state = "f2" 24 | input_load_state = "f4" 25 | input_toggle_fast_forward = "space" 26 | input_pause_toggle = "p" 27 | input_rewind = "r" 28 | 29 | # Joystick Input 30 | input_player1_a_btn = "0" 31 | input_player1_b_btn = "1" 32 | input_player1_y_btn = "4" 33 | input_player1_x_btn = "3" 34 | input_player1_start_btn = "11" 35 | input_player1_select_btn = "10" 36 | input_player1_l_btn = "6" 37 | input_player1_r_btn = "7" 38 | input_player1_left_btn = "h0left" 39 | input_player1_left_axis = "-0" 40 | input_player1_right_btn = "h0right" 41 | input_player1_right_axis = "+0" 42 | input_player1_up_btn = "h0up" 43 | input_player1_up_axis = "-1" 44 | input_player1_down_btn = "h0down" 45 | input_player1_down_axis = "+1" 46 | input_enable_hotkey_btn = "3" 47 | input_exit_emulator_btn = "11" 48 | input_state_slot_increase_btn = "h0right" 49 | input_state_slot_increase_axis = "+0" 50 | input_state_slot_decrease_btn = "h0left" 51 | input_state_slot_decrease_axis = "-0" 52 | input_save_state_btn = "h0up" 53 | input_save_state_axis = "-1" 54 | input_load_state_btn = "h0down" 55 | input_load_state_axis = "+1" 56 | input_toggle_fast_forward_btn = "0" 57 | input_pause_toggle_btn = "10" 58 | input_rewind = "1" 59 | 60 | #include "/opt/retropie/configs/all/retroarch.cfg" 61 | -------------------------------------------------------------------------------- /data/settings.txt: -------------------------------------------------------------------------------- 1 | system.resolution= auto 2 | game.gb.emulator= auto 3 | game.gba.emulator= auto -------------------------------------------------------------------------------- /source/CGameManager.h: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------------------- 2 | // Title: Game Manager 3 | // Program: GameBoy Console 4 | // Authors: Stephen Monn 5 | //----------------------------------------------------------------------------------------- 6 | #ifndef GAME_MANAGER_H 7 | #define GAME_MANAGER_H 8 | 9 | #define CARTRIDGE_TYPE_NONE 0 10 | #define CARTRIDGE_TYPE_GB 1 11 | #define CARTRIDGE_TYPE_GBC 2 12 | #define CARTRIDGE_TYPE_GBA 3 13 | 14 | #define SYNC_CHECK_SAVE_CHANGED 3 15 | #define SYNC_CHECK_SAVE_UNCHANGED 2 16 | #define SYNC_CHECK_SAVE_NONE 1 17 | #define SYNC_CHECK_NOT_CATALOGUED 0 18 | #define SYNC_CHECK_ERROR_NO_CARTRIDGE -1 19 | #define SYNC_CHECK_ERROR_CARTRIDGE_CHANGED -2 20 | #define SYNC_CHECK_ERROR_UNKNOWN -3 21 | 22 | class CSettingsManager; 23 | 24 | //! Manages Game Data 25 | class CGameManager 26 | { 27 | public: 28 | //! Main Constructor 29 | CGameManager(CSettingsManager* settingsManager); 30 | 31 | //! Destructor 32 | ~CGameManager(); 33 | 34 | //! Loads info of connected cartridge 35 | void loadCartridge(); 36 | 37 | //! Gets the type of cartridge currently connected 38 | char getCartridgeType(); 39 | 40 | //! Gets the name of the cartridge currently connected 41 | const char* getCartridgeName(); 42 | 43 | //! Gets the boxart image of the cartridge currently connected 44 | const char* getCartridgeImgBoxart(); 45 | 46 | //! Gets the snap image of the cartridge currently connected 47 | const char* getCartridgeImgSnap(); 48 | 49 | //! Gets the title image of the cartridge currently connected 50 | const char* getCartridgeImgTitle(); 51 | 52 | //! Gets the catalog index of the cartridge currently connected 53 | int getCartridgeCatalogIndex(); 54 | 55 | //! Checks if the cartridge save data has changed since last sync 56 | int syncCartridgeCheck(); 57 | 58 | //! Estimates the amount of time to sync the currently connected cartridge 59 | int syncCartridgeEstimateTime(bool updateCartSave); 60 | 61 | //! Syncs the currently connected cartridge to the catalog 62 | bool syncCartridge(bool updateCartSave); 63 | 64 | //! Plays the game from the given index in catalog 65 | void playGame(int index); 66 | 67 | //! Gets the size of the game catalog 68 | int getCatalogSize(); 69 | 70 | //! Gets the names of the games in the catalog 71 | const char** getCatalogNames(); 72 | 73 | //! Gets the boxart images of the games in the catalog 74 | const char** getCatalogImgBoxarts(); 75 | 76 | //! Removes the given index from the catalog 77 | void removeGame(int index); 78 | 79 | //! Gets the GameBoy emulator option at the given index 80 | const char* getGBEmulatorOption(int index); 81 | 82 | //! Gets the number of GameBoy emulator options 83 | int getNumGBEmulatorOptions(); 84 | 85 | //! Gets the selected GameBoy emulator option 86 | int getGBEmulator(); 87 | 88 | //! Sets the selected GameBoy emulator option 89 | void setGBEmulator(int index); 90 | 91 | //! Gets the GameBoyAdvance emulator option at the given index 92 | const char* getGBAEmulatorOption(int index); 93 | 94 | //! Gets the number of GameBoyAdvance emulator options 95 | int getNumGBAEmulatorOptions(); 96 | 97 | //! Gets the selected GameBoyAdvance emulator option 98 | int getGBAEmulator(); 99 | 100 | //! Sets the selected GameBoyAdvance emulator option 101 | void setGBAEmulator(int index); 102 | 103 | //! Copies all game data to USB drive 104 | void backupToUSB(); 105 | 106 | //! Copies all game data from USB drive 107 | void restoreFromUSB(); 108 | 109 | private: 110 | CSettingsManager* stmgr; 111 | char** availableEmulatorsGB; 112 | int numEmulatorsGB; 113 | int selectedEmulatorGB; 114 | char** availableEmulatorsGBA; 115 | int numEmulatorsGBA; 116 | int selectedEmulatorGBA; 117 | 118 | char cartType; 119 | int cartCatalogIndex; 120 | char* cartName; 121 | char* cartFilename; 122 | char* cartImgBoxart; 123 | char* cartImgSnap; 124 | char* cartImgTitle; 125 | 126 | int catalogSize; 127 | char** catalogNames; 128 | char** catalogFilenames; 129 | char** catalogImgBoxarts; 130 | 131 | //Util functions 132 | void loadCatalog(); 133 | void sortCatalog(); 134 | int addToCatalog(const char* name, const char* filename, const char* boxartImg); 135 | void findAvailableEmulators(); 136 | void initSettings(); 137 | void updateBIOS(); 138 | }; 139 | 140 | #endif 141 | -------------------------------------------------------------------------------- /source/CImageSceneNode.cpp: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------------------- 2 | // Title: Image Scene Node 3 | // Program: GameBoy Console 4 | // Authors: Stephen Monn 5 | //----------------------------------------------------------------------------------------- 6 | #include "CImageSceneNode.h" 7 | #include 8 | 9 | //! Main Constructor 10 | CImageSceneNode::CImageSceneNode(CSceneManager* smgr) 11 | : CSceneNode(smgr), size(0,0), shadow(false), img(0) 12 | { 13 | } 14 | 15 | //! Destructor 16 | CImageSceneNode::~CImageSceneNode() 17 | { 18 | vid_clearTexture(img); 19 | } 20 | 21 | //! Sets the image to use 22 | void CImageSceneNode::setImage(const char* filename, Vector size, bool smooth) 23 | { 24 | this->size = size; 25 | 26 | //load image 27 | vid_clearTexture(img); 28 | if(filename) img = vid_generateImageTexture(filename, size.X, size.Y, smooth); 29 | else img = 0; 30 | } 31 | 32 | //! Sets the image to use 33 | void CImageSceneNode::setImageLayered(const char* filenameBase, const char* filenameTop, unsigned char topOpaque, Vector size, bool smooth) 34 | { 35 | this->size = size; 36 | 37 | //load image 38 | vid_clearTexture(img); 39 | if(filenameBase && filenameTop) { 40 | img = vid_generateImageTexture(filenameBase, size.X, size.Y, smooth); 41 | vid_compositeImageToTexture(img, filenameTop, topOpaque, smooth); 42 | } else { 43 | img = 0; 44 | } 45 | } 46 | 47 | //! Sets the image to use 48 | void CImageSceneNode::setImageLayered(const char* filename, Color color, unsigned char colorOpaque, Vector size, bool smooth) 49 | { 50 | this->size = size; 51 | 52 | //load image 53 | vid_clearTexture(img); 54 | if(filename) { 55 | img = vid_generateImageTexture(filename, size.X, size.Y, smooth); 56 | vid_compositeColorToTexture(img, color.Red, color.Green, color.Blue, colorOpaque); 57 | } else { 58 | img = 0; 59 | } 60 | } 61 | 62 | //! Sets if image should have a shadow 63 | void CImageSceneNode::setShadow(bool shadow) 64 | { 65 | this->shadow = shadow; 66 | } 67 | 68 | //! Gets the size of the image 69 | Vector CImageSceneNode::getSize() const 70 | { 71 | return size; 72 | } 73 | 74 | //! Gets if image has a shadow 75 | bool CImageSceneNode::getShadow() const 76 | { 77 | return shadow; 78 | } 79 | 80 | //! Draws the node 81 | void CImageSceneNode::render() 82 | { 83 | if(img) vid_drawTexture(img, pos.X, pos.Y); 84 | if(shadow) { 85 | Color falloff1 = Color(30,30,30); 86 | vid_drawBox(pos.X-1, pos.Y-1, size.X+2, 1, falloff1.Red, falloff1.Green, falloff1.Blue, 255); 87 | vid_drawBox(pos.X-1, pos.Y+size.Y, size.X+2, 1, falloff1.Red, falloff1.Green, falloff1.Blue, 255); 88 | vid_drawBox(pos.X-1, pos.Y-1, 1, size.Y+2, falloff1.Red, falloff1.Green, falloff1.Blue, 255); 89 | vid_drawBox(pos.X+size.X, pos.Y-1, 1, size.Y+2, falloff1.Red, falloff1.Green, falloff1.Blue, 255); 90 | 91 | Color falloff2 = Color(40,40,40); 92 | vid_drawBox(pos.X, pos.Y-2, size.X, 1, falloff2.Red, falloff2.Green, falloff2.Blue, 255); 93 | vid_drawBox(pos.X, pos.Y+size.Y+1, size.X, 1, falloff2.Red, falloff2.Green, falloff2.Blue, 255); 94 | vid_drawBox(pos.X-2, pos.Y, 1, size.Y, falloff2.Red, falloff2.Green, falloff2.Blue, 255); 95 | vid_drawBox(pos.X+size.X+1, pos.Y, 1, size.Y, falloff2.Red, falloff2.Green, falloff2.Blue, 255); 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /source/CImageSceneNode.h: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------------------- 2 | // Title: Image Scene Node 3 | // Program: GameBoy Console 4 | // Authors: Stephen Monn 5 | //----------------------------------------------------------------------------------------- 6 | #ifndef IMG_SCENE_NODE_H 7 | #define IMG_SCENE_NODE_H 8 | 9 | #include "CSceneNode.h" 10 | #include "Color.h" 11 | #include "Vector.h" 12 | #include 13 | 14 | //! Node for an image. 15 | class CImageSceneNode : public CSceneNode 16 | { 17 | public: 18 | //! Main Constructor 19 | CImageSceneNode(CSceneManager* smgr); 20 | 21 | //! Destructor 22 | ~CImageSceneNode(); 23 | 24 | //! Sets the image to use 25 | void setImage(const char* filename, Vector size, bool smooth); 26 | 27 | //! Sets the image to use 28 | void setImageLayered(const char* filenameBase, const char* filenameTop, unsigned char topOpaque, Vector size, bool smooth); 29 | 30 | //! Sets the image to use 31 | void setImageLayered(const char* filename, Color color, unsigned char colorOpaque, Vector size, bool smooth); 32 | 33 | //! Sets if image should have a shadow 34 | void setShadow(bool shadow); 35 | 36 | //! Gets the size of the image 37 | Vector getSize() const; 38 | 39 | //! Gets if image has a shadow 40 | bool getShadow() const; 41 | 42 | //! Draws the node 43 | virtual void render(); 44 | 45 | private: 46 | Vector size; 47 | bool shadow; 48 | VidTexture* img; 49 | }; 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /source/CMenuManager.h: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------------------- 2 | // Title: Menu Manager 3 | // Program: GameBoy Console 4 | // Authors: Stephen Monn 5 | //----------------------------------------------------------------------------------------- 6 | #ifndef MENU_MANAGER_H 7 | #define MENU_MANAGER_H 8 | 9 | #define MENU_PAGE_STATE_NONE 0 10 | #define MENU_PAGE_STATE_CARTRIDGE 1 11 | #define MENU_PAGE_STATE_CATALOG 2 12 | #define MENU_PAGE_STATE_SETTINGS 3 13 | 14 | #define MENU_SELECTION_STATE_NONE 0 15 | #define MENU_SELECTION_STATE_CARTRIDGE 1 16 | #define MENU_SELECTION_STATE_CATALOG 2 17 | #define MENU_SELECTION_STATE_SETTINGS 3 18 | #define MENU_SELECTION_STATE_POWER 4 19 | 20 | #define MENU_SELECTION_STATE_PLAY 5 21 | #define MENU_SELECTION_STATE_SYNC 6 22 | #define MENU_SELECTION_STATE_REFRESH 7 23 | 24 | #define MENU_SELECTION_STATE_SETTINGS_RESOLUTION 8 25 | #define MENU_SELECTION_STATE_SETTINGS_GB_EMULATOR 9 26 | #define MENU_SELECTION_STATE_SETTINGS_GBA_EMULATOR 10 27 | #define MENU_SELECTION_STATE_SETTINGS_BACKUP_USB 11 28 | #define MENU_SELECTION_STATE_SETTINGS_RESTORE_USB 12 29 | #define MENU_SELECTION_STATE_SETTINGS_CONNECT_BT 13 30 | 31 | #define MENU_SELECTION_STATE_CAROUSEL 1000 32 | 33 | #define MENU_NEXT_SELECTION_UP 0 34 | #define MENU_NEXT_SELECTION_DOWN 1 35 | #define MENU_NEXT_SELECTION_LEFT 2 36 | #define MENU_NEXT_SELECTION_RIGHT 3 37 | 38 | #define MENU_MAX_CATALOG_CAROUSEL 25 39 | #define MENU_MAX_MODAL_BUTTONS 4 40 | 41 | #define MENU_FRAME_RATE 30 42 | #define MENU_PROGRESS_BAR_UPDATE_MILLIS 500 43 | 44 | class CSettingsManager; 45 | class CSceneManager; 46 | class CSceneNode; 47 | class CRectSceneNode; 48 | class COutlineSceneNode; 49 | class CTextSceneNode; 50 | class CImageSceneNode; 51 | 52 | //! Manages Menu GUI elements 53 | class CMenuManager 54 | { 55 | public: 56 | //! Main Constructor 57 | CMenuManager(CSceneManager* smgr, CSettingsManager* stmgr); 58 | 59 | //! Destructor 60 | ~CMenuManager(); 61 | 62 | //! Loads up scene assets to render pages 63 | void loadSceneAssets(); 64 | 65 | //! Clears all scene related data and vid assets 66 | void clearSceneAssets(); 67 | 68 | //! Switches to a null page with the given optional text 69 | void setPageNull(const char* text); 70 | 71 | //! Switches to the cartridge page with no cartridge 72 | void setPageCartridgeEmpty(bool isLoading); 73 | 74 | //! Switches to the cartridge page 75 | void setPageCartridge(const char* title, const char* boxImg, const char* titleImg, const char* snapImg, bool isGBA, bool canPlay); 76 | 77 | //! Switches to the catalog page 78 | void setPageCatalog(const char** titles, const char** art, int count); 79 | 80 | //! Switches to the settings page 81 | void setPageSettings(bool canBackupUSB); 82 | 83 | //! Switches to the play game page 84 | void setPagePlayGame(); 85 | 86 | //! Displays a modal dialog to the user and returns the selection 87 | int showModal(const char* text1, const char* text2, const char** buttonText, const char** buttonDesc, int numButtons); 88 | 89 | //! Displays the progress bar and starts the async update process 90 | void showProgressBar(const char* text, int estimatedDuration); 91 | 92 | //! Ends the progress bar process and returns menu to previous state 93 | void endProgressBar(); 94 | 95 | //! Shows the given text in the bottom right corner until selection or page is changed 96 | void showLoadingText(const char* text); 97 | 98 | //! Sets the current page selection 99 | void setPageSelection(int selection, bool noAnimation); 100 | 101 | //! Gets the current page 102 | int getPage(); 103 | 104 | //! Gets the current page selection 105 | int getPageSelection(); 106 | 107 | //! Gets the next page selection in the given direction 108 | int getNextSelection(char dir); 109 | 110 | //! Gets the catalog index 111 | int getCatalogIndex(); 112 | 113 | //! Renders the menu 114 | void render(); 115 | 116 | private: 117 | CSceneManager* smgr; 118 | CSettingsManager* stmgr; 119 | long time; 120 | int pageState; 121 | int selectionState; 122 | 123 | int carouselPage; 124 | int carouselIndex; 125 | const char** carouselTitles; 126 | const char** carouselArt; 127 | int carouselCount; 128 | 129 | int screenMargin; 130 | bool smallScreen; 131 | 132 | //General Scene Nodes 133 | CRectSceneNode* background; 134 | CRectSceneNode* shade; 135 | CRectSceneNode* modal; 136 | CTextSceneNode* modalText[2]; 137 | CRectSceneNode* modalButton[MENU_MAX_MODAL_BUTTONS]; 138 | CTextSceneNode* modalButtonText[MENU_MAX_MODAL_BUTTONS]; 139 | CImageSceneNode* title; 140 | CTextSceneNode* subtitle; 141 | CTextSceneNode* infotext; 142 | CImageSceneNode* cartButton; 143 | CImageSceneNode* catButton; 144 | CImageSceneNode* settingsButton; 145 | CImageSceneNode* powerButton; 146 | CRectSceneNode* bottomLine; 147 | CImageSceneNode* dpadIcon; 148 | CTextSceneNode* dpadText; 149 | CImageSceneNode* abtnIcon; 150 | CTextSceneNode* abtnText; 151 | CImageSceneNode* bbtnIcon; 152 | CTextSceneNode* bbtnText; 153 | CTextSceneNode* loadingText; 154 | CRectSceneNode* loadingBar; 155 | COutlineSceneNode* cursor; 156 | 157 | //Cartridge Page Scene Nodes 158 | CTextSceneNode* gameTitle; 159 | CImageSceneNode* artBox; 160 | CImageSceneNode* artTitle; 161 | CImageSceneNode* artSnap; 162 | CImageSceneNode* playButton; 163 | CImageSceneNode* syncButton; 164 | CImageSceneNode* refreshButton; 165 | 166 | //Catalog Page Scene Nodes 167 | CTextSceneNode* catGameTitle; 168 | CImageSceneNode* carousel[MENU_MAX_CATALOG_CAROUSEL]; 169 | CImageSceneNode* carouselNext; 170 | CImageSceneNode* carouselPrevious; 171 | CImageSceneNode* miniCarousel[MENU_MAX_CATALOG_CAROUSEL]; 172 | CImageSceneNode* miniCarouselNext; 173 | CImageSceneNode* miniCarouselPrevious; 174 | CRectSceneNode* carouselCursor; 175 | 176 | //Settings Page Scene Nodes 177 | CTextSceneNode* stResolutionLabel; 178 | CTextSceneNode* stResolutionValue; 179 | CTextSceneNode* stGBEmulatorLabel; 180 | CTextSceneNode* stGBEmulatorValue; 181 | CTextSceneNode* stGBAEmulatorLabel; 182 | CTextSceneNode* stGBAEmulatorValue; 183 | CRectSceneNode* stSpacer; 184 | CImageSceneNode* stBtConnectButton; 185 | CImageSceneNode* stUSBBackupButton; 186 | CImageSceneNode* stUSBRestoreButton; 187 | 188 | //Animation data 189 | CSceneNode* cursorTarget; 190 | int carouselTargetX; 191 | unsigned char* showProgressBarSceneNodeLayers; 192 | bool endProgressBarThread; 193 | 194 | //Util functions 195 | void clearPageSpecificNodes(); 196 | CSceneNode* setCarouselIndex(int index, bool updateCursor, bool* noAnimation); 197 | void positionCarousel(int x); 198 | void updateSettings(); 199 | }; 200 | 201 | #endif 202 | -------------------------------------------------------------------------------- /source/COutlineSceneNode.cpp: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------------------- 2 | // Title: Outline Scene Node 3 | // Program: GameBoy Console 4 | // Authors: Stephen Monn 5 | //----------------------------------------------------------------------------------------- 6 | #include "COutlineSceneNode.h" 7 | #include 8 | 9 | //! Main Constructor 10 | COutlineSceneNode::COutlineSceneNode(CSceneManager* smgr) 11 | : CSceneNode(smgr), size(0,0), color(0,0,0) 12 | { 13 | } 14 | 15 | //! Sets the color of the rect 16 | void COutlineSceneNode::setColor(Color color) 17 | { 18 | this->color = color; 19 | } 20 | 21 | //! Sets the size of the rect 22 | void COutlineSceneNode::setSize(Vector size) 23 | { 24 | this->size = size; 25 | } 26 | 27 | //! Gets the color of the rect 28 | Color COutlineSceneNode::getColor() const 29 | { 30 | return color; 31 | } 32 | 33 | //! Gets the size of the rect 34 | Vector COutlineSceneNode::getSize() const 35 | { 36 | return size; 37 | } 38 | 39 | //! Draws the node 40 | void COutlineSceneNode::render() 41 | { 42 | char width = 4; 43 | 44 | vid_drawBox(pos.X-width, pos.Y-width, size.X+(width*2), width, color.Red, color.Green, color.Blue, 255); 45 | vid_drawBox(pos.X-width, pos.Y+size.Y, size.X+(width*2), width, color.Red, color.Green, color.Blue, 255); 46 | vid_drawBox(pos.X-width, pos.Y-width, width, size.Y+(width*2), color.Red, color.Green, color.Blue, 255); 47 | vid_drawBox(pos.X+size.X, pos.Y-width, width, size.Y+(width*2), color.Red, color.Green, color.Blue, 255); 48 | 49 | vid_drawBox(pos.X-(width-1), pos.Y-(width+1), size.X+((width-1)*2), 1, color.Red, color.Green, color.Blue, 255); 50 | vid_drawBox(pos.X-(width-1), pos.Y+size.Y+width, size.X+((width-1)*2), 1, color.Red, color.Green, color.Blue, 255); 51 | vid_drawBox(pos.X-(width+1), pos.Y-(width-1), 1, size.Y+((width-1)*2), color.Red, color.Green, color.Blue, 255); 52 | vid_drawBox(pos.X+size.X+width, pos.Y-(width-1), 1, size.Y+((width-1)*2), color.Red, color.Green, color.Blue, 255); 53 | } 54 | -------------------------------------------------------------------------------- /source/COutlineSceneNode.h: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------------------- 2 | // Title: Outline Scene Node 3 | // Program: GameBoy Console 4 | // Authors: Stephen Monn 5 | //----------------------------------------------------------------------------------------- 6 | #ifndef OUTLINE_SCENE_NODE_H 7 | #define OUTLINE_SCENE_NODE_H 8 | 9 | #include "CSceneNode.h" 10 | #include "Color.h" 11 | #include "Vector.h" 12 | 13 | //! Node for an outline 14 | class COutlineSceneNode : public CSceneNode 15 | { 16 | public: 17 | //! Main Constructor 18 | COutlineSceneNode(CSceneManager* smgr); 19 | 20 | //! Sets the color of the outline 21 | void setColor(Color color); 22 | 23 | //! Sets the size of the outline 24 | void setSize(Vector size); 25 | 26 | //! Gets the color of the outline 27 | Color getColor() const; 28 | 29 | //! Gets the size of the outline 30 | Vector getSize() const; 31 | 32 | //! Draws the node 33 | virtual void render(); 34 | 35 | private: 36 | Vector size; 37 | Color color; 38 | }; 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /source/CRectSceneNode.cpp: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------------------- 2 | // Title: Rectangle Scene Node 3 | // Program: GameBoy Console 4 | // Authors: Stephen Monn 5 | //----------------------------------------------------------------------------------------- 6 | #include "CRectSceneNode.h" 7 | #include 8 | 9 | //! Main Constructor 10 | CRectSceneNode::CRectSceneNode(CSceneManager* smgr) 11 | : CSceneNode(smgr), size(0,0), color(0,0,0), shadow(false), opacity(255) 12 | { 13 | } 14 | 15 | //! Sets the color of the rect 16 | void CRectSceneNode::setColor(Color color) 17 | { 18 | this->color = color; 19 | } 20 | 21 | //! Sets if rect should have a shadow 22 | void CRectSceneNode::setShadow(bool shadow) 23 | { 24 | this->shadow = shadow; 25 | } 26 | 27 | //! Sets the rect opacity 28 | void CRectSceneNode::setOpacity(unsigned char opacity) 29 | { 30 | this->opacity = opacity; 31 | } 32 | 33 | //! Sets the size of the rect 34 | void CRectSceneNode::setSize(Vector size) 35 | { 36 | this->size = size; 37 | } 38 | 39 | //! Gets the color of the rect 40 | Color CRectSceneNode::getColor() const 41 | { 42 | return color; 43 | } 44 | 45 | //! Gets if rect has a shadow 46 | bool CRectSceneNode::getShadow() const 47 | { 48 | return shadow; 49 | } 50 | 51 | //! Gets the rect opacity 52 | unsigned char CRectSceneNode::getOpacity() const 53 | { 54 | return opacity; 55 | } 56 | 57 | //! Gets the size of the rect 58 | Vector CRectSceneNode::getSize() const 59 | { 60 | return size; 61 | } 62 | 63 | //! Draws the node. 64 | void CRectSceneNode::render() 65 | { 66 | vid_drawBox(pos.X, pos.Y, size.X, size.Y, color.Red, color.Green, color.Blue, opacity); 67 | if(shadow) { 68 | Color falloff1 = Color(30,30,30); 69 | vid_drawBox(pos.X-1, pos.Y-1, size.X+2, 1, falloff1.Red, falloff1.Green, falloff1.Blue, 255); 70 | vid_drawBox(pos.X-1, pos.Y+size.Y, size.X+2, 1, falloff1.Red, falloff1.Green, falloff1.Blue, 255); 71 | vid_drawBox(pos.X-1, pos.Y-1, 1, size.Y+2, falloff1.Red, falloff1.Green, falloff1.Blue, 255); 72 | vid_drawBox(pos.X+size.X, pos.Y-1, 1, size.Y+2, falloff1.Red, falloff1.Green, falloff1.Blue, 255); 73 | 74 | Color falloff2 = Color(40,40,40); 75 | vid_drawBox(pos.X, pos.Y-2, size.X, 1, falloff2.Red, falloff2.Green, falloff2.Blue, 255); 76 | vid_drawBox(pos.X, pos.Y+size.Y+1, size.X, 1, falloff2.Red, falloff2.Green, falloff2.Blue, 255); 77 | vid_drawBox(pos.X-2, pos.Y, 1, size.Y, falloff2.Red, falloff2.Green, falloff2.Blue, 255); 78 | vid_drawBox(pos.X+size.X+1, pos.Y, 1, size.Y, falloff2.Red, falloff2.Green, falloff2.Blue, 255); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /source/CRectSceneNode.h: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------------------- 2 | // Title: Rectangle Scene Node 3 | // Program: GameBoy Console 4 | // Authors: Stephen Monn 5 | //----------------------------------------------------------------------------------------- 6 | #ifndef RECT_SCENE_NODE_H 7 | #define RECT_SCENE_NODE_H 8 | 9 | #include "CSceneNode.h" 10 | #include "Color.h" 11 | #include "Vector.h" 12 | 13 | //! Node for a rectangle 14 | class CRectSceneNode : public CSceneNode 15 | { 16 | public: 17 | //! Main Constructor 18 | CRectSceneNode(CSceneManager* smgr); 19 | 20 | //! Sets the color of the rect 21 | void setColor(Color color); 22 | 23 | //! Sets if rect should have a shadow 24 | void setShadow(bool shadow); 25 | 26 | //! Sets the rect opacity 27 | void setOpacity(unsigned char opacity); 28 | 29 | //! Sets the size of the rect 30 | void setSize(Vector size); 31 | 32 | //! Gets the color of the rect 33 | Color getColor() const; 34 | 35 | //! Gets if rect has a shadow 36 | bool getShadow() const; 37 | 38 | //! Gets the rect opacity 39 | unsigned char getOpacity() const; 40 | 41 | //! Gets the size of the rect 42 | Vector getSize() const; 43 | 44 | //! Draws the node 45 | virtual void render(); 46 | 47 | private: 48 | Vector size; 49 | Color color; 50 | bool shadow; 51 | unsigned char opacity; 52 | }; 53 | 54 | #endif 55 | -------------------------------------------------------------------------------- /source/CSceneManager.cpp: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------------------- 2 | // Title: Scene Manager 3 | // Program: GameBoy Console 4 | // Authors: Stephen Monn 5 | //----------------------------------------------------------------------------------------- 6 | #include "CSceneManager.h" 7 | #include "CRectSceneNode.h" 8 | #include "COutlineSceneNode.h" 9 | #include "CImageSceneNode.h" 10 | #include "CTextSceneNode.h" 11 | #include 12 | 13 | //! Main constructor 14 | CSceneManager::CSceneManager() 15 | : nodeListSize(0) 16 | { 17 | } 18 | 19 | //! Destructor 20 | CSceneManager::~CSceneManager() 21 | { 22 | //clear memory 23 | clearScene(); 24 | } 25 | 26 | //! Adds a rectangle node to the scene 27 | CRectSceneNode* CSceneManager::addRectSceneNode(Color color, Vector size, bool shadow) 28 | { 29 | //create the node 30 | CRectSceneNode* node = new CRectSceneNode(this); 31 | node->setPosition(Vector(0,0)); 32 | node->setColor(color); 33 | node->setSize(size); 34 | node->setShadow(shadow); 35 | 36 | //add node to the list 37 | if(nodeListSize+1 < MAX_NUM_NODES) 38 | { 39 | nodeList[nodeListSize] = node; 40 | nodeListSize++; 41 | } 42 | 43 | //return 44 | return node; 45 | } 46 | 47 | //! Adds an outline node to the scene 48 | COutlineSceneNode* CSceneManager::addOutlineSceneNode(Color color, Vector size) 49 | { 50 | //create the node 51 | COutlineSceneNode* node = new COutlineSceneNode(this); 52 | node->setPosition(Vector(0,0)); 53 | node->setColor(color); 54 | node->setSize(size); 55 | 56 | //add node to the list 57 | if(nodeListSize+1 < MAX_NUM_NODES) 58 | { 59 | nodeList[nodeListSize] = node; 60 | nodeListSize++; 61 | } 62 | 63 | //return 64 | return node; 65 | } 66 | 67 | //! Adds an image node to the scene 68 | CImageSceneNode* CSceneManager::addImageSceneNode(const char* filename, Vector size, bool shadow, bool smooth) 69 | { 70 | //create the node 71 | CImageSceneNode* node = new CImageSceneNode(this); 72 | node->setPosition(Vector(0,0)); 73 | node->setImage(filename, size, smooth); 74 | node->setShadow(shadow); 75 | 76 | //add node to the list 77 | if(nodeListSize+1 < MAX_NUM_NODES) 78 | { 79 | nodeList[nodeListSize] = node; 80 | nodeListSize++; 81 | } 82 | 83 | //return 84 | return node; 85 | } 86 | 87 | //! Adds a text node to the scene 88 | CTextSceneNode* CSceneManager::addTextSceneNode(const char* text, Color textColor, Color backgroundColor, int fontSize, bool bold) 89 | { 90 | //create the node 91 | CTextSceneNode* node = new CTextSceneNode(this); 92 | node->setPosition(Vector(0,0)); 93 | node->setText(text, textColor, backgroundColor, fontSize, bold); 94 | 95 | //add node to the list 96 | if(nodeListSize+1 < MAX_NUM_NODES) 97 | { 98 | nodeList[nodeListSize] = node; 99 | nodeListSize++; 100 | } 101 | 102 | //return 103 | return node; 104 | } 105 | 106 | //! Gets a list of nodes in the current scene 107 | CSceneNode** CSceneManager::getSceneNodes() 108 | { 109 | return nodeList; 110 | } 111 | 112 | //! Gets the number of nodes in the current scene 113 | unsigned int CSceneManager::getSceneNodeCount() 114 | { 115 | return nodeListSize; 116 | } 117 | 118 | //! Removes a node from the scene 119 | void CSceneManager::removeNode(CSceneNode* node) 120 | { 121 | for(unsigned int i=0; i=0; i--){ 147 | nodeList[i]->remove(); 148 | } 149 | 150 | //adjust the size 151 | nodeListSize = 0; 152 | } 153 | 154 | //! Draws the scene 155 | void CSceneManager::drawAll() 156 | { 157 | //find max layer 158 | unsigned char maxLayer = 0; 159 | for(int i=0; igetLayer() > maxLayer) maxLayer = nodeList[i]->getLayer(); 161 | } 162 | 163 | //draw each node in layer order 164 | for(int layer=1; layergetLayer() == layer) nodeList[i]->render(); 167 | 168 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 169 | //vid_shadeBox(0, 335, 1920, 550, 0,0,0); 170 | 171 | //set render box? 172 | //draw shade once 173 | //speed up rendering by combining textures? 174 | 175 | //push to screen 176 | vid_flush(); 177 | } 178 | -------------------------------------------------------------------------------- /source/CSceneManager.h: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------------------- 2 | // Title: Scene Manager 3 | // Program: GameBoy Console 4 | // Authors: Stephen Monn 5 | //----------------------------------------------------------------------------------------- 6 | #ifndef SCENE_MANAGER_H 7 | #define SCENE_MANAGER_H 8 | 9 | #include "Color.h" 10 | #include "Vector.h" 11 | 12 | #define MAX_NUM_NODES 512 13 | 14 | #define LAYER_HIDDEN 0 15 | 16 | class CSceneNode; 17 | class CRectSceneNode; 18 | class COutlineSceneNode; 19 | class CImageSceneNode; 20 | class CTextSceneNode; 21 | 22 | //! Class that handles the organization of a scene 23 | class CSceneManager 24 | { 25 | public: 26 | //! Main constructor 27 | CSceneManager(); 28 | 29 | //! Destructor 30 | ~CSceneManager(); 31 | 32 | //! Adds a rectangle node to the scene 33 | CRectSceneNode* addRectSceneNode(Color color, Vector size, bool shadow); 34 | 35 | //! Adds an outline node to the scene 36 | COutlineSceneNode* addOutlineSceneNode(Color color, Vector size); 37 | 38 | //! Adds an image node to the scene 39 | CImageSceneNode* addImageSceneNode(const char* filename, Vector size, bool shadow, bool smooth); 40 | 41 | //! Adds a text node to the scene 42 | CTextSceneNode* addTextSceneNode(const char* text, Color textColor, Color backgroundColor, int fontSize, bool bold); 43 | 44 | //! Gets a list of nodes in the current scene 45 | CSceneNode** getSceneNodes(); 46 | 47 | //! Gets the number of nodes in the current scene 48 | unsigned int getSceneNodeCount(); 49 | 50 | //! Removes a node from the scene 51 | void removeNode(CSceneNode* node); 52 | 53 | //! Clears all nodes from the scene 54 | void clearScene(); 55 | 56 | //! Draws the scene 57 | void drawAll(); 58 | 59 | private: 60 | CSceneNode* nodeList[MAX_NUM_NODES]; 61 | unsigned int nodeListSize; 62 | }; 63 | 64 | #endif 65 | -------------------------------------------------------------------------------- /source/CSceneNode.cpp: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------------------- 2 | // Title: SceneNode 3 | // Program: GameBoy Console 4 | // Authors: Stephen Monn 5 | //----------------------------------------------------------------------------------------- 6 | #include "CSceneNode.h" 7 | #include "CSceneManager.h" 8 | 9 | //! Main Constructor 10 | CSceneNode::CSceneNode(CSceneManager* smgr) 11 | : pos(0,0), layer(LAYER_HIDDEN), navPath(-1), navAText(0), navBText(0), sceneManager(smgr) 12 | { 13 | } 14 | 15 | //! Destructor 16 | CSceneNode::~CSceneNode() 17 | { 18 | remove(); 19 | } 20 | 21 | //! Draws the node 22 | void CSceneNode::render() 23 | { 24 | } 25 | 26 | //! Removes the node from its assigned scene manager 27 | void CSceneNode::remove() 28 | { 29 | sceneManager->removeNode(this); 30 | } 31 | 32 | //! Sets the position of the node 33 | void CSceneNode::setPosition(Vector pos) 34 | { 35 | this->pos = pos; 36 | } 37 | 38 | //! Sets the rendering layer of the node 39 | void CSceneNode::setLayer(unsigned char layer) 40 | { 41 | this->layer = layer; 42 | } 43 | 44 | //! Sets the navigation flag for the node 45 | void CSceneNode::setNavPath(int navPath) 46 | { 47 | this->navPath = navPath; 48 | } 49 | 50 | //! Sets the navigation a text for the node 51 | void CSceneNode::setNavAText(const char* text) 52 | { 53 | this->navAText = text; 54 | } 55 | 56 | //! Sets the navigation b text for the node 57 | void CSceneNode::setNavBText(const char* text) 58 | { 59 | this->navBText = text; 60 | } 61 | 62 | //! Gets the position of the node 63 | Vector CSceneNode::getPosition() const 64 | { 65 | return pos; 66 | } 67 | 68 | //! Gets the size of the node 69 | Vector CSceneNode::getSize() const 70 | { 71 | return Vector(0,0); 72 | } 73 | 74 | //! Gets the rendering layer of the node 75 | unsigned char CSceneNode::getLayer() const 76 | { 77 | return layer; 78 | } 79 | 80 | //! Gets the navigation flag for the node 81 | int CSceneNode::getNavPath() const 82 | { 83 | return navPath; 84 | } 85 | 86 | //! Gets the navigation a text for the node 87 | const char* CSceneNode::getNavAText() const 88 | { 89 | return navAText; 90 | } 91 | 92 | //! Gets the navigation b text for the node 93 | const char* CSceneNode::getNavBText() const 94 | { 95 | return navBText; 96 | } 97 | -------------------------------------------------------------------------------- /source/CSceneNode.h: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------------------- 2 | // Title: SceneNode 3 | // Program: GameBoy Console 4 | // Authors: Stephen Monn 5 | //----------------------------------------------------------------------------------------- 6 | #ifndef SCENE_NODE_H 7 | #define SCENE_NODE_H 8 | 9 | #include "Vector.h" 10 | 11 | class CSceneManager; 12 | 13 | //! Interface for all nodes in a scene 14 | class CSceneNode 15 | { 16 | public: 17 | //! Main Constructor 18 | CSceneNode(CSceneManager* smgr); 19 | 20 | //! Destructor 21 | virtual ~CSceneNode(); 22 | 23 | //! Draws the node 24 | virtual void render(); 25 | 26 | //! Removes the node from its assigned scene manager 27 | virtual void remove(); 28 | 29 | //! Sets the position of the node 30 | virtual void setPosition(Vector pos); 31 | 32 | //! Sets the rendering layer of the node 33 | virtual void setLayer(unsigned char layer); 34 | 35 | //! Sets the navigation flag for the node 36 | virtual void setNavPath(int navPath); 37 | 38 | //! Sets the navigation a text for the node 39 | virtual void setNavAText(const char* text); 40 | 41 | //! Sets the navigation b text for the node 42 | virtual void setNavBText(const char* text); 43 | 44 | //! Gets the position of the node 45 | virtual Vector getPosition() const; 46 | 47 | //! Gets the size of the node 48 | virtual Vector getSize() const; 49 | 50 | //! Gets the rendering layer of the node 51 | virtual unsigned char getLayer() const; 52 | 53 | //! Gets the navigation flag for the node 54 | virtual int getNavPath() const; 55 | 56 | //! Gets the navigation a text for the node 57 | virtual const char* getNavAText() const; 58 | 59 | //! Gets the navigation b text for the node 60 | virtual const char* getNavBText() const; 61 | 62 | protected: 63 | Vector pos; 64 | unsigned char layer; 65 | int navPath; 66 | const char* navAText; 67 | const char* navBText; 68 | CSceneManager* sceneManager; 69 | }; 70 | 71 | #endif 72 | -------------------------------------------------------------------------------- /source/CSettingsManager.cpp: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------------------- 2 | // Title: Game Manager 3 | // Program: GameBoy Console 4 | // Authors: Stephen Monn 5 | //----------------------------------------------------------------------------------------- 6 | #include "CSettingsManager.h" 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | //data constants 14 | static const char* stm_settingsFile = "data/settings.txt"; 15 | 16 | //system wide settings 17 | static const char* stm_resolutionSetting = "system.resolution"; 18 | static const char* const stm_resolutionOptions[] = { "auto", "1920x1080", "1280x720", 0 }; 19 | 20 | //! Main constructor 21 | CSettingsManager::CSettingsManager() 22 | { 23 | std::ifstream in(stm_settingsFile); 24 | std::ostringstream ss; 25 | ss << in.rdbuf(); 26 | fileData = ss.str(); 27 | in.close(); 28 | 29 | //init system settings 30 | char resolution[128]; 31 | this->getPropertyString(stm_resolutionSetting, stm_resolutionOptions[0], resolution, 128); 32 | selectedResolution = 0; 33 | for(int i=0; stm_resolutionOptions[i]; i++) if(strcmp(stm_resolutionOptions[i], resolution)==0) { selectedResolution = i; break; } 34 | this->setResolution(selectedResolution); 35 | } 36 | 37 | //! Destructor 38 | CSettingsManager::~CSettingsManager() 39 | { 40 | } 41 | 42 | //! Gets the string value for the given property 43 | void CSettingsManager::getPropertyString(const char* property, const char* defVal, char* out, int max) 44 | { 45 | if(defVal) std::strcpy(out, defVal); 46 | else for(int i=0; i 0) { 49 | int propertySize = 0; 50 | while(property[propertySize]) propertySize++; 51 | 52 | //search 53 | for(unsigned int i=0; i-1 && out[j] == ' '; j--) out[j] = 0; 102 | 103 | break; 104 | } 105 | } 106 | } 107 | } 108 | } 109 | 110 | //! Gets the integer value for the given property 111 | signed int CSettingsManager::getPropertyInteger(const char* property, signed int defVal) 112 | { 113 | if(fileData.size() > 0) { 114 | char val[32]; 115 | getPropertyString(property, "null", val, 32); 116 | 117 | //check if null 118 | if(strcmp(val, "null")==0) return defVal; 119 | 120 | //get leading sign 121 | int start = 0; 122 | signed int sign = 1; 123 | if(val[0] == '-') { start = 1; sign = -1; } 124 | if(val[0] == '+') { start = 1; } 125 | 126 | //check if valid integer 127 | for(int i=start; i<32; i++) { 128 | if(val[i]==0) break; 129 | if(val[i] < 48 || val[i] > 57) return defVal; 130 | } 131 | 132 | //get integer 133 | signed int value = 0; 134 | for(int i=start; val[i] != 0; i++) value = (value*10) + (val[i]-48); 135 | return value*sign; 136 | } 137 | return defVal; 138 | } 139 | 140 | //! Sets the string value for the given property 141 | void CSettingsManager::setPropertyString(const char* property, const char* value) 142 | { 143 | int propertySize = 0; 144 | while(property[propertySize]) propertySize++; 145 | signed int start = -1; 146 | signed int end = -1; 147 | 148 | //search 149 | if(fileData.size() > 0) { 150 | for(unsigned int i=0; i -1 && end > -1) { 199 | 200 | //update setting line 201 | fileData = fileData.substr(0,start) + ' ' + value + fileData.substr(end,fileData.size()); 202 | } else { 203 | 204 | //add setting line 205 | if(fileData.size() > 0) fileData += "\r\n"; 206 | fileData = fileData + property + "= " + value; 207 | } 208 | saveFile(); 209 | } 210 | 211 | //! Sets the integer value for the given property 212 | void CSettingsManager::setPropertyInteger(const char* property, signed int value) 213 | { 214 | if(fileData.size() > 0) { 215 | char val[32]; 216 | for(int i=0; i<32; i++) val[i] = 0; 217 | 218 | std::stringstream ss; int x = 23; 219 | ss << value; 220 | std::string str = ss.str(); 221 | for(int i=0; i -1 && index < numOptions) return stm_resolutionOptions[index]; 232 | return 0; 233 | } 234 | 235 | //! Gets the number of resolution options 236 | int CSettingsManager::getNumResolutionOptions() 237 | { 238 | int numOptions = 0; 239 | for(int i=0; stm_resolutionOptions[i]; i++) numOptions++; 240 | return numOptions; 241 | } 242 | 243 | //! Gets the set resolution 244 | int CSettingsManager::getResolution() 245 | { 246 | return selectedResolution; 247 | } 248 | 249 | //! Sets the system resolution 250 | void CSettingsManager::setResolution(int index) 251 | { 252 | int numOptions = getNumResolutionOptions(); 253 | if(index < 0) index = numOptions-1; 254 | if(index > numOptions-1) index = 0; 255 | selectedResolution = index; 256 | 257 | if(selectedResolution == 0) system("sudo raspi-config nonint do_resolution 0 0"); 258 | else if(selectedResolution == 1) system("sudo raspi-config nonint do_resolution 1 16"); 259 | else if(selectedResolution == 2) system("sudo raspi-config nonint do_resolution 1 4"); 260 | this->setPropertyString(stm_resolutionSetting, stm_resolutionOptions[selectedResolution]); 261 | } 262 | 263 | //! Saves the settings file 264 | void CSettingsManager::saveFile() 265 | { 266 | if(fileData.size() > 0) { 267 | std::ofstream out(stm_settingsFile); 268 | out << fileData; 269 | out.close(); 270 | } 271 | } 272 | -------------------------------------------------------------------------------- /source/CSettingsManager.h: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------------------- 2 | // Title: Settings Manager 3 | // Program: GameBoy Console 4 | // Authors: Stephen Monn 5 | //----------------------------------------------------------------------------------------- 6 | #ifndef SETTINGS_MANAGER_H 7 | #define SETTINGS_MANAGER_H 8 | #include 9 | 10 | //! Manages Settings Data 11 | class CSettingsManager 12 | { 13 | public: 14 | //! Main Constructor 15 | CSettingsManager(); 16 | 17 | //! Destructor 18 | ~CSettingsManager(); 19 | 20 | //! Gets the string value for the given property 21 | void getPropertyString(const char* property, const char* defVal, char* out, int max); 22 | 23 | //! Gets the integer value for the given property 24 | signed int getPropertyInteger(const char* property, signed int defVal); 25 | 26 | //! Sets the string value for the given property 27 | void setPropertyString(const char* property, const char* value); 28 | 29 | //! Sets the integer value for the given property 30 | void setPropertyInteger(const char* property, signed int value); 31 | 32 | //! Gets the resolution option at the given index 33 | const char* getResolutionOption(int index); 34 | 35 | //! Gets the number of resolution options 36 | int getNumResolutionOptions(); 37 | 38 | //! Gets the set resolution 39 | int getResolution(); 40 | 41 | //! Sets the system resolution 42 | void setResolution(int index); 43 | 44 | private: 45 | std::string fileData; 46 | int selectedResolution; 47 | 48 | //Util functions 49 | void saveFile(); 50 | }; 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /source/CTextSceneNode.cpp: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------------------- 2 | // Title: Text Scene Node 3 | // Program: GameBoy Console 4 | // Authors: Stephen Monn 5 | //----------------------------------------------------------------------------------------- 6 | #include "CTextSceneNode.h" 7 | #include 8 | #include 9 | 10 | //! Main Constructor 11 | CTextSceneNode::CTextSceneNode(CSceneManager* smgr) 12 | : CSceneNode(smgr), img(0), txt(0), shadow(false) 13 | { 14 | } 15 | 16 | //! Destructor 17 | CTextSceneNode::~CTextSceneNode() 18 | { 19 | delete[] txt; 20 | vid_clearTexture(img); 21 | } 22 | 23 | //! Sets the image to use 24 | void CTextSceneNode::setText(const char* text, Color textColor, Color backgroundColor, int fontSize, bool bold) 25 | { 26 | if(txt==0 || text==0 || strcmp(text, txt)!=0) { 27 | 28 | //clear old data 29 | vid_clearTexture(img); 30 | img = 0; 31 | delete[] txt; 32 | txt = 0; 33 | 34 | //load image for text 35 | if(text) { 36 | txt = new char[strlen(text)+1]; 37 | strcpy(txt, text); 38 | img = vid_generateTextTexture(text, textColor.Red, textColor.Green, textColor.Blue, 39 | backgroundColor.Red, backgroundColor.Green, backgroundColor.Blue, fontSize, bold); 40 | } 41 | } 42 | } 43 | 44 | //! Sets if image should have a shadow 45 | void CTextSceneNode::setShadow(bool shadow) 46 | { 47 | this->shadow = shadow; 48 | } 49 | 50 | //! Gets the text 51 | const char* CTextSceneNode::getText() const 52 | { 53 | return txt; 54 | } 55 | 56 | //! Gets the size of the image 57 | Vector CTextSceneNode::getSize() const 58 | { 59 | if(img) return Vector(vid_getTextureWidth(img), vid_getTextureHeight(img)); 60 | return Vector(0,0); 61 | } 62 | 63 | //! Gets if image has a shadow 64 | bool CTextSceneNode::getShadow() const 65 | { 66 | return shadow; 67 | } 68 | 69 | //! Draws the node 70 | void CTextSceneNode::render() 71 | { 72 | if(img) vid_drawTexture(img, pos.X, pos.Y); 73 | if(shadow) { 74 | Vector size = getSize(); 75 | Color falloff1 = Color(30,30,30); 76 | vid_drawBox(pos.X-1, pos.Y-1, size.X+2, 1, falloff1.Red, falloff1.Green, falloff1.Blue, 255); 77 | vid_drawBox(pos.X-1, pos.Y+size.Y, size.X+2, 1, falloff1.Red, falloff1.Green, falloff1.Blue, 255); 78 | vid_drawBox(pos.X-1, pos.Y-1, 1, size.Y+2, falloff1.Red, falloff1.Green, falloff1.Blue, 255); 79 | vid_drawBox(pos.X+size.X, pos.Y-1, 1, size.Y+2, falloff1.Red, falloff1.Green, falloff1.Blue, 255); 80 | 81 | Color falloff2 = Color(40,40,40); 82 | vid_drawBox(pos.X, pos.Y-2, size.X, 1, falloff2.Red, falloff2.Green, falloff2.Blue, 255); 83 | vid_drawBox(pos.X, pos.Y+size.Y+1, size.X, 1, falloff2.Red, falloff2.Green, falloff2.Blue, 255); 84 | vid_drawBox(pos.X-2, pos.Y, 1, size.Y, falloff2.Red, falloff2.Green, falloff2.Blue, 255); 85 | vid_drawBox(pos.X+size.X+1, pos.Y, 1, size.Y, falloff2.Red, falloff2.Green, falloff2.Blue, 255); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /source/CTextSceneNode.h: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------------------- 2 | // Title: Text Scene Node 3 | // Program: GameBoy Console 4 | // Authors: Stephen Monn 5 | //----------------------------------------------------------------------------------------- 6 | #ifndef TEXT_SCENE_NODE_H 7 | #define TEXT_SCENE_NODE_H 8 | 9 | #include "CSceneNode.h" 10 | #include "Color.h" 11 | #include "Vector.h" 12 | #include 13 | 14 | //! Node for a text 15 | class CTextSceneNode : public CSceneNode 16 | { 17 | public: 18 | //! Main Constructor 19 | CTextSceneNode(CSceneManager* smgr); 20 | 21 | //! Destructor 22 | ~CTextSceneNode(); 23 | 24 | //! Sets the text to use 25 | void setText(const char* text, Color textColor, Color backgroundColor, int fontSize, bool bold); 26 | 27 | //! Sets if image should have a shadow 28 | void setShadow(bool shadow); 29 | 30 | //! Gets the text 31 | const char* getText() const; 32 | 33 | //! Gets the size of the text 34 | Vector getSize() const; 35 | 36 | //! Gets if image has a shadow 37 | bool getShadow() const; 38 | 39 | //! Draws the node. 40 | virtual void render(); 41 | 42 | private: 43 | VidTexture* img; 44 | char* txt; 45 | bool shadow; 46 | }; 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /source/Color.h: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------------------- 2 | // Title: Color 3 | // Program: GameBoy Console 4 | // Authors: Stephen Monn 5 | //----------------------------------------------------------------------------------------- 6 | #ifndef COLOR_H 7 | #define COLOR_H 8 | 9 | // Base Colors 10 | #define COLOR_GRAY Color(80,80,80) 11 | #define COLOR_DARKGRAY Color(45,45,45) 12 | #define COLOR_LIGHTGRAY Color(221,221,221) 13 | #define COLOR_WHITE Color(245,245,245) 14 | #define COLOR_OFFWHITE Color(230,230,230) 15 | #define COLOR_LIGHTBLUE Color(109,186,241) 16 | #define COLOR_LIGHTORANGE Color(243,166,111) 17 | #define COLOR_ACCENT Color(83,183,209) 18 | 19 | //! Class that handles color math 20 | class Color 21 | { 22 | public: 23 | //! Default constructor 24 | Color() : Red(0), Green(0), Blue(0) {} 25 | 26 | //! Main constructor 27 | Color(unsigned char r, unsigned char g, unsigned char b) : Red(r), Green(g), Blue(b) {} 28 | 29 | //! Copy constructor 30 | Color(const Color& other) : Red(other.Red), Green(other.Green), Blue(other.Blue) {} 31 | 32 | //! Lerp (linear interpolation) 33 | void lerp(const Color& other, unsigned char per) { 34 | if(Red > other.Red) { 35 | unsigned int rDiff = (unsigned int)Red-(unsigned int)other.Red; 36 | Red = (unsigned int)other.Red + (rDiff*(unsigned int)per)/100; 37 | } else { 38 | unsigned int rDiff = (unsigned int)other.Red-(unsigned int)Red; 39 | Red = (unsigned int)Red + (rDiff*(unsigned int)per)/100; 40 | } 41 | if(Green > other.Green) { 42 | unsigned int rDiff = (unsigned int)Green-(unsigned int)other.Green; 43 | Green = (unsigned int)other.Green + (rDiff*(unsigned int)per)/100; 44 | } else { 45 | unsigned int rDiff = (unsigned int)other.Green-(unsigned int)Green; 46 | Green = (unsigned int)Green + (rDiff*(unsigned int)per)/100; 47 | } 48 | if(Blue > other.Blue) { 49 | unsigned int rDiff = (unsigned int)Blue-(unsigned int)other.Blue; 50 | Blue = (unsigned int)other.Blue + (rDiff*(unsigned int)per)/100; 51 | } else { 52 | unsigned int rDiff = (unsigned int)other.Blue-(unsigned int)Blue; 53 | Blue = (unsigned int)Blue + (rDiff*(unsigned int)per)/100; 54 | } 55 | } 56 | 57 | //! Operators 58 | Color& operator=(const Color& other) { 59 | Red = other.Red; Green = other.Green; Blue = other.Blue; return *this; 60 | } 61 | Color operator+(const Color& other) const { 62 | signed short r = Red + other.Red; if(r > 255) r = 255; 63 | signed short g = Green + other.Green; if(g > 255) g = 255; 64 | signed short b = Blue + other.Blue; if(b > 255) b = 255; 65 | return Color(r, g, b); 66 | } 67 | Color& operator+=(const Color& other) { 68 | signed short r = Red + other.Red; if(r > 255) r = 255; 69 | signed short g = Green + other.Green; if(g > 255) g = 255; 70 | signed short b = Blue + other.Blue; if(b > 255) b = 255; 71 | Red=r; Green=g; Blue=b; return *this; 72 | } 73 | Color operator-(const Color& other) const { 74 | signed short r = Red - other.Red; if(r < 0) r = 0; 75 | signed short g = Green - other.Green; if(g < 0) g = 0; 76 | signed short b = Blue - other.Blue; if(b < 0) b = 0; 77 | return Color(r, g, b); 78 | } 79 | Color& operator-=(const Color& other) { 80 | signed short r = Red - other.Red; if(r < 0) r = 0; 81 | signed short g = Green - other.Green; if(g < 0) g = 0; 82 | signed short b = Blue - other.Blue; if(b < 0) b = 0; 83 | Red=r; Green=g; Blue=b; return *this; 84 | } 85 | Color operator*(const Color& other) const { 86 | unsigned short r = Red * other.Red; if(r > 255) r = 255; 87 | unsigned short g = Green * other.Green; if(g > 255) g = 255; 88 | unsigned short b = Blue * other.Blue; if(b > 255) b = 255; 89 | return Color(r, g, b); 90 | } 91 | Color& operator*=(const Color& other) { 92 | unsigned short r = Red * other.Red; if(r > 255) r = 255; 93 | unsigned short g = Green * other.Green; if(g > 255) g = 255; 94 | unsigned short b = Blue * other.Blue; if(b > 255) b = 255; 95 | Red=r; Green=g; Blue=b; return *this; 96 | } 97 | Color operator*(const int v) const { 98 | int v2 = v; 99 | if(v2 > 255) v2 = 255; 100 | unsigned short r = Red * v2; if(r > 255) r = 255; 101 | unsigned short g = Green * v2; if(g > 255) g = 255; 102 | unsigned short b = Blue * v2; if(b > 255) b = 255; 103 | return Color(r, g, b); 104 | } 105 | Color& operator*=(const int v) { 106 | int v2 = v; 107 | if(v2 > 255) v2 = 255; 108 | unsigned short r = Red * v2; if(r > 255) r = 255; 109 | unsigned short g = Green * v2; if(g > 255) g = 255; 110 | unsigned short b = Blue * v2; if(b > 255) b = 255; 111 | Red=r; Green=g; Blue=b; return *this; 112 | } 113 | Color operator/(const Color& other) const { 114 | return Color(Red / other.Red, Green / other.Green, Blue / other.Blue); 115 | } 116 | Color& operator/=(const Color& other) { 117 | Red/=other.Red; Green/=other.Green; Blue/=other.Blue; return *this; 118 | } 119 | Color operator/(const int v) const { 120 | return Color(Red / v, Green / v, Blue / v); 121 | } 122 | Color& operator/=(const int v) { 123 | Red/=v; Green/=v; Blue/=v; return *this; 124 | } 125 | bool operator==(const Color& other) const { 126 | return Red==other.Red && Green==other.Green && Blue==other.Blue; 127 | } 128 | bool operator!=(const Color& other) const { 129 | return !(Red==other.Red && Green==other.Green && Blue==other.Blue); 130 | } 131 | 132 | //! Red value 133 | unsigned char Red; 134 | 135 | //! Green value 136 | unsigned char Green; 137 | 138 | //! Blue value 139 | unsigned char Blue; 140 | }; 141 | 142 | #endif 143 | -------------------------------------------------------------------------------- /source/Vector.h: -------------------------------------------------------------------------------- 1 | //----------------------------------------------------------------------------------------- 2 | // Title: Vector 3 | // Program: GameBoy Console 4 | // Authors: Stephen Monn 5 | //----------------------------------------------------------------------------------------- 6 | #ifndef VECTOR_H 7 | #define VECTOR_H 8 | 9 | 10 | //! Class that handles Vector math 11 | class Vector 12 | { 13 | public: 14 | //! Default constructor 15 | Vector() : X(0), Y(0) {} 16 | 17 | //! Main constructor 18 | Vector(int x, int y) : X(x), Y(y) {} 19 | 20 | //! Copy constructor 21 | Vector(const Vector& other) : X(other.X), Y(other.Y) {} 22 | 23 | //! Lerp (linear interpolation) 24 | void lerp(const Vector& other, unsigned char per) { 25 | X = ((X+other.X)*per)/100; 26 | Y = ((Y+other.Y)*per)/100; 27 | } 28 | 29 | //! Operators 30 | Vector operator-() const { return Vector(-X, -Y); } 31 | Vector& operator=(const Vector& other) { X = other.X; Y = other.Y; return *this; } 32 | Vector operator+(const Vector& other) const { return Vector(X + other.X, Y + other.Y); } 33 | Vector& operator+=(const Vector& other) { X+=other.X; Y+=other.Y; return *this; } 34 | Vector operator-(const Vector& other) const { return Vector(X - other.X, Y - other.Y); } 35 | Vector& operator-=(const Vector& other) { X-=other.X; Y-=other.Y; return *this; } 36 | Vector operator*(const Vector& other) const { return Vector(X * other.X, Y * other.Y); } 37 | Vector& operator*=(const Vector& other) { X*=other.X; Y*=other.Y; return *this; } 38 | Vector operator*(const int v) const { return Vector(X * v, Y * v); } 39 | Vector& operator*=(const int v) { X*=v; Y*=v; return *this; } 40 | Vector operator/(const Vector& other) const { return Vector(X / other.X, Y / other.Y); } 41 | Vector& operator/=(const Vector& other) { X/=other.X; Y/=other.Y; return *this; } 42 | Vector operator/(const int v) const { return Vector(X / v, Y / v); } 43 | Vector& operator/=(const int v) { X/=v; Y/=v; return *this; } 44 | bool operator==(const Vector& other) const { return X==other.X && Y==other.Y; } 45 | bool operator!=(const Vector& other) const { return !(X==other.X && Y==other.Y); } 46 | 47 | //! X coordinate 48 | int X; 49 | 50 | //! Y coordinate 51 | int Y; 52 | }; 53 | 54 | #endif 55 | -------------------------------------------------------------------------------- /source/core/bt.h: -------------------------------------------------------------------------------- 1 | #ifndef BT_H 2 | #define BT_H 3 | 4 | #define BT_DEVICE_TYPE_UNKNOWN 0 5 | #define BT_DEVICE_TYPE_AUDIOSOURCE 1 6 | #define BT_DEVICE_TYPE_HID 2 7 | 8 | #define BT_PTC_NOT_STARTED 0 9 | #define BT_PTC_SEARCHING 1 10 | #define BT_PTC_PAIRING 2 11 | #define BT_PTC_TRUSTING 3 12 | #define BT_PTC_CONNECTING 4 13 | #define BT_PTC_CONNECTED 5 14 | 15 | typedef struct { 16 | char mac[18]; 17 | char name[256]; 18 | int type; 19 | char paired; 20 | char trusted; 21 | char connected; 22 | } bt_device; 23 | 24 | // Setup and initialize the Bluetooth utils 25 | int bt_init(); 26 | 27 | // Checks if the Bluetooth utils are initialized 28 | char bt_isInit(); 29 | 30 | // Turns on Bluetooth discoverable 31 | void bt_discoverableOn(); 32 | 33 | // Turns off Bluetooth discoverable 34 | void bt_discoverableOff(); 35 | 36 | // Turns on Bluetooth scan 37 | void bt_scanOn(); 38 | 39 | // Turns off Bluetooth scan 40 | void bt_scanOff(); 41 | 42 | // Pairs the given Bluetooth device 43 | char bt_pairDevice(const char* mac); 44 | 45 | // Connects the given Bluetooth device 46 | char bt_connectDevice(const char* mac); 47 | 48 | // Trusts the given Bluetooth device 49 | char bt_trustDevice(const char* mac); 50 | 51 | // Unrusts the given Bluetooth device 52 | char bt_untrustDevice(const char* mac); 53 | 54 | // Removes the given Bluetooth device 55 | char bt_removeDevice(const char* mac); 56 | 57 | // Gets list of bluetooth devices 58 | bt_device** bt_getDevices(); 59 | 60 | // Gets the details of the given device 61 | void bt_getDevicesDetails(bt_device* device); 62 | 63 | // Starts the background pair, trust and connect process 64 | void bt_startPairTrustConnect(const char* name); 65 | 66 | // Checks on the background pair, trust and connect process 67 | char bt_checkPairTrustConnect(); 68 | 69 | // Stops the background pair, trust and connect process 70 | void bt_stopPairTrustConnect(); 71 | 72 | // Cleans up the Bluetooth utils 73 | int bt_close(); 74 | 75 | #endif /* BT_H */ 76 | -------------------------------------------------------------------------------- /source/core/egpio.c: -------------------------------------------------------------------------------- 1 | #include "egpio.h" 2 | #include "spi.h" 3 | #include 4 | 5 | #define SPI_CLK_SPEED 10000000 6 | 7 | #define CHIPA_READ 0x49 8 | #define CHIPA_WRITE 0x48 9 | #define CHIPB_READ 0x43 10 | #define CHIPB_WRITE 0x42 11 | 12 | #define CHIP_REG_CONFIG 0x0A 13 | #define CHIP_REG_DIR 0x00 14 | #define CHIP_REG_DIR2 0x01 15 | #define CHIP_REG_GPIO 0x12 16 | #define CHIP_REG_GPIO2 0x13 17 | #define CHIP_REG_GPPU 0x0C 18 | #define CHIP_REG_GPPU2 0x0D 19 | 20 | #define CHIP_CONFIG_SEQOP 0x20 21 | #define CHIP_CONFIG_HAEN 0x08 22 | 23 | // Data 24 | static char egpio_isInitFlag = 0; 25 | 26 | // Setup and initialize the expanded gpio 27 | int egpio_init() 28 | { 29 | //already initialized? 30 | if(egpio_isInitFlag == 1) return 0; 31 | 32 | //check dependencies 33 | if(!spi_isInit()) { 34 | fprintf(stderr, "egpio_init: SPI dependency is not initialized\n"); 35 | egpio_close(); 36 | return 1; 37 | } 38 | 39 | //config chip A and B 40 | unsigned char buffer[3]; 41 | buffer[0] = CHIPA_WRITE; buffer[1] = CHIP_REG_CONFIG; buffer[2] = CHIP_CONFIG_SEQOP | CHIP_CONFIG_HAEN; 42 | spi_transfer(buffer, 3); 43 | buffer[0] = CHIPB_WRITE; buffer[1] = CHIP_REG_CONFIG; buffer[2] = CHIP_CONFIG_SEQOP | CHIP_CONFIG_HAEN; 44 | spi_transfer(buffer, 3); 45 | 46 | //set defaults 47 | egpio_setPortDirAll(0xFF, 0xFF, 0xFF, 0xFF); 48 | egpio_setPortPullupAll(0x00, 0x00, 0x00, 0x00); 49 | 50 | egpio_isInitFlag = 1; 51 | return 0; 52 | } 53 | 54 | // Checks if the expanded GPIO interface is initialized 55 | char egpio_isInit() 56 | { 57 | return egpio_isInitFlag; 58 | } 59 | 60 | // Sets the direction on the given ports pins (1=input, 0=output) 61 | void egpio_setPortDir(uint8_t port, uint8_t dir) 62 | { 63 | unsigned char chip = CHIPA_WRITE; 64 | if(port == EX_GPIO_PORTC || port == EX_GPIO_PORTD) chip = CHIPB_WRITE; 65 | unsigned char reg = CHIP_REG_DIR; 66 | if(port == EX_GPIO_PORTB || port == EX_GPIO_PORTD) reg = CHIP_REG_DIR2; 67 | unsigned char buffer[3] = { chip, reg, dir }; 68 | spi_transfer(buffer, 3); 69 | } 70 | 71 | // Sets the direction on all port pins (1=input, 0=output) 72 | void egpio_setPortDirAll(uint8_t dirA, uint8_t dirB, uint8_t dirC, uint8_t dirD) 73 | { 74 | unsigned char buffer[4]; 75 | buffer[0] = CHIPA_WRITE; buffer[1] = CHIP_REG_DIR; buffer[2] = dirA; buffer[3] = dirB; 76 | spi_transfer(buffer, 4); 77 | buffer[0] = CHIPB_WRITE; buffer[1] = CHIP_REG_DIR; buffer[2] = dirC; buffer[3] = dirD; 78 | spi_transfer(buffer, 4); 79 | } 80 | 81 | // Sets the direction on port A and B (1=input, 0=output) 82 | void egpio_setPortDirAB(uint8_t dirA, uint8_t dirB) 83 | { 84 | unsigned char buffer[4]; 85 | buffer[0] = CHIPA_WRITE; buffer[1] = CHIP_REG_DIR; buffer[2] = dirA; buffer[3] = dirB; 86 | spi_transfer(buffer, 4); 87 | 88 | } 89 | 90 | // Sets the direction on port C and D (1=input, 0=output) 91 | void egpio_setPortDirCD(uint8_t dirC, uint8_t dirD) 92 | { 93 | unsigned char buffer[4]; 94 | buffer[0] = CHIPB_WRITE; buffer[1] = CHIP_REG_DIR; buffer[2] = dirC; buffer[3] = dirD; 95 | spi_transfer(buffer, 4); 96 | } 97 | 98 | // Sets the weak pullup on the given ports pins (1=on, 0=off) 99 | void egpio_setPortPullup(uint8_t port, uint8_t pullup) 100 | { 101 | unsigned char chip = CHIPA_WRITE; 102 | if(port == EX_GPIO_PORTC || port == EX_GPIO_PORTD) chip = CHIPB_WRITE; 103 | unsigned char reg = CHIP_REG_GPPU; 104 | if(port == EX_GPIO_PORTB || port == EX_GPIO_PORTD) reg = CHIP_REG_GPPU2; 105 | unsigned char buffer[3] = { chip, reg, pullup }; 106 | spi_transfer(buffer, 3); 107 | } 108 | 109 | // Sets the weak pullup on all port pins (1=on, 0=off) 110 | void egpio_setPortPullupAll(uint8_t pullupA, uint8_t pullupB, uint8_t pullupC, uint8_t pullupD) 111 | { 112 | unsigned char buffer[4]; 113 | buffer[0] = CHIPA_WRITE; buffer[1] = CHIP_REG_GPPU; buffer[2] = pullupA; buffer[3] = pullupB; 114 | spi_transfer(buffer, 4); 115 | buffer[0] = CHIPB_WRITE; buffer[1] = CHIP_REG_GPPU; buffer[2] = pullupC; buffer[3] = pullupD; 116 | spi_transfer(buffer, 4); 117 | } 118 | 119 | // Writes the output on the given ports pins (1=high, 0=low) 120 | void egpio_writePort(uint8_t port, uint8_t val) 121 | { 122 | unsigned char chip = CHIPA_WRITE; 123 | if(port == EX_GPIO_PORTC || port == EX_GPIO_PORTD) chip = CHIPB_WRITE; 124 | unsigned char reg = CHIP_REG_GPIO; 125 | if(port == EX_GPIO_PORTB || port == EX_GPIO_PORTD) reg = CHIP_REG_GPIO2; 126 | unsigned char buffer[3] = { chip, reg, val }; 127 | spi_transfer(buffer, 3); 128 | } 129 | 130 | // Writes the output on all port pins (1=high, 0=low) 131 | void egpio_writePortAll(uint8_t valA, uint8_t valB, uint8_t valC, uint8_t valD) 132 | { 133 | unsigned char buffer[4]; 134 | buffer[0] = CHIPA_WRITE; buffer[1] = CHIP_REG_GPIO; buffer[2] = valA; buffer[3] = valB; 135 | spi_transfer(buffer, 4); 136 | buffer[0] = CHIPB_WRITE; buffer[1] = CHIP_REG_GPIO; buffer[2] = valC; buffer[3] = valD; 137 | spi_transfer(buffer, 4); 138 | } 139 | 140 | // Writes the output on port A and B (1=high, 0=low) 141 | void egpio_writePortAB(uint8_t valA, uint8_t valB) 142 | { 143 | unsigned char buffer[4]; 144 | buffer[0] = CHIPA_WRITE; buffer[1] = CHIP_REG_GPIO; buffer[2] = valA; buffer[3] = valB; 145 | spi_transfer(buffer, 4); 146 | } 147 | 148 | // Writes the output on port C and D (1=high, 0=low) 149 | void egpio_writePortCD(uint8_t valC, uint8_t valD) 150 | { 151 | unsigned char buffer[4]; 152 | buffer[0] = CHIPB_WRITE; buffer[1] = CHIP_REG_GPIO; buffer[2] = valC; buffer[3] = valD; 153 | spi_transfer(buffer, 4); 154 | } 155 | 156 | // Reads the values on the given ports pins (1=high, 0=low) 157 | uint8_t egpio_readPort(uint8_t port) 158 | { 159 | unsigned char chip = CHIPA_READ; 160 | if(port == EX_GPIO_PORTC || port == EX_GPIO_PORTD) chip = CHIPB_READ; 161 | unsigned char reg = CHIP_REG_GPIO; 162 | if(port == EX_GPIO_PORTB || port == EX_GPIO_PORTD) reg = CHIP_REG_GPIO2; 163 | unsigned char buffer[3] = { chip, reg, 0x00 }; 164 | spi_transfer(buffer, 3); 165 | return buffer[2]; 166 | } 167 | 168 | // Start a continuous read operation on ports A and B 169 | void egpio_continuousReadAB_start() 170 | { 171 | unsigned char buffer[2] = { CHIPA_READ, CHIP_REG_GPIO }; 172 | spi_read_start(buffer, 2); 173 | } 174 | 175 | // Continues a continuous read operation on ports A and B 176 | void egpio_continuousReadAB_cont(char* buff) 177 | { 178 | buff[0] = spi_read_cont(); 179 | buff[1] = spi_read_cont(); 180 | } 181 | 182 | // Start a continuous read operation on ports A and B 183 | void egpio_continuousReadAB_end() 184 | { 185 | spi_read_end(0, 0); 186 | } 187 | 188 | // Closes the expanded GPIO interface 189 | int egpio_close() 190 | { 191 | egpio_isInitFlag = 0; 192 | return 0; 193 | } 194 | -------------------------------------------------------------------------------- /source/core/egpio.h: -------------------------------------------------------------------------------- 1 | #ifndef EGPIO_H 2 | #define EGPIO_H 3 | #include 4 | 5 | #define EX_GPIO_PORTA 0x00 6 | #define EX_GPIO_PORTB 0x01 7 | #define EX_GPIO_PORTC 0x02 8 | #define EX_GPIO_PORTD 0x03 9 | 10 | // Setup and initialize the expanded GPIO 11 | int egpio_init(); 12 | 13 | // Checks if the expanded GPIO interface is initialized 14 | char egpio_isInit(); 15 | 16 | // Sets the direction on the given ports pins (1=input, 0=output) 17 | void egpio_setPortDir(uint8_t port, uint8_t dir); 18 | 19 | // Sets the direction on all port pins (1=input, 0=output) 20 | void egpio_setPortDirAll(uint8_t dirA, uint8_t dirB, uint8_t dirC, uint8_t dirD); 21 | 22 | // Sets the direction on port A and B (1=input, 0=output) 23 | void egpio_setPortDirAB(uint8_t dirA, uint8_t dirB); 24 | 25 | // Sets the direction on port C and D (1=input, 0=output) 26 | void egpio_setPortDirCD(uint8_t dirC, uint8_t dirD); 27 | 28 | // Sets the weak pullup on the given ports pins (1=on, 0=off) 29 | void egpio_setPortPullup(uint8_t port, uint8_t pullup); 30 | 31 | // Sets the weak pullup on all port pins (1=on, 0=off) 32 | void egpio_setPortPullupAll(uint8_t pullupA, uint8_t pullupB, uint8_t pullupC, uint8_t pullupD); 33 | 34 | // Writes the output on the given ports pins (1=high, 0=low) 35 | void egpio_writePort(uint8_t port, uint8_t val); 36 | 37 | // Writes the output on all port pins (1=high, 0=low) 38 | void egpio_writePortAll(uint8_t valA, uint8_t valB, uint8_t valC, uint8_t valD); 39 | 40 | // Writes the output on port A and B (1=high, 0=low) 41 | void egpio_writePortAB(uint8_t valA, uint8_t valB); 42 | 43 | // Writes the output on port C and D (1=high, 0=low) 44 | void egpio_writePortCD(uint8_t valC, uint8_t valD); 45 | 46 | // Reads the values on the given ports pins (1=high, 0=low) 47 | uint8_t egpio_readPort(uint8_t port); 48 | 49 | // Start a continuous read operation on ports A and B 50 | void egpio_continuousReadAB_start(); 51 | 52 | // Continues a continuous read operation on ports A and B 53 | void egpio_continuousReadAB_cont(char* buff); 54 | 55 | // Start a continuous read operation on ports A and B 56 | void egpio_continuousReadAB_end(); 57 | 58 | // Closes the expanded GPIO interface 59 | int egpio_close(); 60 | 61 | 62 | #endif /* EGPIO_H */ 63 | -------------------------------------------------------------------------------- /source/core/gba/gba.c: -------------------------------------------------------------------------------- 1 | #include "gba.h" 2 | #include "gba_cart.h" 3 | #include "gba_rom.h" 4 | #include "gba_save.h" 5 | #include "gba_sram.h" 6 | #include "gba_flash.h" 7 | #include "gba_eeprom.h" 8 | #include 9 | #include "egpio.h" 10 | 11 | //TODOs: 12 | //-Atmel flash read/write is untested 13 | 14 | // Constants 15 | static const char gba_nintendoLogo[] = { 16 | 0x24, 0xFF, 0xAE, 0x51, 0x69, 0x9A, 0xA2, 0x21, 0x3D, 0x84, 0x82, 0x0A, 17 | 0x84, 0xE4, 0x09, 0xAD, 0x11, 0x24, 0x8B, 0x98, 0xC0, 0x81, 0x7F, 0x21, 0xA3, 0x52, 0xBE, 0x19, 18 | 0x93, 0x09, 0xCE, 0x20, 0x10, 0x46, 0x4A, 0x4A, 0xF8, 0x27, 0x31, 0xEC, 0x58, 0xC7, 0xE8, 0x33, 19 | 0x82, 0xE3, 0xCE, 0xBF, 0x85, 0xF4, 0xDF, 0x94, 0xCE, 0x4B, 0x09, 0xC1, 0x94, 0x56, 0x8A, 0xC0, 20 | 0x13, 0x72, 0xA7, 0xFC, 0x9F, 0x84, 0x4D, 0x73, 0xA3, 0xCA, 0x9A, 0x61, 0x58, 0x97, 0xA3, 0x27, 21 | 0xFC, 0x03, 0x98, 0x76, 0x23, 0x1D, 0xC7, 0x61, 0x03, 0x04, 0xAE, 0x56, 0xBF, 0x38, 0x84, 0x00, 22 | 0x40, 0xA7, 0x0E, 0xFD, 0xFF, 0x52, 0xFE, 0x03, 0x6F, 0x95, 0x30, 0xF1, 0x97, 0xFB, 0xC0, 0x85, 23 | 0x60, 0xD6, 0x80, 0x25, 0xA9, 0x63, 0xBE, 0x03, 0x01, 0x4E, 0x38, 0xE2, 0xF9, 0xA2, 0x34, 0xFF, 24 | 0xBB, 0x3E, 0x03, 0x44, 0x78, 0x00, 0x90, 0xCB, 0x88, 0x11, 0x3A, 0x94, 0x65, 0xC0, 0x7C, 0x63, 25 | 0x87, 0xF0, 0x3C, 0xAF, 0xD6, 0x25, 0xE4, 0x8B, 0x38, 0x0A, 0xAC, 0x72, 0x21, 0xD4, 0xF8, 0x07 26 | }; 27 | 28 | // Data 29 | static char gba_isInitFlag = 0; 30 | static char gba_loaded = 0; 31 | static char gba_gameTitle[13]; 32 | static char gba_gameCode[5]; 33 | static char gba_makerCode[3]; 34 | static unsigned int gba_romSize; 35 | static unsigned int gba_saveType; 36 | static unsigned int gba_saveSize; 37 | 38 | // Helper functions 39 | static char gba_verifyLoaded(); 40 | static void gba_clearData(); 41 | 42 | // Setup and initialize the GBA utils 43 | int gba_init() 44 | { 45 | //already initialized? 46 | if(gba_isInitFlag == 1) return 0; 47 | 48 | //check dependencies 49 | if(!egpio_isInit()) { 50 | fprintf(stderr, "gba_init: eGPIO dependency is not initialized\n"); 51 | gba_close(); 52 | return 1; 53 | } 54 | 55 | //configure pins 56 | gba_cart_powerDown(); 57 | 58 | //init data 59 | gba_clearData(); 60 | 61 | gba_isInitFlag = 1; 62 | return 0; 63 | } 64 | 65 | // Checks if the GBA utils are initialized 66 | char gba_isInit() 67 | { 68 | return gba_isInitFlag; 69 | } 70 | 71 | // Gets the header of a connected GBA cartridge 72 | char gba_loadHeader() 73 | { 74 | int i; 75 | 76 | //read header 77 | char header[192]; 78 | gba_rom_readAt(header, 0x00, 192); 79 | 80 | //verify header checksum 81 | unsigned char chk=0; 82 | for(i=0xA0; i<0xBC; i++) chk = chk - header[i]; 83 | chk = chk - 0x19; 84 | if(header[0xBD] != chk) { 85 | //power down the cart slot 86 | gba_cart_powerDown(); 87 | gba_clearData(); 88 | return gba_loaded; 89 | } 90 | 91 | //extract general data from header 92 | for(i = 0; i < 12; i++) gba_gameTitle[i] = header[0xA0 + i]; 93 | for(i = 0; i < 4; i++) gba_gameCode[i] = header[0xAC + i]; 94 | for(i = 0; i < 2; i++) gba_makerCode[i] = header[0xB0 + i]; 95 | 96 | //determine rom size 97 | gba_romSize = gba_rom_determineSize(); 98 | 99 | //determine save type and size 100 | gba_saveType = gba_save_determineType(); 101 | if(gba_saveType == GBA_SAVE_TYPE_EEPROM_4K) gba_saveSize = GBA_SAVE_SIZE_4K; 102 | else if(gba_saveType == GBA_SAVE_TYPE_EEPROM_64K) gba_saveSize = GBA_SAVE_SIZE_64K; 103 | else if(gba_saveType == GBA_SAVE_TYPE_SRAM_256K) gba_saveSize = GBA_SAVE_SIZE_256K; 104 | else if(gba_saveType == GBA_SAVE_TYPE_SRAM_512K) gba_saveSize = GBA_SAVE_SIZE_512K; 105 | else if(gba_saveType == GBA_SAVE_TYPE_FLASH_512K) gba_saveSize = GBA_SAVE_SIZE_512K; 106 | else if(gba_saveType == GBA_SAVE_TYPE_FLASH_1M) gba_saveSize = GBA_SAVE_SIZE_1M; 107 | else gba_saveSize = 0; 108 | 109 | //power down the cart slot 110 | gba_cart_powerDown(); 111 | 112 | gba_loaded = 1; 113 | return gba_loaded; 114 | } 115 | 116 | // Clears all loaded data for the connected GBA cartridge 117 | void gba_loadClear() 118 | { 119 | gba_clearData(); 120 | } 121 | 122 | // Checks if a GBA cartridge is currently connected and loaded 123 | char gba_isLoaded() 124 | { 125 | gba_verifyLoaded(); 126 | 127 | //power down the cart slot 128 | gba_cart_powerDown(); 129 | return gba_loaded; 130 | } 131 | 132 | // Gets the game title of the loaded GBA cartridge 133 | char* gba_getGameTitle() 134 | { 135 | return gba_gameTitle; 136 | } 137 | 138 | // Gets the game code of the loaded GBA cartridge 139 | char* gba_getGameCode() 140 | { 141 | return gba_gameCode; 142 | } 143 | 144 | // Gets the maker code of the loaded GBA cartridge 145 | char* gba_getMakerCode() 146 | { 147 | return gba_makerCode; 148 | } 149 | 150 | // Gets the ROM size of the loaded GBA cartridge 151 | unsigned int gba_getROMSize() 152 | { 153 | return gba_romSize; 154 | } 155 | 156 | // Gets the Save type of the loaded GBA cartridge 157 | unsigned int gba_getSaveType() 158 | { 159 | return gba_saveType; 160 | } 161 | 162 | // Gets the Save size of the loaded GBA cartridge 163 | unsigned int gba_getSaveSize() 164 | { 165 | return gba_saveSize; 166 | } 167 | 168 | // Read the ROM of a connected GBA cartridge and returns the length 169 | int gba_readROM(char* buffer, unsigned int length) 170 | { 171 | if(gba_verifyLoaded() == 0) gba_loadHeader(); 172 | if(gba_loaded == 0) { 173 | //power down the cart slot 174 | gba_cart_powerDown(); 175 | return GBA_ERROR_NO_CARTRIDGE; 176 | } 177 | 178 | if(length > gba_romSize) length = gba_romSize; 179 | if(length > 0) { 180 | gba_rom_readAt(buffer, 0x00, length); 181 | } 182 | 183 | //power down the cart slot 184 | gba_cart_powerDown(); 185 | return length; 186 | } 187 | 188 | // Read the Save Data of a connected GBA cartridge and returns the size 189 | int gba_readSave(char* buffer, unsigned int length) 190 | { 191 | if(gba_verifyLoaded() == 0) gba_loadHeader(); 192 | if(gba_loaded == 0) { 193 | //power down the cart slot 194 | gba_cart_powerDown(); 195 | return GBA_ERROR_NO_CARTRIDGE; 196 | } 197 | 198 | if(gba_saveType == GBA_SAVE_TYPE_UNKNOWN) { 199 | //power down the cart slot 200 | gba_cart_powerDown(); 201 | return 0; 202 | } 203 | 204 | if(length > gba_saveSize) length = gba_saveSize; 205 | if(length > 0) { 206 | if(gba_saveType == GBA_SAVE_TYPE_SRAM_256K || gba_saveType == GBA_SAVE_TYPE_SRAM_512K) gba_sram_read(buffer, length); 207 | if(gba_saveType == GBA_SAVE_TYPE_FLASH_512K || gba_saveType == GBA_SAVE_TYPE_FLASH_1M) gba_flash_read(buffer, length); 208 | if(gba_saveType == GBA_SAVE_TYPE_EEPROM_4K || gba_saveType == GBA_SAVE_TYPE_EEPROM_64K) gba_eeprom_read(buffer, length); 209 | } 210 | 211 | //power down the cart slot 212 | gba_cart_powerDown(); 213 | return length; 214 | } 215 | 216 | // Write the Save Data to a connected GBA cartridge 217 | int gba_writeSave(char* buffer, unsigned int length) 218 | { 219 | if(gba_loaded == 0) return GBA_ERROR_CARTRIDGE_NOT_LOADED; 220 | if(gba_verifyLoaded() == 0) { 221 | gba_loadHeader(); 222 | if(gba_loaded == 1) return GBA_ERROR_CARTRIDGE_CHANGED; 223 | if(gba_loaded == 0) return GBA_ERROR_NO_CARTRIDGE; 224 | } 225 | 226 | if(gba_saveType == GBA_SAVE_TYPE_UNKNOWN) { 227 | //power down the cart slot 228 | gba_cart_powerDown(); 229 | return 0; 230 | } 231 | 232 | if(length > gba_saveSize) length = gba_saveSize; 233 | if(length > 0) { 234 | if(gba_saveType == GBA_SAVE_TYPE_SRAM_256K || gba_saveType == GBA_SAVE_TYPE_SRAM_512K) gba_sram_write(buffer, length); 235 | if(gba_saveType == GBA_SAVE_TYPE_FLASH_512K || gba_saveType == GBA_SAVE_TYPE_FLASH_1M) gba_flash_write(buffer, length); 236 | if(gba_saveType == GBA_SAVE_TYPE_EEPROM_4K || gba_saveType == GBA_SAVE_TYPE_EEPROM_64K) gba_eeprom_write(buffer, length); 237 | } 238 | 239 | //power down the cart slot 240 | gba_cart_powerDown(); 241 | return length; 242 | } 243 | 244 | // Dumps the first 400 bytes of the connected GBA cartridge 245 | void gba_dumpHeader(char* data) 246 | { 247 | gba_rom_readAt(data, 0x00, 400); 248 | 249 | //power down the cart slot 250 | gba_cart_powerDown(); 251 | } 252 | 253 | // Cleans up the GBA utils 254 | int gba_close() 255 | { 256 | gba_isInitFlag = 0; 257 | return 0; 258 | } 259 | 260 | // Checks that the currently connected GBA cartridge matches what is loaded 261 | static char gba_verifyLoaded() { 262 | int i; 263 | 264 | //return early if not loaded at all 265 | if(gba_loaded == 0) return 0; 266 | 267 | //read header 268 | char header[192]; 269 | gba_rom_readAt(header, 0x00, 192); 270 | 271 | //verify header checksum 272 | unsigned char chk=0; 273 | for(i=0xA0; i<0xBC; i++) chk = chk - header[i]; 274 | chk = chk - 0x19; 275 | if(header[0xBD] != chk) { 276 | gba_clearData(); 277 | return gba_loaded; 278 | } 279 | 280 | //check that the game title, code and maker code match expected 281 | char verified = 1; 282 | for(i = 0; i < 12; i++) { 283 | if(gba_gameTitle[i] != header[0xA0 + i]) { 284 | verified = 0; 285 | break; 286 | } 287 | } 288 | for(i = 0; i < 4; i++) { 289 | if(gba_gameCode[i] != header[0xAC + i]) { 290 | verified = 0; 291 | break; 292 | } 293 | } 294 | for(i = 0; i < 2; i++) { 295 | if(gba_makerCode[i] != header[0xB0 + i]) { 296 | verified = 0; 297 | break; 298 | } 299 | } 300 | if(verified == 0) { 301 | gba_clearData(); 302 | return gba_loaded; 303 | } 304 | 305 | //all good 306 | return gba_loaded; 307 | } 308 | 309 | // Clears loaded data 310 | static void gba_clearData() { 311 | int i; 312 | 313 | gba_loaded = 0; 314 | for(i = 0; i < 13; i++) gba_gameTitle[i] = 0; 315 | for(i = 0; i < 5; i++) gba_gameCode[i] = 0; 316 | for(i = 0; i < 3; i++) gba_makerCode[i] = 0; 317 | gba_saveType = 0; 318 | gba_saveSize = 0; 319 | gba_romSize = 0; 320 | } 321 | -------------------------------------------------------------------------------- /source/core/gba/gba.h: -------------------------------------------------------------------------------- 1 | #ifndef GBA_H 2 | #define GBA_H 3 | 4 | #define GBA_SAVE_TYPE_UNKNOWN 0 5 | #define GBA_SAVE_TYPE_EEPROM_4K 1 6 | #define GBA_SAVE_TYPE_EEPROM_64K 2 7 | #define GBA_SAVE_TYPE_SRAM_256K 3 8 | #define GBA_SAVE_TYPE_SRAM_512K 4 9 | #define GBA_SAVE_TYPE_FLASH_512K 5 10 | #define GBA_SAVE_TYPE_FLASH_1M 6 11 | 12 | #define GBA_ERROR_NO_CARTRIDGE -1 13 | #define GBA_ERROR_CARTRIDGE_CHANGED -2 14 | #define GBA_ERROR_CARTRIDGE_NOT_LOADED -3 15 | 16 | // Setup and initialize the GBA utils 17 | int gba_init(); 18 | 19 | // Checks if the GBA utils are initialized 20 | char gba_isInit(); 21 | 22 | // Loads the header and basic data of the connected GBA cartridge 23 | char gba_loadHeader(); 24 | 25 | // Clears all loaded data for the connected GBA cartridge 26 | void gba_loadClear(); 27 | 28 | // Checks if a GBA cartridge is currently connected and loaded 29 | char gba_isLoaded(); 30 | 31 | // Gets the game title of the loaded GBA cartridge 32 | char* gba_getGameTitle(); 33 | 34 | // Gets the game code of the loaded GBA cartridge 35 | char* gba_getGameCode(); 36 | 37 | // Gets the maker code of the loaded GBA cartridge 38 | char* gba_getMakerCode(); 39 | 40 | // Gets the ROM size of the loaded GBA cartridge 41 | unsigned int gba_getROMSize(); 42 | 43 | // Gets the Save type of the loaded GBA cartridge 44 | unsigned int gba_getSaveType(); 45 | 46 | // Gets the Save size of the loaded GBA cartridge 47 | unsigned int gba_getSaveSize(); 48 | 49 | // Read the ROM of a connected GBA cartridge and returns the size 50 | int gba_readROM(char* buffer, unsigned int length); 51 | 52 | // Read the Save Data of a connected GBA cartridge and returns the size 53 | int gba_readSave(char* buffer, unsigned int length); 54 | 55 | // Write the Save Data to a connected GBA cartridge 56 | int gba_writeSave(char* buffer, unsigned int length); 57 | 58 | // Dumps the first 400 bytes of the connected GBA cartridge 59 | void gba_dumpHeader(char* data); 60 | 61 | // Cleans up the GBA utils 62 | int gba_close(); 63 | 64 | #endif /* GBA_H */ 65 | -------------------------------------------------------------------------------- /source/core/gba/gba_cart.c: -------------------------------------------------------------------------------- 1 | #include "gba.h" 2 | #include "gba_cart.h" 3 | #include "egpio.h" 4 | #include "spi.h" 5 | 6 | #define GBA_PWR_ON_DELAY 1000000 7 | #define _1(x) (x) 8 | #define _0(x) ((unsigned char)~(x)) 9 | 10 | // Data 11 | static char gba_power = 0; 12 | 13 | // Powers up the cartridge slot to the null state 14 | void gba_cart_powerUp() 15 | { 16 | //switch on power while setting pins to default state all pins 17 | egpio_setPortDirAll(0x00, 0x00, 0x00, _1(GBA_IRQ + GBA_DTSW) | _0(GBA_CS + GBA_WR + GBA_CS2 + GBA_CLK + GBA_PWR)); //default: 1 18 | egpio_writePortAll(0x00, 0x00, 0x00, _1(GBA_CS + GBA_WR + GBA_CS2) & _0(GBA_CLK + GBA_PWR)); //default: 0 19 | spi_setGPIODir(GBA_GPIO_RD, 0x00); 20 | spi_writeGPIO(GBA_GPIO_RD, 0x01); 21 | 22 | //wait for things to power up 23 | if(gba_power == 0) { 24 | gba_cart_delay(GBA_PWR_ON_DELAY); 25 | gba_power = 1; 26 | } 27 | } 28 | 29 | // Powers down the cartridge slot to an all ground state 30 | void gba_cart_powerDown() 31 | { 32 | //disconnect pins 33 | egpio_setPortPullupAll(0x00, 0x00, 0x00, GBA_DTSW); 34 | egpio_setPortDirAll(0xFF, 0xFF, 0xFF, _1(GBA_CS + GBA_WR + GBA_CS2 + GBA_CLK + GBA_IRQ + GBA_DTSW) | _0(GBA_PWR)); //default: 1 35 | spi_setGPIODir(GBA_GPIO_RD, 0x01); 36 | 37 | //switch off power 38 | egpio_writePort(EX_GPIO_PORTD, _1(GBA_PWR)); 39 | 40 | //gnd all pins 41 | egpio_writePortAll(0x00, 0x00, 0x00, _1(GBA_PWR) & _0(GBA_CS + GBA_WR + GBA_CS2 + GBA_CLK)); //default: 0 42 | spi_writeGPIO(GBA_GPIO_RD, 0x00); 43 | egpio_setPortDirAll(0x00, 0x00, 0x00, _1(GBA_IRQ + GBA_DTSW) | _0(GBA_CS + GBA_WR + GBA_CS2 + GBA_CLK + GBA_PWR)); //default: 1 44 | spi_setGPIODir(GBA_GPIO_RD, 0x00); 45 | gba_power = 0; 46 | } 47 | 48 | // Util function to delay for the given period 49 | void gba_cart_delay(int t) { 50 | volatile int i=0; 51 | for(;i GBA_SAVE_SIZE_4K) numReads = 1024; 30 | for(j = 0; j < numReads && index < length; j++) { 31 | 32 | //setup for EEPROM write 33 | egpio_setPortDir(EX_GPIO_PORTA, 0x00); 34 | egpio_writePort(EX_GPIO_PORTC, 0x80); 35 | egpio_writePort(EX_GPIO_PORTD, _1(GBA_WR + GBA_CS2) & _0(GBA_CS + GBA_CLK + GBA_PWR)); 36 | 37 | //write the read command to EEPROM 38 | if(length > GBA_SAVE_SIZE_4K) { 39 | gba_eeprom_writeByte(EEPROM_READ | (char)((j >> 8) & 0x03), 0); 40 | gba_eeprom_writeByte((char) j, 1); 41 | } else { 42 | gba_eeprom_writeByte(EEPROM_READ | (char) j, 1); 43 | } 44 | 45 | //switch back to defaults 46 | egpio_writePort(EX_GPIO_PORTC, 0x00); 47 | egpio_writePort(EX_GPIO_PORTD, _1(GBA_CS + GBA_WR + GBA_CS2) & _0(GBA_CLK + GBA_PWR)); 48 | 49 | //setup for EEPROM read 50 | egpio_setPortDir(EX_GPIO_PORTA, 0x01); 51 | egpio_writePort(EX_GPIO_PORTC, 0x80); 52 | egpio_writePort(EX_GPIO_PORTD, _1(GBA_WR + GBA_CS2) & _0(GBA_CS + GBA_CLK + GBA_PWR)); 53 | 54 | //clock in the 64 bits of data 55 | buffer[index++] = gba_eeprom_readByte(1); 56 | for(i = 1; i < 8; i++) { 57 | buffer[index++] = gba_eeprom_readByte(0); 58 | } 59 | 60 | //back to defaults 61 | egpio_writePort(EX_GPIO_PORTC, 0x00); 62 | egpio_writePort(EX_GPIO_PORTD, _1(GBA_CS + GBA_WR + GBA_CS2) & _0(GBA_CLK + GBA_PWR)); 63 | } 64 | } 65 | 66 | // Writes to the EEPROM of a connected GBA cartridge 67 | void gba_eeprom_write(char* buffer, unsigned int length) 68 | { 69 | int i, j; 70 | 71 | //ensure default state 72 | gba_cart_powerUp(); 73 | 74 | //determine if 4K or 64K and start loop 75 | int index = 0; 76 | int numWrites = 64; 77 | if(length > GBA_SAVE_SIZE_4K) numWrites = 1024; 78 | for(j = 0; j < numWrites; j++) { 79 | 80 | //setup for EEPROM write 81 | egpio_setPortDir(EX_GPIO_PORTA, 0x00); 82 | egpio_writePort(EX_GPIO_PORTC, 0x80); 83 | egpio_writePort(EX_GPIO_PORTD, _1(GBA_WR + GBA_CS2) & _0(GBA_CS + GBA_CLK + GBA_PWR)); 84 | 85 | //write the write command to EEPROM 86 | if(length > GBA_SAVE_SIZE_4K) { 87 | gba_eeprom_writeByte(EEPROM_WRITE | (char)((j >> 8) & 0x03), 0); 88 | gba_eeprom_writeByte((char) j, 0); 89 | } else { 90 | gba_eeprom_writeByte(EEPROM_WRITE | (char) j, 0); 91 | } 92 | 93 | //clock out the 64 bits of data 94 | for(i = 0; i < 7; i++) { 95 | gba_eeprom_writeByte(buffer[index++], 0); 96 | } 97 | gba_eeprom_writeByte(buffer[index++], 1); 98 | 99 | //back to defaults 100 | egpio_writePort(EX_GPIO_PORTC, 0x00); 101 | egpio_writePort(EX_GPIO_PORTD, _1(GBA_CS + GBA_WR + GBA_CS2) & _0(GBA_CLK + GBA_PWR)); 102 | 103 | //must wait before next write 104 | gba_cart_delay(700000); //7ms 105 | } 106 | } 107 | 108 | // Clocks a bit out to the EEPROM 109 | static void gba_eeprom_writeByte(char byte, char includeStop) { 110 | int i; 111 | for(i=0; i<8; i++) { 112 | egpio_writePort(EX_GPIO_PORTA, (byte >> (7-i)) & 0x01); 113 | egpio_writePort(EX_GPIO_PORTD, _1(GBA_CS2) & _0(GBA_CS + GBA_WR + GBA_CLK + GBA_PWR)); 114 | egpio_writePort(EX_GPIO_PORTD, _1(GBA_WR + GBA_CS2) & _0(GBA_CS + GBA_CLK + GBA_PWR)); 115 | } 116 | if(includeStop) { 117 | egpio_writePort(EX_GPIO_PORTA, 0x00); 118 | egpio_writePort(EX_GPIO_PORTD, _1(GBA_CS2) & _0(GBA_CS + GBA_WR + GBA_CLK + GBA_PWR)); 119 | egpio_writePort(EX_GPIO_PORTD, _1(GBA_WR + GBA_CS2) & _0(GBA_CS + GBA_CLK + GBA_PWR)); 120 | } 121 | } 122 | 123 | // Clocks a bit in form the EEPROM 124 | static char gba_eeprom_readByte(char ignoreStart) { 125 | int i; 126 | char byte = 0x00; 127 | if(ignoreStart) { 128 | for(i=0; i<4; i++) { 129 | spi_writeGPIO(GBA_GPIO_RD, 0x00); 130 | gba_cart_delay(200); //600ns 131 | spi_writeGPIO(GBA_GPIO_RD, 0x01); 132 | gba_cart_delay(200); //600ns 133 | } 134 | } 135 | for(i=0; i<8; i++) { 136 | spi_writeGPIO(GBA_GPIO_RD, 0x00); 137 | gba_cart_delay(200); //600ns 138 | byte |= egpio_readPort(EX_GPIO_PORTA) << (7-i); 139 | spi_writeGPIO(GBA_GPIO_RD, 0x01); 140 | gba_cart_delay(200); //600ns 141 | } 142 | return byte; 143 | } 144 | -------------------------------------------------------------------------------- /source/core/gba/gba_eeprom.h: -------------------------------------------------------------------------------- 1 | #ifndef GBA_EEPROM_H 2 | #define GBA_EEPROM_H 3 | 4 | // Reads the EEPROM of a connected GBA cartridge 5 | void gba_eeprom_read(char* buffer, unsigned int length); 6 | 7 | // Writes to the EEPROM of a connected GBA cartridge 8 | void gba_eeprom_write(char* buffer, unsigned int length); 9 | 10 | #endif /* GBA_EEPROM_H */ 11 | -------------------------------------------------------------------------------- /source/core/gba/gba_flash.c: -------------------------------------------------------------------------------- 1 | #include "gba.h" 2 | #include "gba_cart.h" 3 | #include "gba_save.h" 4 | #include "gba_flash.h" 5 | #include "egpio.h" 6 | #include "spi.h" 7 | 8 | #define _1(x) (x) 9 | #define _0(x) ((unsigned char)~(x)) 10 | 11 | // Helper functions 12 | static void gba_flash_writeAtmel(char* buffer, unsigned int length); 13 | static void gba_flash_writeOther(char* buffer, unsigned int length); 14 | static void gba_flash_writeBus(int address, char data); 15 | 16 | // Reads the Flash/SRAM of a connected GBA cartridge 17 | void gba_flash_read(char* buffer, unsigned int length) 18 | { 19 | //read as much as possible from bank 0 20 | unsigned int numReads = length; 21 | if(length > GBA_SAVE_SIZE_512K) numReads = GBA_SAVE_SIZE_512K; 22 | gba_flash_readAt(buffer, 0, numReads); 23 | 24 | //read more from bank 1 if needed 25 | if(length > GBA_SAVE_SIZE_512K) { 26 | buffer += GBA_SAVE_SIZE_512K; 27 | length -= GBA_SAVE_SIZE_512K; 28 | gba_flash_readAt(buffer, GBA_SAVE_SIZE_512K, length); 29 | } 30 | } 31 | 32 | // Reads Save data like Flash or SRAM from the given address 33 | void gba_flash_readAt(char* buffer, unsigned int start, unsigned int length) 34 | { 35 | int i; 36 | 37 | //ensure default state 38 | gba_cart_powerUp(); 39 | 40 | //pull GBA_CS2 pin low while we read data 41 | egpio_writePort(EX_GPIO_PORTD, _1(GBA_CS + GBA_WR) & _0(GBA_CS2 + GBA_CLK + GBA_PWR)); 42 | 43 | //switch to bank 1 if starting past 512K 44 | if(start >= GBA_SAVE_SIZE_512K) { 45 | egpio_setPortDir(EX_GPIO_PORTC, 0x00); 46 | gba_flash_writeBus(0x5555, 0xAA); 47 | gba_flash_writeBus(0x2AAA, 0x55); 48 | gba_flash_writeBus(0x5555, 0xB0); 49 | gba_flash_writeBus(0x0000, 0x01); 50 | gba_cart_delay(500000); //5ms 51 | } 52 | 53 | //read the data 54 | egpio_setPortDir(EX_GPIO_PORTC, 0xFF); 55 | unsigned int offset = start; 56 | if(start >= GBA_SAVE_SIZE_512K) offset -= GBA_SAVE_SIZE_512K; 57 | for(i = 0; i < length; i++) { 58 | 59 | //set the address 60 | unsigned int address = offset + i; 61 | egpio_writePortAB((char) address, (char) (address >> 8)); 62 | 63 | //pull RD pin low while we read data 64 | spi_writeGPIO(GBA_GPIO_RD, 0x00); 65 | buffer[i] = egpio_readPort(EX_GPIO_PORTC); 66 | spi_writeGPIO(GBA_GPIO_RD, 0x01); 67 | } 68 | 69 | //switch back to bank 0 if starting past 512K 70 | if(start >= GBA_SAVE_SIZE_512K) { 71 | egpio_setPortDir(EX_GPIO_PORTC, 0x00); 72 | gba_flash_writeBus(0x5555, 0xAA); 73 | gba_flash_writeBus(0x2AAA, 0x55); 74 | gba_flash_writeBus(0x5555, 0xB0); 75 | gba_flash_writeBus(0x0000, 0x00); 76 | gba_cart_delay(500000); //5ms 77 | } 78 | 79 | //pull RD and GBA_CS2 back to high 80 | egpio_writePort(EX_GPIO_PORTD, _1(GBA_CS + GBA_WR + GBA_CS2) & _0(GBA_CLK + GBA_PWR)); 81 | spi_writeGPIO(GBA_GPIO_RD, 0x01); 82 | } 83 | 84 | // Writes to the Flash memory of a connected GBA cartridge 85 | void gba_flash_write(char* buffer, unsigned int length) 86 | { 87 | char manufacturerId, deviceId; 88 | char flashManufacturer = gba_flash_checkManufacturer(&manufacturerId, &deviceId); 89 | 90 | //ensure default state 91 | gba_cart_powerUp(); 92 | 93 | //write flash according to manufacturer 94 | if(flashManufacturer == GBA_FLASH_MANUFACTURER_ATMEL) { 95 | gba_flash_writeAtmel(buffer, length); 96 | } else if(flashManufacturer == GBA_FLASH_MANUFACTURER_OTHER) { 97 | gba_flash_writeOther(buffer, length); 98 | } 99 | 100 | //pull GBA_CS2, RD and WR back to high 101 | egpio_writePort(EX_GPIO_PORTD, _1(GBA_CS + GBA_WR + GBA_CS2) & _0(GBA_CLK + GBA_PWR)); 102 | spi_writeGPIO(GBA_GPIO_RD, 0x01); 103 | } 104 | 105 | // Reads the manufacturer code of the flash chip 106 | char gba_flash_checkManufacturer(char* manufacturerId, char* deviceId) 107 | { 108 | //ensure default state 109 | gba_cart_powerUp(); 110 | 111 | //pull GBA_CS2 pin low while we write data 112 | egpio_writePort(EX_GPIO_PORTD, _1(GBA_CS + GBA_WR) & _0(GBA_CS2 + GBA_CLK + GBA_PWR)); 113 | 114 | //write the bus cycles for software id entry 115 | gba_flash_writeBus(0x5555, 0xAA); 116 | gba_flash_writeBus(0x2AAA, 0x55); 117 | gba_flash_writeBus(0x5555, 0x90); 118 | gba_cart_delay(500000); //5ms 119 | 120 | //read manufacturer id 121 | egpio_setPortDir(EX_GPIO_PORTC, 0xFF); 122 | egpio_writePortAB(0x00, 0x00); 123 | spi_writeGPIO(GBA_GPIO_RD, 0x00); 124 | manufacturerId[0] = egpio_readPort(EX_GPIO_PORTC); 125 | spi_writeGPIO(GBA_GPIO_RD, 0x01); 126 | 127 | //read device id 128 | egpio_writePortAB(0x01, 0x00); 129 | spi_writeGPIO(GBA_GPIO_RD, 0x00); 130 | deviceId[0] = egpio_readPort(EX_GPIO_PORTC); 131 | spi_writeGPIO(GBA_GPIO_RD, 0x01); 132 | 133 | //write the bus cycles for software id exit 134 | egpio_setPortDir(EX_GPIO_PORTC, 0x00); 135 | gba_flash_writeBus(0x5555, 0xAA); 136 | gba_flash_writeBus(0x2AAA, 0x55); 137 | gba_flash_writeBus(0x5555, 0xF0); 138 | gba_cart_delay(500000); //5ms 139 | 140 | //pull GBA_CS2 back to high 141 | egpio_writePort(EX_GPIO_PORTD, _1(GBA_CS + GBA_WR + GBA_CS2) & _0(GBA_CLK + GBA_PWR)); 142 | spi_writeGPIO(GBA_GPIO_RD, 0x01); 143 | 144 | //return the manufacturer 145 | if(manufacturerId[0] == 0x1F) return GBA_FLASH_MANUFACTURER_ATMEL; 146 | if(manufacturerId[0] == 0xBF) return GBA_FLASH_MANUFACTURER_OTHER; 147 | if(manufacturerId[0] == 0xC2) return GBA_FLASH_MANUFACTURER_OTHER; 148 | if(manufacturerId[0] == 0x32) return GBA_FLASH_MANUFACTURER_OTHER; 149 | if(manufacturerId[0] == 0x62) return GBA_FLASH_MANUFACTURER_OTHER; 150 | return GBA_FLASH_MANUFACTURER_UNKNOWN; 151 | } 152 | 153 | // Writes to the Flash memory of a connected GBA cartridge (atmel manufacturer) 154 | static void gba_flash_writeAtmel(char* buffer, unsigned int length) { 155 | int i, j; 156 | 157 | //pull GBA_CS2 pin low while we write data 158 | egpio_writePort(EX_GPIO_PORTD, _1(GBA_CS + GBA_WR) & _0(GBA_CS2 + GBA_CLK + GBA_PWR)); 159 | 160 | for(i = 0; i < length; i += 128) { 161 | 162 | //write the bus cycles for sector program 163 | gba_flash_writeBus(0x5555, 0xAA); 164 | gba_flash_writeBus(0x2AAA, 0x55); 165 | gba_flash_writeBus(0x5555, 0xA0); 166 | for (j = 0; j < 128; j++) { 167 | gba_flash_writeBus(i + j, buffer[i]); 168 | } 169 | gba_cart_delay(2000000); //20ms 170 | } 171 | } 172 | 173 | // Writes to the Flash memory of a connected GBA cartridge (other manufacturer) 174 | static void gba_flash_writeOther(char* buffer, unsigned int length) { 175 | int i; 176 | 177 | //pull GBA_CS2 pin low while we write data 178 | egpio_writePort(EX_GPIO_PORTD, _1(GBA_CS + GBA_WR) & _0(GBA_CS2 + GBA_CLK + GBA_PWR)); 179 | 180 | //cap the num data to read if we need to bank switch later 181 | unsigned int numWrites = length; 182 | if(numWrites > GBA_SAVE_SIZE_512K) numWrites = GBA_SAVE_SIZE_512K; 183 | for(i = 0; i < numWrites; i += 0x1000) { 184 | 185 | //write the bus cycles for sector erase 186 | gba_flash_writeBus(0x5555, 0xAA); 187 | gba_flash_writeBus(0x2AAA, 0x55); 188 | gba_flash_writeBus(0x5555, 0x80); 189 | gba_flash_writeBus(0x5555, 0xAA); 190 | gba_flash_writeBus(0x2AAA, 0x55); 191 | gba_flash_writeBus(i, 0x30); 192 | gba_cart_delay(10000000); //25ms (100ms to be safe) 193 | } 194 | for(i = 0; i < numWrites; i++) { 195 | 196 | //write the bus cycles for byte program 197 | gba_flash_writeBus(0x5555, 0xAA); 198 | gba_flash_writeBus(0x2AAA, 0x55); 199 | gba_flash_writeBus(0x5555, 0xA0); 200 | gba_flash_writeBus(i, buffer[i]); 201 | gba_cart_delay(700); //7us (20us between each WR pulse) 202 | } 203 | 204 | //bank switch if there's still more to write 205 | if(length > GBA_SAVE_SIZE_512K) { 206 | 207 | //switch to bank 1 208 | gba_flash_writeBus(0x5555, 0xAA); 209 | gba_flash_writeBus(0x2AAA, 0x55); 210 | gba_flash_writeBus(0x5555, 0xB0); 211 | gba_flash_writeBus(0x0000, 0x01); 212 | gba_cart_delay(500000); //5ms 213 | 214 | //write the rest of the data 215 | numWrites = length - GBA_SAVE_SIZE_512K; 216 | for(i = 0; i < numWrites; i += 0x1000) { 217 | 218 | //write the bus cycles for sector erase 219 | gba_flash_writeBus(0x5555, 0xAA); 220 | gba_flash_writeBus(0x2AAA, 0x55); 221 | gba_flash_writeBus(0x5555, 0x80); 222 | gba_flash_writeBus(0x5555, 0xAA); 223 | gba_flash_writeBus(0x2AAA, 0x55); 224 | gba_flash_writeBus(i, 0x30); 225 | gba_cart_delay(10000000); //25ms (100ms to be safe) 226 | } 227 | for(i = 0; i < numWrites; i++) { 228 | 229 | //write the bus cycles for byte program 230 | gba_flash_writeBus(0x5555, 0xAA); 231 | gba_flash_writeBus(0x2AAA, 0x55); 232 | gba_flash_writeBus(0x5555, 0xA0); 233 | gba_flash_writeBus(i, buffer[GBA_SAVE_SIZE_512K + i]); 234 | gba_cart_delay(700); //7us (20us between each WR pulse) 235 | } 236 | 237 | //switch back to bank 0 238 | gba_flash_writeBus(0x5555, 0xAA); 239 | gba_flash_writeBus(0x2AAA, 0x55); 240 | gba_flash_writeBus(0x5555, 0xB0); 241 | gba_flash_writeBus(0x0000, 0x00); 242 | gba_cart_delay(500000); //5ms 243 | } 244 | } 245 | 246 | // Write a bus cycle to flash 247 | static void gba_flash_writeBus(int address, char data) { 248 | egpio_writePortAB((char) address, (char) (address >> 8)); 249 | egpio_writePort(EX_GPIO_PORTC, data); 250 | 251 | egpio_writePort(EX_GPIO_PORTD, _1(GBA_CS) & _0(GBA_WR + GBA_CS2 + GBA_CLK + GBA_PWR)); 252 | egpio_writePort(EX_GPIO_PORTD, _1(GBA_CS + GBA_WR) & _0(GBA_CS2 + GBA_CLK + GBA_PWR)); 253 | } 254 | -------------------------------------------------------------------------------- /source/core/gba/gba_flash.h: -------------------------------------------------------------------------------- 1 | #ifndef GBA_FLASH_H 2 | #define GBA_FLASH_H 3 | 4 | #define GBA_FLASH_MANUFACTURER_ATMEL 0x00 5 | #define GBA_FLASH_MANUFACTURER_OTHER 0x01 6 | #define GBA_FLASH_MANUFACTURER_UNKNOWN 0x03 7 | 8 | // Reads the Flash of a connected GBA cartridge 9 | void gba_flash_read(char* buffer, unsigned int length); 10 | 11 | // Reads the Flash from the given address of a connected GBA cartridge 12 | void gba_flash_readAt(char* buffer, unsigned int start, unsigned int length); 13 | 14 | // Writes to the Flash memory of a connected GBA cartridge 15 | void gba_flash_write(char* buffer, unsigned int length); 16 | 17 | // Reads the manufacturer code of the Flash chip 18 | char gba_flash_checkManufacturer(char* manufacturerId, char* deviceId); 19 | 20 | #endif /* GBA_FLASH_H */ 21 | -------------------------------------------------------------------------------- /source/core/gba/gba_rom.c: -------------------------------------------------------------------------------- 1 | #include "gba.h" 2 | #include "gba_cart.h" 3 | #include "gba_rom.h" 4 | #include "egpio.h" 5 | #include "spi.h" 6 | 7 | #define _1(x) (x) 8 | #define _0(x) ((unsigned char)~(x)) 9 | 10 | // Read the ROM of a connected GBA cartridge at the given start and length 11 | void gba_rom_readAt(char* buffer, unsigned int start, unsigned int length) 12 | { 13 | int i; 14 | char addr0 = (char) (start / 2); 15 | char addr1 = (char) ((start / 2) >> 8); 16 | char addr2 = (char) ((start / 2) >> 16); 17 | 18 | //ensure default state 19 | gba_cart_powerUp(); 20 | 21 | //pull GBA_CS low to latch the address 22 | egpio_writePortAll(addr0, addr1, addr2, _1(GBA_CS + GBA_WR + GBA_CS2) & _0(GBA_CLK + GBA_PWR)); 23 | egpio_writePort(EX_GPIO_PORTD, _1(GBA_WR + GBA_CS2) & _0(GBA_CS + GBA_CLK + GBA_PWR)); 24 | 25 | //set data pins as inputs now 26 | egpio_setPortDirAB(0xFF, 0xFF); 27 | 28 | //read all ROM data 29 | egpio_continuousReadAB_start(); 30 | for(i = 0; i < length; i += 2) { 31 | 32 | //pull RD pin low while we read data 33 | spi_writeGPIO(GBA_GPIO_RD, 0x00); 34 | egpio_continuousReadAB_cont(buffer+i); 35 | spi_writeGPIO(GBA_GPIO_RD, 0x01); 36 | } 37 | egpio_continuousReadAB_end(); 38 | 39 | //pull GBA_CS back to high 40 | egpio_writePort(EX_GPIO_PORTD, _1(GBA_CS + GBA_WR + GBA_CS2) & _0(GBA_CLK + GBA_PWR)); 41 | spi_writeGPIO(GBA_GPIO_RD, 0x01); 42 | } 43 | 44 | // Try to figure out the connected GBA cartridge ROM size 45 | int gba_rom_determineSize() 46 | { 47 | //note: based on the assumption that the rom chips internal counter rolls back to zero (the header) 48 | int i, match; 49 | char buffer[200]; 50 | 51 | //read header 52 | char header[192]; 53 | gba_rom_readAt(header, 0x00, 192); 54 | 55 | //4MB? 56 | match = 1; 57 | gba_rom_readAt(buffer, GBA_ROM_SIZE_4MB - 8, 200); 58 | for(i = 0; i < 192; i++) { 59 | if(buffer[i + 8] != header[i]) { 60 | match = 0; 61 | break; 62 | } 63 | } 64 | if(match == 1) return GBA_ROM_SIZE_4MB; 65 | 66 | //8MB? 67 | match = 1; 68 | gba_rom_readAt(buffer, GBA_ROM_SIZE_8MB - 8, 200); 69 | for(i = 0; i < 192; i++) { 70 | if(buffer[i + 8] != header[i]) { 71 | match = 0; 72 | break; 73 | } 74 | } 75 | if(match == 1) return GBA_ROM_SIZE_8MB; 76 | 77 | //16MB? 78 | match = 1; 79 | gba_rom_readAt(buffer, GBA_ROM_SIZE_16MB - 8, 200); 80 | for(i = 0; i < 192; i++) { 81 | if(buffer[i + 8] != header[i]) { 82 | match = 0; 83 | break; 84 | } 85 | } 86 | if(match == 1) return GBA_ROM_SIZE_16MB; 87 | 88 | return GBA_ROM_SIZE_32MB; 89 | } 90 | -------------------------------------------------------------------------------- /source/core/gba/gba_rom.h: -------------------------------------------------------------------------------- 1 | #ifndef GBA_ROM_H 2 | #define GBA_ROM_H 3 | 4 | #define GBA_ROM_SIZE_4MB 4194304 5 | #define GBA_ROM_SIZE_8MB 8388608 6 | #define GBA_ROM_SIZE_16MB 16777216 7 | #define GBA_ROM_SIZE_32MB 33554432 8 | 9 | // Read the ROM of a connected GBA cartridge at the given start and length 10 | void gba_rom_readAt(char* buffer, unsigned int start, unsigned int length); 11 | 12 | // Try to figure out the connected GBA cartridge ROM size 13 | int gba_rom_determineSize(); 14 | 15 | #endif /* GBA_ROM_H */ 16 | -------------------------------------------------------------------------------- /source/core/gba/gba_save.c: -------------------------------------------------------------------------------- 1 | #include "gba.h" 2 | #include "gba_sram.h" 3 | #include "gba_flash.h" 4 | #include "gba_eeprom.h" 5 | #include "gba_save.h" 6 | 7 | // Leniency percentages for adhering to save type check assumptions 8 | #define LENIENCY_EEPROM_CHECK 97 9 | #define LENIENCY_FLASH_OR_SRAM_CHECK 95 10 | #define LENIENCY_SRAM_CHECK 95 11 | #define LENIENCY_FLASH_CHECK 95 12 | 13 | // Helper functions 14 | static char gba_save_checkHasFlashOrSRAM(); 15 | static int gba_save_checkSRAM(); 16 | static int gba_save_checkFlash(); 17 | static int gba_save_checkEEPROM(); 18 | 19 | // Util functions 20 | static char gba_save_countBits(char byte); 21 | static char gba_save_countDiff(char byte0, char byte1); 22 | 23 | // Try to figure out the connected GBA cartridge Save type and size 24 | int gba_save_determineType() 25 | { 26 | int i; 27 | 28 | //has eeprom? 29 | int eeprom = gba_save_checkEEPROM(); 30 | if(eeprom > 0) return eeprom; 31 | 32 | //has sram/flash? 33 | if(gba_save_checkHasFlashOrSRAM() == 1) { 34 | 35 | //has sram? 36 | int sram = gba_save_checkSRAM(); 37 | if(sram > 0) return sram; 38 | 39 | //has flash? 40 | int flash = gba_save_checkFlash(); 41 | if(flash > 0) return flash; 42 | } 43 | 44 | return GBA_SAVE_TYPE_UNKNOWN; 45 | } 46 | 47 | // Checks if the connected GBA cartridge contains an SRAM or Flash chip 48 | static char gba_save_checkHasFlashOrSRAM() { 49 | //note: based on the assumption that if no sram or flash is connected we will just get zeros 50 | int i, j, margin; 51 | 52 | //check for the existence of data 53 | char buffer[64]; 54 | for(i = 0; i < 128; i++) { 55 | gba_flash_readAt(buffer, i * (GBA_SAVE_SIZE_512K / 128), 64); 56 | int numBits = 0; 57 | for(j = 0; j < 64; j++) { 58 | numBits += gba_save_countBits(buffer[j]); 59 | } 60 | margin = ((64 * 8) * (100 - LENIENCY_FLASH_OR_SRAM_CHECK)) / 100; 61 | if(numBits > margin) return 1; 62 | } 63 | 64 | return 0; 65 | } 66 | 67 | // Checks if the connected GBA cartridge contains an SRAM chip and returns its size 68 | static int gba_save_checkSRAM() { 69 | //note: based on the assumption that we can successfully write and read a byte 70 | //note: size is based on the assumption that sram read past size will start repeating 71 | int i, margin; 72 | 73 | //read first byte 74 | char buffer[64]; 75 | gba_sram_readAt(buffer, 0, 1); 76 | 77 | //try to write the inverse 78 | buffer[1] = ~buffer[0]; 79 | gba_sram_write(buffer + 1, 1); 80 | 81 | //read first byte again and check if it changed 82 | gba_sram_readAt(buffer + 2, 0, 1); 83 | if(buffer[2] == buffer[0]) return GBA_SAVE_TYPE_UNKNOWN; 84 | 85 | //correct the byte we wrote over and check for successfull write 86 | gba_sram_write(buffer, 1); 87 | if(buffer[2] != buffer[1]) return GBA_SAVE_TYPE_UNKNOWN; 88 | 89 | //determine the size 90 | char start[64]; 91 | int diffBits = 0; 92 | gba_sram_readAt(start, 0, 64); 93 | gba_sram_readAt(buffer, GBA_SAVE_SIZE_256K, 64); 94 | for(i = 0; i < 64; i++) diffBits += gba_save_countDiff(start[i], buffer[i]); 95 | gba_sram_readAt(start, GBA_SAVE_SIZE_256K - 64, 64); 96 | gba_sram_readAt(buffer, GBA_SAVE_SIZE_512K - 64, 64); 97 | for(i = 0; i < 64; i++) diffBits += gba_save_countDiff(start[i], buffer[i]); 98 | margin = ((128 * 8) * (100 - LENIENCY_SRAM_CHECK)) / 100; 99 | if(diffBits < margin) return GBA_SAVE_TYPE_SRAM_256K; 100 | 101 | return GBA_SAVE_TYPE_SRAM_512K; 102 | } 103 | 104 | // Checks if the connected GBA cartridge contains a Flash chip and returns its size 105 | static int gba_save_checkFlash() { 106 | //note: based on the assumption of known manufacturer and device id sizes 107 | //note: size is based on the assumption that flash read past size will start repeating 108 | int i, margin; 109 | 110 | //get manufacturer and device to check 111 | char manufacturerId, deviceId; 112 | char flashManufacturer = gba_flash_checkManufacturer(&manufacturerId, &deviceId); 113 | if(manufacturerId == 0xBF && deviceId == 0xD4) return GBA_SAVE_TYPE_FLASH_512K; 114 | if(manufacturerId == 0x1F && deviceId == 0x3D) return GBA_SAVE_TYPE_FLASH_512K; 115 | if(manufacturerId == 0xC2 && deviceId == 0x1C) return GBA_SAVE_TYPE_FLASH_512K; 116 | if(manufacturerId == 0x32 && deviceId == 0x1B) return GBA_SAVE_TYPE_FLASH_512K; 117 | if(manufacturerId == 0xC2 && deviceId == 0x09) return GBA_SAVE_TYPE_FLASH_1M; 118 | if(manufacturerId == 0x62 && deviceId == 0x13) return GBA_SAVE_TYPE_FLASH_1M; 119 | 120 | //backup method to determine size (check start and end of sections for repeat) 121 | char start[64]; 122 | char buffer[64]; 123 | int diffBits = 0; 124 | gba_flash_readAt(start, 0, 64); 125 | gba_flash_readAt(buffer, GBA_SAVE_SIZE_512K, 64); 126 | for(i = 0; i < 64; i++) diffBits += gba_save_countDiff(start[i], buffer[i]); 127 | gba_flash_readAt(start, GBA_SAVE_SIZE_512K - 64, 64); 128 | gba_flash_readAt(buffer, GBA_SAVE_SIZE_1M - 64, 64); 129 | for(i = 0; i < 64; i++) diffBits += gba_save_countDiff(start[i], buffer[i]); 130 | margin = ((128 * 8) * (100 - LENIENCY_FLASH_CHECK)) / 100; 131 | if(diffBits < margin) return GBA_SAVE_TYPE_FLASH_512K; 132 | 133 | return GBA_SAVE_TYPE_FLASH_1M; 134 | } 135 | 136 | // Checks if the connected GBA cartridge contains an EEPROM chip and returns its size 137 | static int gba_save_checkEEPROM() { 138 | //note: based on the assumption that a cartridge without eeprom will return all 0s or 1s when trying to be read as such 139 | //note: size is based on assumption that a 4k read like a 64k just repeats the same eight bytes 140 | int i, j, margin; 141 | 142 | //get data to analyze 143 | int bufferSize = GBA_SAVE_SIZE_4K + 8; 144 | char buffer[GBA_SAVE_SIZE_4K + 8]; 145 | gba_eeprom_read(buffer, bufferSize); 146 | 147 | //has eeprom? (not all 0x00 or 0xFF with a bit of leniency) 148 | int numBits = 0; 149 | for(i = 0; i < bufferSize; i++) { 150 | numBits += gba_save_countBits(buffer[i]); 151 | } 152 | margin = ((bufferSize * 8) * LENIENCY_EEPROM_CHECK) / 100; 153 | if(numBits > margin || numBits < (bufferSize * 8) - margin) return 0; 154 | 155 | //actually 4k? 156 | int diffBits = 0; 157 | for(i=8; i < bufferSize; i += 8) { 158 | for(j = 0; j < 8; j++) { 159 | diffBits += gba_save_countDiff(buffer[i + j], buffer[(i + j) - 8]); 160 | } 161 | } 162 | margin = (((bufferSize - 8) * 8) * (100 - LENIENCY_EEPROM_CHECK)) / 100; 163 | if(diffBits < margin) return GBA_SAVE_TYPE_EEPROM_4K; 164 | 165 | return GBA_SAVE_TYPE_EEPROM_64K; 166 | } 167 | 168 | // Counts the number of 1s in the given byte 169 | static char gba_save_countBits(char byte) { 170 | char i, count = 0; 171 | for(i = 0; i < 8; i++) 172 | if((byte >> i) & 0x01 == 0x01) count++; 173 | return count; 174 | } 175 | 176 | // Counts the number of differences between the two given bytes 177 | static char gba_save_countDiff(char byte0, char byte1) { 178 | char i, count = 0; 179 | for(i = 0; i < 8; i++) { 180 | char mask = 0x01 << i; 181 | if((byte0 & mask) != (byte1 & mask)) count++; 182 | } 183 | return count; 184 | } 185 | -------------------------------------------------------------------------------- /source/core/gba/gba_save.h: -------------------------------------------------------------------------------- 1 | #ifndef GBA_SAVE_H 2 | #define GBA_SAVE_H 3 | 4 | #define GBA_SAVE_SIZE_4K 512 5 | #define GBA_SAVE_SIZE_64K 8192 6 | #define GBA_SAVE_SIZE_256K 32768 7 | #define GBA_SAVE_SIZE_512K 65536 8 | #define GBA_SAVE_SIZE_1M 131072 9 | 10 | // Try to figure out the connected GBA cartridge Save type and size 11 | int gba_save_determineType(); 12 | 13 | #endif /* GBA_SAVE_H */ 14 | -------------------------------------------------------------------------------- /source/core/gba/gba_sram.c: -------------------------------------------------------------------------------- 1 | #include "gba.h" 2 | #include "gba_cart.h" 3 | #include "gba_save.h" 4 | #include "gba_sram.h" 5 | #include "egpio.h" 6 | #include "spi.h" 7 | 8 | #define _1(x) (x) 9 | #define _0(x) ((unsigned char)~(x)) 10 | 11 | // Reads the SRAM of a connected GBA cartridge 12 | void gba_sram_read(char* buffer, unsigned int length) 13 | { 14 | gba_sram_readAt(buffer, 0, length); 15 | } 16 | 17 | // Reads the SRAM from the given address of a connected GBA cartridge 18 | void gba_sram_readAt(char* buffer, unsigned int start, unsigned int length) 19 | { 20 | int i; 21 | 22 | //ensure default state 23 | gba_cart_powerUp(); 24 | 25 | //pull GBA_CS2 pin low while we read data 26 | egpio_writePort(EX_GPIO_PORTD, _1(GBA_CS + GBA_WR) & _0(GBA_CS2 + GBA_CLK + GBA_PWR)); 27 | 28 | //read the data 29 | egpio_setPortDir(EX_GPIO_PORTC, 0xFF); 30 | if(start >= GBA_SAVE_SIZE_512K) start -= GBA_SAVE_SIZE_512K; 31 | if(length > GBA_SAVE_SIZE_512K) length = GBA_SAVE_SIZE_512K; 32 | for(i = 0; i < length; i++) { 33 | 34 | //set the address 35 | unsigned int address = start + i; 36 | egpio_writePortAB((char) address, (char) (address >> 8)); 37 | 38 | //pull RD pin low while we read data 39 | spi_writeGPIO(GBA_GPIO_RD, 0x00); 40 | buffer[i] = egpio_readPort(EX_GPIO_PORTC); 41 | spi_writeGPIO(GBA_GPIO_RD, 0x01); 42 | } 43 | 44 | //pull RD and GBA_CS2 back to high 45 | egpio_writePort(EX_GPIO_PORTD, _1(GBA_CS + GBA_WR + GBA_CS2) & _0(GBA_CLK + GBA_PWR)); 46 | spi_writeGPIO(GBA_GPIO_RD, 0x01); 47 | } 48 | 49 | // Writes to the SRAM of a connected GBA cartridge 50 | void gba_sram_write(char* buffer, unsigned int length) 51 | { 52 | int i; 53 | 54 | //ensure default state 55 | gba_cart_powerUp(); 56 | 57 | //pull GBA_CS2 pin low while we write data 58 | egpio_writePort(EX_GPIO_PORTD, _1(GBA_CS + GBA_WR) & _0(GBA_CS2 + GBA_CLK + GBA_PWR)); 59 | for(i = 0; i < length; i++) { 60 | 61 | //set the address and data 62 | egpio_writePortAB((char) i, (char) (i >> 8)); 63 | egpio_writePort(EX_GPIO_PORTC, buffer[i]); 64 | 65 | //pull WR pin low to write data 66 | egpio_writePort(EX_GPIO_PORTD, _1(GBA_CS) & _0(GBA_WR + GBA_CS2 + GBA_CLK + GBA_PWR)); 67 | gba_cart_delay(100); //1us 68 | egpio_writePort(EX_GPIO_PORTD, _1(GBA_CS + GBA_WR) & _0(GBA_CS2 + GBA_CLK + GBA_PWR)); 69 | } 70 | 71 | //pull WR and GBA_CS2 back to high 72 | egpio_writePort(EX_GPIO_PORTD, _1(GBA_CS + GBA_WR + GBA_CS2) & _0(GBA_CLK + GBA_PWR)); 73 | spi_writeGPIO(GBA_GPIO_RD, 0x01); 74 | } 75 | -------------------------------------------------------------------------------- /source/core/gba/gba_sram.h: -------------------------------------------------------------------------------- 1 | #ifndef GBA_SRAM_H 2 | #define GBA_SRAM_H 3 | 4 | // Reads the SRAM of a connected GBA cartridge 5 | void gba_sram_read(char* buffer, unsigned int length); 6 | 7 | // Reads the SRAM from the given address of a connected GBA cartridge 8 | void gba_sram_readAt(char* buffer, unsigned int start, unsigned int length); 9 | 10 | // Writes to the SRAM of a connected GBA cartridge 11 | void gba_sram_write(char* buffer, unsigned int length); 12 | 13 | #endif /* GBA_SRAM_H */ 14 | -------------------------------------------------------------------------------- /source/core/gbc/gbc.c: -------------------------------------------------------------------------------- 1 | #include "gbc.h" 2 | #include "gbc_cart.h" 3 | #include "gbc_rom.h" 4 | #include "gbc_mbc1.h" 5 | #include "gbc_mbc2.h" 6 | #include "gbc_mbc3.h" 7 | #include "gbc_mbc5.h" 8 | #include 9 | #include 10 | #include "egpio.h" 11 | 12 | #define GBC_CT_ROMONLY 0x00 13 | #define GBC_CT_MBC1 0x01 14 | #define GBC_CT_MBC1_RAM 0x02 15 | #define GBC_CT_MBC1_RAM_BAT 0x03 16 | #define GBC_CT_MBC2 0x05 17 | #define GBC_CT_MBC2_BAT 0x06 18 | #define GBC_CT_ROM_RAM 0x08 19 | #define GBC_CT_ROM_RAM_BAT 0x09 20 | #define GBC_CT_MMM01 0x0B 21 | #define GBC_CT_MMM01_RAM 0x0C 22 | #define GBC_CT_MMM01_RAM_BAT 0x0D 23 | #define GBC_CT_MBC3_TMR_BAT 0x0F 24 | #define GBC_CT_MBC3_TMR_RAM_BAT 0x10 25 | #define GBC_CT_MBC3 0x11 26 | #define GBC_CT_MBC3_RAM 0x12 27 | #define GBC_CT_MBC3_RAM_BAT 0x13 28 | #define GBC_CT_MBC5 0x19 29 | #define GBC_CT_MBC5_RAM 0x1A 30 | #define GBC_CT_MBC5_RAM_BAT 0x1B 31 | #define GBC_CT_MBC5_RMBL 0x1C 32 | #define GBC_CT_MBC5_RMBL_RAM 0x1D 33 | #define GBC_CT_MBC5_RMBL_RAM_BAT 0x1E 34 | #define GBC_CT_MBC6 0x20 35 | #define GBC_CT_MBC7_SNSR_RMBL_RAM_BAT 0x22 36 | #define GBC_CT_HuC3 0xFE 37 | #define GBC_CT_HuC1_RAM_BAT 0xFF 38 | 39 | //TODOs: 40 | //-Support MBC6, MBC7, MMM01, HuC3, HuC1 41 | 42 | // Constants 43 | static const char gbc_nintendoLogo[] = { 44 | 0xCE, 0xED, 0x66, 0x66, 0xCC, 0x0D, 0x00, 0x0B, 0x03, 0x73, 0x00, 0x83, 0x00, 0x0C, 0x00, 0x0D, 45 | 0x00, 0x08, 0x11, 0x1F, 0x88, 0x89, 0x00, 0x0E, 0xDC, 0xCC, 0x6E, 0xE6, 0xDD, 0xDD, 0xD9, 0x99, 46 | 0xBB, 0xBB, 0x67, 0x63, 0x6E, 0x0E, 0xEC, 0xCC, 0xDD, 0xDC, 0x99, 0x9F, 0xBB, 0xB9, 0x33, 0x3E 47 | }; 48 | 49 | // Data 50 | static char gbc_isInitFlag = 0; 51 | static char gbc_loaded = 0; 52 | static char gbc_gameTitle[17]; 53 | static char gbc_gameSHA1[41]; 54 | static char gbc_flagCGB; 55 | static char gbc_memController; 56 | static unsigned int gbc_romSize; 57 | static unsigned int gbc_saveSize; 58 | 59 | // Helper functions 60 | static unsigned int gbc_readROMNoMemCtrl(char* buffer, unsigned int length); 61 | static unsigned int gbc_readRAMNoMemCtrl(char* buffer, unsigned int length); 62 | static unsigned int gbc_writeRAMNoMemCtrl(char* buffer, unsigned int length); 63 | static char gbc_verifyLoaded(); 64 | static void gbc_clearData(); 65 | 66 | // Util functions 67 | static void gbc_cleanString(char* str); 68 | 69 | // Setup and initialize the GB utils 70 | int gbc_init() 71 | { 72 | //already initialized? 73 | if(gbc_isInitFlag == 1) return 0; 74 | 75 | //check dependencies 76 | if(!egpio_isInit()) { 77 | fprintf(stderr, "gbc_init: eGPIO dependency is not initialized\n"); 78 | gbc_close(); 79 | return 1; 80 | } 81 | 82 | //configure pins 83 | gbc_cart_powerDown(); 84 | 85 | //init data 86 | gbc_clearData(); 87 | 88 | gbc_isInitFlag = 1; 89 | return 0; 90 | } 91 | 92 | // Checks if the GB utils are initialized 93 | char gbc_isInit() 94 | { 95 | return gbc_isInitFlag; 96 | } 97 | 98 | // Gets the header of a connected GB cartridge 99 | char gbc_loadHeader() 100 | { 101 | int i; 102 | 103 | //wake up cartridge with a few reads (some seem to need it) 104 | char data[1024]; 105 | gbc_rom_readAt(data, 0x00, 4); 106 | 107 | //read header 108 | gbc_rom_readAt(data, 0x00, 1024); 109 | char* header = &(data[0x100]); 110 | 111 | //verify header checksum 112 | unsigned char chk=0; 113 | for(i=0x34; i<0x4D; i++) chk = chk - header[i]; 114 | chk = chk - 0x19; 115 | if(header[0x4D] != chk) { 116 | //power down the cart slot 117 | gbc_cart_powerDown(); 118 | gbc_clearData(); 119 | return gbc_loaded; 120 | } 121 | 122 | //extract general data from header 123 | for(i = 0; i < 16; i++) gbc_gameTitle[i] = header[0x34 + i]; 124 | 125 | //check for CGB flag 126 | if((gbc_gameTitle[15] & 0x80) == 0x80) { 127 | if((gbc_gameTitle[15] & 0xC0) == 0xC0) gbc_flagCGB = GBC_FLAG_CGB_ONLY; 128 | else gbc_flagCGB = GBC_FLAG_CGB_COMPATIBLE; 129 | gbc_gameTitle[15] = 0; 130 | } else { 131 | gbc_flagCGB = GBC_FLAG_CGB_UNSUPPORTED; 132 | } 133 | 134 | //clean game title 135 | gbc_cleanString(gbc_gameTitle); 136 | 137 | //determine memory controller 138 | if(header[0x47]==GBC_CT_MBC1 || header[0x47]==GBC_CT_MBC1_RAM || header[0x47]==GBC_CT_MBC1_RAM_BAT) { 139 | gbc_memController = GBC_MEM_CTRL_MBC1; 140 | 141 | } else if(header[0x47]==GBC_CT_MBC2 || header[0x47]==GBC_CT_MBC2_BAT) { 142 | gbc_memController = GBC_MEM_CTRL_MBC2; 143 | 144 | } else if(header[0x47]==GBC_CT_MBC3_TMR_BAT || header[0x47]==GBC_CT_MBC3_TMR_RAM_BAT || header[0x47]==GBC_CT_MBC3 145 | || header[0x47]==GBC_CT_MBC3_RAM || header[0x47]==GBC_CT_MBC3_RAM_BAT) { 146 | gbc_memController = GBC_MEM_CTRL_MBC3; 147 | 148 | } else if(header[0x47]==GBC_CT_MBC5 || header[0x47]==GBC_CT_MBC5_RAM || header[0x47]==GBC_CT_MBC5_RAM_BAT 149 | || header[0x47]==GBC_CT_MBC5_RMBL || header[0x47]==GBC_CT_MBC5_RMBL_RAM || header[0x47]==GBC_CT_MBC5_RMBL_RAM_BAT) { 150 | gbc_memController = GBC_MEM_CTRL_MBC5; 151 | 152 | } else if(header[0x47]==GBC_CT_MMM01 || header[0x47]==GBC_CT_MMM01_RAM || header[0x47]==GBC_CT_MMM01_RAM_BAT) { 153 | gbc_memController = GBC_MEM_CTRL_NONE; //not yet supported 154 | 155 | } else if(header[0x47]==GBC_CT_MBC6) { 156 | gbc_memController = GBC_MEM_CTRL_NONE; //not yet supported 157 | 158 | } else if(header[0x47]==GBC_CT_MBC7_SNSR_RMBL_RAM_BAT) { 159 | gbc_memController = GBC_MEM_CTRL_NONE; //not yet supported 160 | 161 | } else if(header[0x47]==GBC_CT_HuC1_RAM_BAT) { 162 | gbc_memController = GBC_MEM_CTRL_NONE; //not yet supported 163 | 164 | } else if(header[0x47]==GBC_CT_HuC3) { 165 | gbc_memController = GBC_MEM_CTRL_NONE; //not yet supported 166 | 167 | } else { 168 | gbc_memController = GBC_MEM_CTRL_NONE; 169 | } 170 | 171 | //determine rom size 172 | if(header[0x48] == 0x01) gbc_romSize = GBC_64K; 173 | else if(header[0x48] == 0x02) gbc_romSize = GBC_128K; 174 | else if(header[0x48] == 0x03) gbc_romSize = GBC_256K; 175 | else if(header[0x48] == 0x04) gbc_romSize = GBC_512K; 176 | else if(header[0x48] == 0x05) gbc_romSize = GBC_1M; 177 | else if(header[0x48] == 0x06) gbc_romSize = GBC_2M; 178 | else if(header[0x48] == 0x07) gbc_romSize = GBC_4M; 179 | else if(header[0x48] == 0x08) gbc_romSize = GBC_8M; 180 | else if(header[0x48] == 0x52) gbc_romSize = GBC_1p1M; 181 | else if(header[0x48] == 0x53) gbc_romSize = GBC_1p2M; 182 | else if(header[0x48] == 0x54) gbc_romSize = GBC_1p5M; 183 | else gbc_romSize = GBC_32K; 184 | 185 | //determine save size 186 | if(header[0x47]==GBC_CT_MBC1_RAM_BAT || header[0x47]==GBC_CT_ROM_RAM_BAT || header[0x47]==GBC_CT_MMM01_RAM_BAT 187 | || header[0x47]==GBC_CT_MBC3_TMR_RAM_BAT || header[0x47]==GBC_CT_MBC3_RAM_BAT || header[0x47]==GBC_CT_MBC5_RAM_BAT 188 | || header[0x47]==GBC_CT_MBC5_RMBL_RAM_BAT || header[0x47]==GBC_CT_MBC7_SNSR_RMBL_RAM_BAT || header[0x47]==GBC_CT_HuC1_RAM_BAT) { 189 | if(header[0x49] == 0x01) gbc_saveSize = GBC_2K; 190 | else if(header[0x49] == 0x02) gbc_saveSize = GBC_8K; 191 | else if(header[0x49] == 0x03) gbc_saveSize = GBC_32K; 192 | else if(header[0x49] == 0x04) gbc_saveSize = GBC_128K; 193 | else if(header[0x49] == 0x05) gbc_saveSize = GBC_64K; 194 | else gbc_saveSize = 0; 195 | } else { 196 | gbc_saveSize = 0; 197 | } 198 | 199 | //calculate sha1 hash of first 1k bytes 200 | unsigned char sha1_1k[20]; 201 | SHA1((unsigned char*)data, 1024, sha1_1k); 202 | for(i=0; i<20; i++) sprintf(&(gbc_gameSHA1[i*2]), "%02X", sha1_1k[i]); 203 | gbc_gameSHA1[40] = 0; 204 | 205 | //power down the cart slot 206 | gbc_cart_powerDown(); 207 | 208 | gbc_loaded = 1; 209 | return gbc_loaded; 210 | } 211 | 212 | // Clears all loaded data for the connected GB cartridge 213 | void gbc_loadClear() 214 | { 215 | gbc_clearData(); 216 | } 217 | 218 | // Checks if a GB cartridge is currently connected and loaded 219 | char gbc_isLoaded() 220 | { 221 | gbc_verifyLoaded(); 222 | 223 | //power down the cart slot 224 | gbc_cart_powerDown(); 225 | return gbc_loaded; 226 | } 227 | 228 | // Gets the game title of the loaded GB cartridge 229 | char* gbc_getGameTitle() 230 | { 231 | return gbc_gameTitle; 232 | } 233 | 234 | // Gets the game sha1 hash for the first 1k of rom of the loaded GB cartridge 235 | char* gbc_getGameSHA1() 236 | { 237 | return gbc_gameSHA1; 238 | } 239 | 240 | // Gets the CGB flag of the loaded GB cartridge 241 | char gbc_getCGBFlag() 242 | { 243 | return gbc_flagCGB; 244 | } 245 | 246 | // Gets the memory controller type of the loaded GB cartridge 247 | char gbc_getMemoryController() 248 | { 249 | return gbc_memController; 250 | } 251 | 252 | // Gets the ROM size of the loaded GB cartridge 253 | unsigned int gbc_getROMSize() 254 | { 255 | return gbc_romSize; 256 | } 257 | 258 | // Gets the Save size of the loaded GB cartridge 259 | unsigned int gbc_getSaveSize() 260 | { 261 | return gbc_saveSize; 262 | } 263 | 264 | // Read the ROM of a connected GB cartridge and returns the length 265 | int gbc_readROM(char* buffer, unsigned int length) 266 | { 267 | if(gbc_verifyLoaded() == 0) gbc_loadHeader(); 268 | if(gbc_loaded == 0) { 269 | //power down the cart slot 270 | gbc_cart_powerDown(); 271 | return GBC_ERROR_NO_CARTRIDGE; 272 | } 273 | 274 | if(length > gbc_romSize) length = gbc_romSize; 275 | if(length > 0) { 276 | if(gbc_memController == GBC_MEM_CTRL_MBC1) length = gbc_mbc1_readROM(buffer, length); 277 | else if(gbc_memController == GBC_MEM_CTRL_MBC2) length = gbc_mbc2_readROM(buffer, length); 278 | else if(gbc_memController == GBC_MEM_CTRL_MBC3) length = gbc_mbc3_readROM(buffer, length); 279 | else if(gbc_memController == GBC_MEM_CTRL_MBC5) length = gbc_mbc5_readROM(buffer, length); 280 | else length = gbc_readROMNoMemCtrl(buffer, length); 281 | } 282 | 283 | //power down the cart slot 284 | gbc_cart_powerDown(); 285 | return length; 286 | } 287 | 288 | // Read the Save Data of a connected GB cartridge and returns the size 289 | int gbc_readSave(char* buffer, unsigned int length) 290 | { 291 | if(gbc_verifyLoaded() == 0) gbc_loadHeader(); 292 | if(gbc_loaded == 0) { 293 | //power down the cart slot 294 | gbc_cart_powerDown(); 295 | return GBC_ERROR_NO_CARTRIDGE; 296 | } 297 | 298 | if(length > gbc_saveSize) length = gbc_saveSize; 299 | if(length > 0) { 300 | if(gbc_memController == GBC_MEM_CTRL_MBC1) length = gbc_mbc1_readRAM(buffer, length); 301 | else if(gbc_memController == GBC_MEM_CTRL_MBC3) length = gbc_mbc3_readRAM(buffer, length); 302 | else if(gbc_memController == GBC_MEM_CTRL_MBC5) length = gbc_mbc5_readRAM(buffer, length); 303 | else length = gbc_readRAMNoMemCtrl(buffer, length); 304 | } 305 | 306 | //power down the cart slot 307 | gbc_cart_powerDown(); 308 | return length; 309 | } 310 | 311 | // Write the Save Data to a connected GB cartridge 312 | int gbc_writeSave(char* buffer, unsigned int length) 313 | { 314 | if(gbc_loaded == 0) return GBC_ERROR_CARTRIDGE_NOT_LOADED; 315 | if(gbc_verifyLoaded() == 0) { 316 | gbc_loadHeader(); 317 | if(gbc_loaded == 1) return GBC_ERROR_CARTRIDGE_CHANGED; 318 | if(gbc_loaded == 0) return GBC_ERROR_NO_CARTRIDGE; 319 | } 320 | 321 | if(length > gbc_saveSize) length = gbc_saveSize; 322 | if(length > 0) { 323 | if(gbc_memController == GBC_MEM_CTRL_MBC1) length = gbc_mbc1_writeRAM(buffer, length); 324 | else if(gbc_memController == GBC_MEM_CTRL_MBC3) length = gbc_mbc3_writeRAM(buffer, length); 325 | else if(gbc_memController == GBC_MEM_CTRL_MBC5) length = gbc_mbc5_writeRAM(buffer, length); 326 | else length = gbc_writeRAMNoMemCtrl(buffer, length); 327 | } 328 | 329 | //power down the cart slot 330 | gbc_cart_powerDown(); 331 | return length; 332 | } 333 | 334 | // Dumps the first 400 bytes of the connected GB cartridge 335 | void gbc_dumpHeader(char* data) 336 | { 337 | gbc_rom_readAt(data, 0x00, 400); 338 | 339 | //power down the cart slot 340 | gbc_cart_powerDown(); 341 | } 342 | 343 | // Cleans up the GB utils 344 | int gbc_close() 345 | { 346 | gbc_isInitFlag = 0; 347 | return 0; 348 | } 349 | 350 | // Read ROM for No Memory Controller 351 | static unsigned int gbc_readROMNoMemCtrl(char* buffer, unsigned int length) { 352 | if(length > GBC_32K) length = GBC_32K; 353 | gbc_rom_readAt(buffer, 0x00, length); 354 | return length; 355 | } 356 | 357 | // Read RAM for No Memory Controller 358 | static unsigned int gbc_readRAMNoMemCtrl(char* buffer, unsigned int length) { 359 | if(length > GBC_32K) length = GBC_32K; 360 | gbc_rom_readAt(buffer, GBC_32K, length); 361 | return length; 362 | } 363 | 364 | // Write RAM for No Memory Controller 365 | static unsigned int gbc_writeRAMNoMemCtrl(char* buffer, unsigned int length) { 366 | if(length > GBC_32K) length = GBC_32K; 367 | gbc_rom_writeAt(buffer, GBC_32K, length); 368 | return length; 369 | } 370 | 371 | // Checks that the currently connected GB cartridge matches what is loaded 372 | static char gbc_verifyLoaded() { 373 | int i; 374 | 375 | //return early if not loaded at all 376 | if(gbc_loaded == 0) return 0; 377 | 378 | //read header 379 | char header[80]; 380 | gbc_rom_readAt(header, 0x100, 80); 381 | 382 | //verify header checksum 383 | unsigned char chk=0; 384 | for(i=0x34; i<0x4D; i++) chk = chk - header[i]; 385 | chk = chk - 0x19; 386 | if(header[0x4D] != chk) { 387 | gbc_clearData(); 388 | return gbc_loaded; 389 | } 390 | 391 | //extract general data from header 392 | char temp_gameTitle[17]; 393 | for(i = 0; i < 16; i++) temp_gameTitle[i] = header[0x34 + i]; 394 | 395 | //check for CGB flag 396 | char temp_flagCGB; 397 | if((temp_gameTitle[15] & 0x80) == 0x80) { 398 | if((temp_gameTitle[15] & 0xC0) == 0xC0) temp_flagCGB = GBC_FLAG_CGB_ONLY; 399 | else temp_flagCGB = GBC_FLAG_CGB_COMPATIBLE; 400 | temp_gameTitle[15] = 0; 401 | } else { 402 | temp_flagCGB = GBC_FLAG_CGB_UNSUPPORTED; 403 | } 404 | 405 | //clean game title 406 | gbc_cleanString(temp_gameTitle); 407 | 408 | //check that the game title and CGB flag match expected 409 | char verified = 1; 410 | for(i = 0; i < 16; i++) { 411 | if(gbc_gameTitle[i] != temp_gameTitle[i]) { 412 | verified = 0; 413 | break; 414 | } 415 | } 416 | if(gbc_flagCGB != temp_flagCGB) { 417 | verified = 0; 418 | } 419 | if(verified == 0) { 420 | gbc_clearData(); 421 | return gbc_loaded; 422 | } 423 | 424 | //all good 425 | return gbc_loaded; 426 | } 427 | 428 | // Clears loaded data 429 | static void gbc_clearData() { 430 | int i; 431 | 432 | gbc_loaded = 0; 433 | for(i = 0; i < 17; i++) gbc_gameTitle[i] = 0; 434 | gbc_flagCGB = GBC_FLAG_CGB_UNSUPPORTED; 435 | gbc_memController = GBC_MEM_CTRL_NONE; 436 | gbc_saveSize = 0; 437 | gbc_romSize = 0; 438 | } 439 | 440 | // Removes all invalid characters 441 | static void gbc_cleanString(char* str) { 442 | int i = 0; 443 | while(str[i]) { 444 | if(str[i] < 0x20) { 445 | str[i] = str[i+1]; 446 | } else { 447 | if(str[i] == 0x20) str[i] = '_'; 448 | i++; 449 | } 450 | } 451 | 452 | i--; 453 | while(str[i]) { 454 | if(str[i] == '_') str[i] = 0; 455 | else break; 456 | i--; 457 | } 458 | } 459 | -------------------------------------------------------------------------------- /source/core/gbc/gbc.h: -------------------------------------------------------------------------------- 1 | #ifndef GBC_H 2 | #define GBC_H 3 | 4 | #define GBC_FLAG_CGB_UNSUPPORTED 0 5 | #define GBC_FLAG_CGB_COMPATIBLE 1 6 | #define GBC_FLAG_CGB_ONLY 2 7 | 8 | #define GBC_MEM_CTRL_NONE 0 9 | #define GBC_MEM_CTRL_MBC1 1 10 | #define GBC_MEM_CTRL_MBC2 2 11 | #define GBC_MEM_CTRL_MBC3 3 12 | #define GBC_MEM_CTRL_MBC5 4 13 | 14 | #define GBC_ERROR_NO_CARTRIDGE -1 15 | #define GBC_ERROR_CARTRIDGE_CHANGED -2 16 | #define GBC_ERROR_CARTRIDGE_NOT_LOADED -3 17 | 18 | // Setup and initialize the GB utils 19 | int gbc_init(); 20 | 21 | // Checks if the GB utils are initialized 22 | char gbc_isInit(); 23 | 24 | // Loads the header and basic data of the connected GB cartridge 25 | char gbc_loadHeader(); 26 | 27 | // Clears all loaded data for the connected GB cartridge 28 | void gbc_loadClear(); 29 | 30 | // Checks if a GB cartridge is currently connected and loaded 31 | char gbc_isLoaded(); 32 | 33 | // Gets the game title of the loaded GB cartridge 34 | char* gbc_getGameTitle(); 35 | 36 | // Gets the game sha1 hash for the first 1k of rom of the loaded GB cartridge 37 | char* gbc_getGameSHA1(); 38 | 39 | // Gets the CGB flag of the loaded GB cartridge 40 | char gbc_getCGBFlag(); 41 | 42 | // Gets the memory controller type of the loaded GB cartridge 43 | char gbc_getMemoryController(); 44 | 45 | // Gets the ROM size of the loaded GB cartridge 46 | unsigned int gbc_getROMSize(); 47 | 48 | // Gets the Save size of the loaded GB cartridge 49 | unsigned int gbc_getSaveSize(); 50 | 51 | // Read the ROM of a connected GB cartridge and returns the size 52 | int gbc_readROM(char* buffer, unsigned int length); 53 | 54 | // Read the Save Data of a connected GB cartridge and returns the size 55 | int gbc_readSave(char* buffer, unsigned int length); 56 | 57 | // Write the Save Data to a connected GB cartridge 58 | int gbc_writeSave(char* buffer, unsigned int length); 59 | 60 | // Dumps the first 400 bytes of the connected GB cartridge 61 | void gbc_dumpHeader(char* data); 62 | 63 | // Cleans up the GB utils 64 | int gbc_close(); 65 | 66 | #endif /* GBC_H */ 67 | -------------------------------------------------------------------------------- /source/core/gbc/gbc_cart.c: -------------------------------------------------------------------------------- 1 | #include "gbc.h" 2 | #include "gbc_cart.h" 3 | #include "egpio.h" 4 | #include "spi.h" 5 | 6 | #define GBC_PWR_ON_DELAY 1000000 7 | #define _1(x) (x) 8 | #define _0(x) ((unsigned char)~(x)) 9 | 10 | // Data 11 | static char gbc_power = 0; 12 | 13 | // Powers up the cartridge slot to the null state 14 | void gbc_cart_powerUp() 15 | { 16 | //switch on power while setting pins to default state all pins 17 | egpio_setPortDirAll(0x00, 0x00, 0x00, _1(GBC_AUD + GBC_DTSW) | _0(GBC_CSRAM + GBC_WR + GBC_RST + GBC_CLK + GBC_PWR)); //default: 1 18 | egpio_writePortAll(0x00, 0x00, 0x00, _1(GBC_CSRAM + GBC_WR + GBC_RST) & _0(GBC_CLK + GBC_PWR)); //default: 0 19 | spi_writeGPIO(GBC_GPIO_RD, 0x01); 20 | 21 | //wait for things to power up 22 | if(gbc_power == 0) { 23 | gbc_cart_delay(GBC_PWR_ON_DELAY); 24 | gbc_power = 1; 25 | } 26 | } 27 | 28 | // Powers down the cartridge slot to an all ground state 29 | void gbc_cart_powerDown() 30 | { 31 | //disconnect pins 32 | egpio_setPortPullupAll(0x00, 0x00, 0x00, GBC_DTSW); 33 | egpio_setPortDirAll(0xFF, 0xFF, 0xFF, _1(GBC_CSRAM + GBC_WR + GBC_RST + GBC_CLK + GBC_AUD + GBC_DTSW) | _0(GBC_PWR)); //default: 1 34 | spi_setGPIODir(GBC_GPIO_RD, 0x01); 35 | 36 | //switch off power 37 | egpio_writePort(EX_GPIO_PORTD, _1(GBC_PWR)); 38 | 39 | //gnd all pins 40 | egpio_writePortAll(0x00, 0x00, 0x00, _1(GBC_PWR) & _0(GBC_CSRAM + GBC_WR + GBC_RST + GBC_CLK)); //default: 0 41 | spi_writeGPIO(GBC_GPIO_RD, 0x00); 42 | egpio_setPortDirAll(0x00, 0x00, 0x00, _1(GBC_AUD + GBC_DTSW) | _0(GBC_CSRAM + GBC_WR + GBC_RST + GBC_CLK + GBC_PWR)); //default: 1 43 | spi_setGPIODir(GBC_GPIO_RD, 0x00); 44 | gbc_power = 0; 45 | } 46 | 47 | // Delay function 48 | void gbc_cart_delay(int t) { 49 | volatile int i=0; 50 | for(;i> 5) & 0x03); 25 | gbc_rom_writeByte(bankNum0, 0x2000); 26 | gbc_rom_writeByte(bankNum1, 0x4000); 27 | 28 | //read more data 29 | unsigned int index = i * GBC_16K; 30 | gbc_rom_readAt(buffer + index, GBC_16K, GBC_16K); 31 | } 32 | 33 | //set back to bank 1 34 | gbc_rom_writeByte(0x01, 0x2000); 35 | gbc_rom_writeByte(0x00, 0x4000); 36 | 37 | return length; 38 | } 39 | 40 | // Read RAM for MBC1 Memory Controller 41 | unsigned int gbc_mbc1_readRAM(char* buffer, unsigned int length) 42 | { 43 | return gbc_mbc1_rwRAM(buffer, length, 0); 44 | } 45 | 46 | // Write RAM for MBC1 Memory Controller 47 | unsigned int gbc_mbc1_writeRAM(char* buffer, unsigned int length) 48 | { 49 | return gbc_mbc1_rwRAM(buffer, length, 1); 50 | } 51 | 52 | // Read RAM for MBC1 Memory Controller 53 | static unsigned int gbc_mbc1_rwRAM(char* buffer, unsigned int length, char isWrite) { 54 | int i; 55 | unsigned int numBanks = length / GBC_8K; 56 | 57 | //enable RAM 58 | gbc_rom_writeByte(0x0A, 0x0100); 59 | 60 | //set to RAM banking mode 61 | gbc_rom_writeByte(0x01, 0x6000); 62 | 63 | //read/write the banks 64 | for(i = 0; i < numBanks; i++) { 65 | //set bank 66 | char bankNum0 = (char) (i & 0x03); 67 | gbc_rom_writeByte(bankNum0, 0x4000); 68 | 69 | //read more data 70 | unsigned int index = i * GBC_8K; 71 | if(isWrite) gbc_rom_writeAt(buffer + index, 0xA000, GBC_8K); 72 | else gbc_rom_readAt(buffer + index, 0xA000, GBC_8K); 73 | } 74 | 75 | //set back to ROM banking mode 76 | gbc_rom_writeByte(0x00, 0x6000); 77 | 78 | //set back to bank 0 and disable RAM 79 | gbc_rom_writeByte(0x00, 0x4000); 80 | gbc_rom_writeByte(0x00, 0x0100); 81 | 82 | return length; 83 | } 84 | -------------------------------------------------------------------------------- /source/core/gbc/gbc_mbc1.h: -------------------------------------------------------------------------------- 1 | #ifndef GBC_MBC1_H 2 | #define GBC_MBC1_H 3 | 4 | // Read ROM for MBC1 Memory Controller 5 | unsigned int gbc_mbc1_readROM(char* buffer, unsigned int length); 6 | 7 | // Read RAM for MBC1 Memory Controller 8 | unsigned int gbc_mbc1_readRAM(char* buffer, unsigned int length); 9 | 10 | // Write RAM for MBC1 Memory Controller 11 | unsigned int gbc_mbc1_writeRAM(char* buffer, unsigned int length); 12 | 13 | #endif /* GBC_MBC1_H */ 14 | -------------------------------------------------------------------------------- /source/core/gbc/gbc_mbc2.c: -------------------------------------------------------------------------------- 1 | #include "gbc.h" 2 | #include "gbc_rom.h" 3 | #include "gbc_mbc2.h" 4 | 5 | // Read ROM for MBC2 Memory Controller 6 | unsigned int gbc_mbc2_readROM(char* buffer, unsigned int length) 7 | { 8 | int i; 9 | unsigned int numBanks = length / GBC_16K; 10 | 11 | //read bank 0 12 | gbc_rom_readAt(buffer, 0x00, GBC_16K); 13 | 14 | //read the remaining banks 15 | for(i = 1; i < numBanks; i++) { 16 | //set bank 17 | char bankNum0 = (char) (i & 0x0F); 18 | gbc_rom_writeByte(bankNum0, 0x2100); 19 | 20 | //read more data 21 | unsigned int index = i * GBC_16K; 22 | gbc_rom_readAt(buffer + index, GBC_16K, GBC_16K); 23 | } 24 | 25 | //set back to bank 1 26 | gbc_rom_writeByte(0x01, 0x2100); 27 | 28 | return length; 29 | } 30 | -------------------------------------------------------------------------------- /source/core/gbc/gbc_mbc2.h: -------------------------------------------------------------------------------- 1 | #ifndef GBC_MBC2_H 2 | #define GBC_MBC2_H 3 | 4 | // Read ROM for MBC2 Memory Controller 5 | unsigned int gbc_mbc2_readROM(char* buffer, unsigned int length); 6 | 7 | #endif /* GBC_MBC2_H */ 8 | -------------------------------------------------------------------------------- /source/core/gbc/gbc_mbc3.c: -------------------------------------------------------------------------------- 1 | #include "gbc.h" 2 | #include "gbc_rom.h" 3 | #include "gbc_mbc3.h" 4 | 5 | // Helper functions 6 | static unsigned int gbc_mbc3_rwRAM(char* buffer, unsigned int length, char isWrite); 7 | 8 | // Read ROM for MBC3 Memory Controller 9 | unsigned int gbc_mbc3_readROM(char* buffer, unsigned int length) 10 | { 11 | int i; 12 | unsigned int numBanks = length / GBC_16K; 13 | 14 | //read bank 0 15 | gbc_rom_readAt(buffer, 0x00, GBC_16K); 16 | 17 | //read the remaining banks 18 | for(i = 1; i < numBanks; i++) { 19 | //set bank 20 | char bankNum0 = (char) (i & 0x7F); 21 | gbc_rom_writeByte(bankNum0, 0x2000); 22 | 23 | //read more data 24 | unsigned int index = i * GBC_16K; 25 | gbc_rom_readAt(buffer + index, GBC_16K, GBC_16K); 26 | } 27 | 28 | //set back to bank 1 29 | gbc_rom_writeByte(0x01, 0x2000); 30 | 31 | return length; 32 | } 33 | 34 | // Read RAM for MBC3 Memory Controller 35 | unsigned int gbc_mbc3_readRAM(char* buffer, unsigned int length) 36 | { 37 | return gbc_mbc3_rwRAM(buffer, length, 0); 38 | } 39 | 40 | // Write RAM for MBC3 Memory Controller 41 | unsigned int gbc_mbc3_writeRAM(char* buffer, unsigned int length) 42 | { 43 | return gbc_mbc3_rwRAM(buffer, length, 1); 44 | } 45 | 46 | // Read RAM for MBC3 Memory Controller 47 | static unsigned int gbc_mbc3_rwRAM(char* buffer, unsigned int length, char isWrite) { 48 | int i; 49 | unsigned int numBanks = length / GBC_8K; 50 | 51 | //enable RAM 52 | gbc_rom_writeByte(0x0A, 0x0100); 53 | 54 | //read/write the banks 55 | for(i = 0; i < numBanks; i++) { 56 | //set bank 57 | char bankNum0 = (char) (i & 0x07); 58 | gbc_rom_writeByte(bankNum0, 0x4000); 59 | 60 | //read more data 61 | unsigned int index = i * GBC_8K; 62 | if(isWrite) gbc_rom_writeAt(buffer + index, 0xA000, GBC_8K); 63 | else gbc_rom_readAt(buffer + index, 0xA000, GBC_8K); 64 | } 65 | 66 | //set back to bank 0 and disable RAM 67 | gbc_rom_writeByte(0x00, 0x4000); 68 | gbc_rom_writeByte(0x00, 0x0100); 69 | 70 | return length; 71 | } 72 | -------------------------------------------------------------------------------- /source/core/gbc/gbc_mbc3.h: -------------------------------------------------------------------------------- 1 | #ifndef GBC_MBC3_H 2 | #define GBC_MBC3_H 3 | 4 | // Read ROM for MBC3 Memory Controller 5 | unsigned int gbc_mbc3_readROM(char* buffer, unsigned int length); 6 | 7 | // Read RAM for MBC3 Memory Controller 8 | unsigned int gbc_mbc3_readRAM(char* buffer, unsigned int length); 9 | 10 | // Write RAM for MBC3 Memory Controller 11 | unsigned int gbc_mbc3_writeRAM(char* buffer, unsigned int length); 12 | 13 | #endif /* GBC_MBC3_H */ 14 | -------------------------------------------------------------------------------- /source/core/gbc/gbc_mbc5.c: -------------------------------------------------------------------------------- 1 | #include "gbc.h" 2 | #include "gbc_rom.h" 3 | #include "gbc_mbc5.h" 4 | 5 | // Helper functions 6 | static unsigned int gbc_mbc5_rwRAM(char* buffer, unsigned int length, char isWrite); 7 | 8 | // Read ROM for MBC5 Memory Controller 9 | unsigned int gbc_mbc5_readROM(char* buffer, unsigned int length) 10 | { 11 | int i; 12 | unsigned int numBanks = length / GBC_16K; 13 | 14 | //read bank 0 15 | gbc_rom_readAt(buffer, 0x00, GBC_16K); 16 | 17 | //read the remaining banks 18 | for(i = 1; i < numBanks; i++) { 19 | //set bank 20 | char bankNum0 = (char) i; 21 | char bankNum1 = (char) (i >> 8); 22 | gbc_rom_writeByte(bankNum1, 0x3000); 23 | gbc_rom_writeByte(bankNum0, 0x2000); 24 | 25 | //read more data 26 | unsigned int index = i * GBC_16K; 27 | gbc_rom_readAt(buffer + index, GBC_16K, GBC_16K); 28 | } 29 | 30 | //set back to bank 1 31 | gbc_rom_writeByte(0x00, 0x3000); 32 | gbc_rom_writeByte(0x01, 0x2000); 33 | 34 | return length; 35 | } 36 | 37 | // Read RAM for MBC5 Memory Controller 38 | unsigned int gbc_mbc5_readRAM(char* buffer, unsigned int length) 39 | { 40 | return gbc_mbc5_rwRAM(buffer, length, 0); 41 | } 42 | 43 | // Write RAM for MBC5 Memory Controller 44 | unsigned int gbc_mbc5_writeRAM(char* buffer, unsigned int length) 45 | { 46 | return gbc_mbc5_rwRAM(buffer, length, 1); 47 | } 48 | 49 | // Read RAM for MBC5 Memory Controller 50 | static unsigned int gbc_mbc5_rwRAM(char* buffer, unsigned int length, char isWrite) { 51 | int i; 52 | unsigned int numBanks = length / GBC_8K; 53 | 54 | //enable RAM 55 | gbc_rom_writeByte(0x0A, 0x0100); 56 | 57 | //read/write the banks 58 | for(i = 0; i < numBanks; i++) { 59 | //set bank 60 | char bankNum0 = (char) (i & 0x0F); 61 | gbc_rom_writeByte(bankNum0, 0x4000); 62 | 63 | //read more data 64 | unsigned int index = i * GBC_8K; 65 | if(isWrite) gbc_rom_writeAt(buffer + index, 0xA000, GBC_8K); 66 | else gbc_rom_readAt(buffer + index, 0xA000, GBC_8K); 67 | } 68 | 69 | //set back to bank 0 and disable RAM 70 | gbc_rom_writeByte(0x00, 0x4000); 71 | gbc_rom_writeByte(0x00, 0x0100); 72 | 73 | return length; 74 | } 75 | -------------------------------------------------------------------------------- /source/core/gbc/gbc_mbc5.h: -------------------------------------------------------------------------------- 1 | #ifndef GBC_MBC5_H 2 | #define GBC_MBC5_H 3 | 4 | // Read ROM for MBC5 Memory Controller 5 | unsigned int gbc_mbc5_readROM(char* buffer, unsigned int length); 6 | 7 | // Read RAM for MBC5 Memory Controller 8 | unsigned int gbc_mbc5_readRAM(char* buffer, unsigned int length); 9 | 10 | // Write RAM for MBC5 Memory Controller 11 | unsigned int gbc_mbc5_writeRAM(char* buffer, unsigned int length); 12 | 13 | #endif /* GBC_MBC5_H */ 14 | -------------------------------------------------------------------------------- /source/core/gbc/gbc_rom.c: -------------------------------------------------------------------------------- 1 | #include "gbc.h" 2 | #include "gbc_cart.h" 3 | #include "gbc_rom.h" 4 | #include "egpio.h" 5 | #include "spi.h" 6 | 7 | #define _1(x) (x) 8 | #define _0(x) ((unsigned char)~(x)) 9 | 10 | // Read the ROM of a connected GB cartridge at the given start and length 11 | void gbc_rom_readAt(char* buffer, unsigned int start, unsigned int length) 12 | { 13 | int i; 14 | 15 | //determine ROM vs RAM 16 | if(start < GBC_32K) { 17 | if((start + length) > GBC_32K) length = GBC_32K - start; 18 | } else { 19 | if(start > GBC_64K) start = GBC_64K; 20 | if((start + length) > GBC_64K) length = GBC_64K - start; 21 | } 22 | 23 | //ensure default state 24 | gbc_cart_powerUp(); 25 | egpio_setPortDir(EX_GPIO_PORTC, 0xFF); 26 | 27 | //pull GBC_GPIO_RD pin low while we read data 28 | spi_writeGPIO(GBC_GPIO_RD, 0x00); 29 | 30 | //read ROM data 31 | for(i = 0; i < length; i++) { 32 | 33 | //write address and read data 34 | char addr0 = (char) (start + i); 35 | char addr1 = (char) ((start + i) >> 8); 36 | if(i==0 || addr0 == 0) egpio_writePortAB(addr0, addr1); 37 | else egpio_writePort(EX_GPIO_PORTA, addr0); 38 | 39 | //pulse cs on each read for ram 40 | if(start >= GBC_32K) { 41 | egpio_writePort(EX_GPIO_PORTD, _1(GBC_WR + GBC_RST) & _0(GBC_CSRAM + GBC_CLK + GBC_PWR)); 42 | gbc_cart_delay(20); 43 | } 44 | 45 | buffer[i] = egpio_readPort(EX_GPIO_PORTC); 46 | 47 | //cs high again 48 | if(start >= GBC_32K) egpio_writePort(EX_GPIO_PORTD, _1(GBC_CSRAM + GBC_WR + GBC_RST) & _0(GBC_CLK + GBC_PWR)); 49 | } 50 | 51 | //pull RD and CSRAM back to high 52 | egpio_writePort(EX_GPIO_PORTD, _1(GBC_CSRAM + GBC_WR + GBC_RST) & _0(GBC_CLK + GBC_PWR)); 53 | spi_writeGPIO(GBC_GPIO_RD, 0x01); 54 | } 55 | 56 | // Wrties to the RAM of a connected GB cartridge at the given start and length 57 | void gbc_rom_writeAt(char* buffer, unsigned int start, unsigned int length) 58 | { 59 | int i; 60 | 61 | //cleanse data 62 | if(start < GBC_32K) return; 63 | if(start > GBC_64K) start = GBC_64K; 64 | if((start + length) > GBC_64K) length = GBC_64K - start; 65 | 66 | //ensure default state 67 | gbc_cart_powerUp(); 68 | 69 | //write RAM data 70 | for(i = 0; i < length; i++) { 71 | 72 | //write address and data 73 | char addr0 = (char) (start + i); 74 | char addr1 = (char) ((start + i) >> 8); 75 | if(i==0 || addr0 == 0) egpio_writePortAB(addr0, addr1); 76 | else egpio_writePort(EX_GPIO_PORTA, addr0); 77 | egpio_writePort(EX_GPIO_PORTC, buffer[i]); 78 | 79 | //toggle the WR and CS line 80 | egpio_writePort(EX_GPIO_PORTD, _1(GBC_RST) & _0(GBC_CSRAM + GBC_WR + GBC_CLK + GBC_PWR)); 81 | gbc_cart_delay(20); 82 | egpio_writePort(EX_GPIO_PORTD, _1(GBC_CSRAM + GBC_WR + GBC_RST) & _0(GBC_CLK + GBC_PWR)); 83 | } 84 | 85 | //pull WR and CSRAM back to high 86 | egpio_writePort(EX_GPIO_PORTD, _1(GBC_CSRAM + GBC_WR + GBC_RST) & _0(GBC_CLK + GBC_PWR)); 87 | } 88 | 89 | // Writes to ROM for bank switching 90 | void gbc_rom_writeByte(char byte, unsigned int address) 91 | { 92 | if(address > GBC_64K) address = GBC_64K; 93 | char addr0 = (char) address; 94 | char addr1 = (char) (address >> 8); 95 | 96 | //ensure default state 97 | gbc_cart_powerUp(); 98 | 99 | //set data 100 | egpio_writePortAll(addr0, addr1, byte, _1(GBC_CSRAM + GBC_WR + GBC_RST) & _0(GBC_CLK + GBC_PWR)); 101 | 102 | //pull WR low to write 103 | egpio_writePort(EX_GPIO_PORTD, _1(GBC_CSRAM + GBC_RST) & _0(GBC_WR + GBC_CLK + GBC_PWR)); 104 | egpio_writePort(EX_GPIO_PORTD, _1(GBC_CSRAM + GBC_WR + GBC_RST) & _0(GBC_CLK + GBC_PWR)); 105 | } 106 | 107 | -------------------------------------------------------------------------------- /source/core/gbc/gbc_rom.h: -------------------------------------------------------------------------------- 1 | #ifndef GBC_ROM_H 2 | #define GBC_ROM_H 3 | 4 | #define GBC_2K 2048 5 | #define GBC_8K 8192 6 | #define GBC_16K 16384 7 | #define GBC_32K 32768 8 | #define GBC_64K 65536 9 | #define GBC_128K 131072 10 | #define GBC_256K 262144 11 | #define GBC_512K 524288 12 | #define GBC_1M 1048576 13 | #define GBC_2M 2097152 14 | #define GBC_4M 4194304 15 | #define GBC_8M 8388608 16 | #define GBC_1p1M 1179648 17 | #define GBC_1p2M 1310720 18 | #define GBC_1p5M 1572864 19 | 20 | // Read the ROM of a connected GB cartridge at the given start and length 21 | void gbc_rom_readAt(char* buffer, unsigned int start, unsigned int length); 22 | 23 | // Wrties to the RAM of a connected GB cartridge at the given start and length 24 | void gbc_rom_writeAt(char* buffer, unsigned int start, unsigned int length); 25 | 26 | // Writes to ROM for bank switching 27 | void gbc_rom_writeByte(char byte, unsigned int address); 28 | 29 | #endif /* GBC_ROM_H */ 30 | -------------------------------------------------------------------------------- /source/core/gbx.c: -------------------------------------------------------------------------------- 1 | #include "gbx.h" 2 | #include "gbc/gbc.h" 3 | #include "gba/gba.h" 4 | #include 5 | #include 6 | #include 7 | #include "egpio.h" 8 | #include "spi.h" 9 | 10 | #define GBX_DTSW 0x40 11 | #define GBX_SPI_KEY 0xC42C4865 12 | 13 | // Data 14 | static char gbx_isInitFlag = 0; 15 | 16 | // Helper functions 17 | static char gbx_isGB(); 18 | static char gbx_isLoaded_noLock(); 19 | 20 | // Setup and initialize the GBx utils 21 | int gbx_init() 22 | { 23 | //already initialized? 24 | if(gbx_isInitFlag == 1) return 0; 25 | 26 | //init and check dependencies 27 | gbc_init(); 28 | gba_init(); 29 | if(!gbc_isInit() || !gba_isInit()) { 30 | if(!gbc_isInit()) fprintf(stderr, "gbx_init: GBC Utils dependency failed to initialize\n"); 31 | if(!gba_isInit()) fprintf(stderr, "gbx_init: GBA Utils dependency failed to initialize\n"); 32 | gbx_close(); 33 | return 1; 34 | } 35 | 36 | gbx_isInitFlag = 1; 37 | return 0; 38 | } 39 | 40 | // Checks if the GBx utils are initialized 41 | int gbx_isInit() 42 | { 43 | return gbx_isInitFlag; 44 | } 45 | 46 | // Loads the header and basic data of the connected GBx cartridge 47 | char gbx_loadHeader() 48 | { 49 | char result = 0; 50 | spi_obtainLock(GBX_SPI_KEY, 0); 51 | 52 | if(gbx_isGB()) { 53 | gba_loadClear(); 54 | result = gbc_loadHeader(); 55 | } else { 56 | gbc_loadClear(); 57 | result = gba_loadHeader(); 58 | } 59 | 60 | spi_unlock(GBX_SPI_KEY); 61 | return result; 62 | } 63 | 64 | // Checks if a GBx cartridge is currently connected and loaded 65 | char gbx_isLoaded() 66 | { 67 | char result = 0; 68 | spi_obtainLock(GBX_SPI_KEY, 0); 69 | result = gbx_isLoaded_noLock(); 70 | spi_unlock(GBX_SPI_KEY); 71 | return result; 72 | } 73 | 74 | // Prints the info of the connected GBx cartridge 75 | void gbx_printInfo() 76 | { 77 | if(gba_getROMSize() > 0) { 78 | printf("Game Title: %s\n", gba_getGameTitle()); 79 | printf("Game Code: %s\n", gba_getGameCode()); 80 | printf("Maker Code: %s\n", gba_getMakerCode()); 81 | printf("ROM Size: %d\n", gba_getROMSize()); 82 | if(gba_getSaveType() == GBA_SAVE_TYPE_EEPROM_4K) printf("Save Type: EEPROM_4K\n"); 83 | if(gba_getSaveType() == GBA_SAVE_TYPE_EEPROM_64K) printf("Save Type: EEPROM_64K\n"); 84 | if(gba_getSaveType() == GBA_SAVE_TYPE_SRAM_256K) printf("Save Type: SRAM_256K\n"); 85 | if(gba_getSaveType() == GBA_SAVE_TYPE_SRAM_512K) printf("Save Type: SRAM_512K\n"); 86 | if(gba_getSaveType() == GBA_SAVE_TYPE_FLASH_512K) printf("Save Type: FLASH_512K\n"); 87 | if(gba_getSaveType() == GBA_SAVE_TYPE_FLASH_1M) printf("Save Type: FLASH_1M\n"); 88 | if(gba_getSaveType() == GBA_SAVE_TYPE_UNKNOWN) printf("Save Type: unknown\n"); 89 | } else if(gbc_getROMSize() > 0) { 90 | printf("Game Title: %s\n", gbc_getGameTitle()); 91 | printf("SHA1 [First 1024]: %s\n", gbc_getGameSHA1()); 92 | if(gbc_getCGBFlag() == GBC_FLAG_CGB_UNSUPPORTED) printf("CGB Flag: Original GB Game\n"); 93 | if(gbc_getCGBFlag() == GBC_FLAG_CGB_COMPATIBLE) printf("CGB Flag: GBC Compatible Features\n"); 94 | if(gbc_getCGBFlag() == GBC_FLAG_CGB_ONLY) printf("CGB Flag: GBC Only\n"); 95 | if(gbc_getMemoryController() == GBC_MEM_CTRL_NONE) printf("Mem Ctrl: None\n"); 96 | if(gbc_getMemoryController() == GBC_MEM_CTRL_MBC1) printf("Mem Ctrl: MBC1\n"); 97 | if(gbc_getMemoryController() == GBC_MEM_CTRL_MBC2) printf("Mem Ctrl: MBC2\n"); 98 | if(gbc_getMemoryController() == GBC_MEM_CTRL_MBC3) printf("Mem Ctrl: MBC3\n"); 99 | if(gbc_getMemoryController() == GBC_MEM_CTRL_MBC5) printf("Mem Ctrl: MBC5\n"); 100 | printf("ROM Size: %d\n", gbc_getROMSize()); 101 | printf("Save Size: %d\n", gbc_getSaveSize()); 102 | } else { 103 | printf("No Cartridge...\n"); 104 | } 105 | } 106 | 107 | // Gets the type of GBx cartridge currently connected 108 | char gbx_getCartridgeType() 109 | { 110 | if(gbc_getROMSize() > 0) { 111 | if(gbc_getCGBFlag() == GBC_FLAG_CGB_UNSUPPORTED) return GBX_CARTRIDGE_TYPE_GB; 112 | else return GBX_CARTRIDGE_TYPE_GBC; 113 | } else if(gba_getROMSize() > 0) { 114 | return GBX_CARTRIDGE_TYPE_GBA; 115 | } 116 | return GBX_CARTRIDGE_TYPE_NONE; 117 | } 118 | 119 | // Gets the game title of the connected GBx cartridge 120 | char* gbx_getGameTitle() 121 | { 122 | if(gba_getROMSize() > 0) { 123 | return gba_getGameTitle(); 124 | } 125 | return gbc_getGameTitle(); 126 | } 127 | 128 | // Gets the game identifier of the connected GBx cartridge 129 | char* gbx_getGameIdentifier() 130 | { 131 | if(gba_getROMSize() > 0) { 132 | return gba_getGameCode(); 133 | } 134 | return gbc_getGameSHA1(); 135 | } 136 | 137 | // Gets the ROM size of the connected GBx cartridge 138 | unsigned int gbx_getROMSize() 139 | { 140 | if(gba_getROMSize() > 0) { 141 | return gba_getROMSize(); 142 | } 143 | return gbc_getROMSize(); 144 | } 145 | 146 | // Gets the Save size of the connected GBx cartridge 147 | unsigned int gbx_getSaveSize() 148 | { 149 | if(gba_getROMSize() > 0) { 150 | return gba_getSaveSize(); 151 | } 152 | return gbc_getSaveSize(); 153 | } 154 | 155 | // Gets the estimated amount of time to read GBx cartridge ROM (millis) 156 | unsigned int gbx_timeToReadROM() 157 | { 158 | if(gba_getROMSize() > 0) { 159 | return ((gba_getROMSize()/100)*1405)/10000; //0.0014050436 160 | } 161 | return ((gbc_getROMSize()/100)*10255)/10000; //0.01025515666 162 | } 163 | 164 | // Gets the estimated amount of time to read GBx cartridge Save (millis) 165 | unsigned int gbx_timeToReadSave() 166 | { 167 | if(gba_getROMSize() > 0) { 168 | if(gba_getSaveType()==GBA_SAVE_TYPE_EEPROM_4K) return 53; 169 | if(gba_getSaveType()==GBA_SAVE_TYPE_EEPROM_64K) return 946; 170 | if(gba_getSaveType()==GBA_SAVE_TYPE_SRAM_256K) return 361; 171 | if(gba_getSaveType()==GBA_SAVE_TYPE_SRAM_512K) return 722; 172 | if(gba_getSaveType()==GBA_SAVE_TYPE_FLASH_512K) return 720; 173 | if(gba_getSaveType()==GBA_SAVE_TYPE_FLASH_1M) return 1449; 174 | return 1500; 175 | } 176 | return ((gbc_getSaveSize()/100)*21314)/10000; //0.02131436 177 | } 178 | 179 | // Gets the estimated amount of time to write GBx cartridge Save (millis) 180 | unsigned int gbx_timeToWriteSave() 181 | { 182 | if(gba_getROMSize() > 0) { 183 | if(gba_getSaveType()==GBA_SAVE_TYPE_EEPROM_4K) return 541; 184 | if(gba_getSaveType()==GBA_SAVE_TYPE_EEPROM_64K) return 13289; 185 | if(gba_getSaveType()==GBA_SAVE_TYPE_SRAM_256K) return 734; 186 | if(gba_getSaveType()==GBA_SAVE_TYPE_SRAM_512K) return 1468; 187 | if(gba_getSaveType()==GBA_SAVE_TYPE_FLASH_512K) return 8638; 188 | if(gba_getSaveType()==GBA_SAVE_TYPE_FLASH_1M) return 16861; 189 | return 15000; 190 | } 191 | return ((gbc_getSaveSize()/100)*22158)/10000; //0.02215844 192 | } 193 | 194 | // Read the ROM of the connected GBx cartridge 195 | int gbx_readROM(char* data) 196 | { 197 | spi_obtainLock(GBX_SPI_KEY, 0); 198 | 199 | int result = GBX_ERROR_NO_CARTRIDGE; 200 | if(gba_getROMSize() > 0) { 201 | result = gba_readROM(data, gba_getROMSize()); 202 | } 203 | else if(gbc_getROMSize() > 0) { 204 | result = gbc_readROM(data, gbc_getROMSize()); 205 | } 206 | 207 | spi_unlock(GBX_SPI_KEY); 208 | return result; 209 | } 210 | 211 | // Read the Save Data of the connected GBx cartridge 212 | int gbx_readSave(char* data) 213 | { 214 | spi_obtainLock(GBX_SPI_KEY, 0); 215 | 216 | int result = GBX_ERROR_NO_CARTRIDGE; 217 | if(gba_getSaveSize() > 0) { 218 | result = gba_readSave(data, gba_getSaveSize()); 219 | } 220 | else if(gbc_getSaveSize() > 0) { 221 | result = gbc_readSave(data, gbc_getSaveSize()); 222 | } 223 | 224 | spi_unlock(GBX_SPI_KEY); 225 | return result; 226 | } 227 | 228 | // Write the Save Data to the connected GBx cartridge 229 | int gbx_writeSave(char* data) 230 | { 231 | spi_obtainLock(GBX_SPI_KEY, 0); 232 | 233 | //double check that the believed loaded cartridge is correct 234 | if(gbx_getROMSize() == 0) { 235 | spi_unlock(GBX_SPI_KEY); 236 | return GBX_ERROR_CARTRIDGE_NOT_LOADED; 237 | } 238 | if(gbx_isLoaded_noLock() == 0) { 239 | gbx_loadHeader(); 240 | 241 | spi_unlock(GBX_SPI_KEY); 242 | if(gbx_getROMSize() > 0) return GBX_ERROR_CARTRIDGE_CHANGED; 243 | return GBX_ERROR_NO_CARTRIDGE; 244 | } 245 | 246 | //write data 247 | int result = GBX_ERROR_NO_CARTRIDGE; 248 | if(gba_getSaveSize() > 0) { 249 | result = gba_writeSave(data, gba_getSaveSize()); 250 | } 251 | else if(gbc_getSaveSize() > 0) { 252 | result = gbc_writeSave(data, gbc_getSaveSize()); 253 | } 254 | 255 | spi_unlock(GBX_SPI_KEY); 256 | return result; 257 | } 258 | 259 | // Checks the state of the cartridge detector switch 260 | char gbx_checkDetectorSwitch() 261 | { 262 | char result = 0; 263 | spi_obtainLock(GBX_SPI_KEY, 0); 264 | 265 | if(gbx_isGB()) result = 1; 266 | 267 | spi_unlock(GBX_SPI_KEY); 268 | return result; 269 | } 270 | 271 | // Dumps the first 400 bytes of the connected GBx cartridge 272 | void gbx_dumpHeader(char* data) 273 | { 274 | spi_obtainLock(GBX_SPI_KEY, 0); 275 | 276 | if(gbx_isGB()) gbc_dumpHeader(data); 277 | else gba_dumpHeader(data); 278 | 279 | spi_unlock(GBX_SPI_KEY); 280 | } 281 | 282 | // Cleans up the GBx utils 283 | int gbx_close() 284 | { 285 | //close dependencies 286 | gbc_close(); 287 | gba_close(); 288 | 289 | gbx_isInitFlag = 0; 290 | return 0; 291 | } 292 | 293 | // Checks for the GB cartridge detector switch 294 | static char gbx_isGB() { 295 | char state = egpio_readPort(EX_GPIO_PORTD); 296 | if((state & GBX_DTSW) == GBX_DTSW) { 297 | return 0; 298 | } 299 | return 1; 300 | } 301 | 302 | // Checks if a GB cartridge is currently connected and loaded 303 | static char gbx_isLoaded_noLock() { 304 | if(gbc_getROMSize() > 0) { 305 | if(gbc_isLoaded() == 1) return 1; 306 | } else if(gba_getROMSize() > 0) { 307 | if(gba_isLoaded() == 1) return 1; 308 | } 309 | return 0; 310 | } 311 | -------------------------------------------------------------------------------- /source/core/gbx.h: -------------------------------------------------------------------------------- 1 | #ifndef GBX_H 2 | #define GBX_H 3 | 4 | #define GBX_CARTRIDGE_TYPE_NONE 0 5 | #define GBX_CARTRIDGE_TYPE_GB 1 6 | #define GBX_CARTRIDGE_TYPE_GBC 2 7 | #define GBX_CARTRIDGE_TYPE_GBA 3 8 | 9 | #define GBX_ERROR_NO_CARTRIDGE -1 10 | #define GBX_ERROR_CARTRIDGE_CHANGED -2 11 | #define GBX_ERROR_CARTRIDGE_NOT_LOADED -3 12 | 13 | // Setup and initialize the GBx utils 14 | int gbx_init(); 15 | 16 | // Checks if the GBx utils are initialized 17 | int gbx_isInit(); 18 | 19 | // Loads the header and basic data of the connected GBx cartridge 20 | char gbx_loadHeader(); 21 | 22 | // Checks if a GBx cartridge is currently connected and loaded 23 | char gbx_isLoaded(); 24 | 25 | // Prints the info of the connected GBx cartridge 26 | void gbx_printInfo(); 27 | 28 | // Gets the type of GBx cartridge currently connected 29 | char gbx_getCartridgeType(); 30 | 31 | // Gets the game title of the connected GBx cartridge 32 | char* gbx_getGameTitle(); 33 | 34 | // Gets the game identifier of the connected GBx cartridge 35 | char* gbx_getGameIdentifier(); 36 | 37 | // Gets the ROM size of the connected GBx cartridge 38 | unsigned int gbx_getROMSize(); 39 | 40 | // Gets the Save size of the connected GBx cartridge 41 | unsigned int gbx_getSaveSize(); 42 | 43 | // Gets the estimated amount of time to read GBx cartridge ROM (millis) 44 | unsigned int gbx_timeToReadROM(); 45 | 46 | // Gets the estimated amount of time to read GBx cartridge Save (millis) 47 | unsigned int gbx_timeToReadSave(); 48 | 49 | // Gets the estimated amount of time to write GBx cartridge Save (millis) 50 | unsigned int gbx_timeToWriteSave(); 51 | 52 | // Read the ROM of the connected GBx cartridge 53 | int gbx_readROM(char* data); 54 | 55 | // Read the Save Data of the connected GBx cartridge 56 | int gbx_readSave(char* data); 57 | 58 | // Write the Save Data to the connected GBx cartridge 59 | int gbx_writeSave(char* data); 60 | 61 | // Checks the state of the cartridge detector switch 62 | char gbx_checkDetectorSwitch(); 63 | 64 | // Dumps the first 400 bytes of the connected GBx cartridge 65 | void gbx_dumpHeader(char* data); 66 | 67 | // Cleans up the GBx utils 68 | int gbx_close(); 69 | 70 | #endif /* GBX_H */ 71 | -------------------------------------------------------------------------------- /source/core/inp.h: -------------------------------------------------------------------------------- 1 | #ifndef INP_H 2 | #define INP_H 3 | 4 | #define INP_BTN_A 0 5 | #define INP_BTN_B 1 6 | #define INP_BTN_X 2 7 | #define INP_BTN_Y 3 8 | #define INP_BTN_RT 4 9 | #define INP_BTN_LF 5 10 | #define INP_BTN_UP 6 11 | #define INP_BTN_DN 7 12 | #define INP_BTN_SL 8 13 | #define INP_BTN_ST 9 14 | #define INP_BTN_L 10 15 | #define INP_BTN_R 11 16 | 17 | #define INP_TYPE_UNKNOWN 0 18 | #define INP_TYPE_KEYBOARD 1 19 | #define INP_TYPE_JOYSTICK 2 20 | 21 | // Setup and initialize the Controller interface 22 | int inp_init(char autoHotkey, char autoShutdown); 23 | 24 | // Checks if the Controller interface is initialized 25 | char inp_isInit(); 26 | 27 | // Updates the button holding state 28 | void inp_updateButtonState(); 29 | 30 | // Gets the holding state of the given button 31 | unsigned char inp_getButtonState(char button); 32 | 33 | // Gets the type of the last active input device 34 | char inp_getInputType(); 35 | 36 | // Closes the Controller interface 37 | int inp_close(); 38 | 39 | 40 | #endif /* INP_H */ 41 | -------------------------------------------------------------------------------- /source/core/nrf.c: -------------------------------------------------------------------------------- 1 | #include "nrf.h" 2 | #include "spi.h" 3 | #include 4 | #include 5 | 6 | #define SPI_CLK_SPEED 10000000 7 | #define NRF_SPI_KEY 0x7258AE90 8 | 9 | #define PIN_CE 19 10 | #define PIN_CSN 26 11 | 12 | // Data 13 | static char nrf_isInitFlag = 0; 14 | 15 | // Util Functions 16 | static void nrf_sleep(long usec); 17 | 18 | // Setup and initialize the nRF24L01 interface 19 | int nrf_init() 20 | { 21 | //already initialized? 22 | if(nrf_isInitFlag == 1) return 0; 23 | 24 | //check dependencies 25 | if(!spi_isInit()) { 26 | fprintf(stderr, "nrf_init: SPI dependency is not initialized\n"); 27 | nrf_close(); 28 | return 1; 29 | } 30 | 31 | //setup select pins 32 | spi_setGPIODir(PIN_CE, 0x00); 33 | spi_setGPIODir(PIN_CSN, 0x00); 34 | spi_writeGPIO(PIN_CE, 0); 35 | spi_writeGPIO(PIN_CSN, 1); 36 | nrf_sleep(50*1000); 37 | 38 | nrf_isInitFlag = 1; 39 | return 0; 40 | } 41 | 42 | // Checks if the nRF24L01 interface is initialized 43 | char nrf_isInit() 44 | { 45 | return nrf_isInitFlag; 46 | } 47 | 48 | // Enables the nRF24L01 chip 49 | void nrf_enable() 50 | { 51 | spi_writeGPIO(PIN_CE, 1); 52 | } 53 | 54 | // Disables the nRF24L01 chip 55 | void nrf_disable() 56 | { 57 | spi_writeGPIO(PIN_CE, 0); 58 | } 59 | 60 | // Write one byte into the given register 61 | void nrf_configRegister(uint8_t reg, uint8_t value) 62 | { 63 | spi_obtainLock(NRF_SPI_KEY, 1); 64 | spi_writeGPIO(PIN_CSN, 0); 65 | 66 | unsigned char buf[2]; 67 | buf[0] = W_REGISTER | (REGISTER_MASK & reg); 68 | buf[1] = value; 69 | spi_transfer(buf, 2); 70 | 71 | spi_writeGPIO(PIN_CSN, 1); 72 | spi_unlock(NRF_SPI_KEY); 73 | } 74 | 75 | // Reads an array of bytes from the given registers 76 | void nrf_readRegister(uint8_t reg, uint8_t* value, uint8_t len) 77 | { 78 | int i; 79 | for(i=0; i 4 | 5 | #define CONFIG 0x00 6 | #define EN_AA 0x01 7 | #define EN_RXADDR 0x02 8 | #define SETUP_AW 0x03 9 | #define SETUP_RETR 0x04 10 | #define RF_CH 0x05 11 | #define RF_SETUP 0x06 12 | #define STATUS 0x07 13 | #define OBSERVE_TX 0x08 14 | #define CD 0x09 15 | #define RX_ADDR_P0 0x0A 16 | #define RX_ADDR_P1 0x0B 17 | #define RX_ADDR_P2 0x0C 18 | #define RX_ADDR_P3 0x0D 19 | #define RX_ADDR_P4 0x0E 20 | #define RX_ADDR_P5 0x0F 21 | #define TX_ADDR 0x10 22 | #define RX_PW_P0 0x11 23 | #define RX_PW_P1 0x12 24 | #define RX_PW_P2 0x13 25 | #define RX_PW_P3 0x14 26 | #define RX_PW_P4 0x15 27 | #define RX_PW_P5 0x16 28 | #define FIFO_STATUS 0x17 29 | 30 | #define MASK_RX_DR 6 31 | #define MASK_TX_DS 5 32 | #define MASK_MAX_RT 4 33 | #define EN_CRC 3 34 | #define CRCO 2 35 | #define PWR_UP 1 36 | #define PRIM_RX 0 37 | #define ENAA_P5 5 38 | #define ENAA_P4 4 39 | #define ENAA_P3 3 40 | #define ENAA_P2 2 41 | #define ENAA_P1 1 42 | #define ENAA_P0 0 43 | #define ERX_P5 5 44 | #define ERX_P4 4 45 | #define ERX_P3 3 46 | #define ERX_P2 2 47 | #define ERX_P1 1 48 | #define ERX_P0 0 49 | #define AW 0 50 | #define ARD 4 51 | #define ARC 0 52 | #define PLL_LOCK 4 53 | #define RF_DR 3 54 | #define RF_PWR 1 55 | #define LNA_HCURR 0 56 | #define RX_DR 6 57 | #define TX_DS 5 58 | #define MAX_RT 4 59 | #define RX_P_NO 1 60 | #define TX_FULL 0 61 | #define PLOS_CNT 4 62 | #define ARC_CNT 0 63 | #define TX_REUSE 6 64 | #define FIFO_FULL 5 65 | #define TX_EMPTY 4 66 | #define RX_FULL 1 67 | #define RX_EMPTY 0 68 | 69 | #define R_REGISTER 0x00 70 | #define W_REGISTER 0x20 71 | #define REGISTER_MASK 0x1F 72 | #define R_RX_PAYLOAD 0x61 73 | #define W_TX_PAYLOAD 0xA0 74 | #define FLUSH_TX 0xE1 75 | #define FLUSH_RX 0xE2 76 | #define REUSE_TX_PL 0xE3 77 | #define NOP 0xFF 78 | 79 | // Setup and initialize the nRF24L01 interface 80 | int nrf_init(); 81 | 82 | // Checks if the nRF24L01 interface is initialized 83 | char nrf_isInit(); 84 | 85 | // Enables the nRF24L01 chip 86 | void nrf_enable(); 87 | 88 | // Disables the nRF24L01 chip 89 | void nrf_disable(); 90 | 91 | // Write one byte into the given register 92 | void nrf_configRegister(uint8_t reg, uint8_t value); 93 | 94 | // Reads an array of bytes from the given registers 95 | void nrf_readRegister(uint8_t reg, uint8_t* value, uint8_t len); 96 | 97 | // Writes an array of bytes into the given registers 98 | void nrf_writeRegister(uint8_t reg, uint8_t* value, uint8_t len); 99 | 100 | // Flush RX and TX FIFO 101 | void nrf_flushRxTx(); 102 | 103 | // Read the status register 104 | uint8_t nrf_status(); 105 | 106 | // Read the rx payload 107 | void nrf_readRxPayload(uint8_t* value, uint8_t len); 108 | 109 | // Write the rx payload 110 | void nrf_writeTxPayload(uint8_t* value, uint8_t len); 111 | 112 | // Closes the nRF24L01 interface 113 | int nrf_close(); 114 | 115 | 116 | #endif /* NRF_H */ 117 | -------------------------------------------------------------------------------- /source/core/spi.h: -------------------------------------------------------------------------------- 1 | #ifndef SPI_H 2 | #define SPI_H 3 | #include 4 | 5 | // Setup and initialize the SPI interface 6 | int spi_init(uint32_t clockSpeedHz); 7 | 8 | // Checks if the SPI interface is initialized 9 | uint8_t spi_isInit(); 10 | 11 | // Sets the direction of the given pin (1=input, 0=output) 12 | void spi_setGPIODir(uint8_t pin, uint8_t dir); 13 | 14 | // Sets the weak pullup or pulldown on the given pin (0=off, 1=down, 2=up) 15 | void spi_setGPIOPud(uint8_t pin, uint8_t pud); 16 | 17 | // Writes the output value of the given pin (1=high, 0=low) 18 | void spi_writeGPIO(uint8_t pin, uint8_t val); 19 | 20 | // Reads the output value of the given pin (1=high, 0=low) 21 | uint8_t spi_readGPIO(uint8_t pin); 22 | 23 | // Locks the SPI interface from use in other threads 24 | void spi_obtainLock(uint32_t key, uint8_t disableCS); 25 | 26 | // Unlocks the SPI interface for use in other threads 27 | void spi_unlock(uint32_t key); 28 | 29 | // Writes (and reads) an number of bytes to SPI 30 | void spi_transfer(uint8_t* buf, uint32_t len); 31 | 32 | // Starts a long read operation by writing the given bytes to SPI 33 | void spi_read_start(uint8_t* buf, uint32_t len); 34 | 35 | // Reads a single byte from SPI (continuation for long read) 36 | uint8_t spi_read_cont(); 37 | 38 | // Ends a long read operation by writing the given bytes to SPI 39 | void spi_read_end(uint8_t* buf, uint32_t len); 40 | 41 | // Closes the SPI interface 42 | int spi_close(); 43 | 44 | 45 | #endif /* SPI_H */ 46 | -------------------------------------------------------------------------------- /source/core/usb.c: -------------------------------------------------------------------------------- 1 | #include "usb.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | // Constants 9 | static const char* usb_mountLocation = "/media/USBFlash"; 10 | 11 | // Data 12 | static char usb_isInitFlag = 0; 13 | static char usb_available = 0; 14 | static char usb_mounted = 0; 15 | 16 | // Helper Functions 17 | static char usb_checkAvailable(); 18 | 19 | // Setup and initialize the USB Storage interface 20 | int usb_init() 21 | { 22 | usb_isInitFlag = 1; 23 | return 0; 24 | } 25 | 26 | // Checks if the USB Storage interface is initialized 27 | char usb_isInit() 28 | { 29 | return usb_isInitFlag; 30 | } 31 | 32 | // Gets the path of the USB Storage device 33 | const char* usb_getPath() 34 | { 35 | return usb_mountLocation; 36 | } 37 | 38 | // Gets if the USB Storage device is available 39 | char usb_isAvailable() 40 | { 41 | return usb_checkAvailable(); 42 | } 43 | 44 | // Gets if the USB Storage device is mounted 45 | char usb_isMounted() 46 | { 47 | return usb_mounted; 48 | } 49 | 50 | // Mounts the USB Storage device 51 | char usb_mount() 52 | { 53 | char command[1024]; 54 | 55 | //make sure the mount directory exists 56 | sprintf(command, "sudo -u$USER mkdir -p -m=0777 \"%s\"", usb_mountLocation); 57 | system(command); 58 | 59 | //try to mount sda1 60 | sprintf(command, "sudo mount /dev/sda1 %s > /dev/null 2>&1", usb_mountLocation); 61 | system(command); 62 | 63 | //check if actually mounted 64 | usb_mounted = 0; 65 | FILE *fp = popen("sudo mount", "r"); 66 | if (fp != NULL) { 67 | char buff[1024]; 68 | while (fgets(buff, 1024, fp) != NULL) { 69 | if(strncmp(buff, "/dev/sda1", 9)==0) { 70 | if(strncmp(buff+13, usb_mountLocation, strlen(usb_mountLocation))==0) { 71 | usb_mounted = 1; 72 | } 73 | } 74 | } 75 | pclose(fp); 76 | } 77 | return usb_mounted; 78 | } 79 | 80 | // Unmounts the USB Storage device 81 | void usb_unmount() 82 | { 83 | char command[1024]; 84 | sprintf(command, "sudo umount /dev/sda1 > /dev/null 2>&1"); 85 | system(command); 86 | usb_mounted = 0; 87 | } 88 | 89 | // Closes the USB Storage interface 90 | int usb_close() 91 | { 92 | usb_unmount(); 93 | 94 | usb_isInitFlag = 0; 95 | return 0; 96 | } 97 | 98 | // Helper function to check if USB storage device is connected 99 | static char usb_checkAvailable() { 100 | usb_available = 0; 101 | FILE *fp = popen("sudo test -e /dev/sda1 ; echo $?", "r"); 102 | if (fp != NULL) { 103 | char buff[32]; 104 | while (fgets(buff, 32, fp) != NULL) { 105 | if(strncmp(buff, "0", 1)==0) usb_available = 1; 106 | } 107 | pclose(fp); 108 | } 109 | return usb_available; 110 | } 111 | -------------------------------------------------------------------------------- /source/core/usb.h: -------------------------------------------------------------------------------- 1 | #ifndef USB_H 2 | #define USB_H 3 | 4 | // Setup and initialize the USB Storage interface 5 | int usb_init(); 6 | 7 | // Checks if the USB Storage interface is initialized 8 | char usb_isInit(); 9 | 10 | // Gets the path of the USB Storage device 11 | const char* usb_getPath(); 12 | 13 | // Gets if the USB Storage device is available 14 | char usb_isAvailable(); 15 | 16 | // Gets if the USB Storage device is mounted 17 | char usb_isMounted(); 18 | 19 | // Mounts the USB Storage device 20 | char usb_mount(); 21 | 22 | // Unmounts the USB Storage device 23 | void usb_unmount(); 24 | 25 | // Closes the USB Storage interface 26 | int usb_close(); 27 | 28 | 29 | #endif /* USB_H */ 30 | -------------------------------------------------------------------------------- /source/core/vid.c: -------------------------------------------------------------------------------- 1 | #include "vid.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #define INIT_FLAG_NOT 0 11 | #define INIT_FLAG_PARTIAL 1 12 | #define INIT_FLAG_FULL 2 13 | 14 | #define SURFACE_TYPE SDL_SWSURFACE 15 | #define MAX_IMAGE_CACHE_FILENAME_SIZE 256 16 | 17 | // Data 18 | static char vid_isInitFlag = INIT_FLAG_NOT; 19 | static SDL_Surface* vid_scrMain = NULL; 20 | static char vid_cachedImageFilename[MAX_IMAGE_CACHE_FILENAME_SIZE]; 21 | static SDL_Surface* vid_cachedImage = NULL; 22 | static int vid_cachedFontSize = -1; 23 | static TTF_Font* vid_cachedFont = NULL; 24 | static SDL_Surface* vid_shade = NULL; 25 | 26 | // Setup and initialize the Video interface 27 | int vid_init() 28 | { 29 | //already initialized? 30 | if(vid_isInitFlag == INIT_FLAG_FULL) return 0; 31 | 32 | //initialize SDL 33 | if(vid_isInitFlag == INIT_FLAG_NOT) { 34 | int imgFlags = IMG_INIT_PNG | IMG_INIT_JPG; 35 | if(SDL_Init(SDL_INIT_VIDEO) < 0) { 36 | fprintf(stderr, "vid_init: ERROR in SDL_Init() %s\n", SDL_GetError()); 37 | vid_close(); 38 | return 1; 39 | } 40 | if(!(IMG_Init(imgFlags) & imgFlags )) { 41 | fprintf(stderr, "vid_init: ERROR in IMG_Init() %s\n", IMG_GetError()); 42 | vid_close(); 43 | return 1; 44 | } 45 | if(TTF_Init() < 0) { 46 | fprintf(stderr, "vid_init: ERROR in TTF_Init() %s\n", TTF_GetError()); 47 | vid_close(); 48 | return 1; 49 | } 50 | 51 | //get current screen info 52 | const SDL_VideoInfo* vInfo = SDL_GetVideoInfo(); 53 | if (!vInfo) { 54 | fprintf(stderr,"vid_init: ERROR in SDL_GetVideoInfo() %s\n", SDL_GetError()); 55 | vid_close(); 56 | return 1; 57 | } 58 | int nResX = vInfo->current_w; 59 | int nResY = vInfo->current_h; 60 | int nDepth = vInfo->vfmt->BitsPerPixel; 61 | 62 | //configure the video mode 63 | SDL_ShowCursor(SDL_DISABLE); 64 | vid_scrMain = SDL_SetVideoMode(nResX, nResY, nDepth, SURFACE_TYPE); //SDL_HWSURFACE SDL_DOUBLEBUF 65 | if(vid_scrMain == 0) { 66 | fprintf(stderr,"vid_init: ERROR in SDL_SetVideoMode() %s\n",SDL_GetError()); 67 | vid_close(); 68 | return 1; 69 | } 70 | } 71 | 72 | //create shade surface 73 | vid_shade = SDL_CreateRGBSurface(SURFACE_TYPE, vid_scrMain->w, vid_scrMain->h, vid_scrMain->format->BitsPerPixel, 74 | vid_scrMain->format->Rmask, vid_scrMain->format->Gmask, vid_scrMain->format->Bmask, vid_scrMain->format->Amask); 75 | 76 | vid_isInitFlag = INIT_FLAG_FULL; 77 | return 0; 78 | } 79 | 80 | // Gets the current width of the screen 81 | int vid_getScreenWidth() 82 | { 83 | if(vid_scrMain) return vid_scrMain->w; 84 | return 0; 85 | } 86 | 87 | // Gets the current height of the screen 88 | int vid_getScreenHeight() 89 | { 90 | if(vid_scrMain) return vid_scrMain->h; 91 | return 0; 92 | } 93 | 94 | // Gets the given textures width 95 | int vid_getTextureWidth(VidTexture* t) 96 | { 97 | if(t > 0) return ((SDL_Surface*)t)->w; 98 | return 0; 99 | } 100 | 101 | // Gets the given textures height 102 | int vid_getTextureHeight(VidTexture* t) 103 | { 104 | if(t > 0) return ((SDL_Surface*)t)->h; 105 | return 0; 106 | } 107 | 108 | // Saves the current screen as a bitmap 109 | void vid_saveScreen(const char* file) 110 | { 111 | if(vid_scrMain && file) { 112 | SDL_SaveBMP(vid_scrMain, file); 113 | } 114 | } 115 | 116 | // Checks if the Video interface is initialized 117 | char vid_isInit() 118 | { 119 | if(vid_isInitFlag == INIT_FLAG_FULL) return 1; 120 | return 0; 121 | } 122 | 123 | // Draws a box to the video buffer 124 | void vid_drawBox(int x, int y, int w, int h, unsigned char r, unsigned char g, unsigned char b, unsigned char opaque) 125 | { 126 | int i, j; 127 | if(vid_scrMain) { 128 | Uint32 color = SDL_MapRGBA(vid_scrMain->format, r, g, b, 0); 129 | SDL_Rect rectBox = {(signed short)x, (signed short)y, (unsigned short)w, (unsigned short)h}; 130 | if(opaque == 255) { 131 | SDL_FillRect(vid_scrMain, &rectBox, color); 132 | } else { 133 | SDL_Rect shadeBox = {0, 0, (unsigned short)w, (unsigned short)h}; 134 | SDL_FillRect(vid_shade, &shadeBox, color); 135 | 136 | SDL_SetAlpha(vid_shade, SDL_SRCALPHA, opaque); 137 | SDL_BlitSurface(vid_shade, &shadeBox, vid_scrMain, &rectBox); 138 | } 139 | } 140 | } 141 | 142 | // Draws a texture to the video buffer 143 | void vid_drawTexture(VidTexture* t, int x, int y) 144 | { 145 | if(vid_scrMain && t > 0) { 146 | SDL_Surface* tSurface = (SDL_Surface*)t; 147 | SDL_Rect offset = {(signed short)x, (signed short)y, 0, 0}; 148 | SDL_BlitSurface(tSurface, NULL, vid_scrMain, &offset); 149 | } 150 | } 151 | 152 | // Generates a texture from the given image file 153 | VidTexture* vid_generateImageTexture(const char* filename, int w, int h, char smooth) 154 | { 155 | if(vid_scrMain) { 156 | //image already cached? 157 | if(strcmp(filename, vid_cachedImageFilename) != 0) { 158 | if(vid_cachedImage) SDL_FreeSurface(vid_cachedImage); 159 | SDL_Surface* imgSurfaceRaw = IMG_Load(filename); 160 | vid_cachedImage = SDL_ConvertSurface(imgSurfaceRaw, vid_scrMain->format, SURFACE_TYPE); 161 | SDL_FreeSurface(imgSurfaceRaw); 162 | strncpy(vid_cachedImageFilename, filename, MAX_IMAGE_CACHE_FILENAME_SIZE); 163 | vid_cachedImageFilename[MAX_IMAGE_CACHE_FILENAME_SIZE-1] = 0; 164 | } 165 | 166 | SDL_Surface* imgSurface = NULL; 167 | if(vid_cachedImage->format->BitsPerPixel == 32 || vid_cachedImage->format->BitsPerPixel == 8) { 168 | imgSurface = zoomSurface(vid_cachedImage, (double)w/(double)(vid_cachedImage->w), (double)h/(double)(vid_cachedImage->h), smooth); 169 | } else { 170 | //make sure to convert back to optimized format 171 | SDL_Surface* imgSurfaceRaw2 = zoomSurface(vid_cachedImage, (double)w/(double)(vid_cachedImage->w), (double)h/(double)(vid_cachedImage->h), smooth); 172 | imgSurface = SDL_ConvertSurface(imgSurfaceRaw2, vid_scrMain->format, SURFACE_TYPE); 173 | SDL_FreeSurface(imgSurfaceRaw2); 174 | } 175 | 176 | return (VidTexture*)imgSurface; 177 | } 178 | return 0; 179 | } 180 | 181 | // Generates a texture from the given text 182 | VidTexture* vid_generateTextTexture(const char* text, unsigned char rF, unsigned char gF, unsigned char bF, 183 | unsigned char rB, unsigned char gB, unsigned char bB, char fontSize, char isBold) 184 | { 185 | if(vid_scrMain) { 186 | //font already cached? 187 | if(vid_cachedFontSize != (int)fontSize) { 188 | if(vid_cachedFont) TTF_CloseFont(vid_cachedFont); 189 | vid_cachedFont = TTF_OpenFont("data/img/font.ttf", fontSize); 190 | vid_cachedFontSize = fontSize; 191 | } 192 | 193 | SDL_Color foregroundColor = {rF, gF, bF}; 194 | SDL_Color backgroundColor = {rB, gB, bB}; 195 | if(isBold) TTF_SetFontStyle(vid_cachedFont, TTF_STYLE_BOLD); 196 | else TTF_SetFontStyle(vid_cachedFont, TTF_STYLE_NORMAL); 197 | SDL_Surface* textSurfaceRaw = TTF_RenderText_Shaded(vid_cachedFont, text, foregroundColor, backgroundColor); 198 | SDL_Surface* textSurface = SDL_ConvertSurface(textSurfaceRaw, vid_scrMain->format, SURFACE_TYPE); 199 | 200 | SDL_FreeSurface(textSurfaceRaw); 201 | return (VidTexture*)textSurface; 202 | } 203 | return 0; 204 | } 205 | 206 | // Generates a texture from the current state of the screen 207 | VidTexture* vid_generateScreenTexture(int x, int y, int w, int h) 208 | { 209 | if(vid_scrMain) { 210 | SDL_Surface* screenSurface = SDL_CreateRGBSurface(SURFACE_TYPE, (unsigned short)w, (unsigned short)h, vid_scrMain->format->BitsPerPixel, 211 | vid_scrMain->format->Rmask, vid_scrMain->format->Gmask, vid_scrMain->format->Bmask, vid_scrMain->format->Amask); 212 | SDL_Rect rect = {(signed short)x, (signed short)y, (unsigned short)w, (unsigned short)h}; 213 | SDL_BlitSurface(vid_scrMain, &rect, screenSurface, NULL); 214 | 215 | return (VidTexture*)screenSurface; 216 | } 217 | return 0; 218 | } 219 | 220 | // Compsites the given image onto the given texture 221 | void vid_compositeImageToTexture(VidTexture* t, const char* filename, unsigned char opaque, char smooth) 222 | { 223 | if(vid_scrMain) { 224 | SDL_Surface* tSurface = (SDL_Surface*)t; 225 | 226 | SDL_Surface* imgSurfaceRaw = IMG_Load(filename); 227 | SDL_Surface* imgSurfaceZoomed = zoomSurface(imgSurfaceRaw, (double)tSurface->w/(double)(imgSurfaceRaw->w), (double)tSurface->h/(double)(imgSurfaceRaw->h), smooth); 228 | SDL_FreeSurface(imgSurfaceRaw); 229 | SDL_Surface* imgSurfaceOpt = SDL_ConvertSurface(imgSurfaceZoomed, vid_scrMain->format, SURFACE_TYPE); 230 | SDL_FreeSurface(imgSurfaceZoomed); 231 | 232 | SDL_SetAlpha(imgSurfaceOpt, SDL_SRCALPHA, opaque); 233 | SDL_BlitSurface(imgSurfaceOpt, NULL, tSurface, NULL); 234 | SDL_FreeSurface(imgSurfaceOpt); 235 | } 236 | } 237 | 238 | // Compsites the given color onto the given texture 239 | void vid_compositeColorToTexture(VidTexture* t, unsigned char r, unsigned char g, unsigned char b, unsigned char opaque) 240 | { 241 | if(vid_scrMain) { 242 | SDL_Surface* tSurface = (SDL_Surface*)t; 243 | 244 | SDL_Surface* colorSurface = SDL_CreateRGBSurface(SURFACE_TYPE, tSurface->w, tSurface->h, tSurface->format->BitsPerPixel, 245 | tSurface->format->Rmask, tSurface->format->Gmask, tSurface->format->Bmask, tSurface->format->Amask); 246 | Uint32 color = SDL_MapRGBA(vid_scrMain->format, r, g, b, 0); 247 | SDL_Rect rectBox = {0, 0, (unsigned short)tSurface->w, (unsigned short)tSurface->h}; 248 | SDL_FillRect(colorSurface, &rectBox, color); 249 | 250 | SDL_SetAlpha(colorSurface, SDL_SRCALPHA, opaque); 251 | SDL_BlitSurface(colorSurface, NULL, tSurface, NULL); 252 | SDL_FreeSurface(colorSurface); 253 | } 254 | } 255 | 256 | // Clears memory for the given texture 257 | void vid_clearTexture(VidTexture* t) 258 | { 259 | if(t > 0) { 260 | SDL_Surface* tSurface = (SDL_Surface*)t; 261 | if(tSurface) SDL_FreeSurface(tSurface); 262 | } 263 | } 264 | 265 | // Flushes the video buffer to the screen 266 | void vid_flush() 267 | { 268 | if(vid_scrMain) { 269 | SDL_Flip(vid_scrMain); 270 | } 271 | } 272 | 273 | // Clears any cached elements (must reinitialize) 274 | int vid_clear() 275 | { 276 | //clear resources 277 | if(vid_shade) SDL_FreeSurface(vid_shade); 278 | vid_shade = NULL; 279 | if(vid_cachedImage) SDL_FreeSurface(vid_cachedImage); 280 | vid_cachedImage = NULL; 281 | vid_cachedImageFilename[0] = 0; 282 | if(vid_cachedFont) TTF_CloseFont(vid_cachedFont); 283 | vid_cachedFont = NULL; 284 | vid_cachedFontSize = -1; 285 | 286 | vid_isInitFlag = INIT_FLAG_PARTIAL; 287 | return 0; 288 | } 289 | 290 | // Closes the Video interface 291 | int vid_close() 292 | { 293 | //clear resources 294 | if(vid_scrMain) SDL_FreeSurface(vid_scrMain); 295 | vid_scrMain = NULL; 296 | vid_clear(); 297 | 298 | //close down SDL 299 | TTF_Quit(); 300 | IMG_Quit(); 301 | SDL_Quit(); 302 | 303 | vid_isInitFlag = INIT_FLAG_NOT; 304 | return 0; 305 | } 306 | -------------------------------------------------------------------------------- /source/core/vid.h: -------------------------------------------------------------------------------- 1 | #ifndef VID_H 2 | #define VID_H 3 | 4 | typedef void VidTexture; 5 | 6 | // Setup and initialize the Video interface 7 | int vid_init(); 8 | 9 | // Checks if the Video interface is initialized 10 | char vid_isInit(); 11 | 12 | // Gets the current width of the screen 13 | int vid_getScreenWidth(); 14 | 15 | // Gets the current height of the screen 16 | int vid_getScreenHeight(); 17 | 18 | // Gets the given textures width 19 | int vid_getTextureWidth(VidTexture* t); 20 | 21 | // Gets the given textures height 22 | int vid_getTextureHeight(VidTexture* t); 23 | 24 | // Saves the current screen as a bitmap 25 | void vid_saveScreen(const char* file); 26 | 27 | // Draws a box to the video buffer 28 | void vid_drawBox(int x, int y, int w, int h, unsigned char r, unsigned char g, unsigned char b, unsigned char opaque); 29 | 30 | // Draws a texture to the video buffer 31 | void vid_drawTexture(VidTexture* t, int x, int y); 32 | 33 | // Generates a texture from the given image file 34 | VidTexture* vid_generateImageTexture(const char* filename, int w, int h, char smooth); 35 | 36 | // Generates a texture from the given text 37 | VidTexture* vid_generateTextTexture(const char* text, unsigned char rF, unsigned char gF, unsigned char bF, 38 | unsigned char rB, unsigned char gB, unsigned char bB, char fontSize, char isBold); 39 | 40 | // Generates a texture from the current state of the screen 41 | VidTexture* vid_generateScreenTexture(int x, int y, int w, int h); 42 | 43 | // Compsites the given image onto the given texture 44 | void vid_compositeImageToTexture(VidTexture* t, const char* filename, unsigned char opaque, char smooth); 45 | 46 | // Compsites the given color onto the given texture 47 | void vid_compositeColorToTexture(VidTexture* t, unsigned char r, unsigned char g, unsigned char b, unsigned char opaque); 48 | 49 | // Clears memory for the given texture 50 | void vid_clearTexture(VidTexture* t); 51 | 52 | // Flushes the video buffer to the screen 53 | void vid_flush(); 54 | 55 | // Clears any cached elements (must reinitialize) 56 | int vid_clear(); 57 | 58 | // Closes the Video interface 59 | int vid_close(); 60 | 61 | 62 | #endif /* VID_H */ 63 | -------------------------------------------------------------------------------- /source/core/vkey.c: -------------------------------------------------------------------------------- 1 | #include "vkey.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | // Constants 11 | static const char* vkey_deviceId = "vkey-uinput"; 12 | static const int vkey_keyBits[] = { KEY_A, KEY_B, KEY_C, KEY_D, KEY_E, KEY_F, KEY_G, KEY_H, KEY_I, KEY_J, KEY_K, 13 | KEY_L, KEY_M, KEY_N, KEY_O, KEY_P, KEY_Q, KEY_R, KEY_S, KEY_T, KEY_U, KEY_V, KEY_W, KEY_X, KEY_Y, KEY_Z, 14 | KEY_0, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, KEY_8, KEY_9, 15 | KEY_KP0, KEY_KP1, KEY_KP2, KEY_KP3, KEY_KP4, KEY_KP5, KEY_KP6, KEY_KP7, KEY_KP8, KEY_KP9, 16 | KEY_KPASTERISK, KEY_KPMINUS, KEY_KPPLUS, KEY_KPDOT, KEY_KPJPCOMMA, KEY_KPENTER, KEY_KPSLASH, KEY_KPEQUAL, KEY_KPPLUSMINUS, 17 | KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5, KEY_F6, KEY_F7, KEY_F8, KEY_F9, KEY_F10, KEY_F11, KEY_F12, 18 | KEY_ESC, KEY_MINUS, KEY_EQUAL, KEY_BACKSPACE, KEY_TAB, KEY_LEFTBRACE, KEY_RIGHTBRACE, KEY_ENTER, KEY_LEFTCTRL, 19 | KEY_RIGHTCTRL, KEY_SEMICOLON, KEY_APOSTROPHE, KEY_GRAVE, KEY_LEFTSHIFT, KEY_RIGHTSHIFT, KEY_BACKSLASH, KEY_COMMA, 20 | KEY_DOT, KEY_SLASH, KEY_LEFTALT, KEY_RIGHTALT, KEY_SPACE, KEY_CAPSLOCK, KEY_NUMLOCK, KEY_SCROLLLOCK, KEY_HOME, 21 | KEY_PAGEUP, KEY_PAGEDOWN, KEY_UP, KEY_DOWN, KEY_LEFT, KEY_RIGHT, KEY_END, KEY_INSERT, KEY_DELETE 22 | }; 23 | 24 | // Data 25 | static int vkey_fd = -1; 26 | 27 | // Helper functions 28 | static void vkey_emit(int type, int code, int val); 29 | 30 | // Setup and initialize the virtual keyboard 31 | int vkey_init() 32 | { 33 | int i; 34 | 35 | //already initialized? 36 | if(vkey_fd != -1) return 0; 37 | 38 | //open device 39 | if((vkey_fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK) ) < 0) { 40 | fprintf(stderr, "vkey_init: Unable to open /dev/uinput: %s\n", strerror(errno)); 41 | vkey_close(); 42 | return 1; 43 | } 44 | 45 | //set phys 46 | ioctl(vkey_fd, UI_SET_PHYS, vkey_deviceId); 47 | 48 | //enable types and keys 49 | ioctl(vkey_fd, UI_SET_EVBIT, EV_KEY); 50 | ioctl(vkey_fd, UI_SET_EVBIT, EV_ABS); 51 | for(i=0; i<102; i++) ioctl(vkey_fd, UI_SET_KEYBIT, vkey_keyBits[i]); 52 | 53 | //set axis absolute values (necessary for emulators) 54 | struct uinput_abs_setup abs_setup; 55 | memset(&abs_setup, 0, sizeof(abs_setup)); 56 | abs_setup.code = ABS_X; 57 | abs_setup.absinfo.value = 0; 58 | abs_setup.absinfo.minimum = 255; 59 | abs_setup.absinfo.maximum = 0; 60 | abs_setup.absinfo.fuzz = 0; 61 | abs_setup.absinfo.flat = 0; 62 | abs_setup.absinfo.resolution = 0; 63 | ioctl(vkey_fd, UI_ABS_SETUP, &abs_setup); 64 | abs_setup.code = ABS_Y; 65 | ioctl(vkey_fd, UI_ABS_SETUP, &abs_setup); 66 | 67 | //setup deivce info 68 | struct uinput_setup usetup; 69 | memset(&usetup, 0, sizeof(usetup)); 70 | strncpy(usetup.name, vkey_deviceId, sizeof(usetup.name) - 1); 71 | usetup.id.vendor = 0x1; 72 | usetup.id.product = 0x1; 73 | usetup.id.version = 0x1; 74 | usetup.id.bustype = 0x3; 75 | usetup.ff_effects_max = FF_MAX_EFFECTS; 76 | ioctl(vkey_fd, UI_DEV_SETUP, &usetup); 77 | 78 | //create device 79 | ioctl(vkey_fd, UI_DEV_CREATE); 80 | 81 | //wait some time until the Window Manager can get the reference 82 | //for the new virtual device to receive data from 83 | sleep(1); 84 | return 0; 85 | } 86 | 87 | // Checks if the Virtual Keyboard interface is initialized 88 | char vkey_isInit() 89 | { 90 | if(vkey_fd != -1) return 1; 91 | return 0; 92 | } 93 | 94 | // Gets the name of the virtual keyboard 95 | const char* vkey_getDeviceName() 96 | { 97 | return vkey_deviceId; 98 | } 99 | 100 | // Sets the state of the given key 101 | void vkey_setKeyState(int code, char state) 102 | { 103 | if(vkey_fd >= 0) { 104 | if(state > 0) state = 1; 105 | vkey_emit(EV_KEY, code, state); 106 | vkey_emit(EV_SYN, SYN_REPORT, 0); 107 | } 108 | } 109 | 110 | // Closes the virtual keyboard 111 | int vkey_close() 112 | { 113 | if(vkey_fd >= 0) { 114 | ioctl(vkey_fd, UI_DEV_DESTROY); 115 | close(vkey_fd); 116 | vkey_fd = -1; 117 | } 118 | 119 | return 0; 120 | } 121 | 122 | // Emits code value for the virtual device 123 | static void vkey_emit(int type, int code, int val) { 124 | struct input_event ie; 125 | memset(&ie, 0, sizeof(ie)); 126 | ie.type = type; 127 | ie.code = code; 128 | ie.value = val; 129 | write(vkey_fd, &ie, sizeof(ie)); 130 | } 131 | -------------------------------------------------------------------------------- /source/core/vkey.h: -------------------------------------------------------------------------------- 1 | #ifndef VKEY_H 2 | #define VKEY_H 3 | 4 | #define KEY_A 30 5 | #define KEY_B 48 6 | #define KEY_C 46 7 | #define KEY_D 32 8 | #define KEY_E 18 9 | #define KEY_F 33 10 | #define KEY_G 34 11 | #define KEY_H 35 12 | #define KEY_I 23 13 | #define KEY_J 36 14 | #define KEY_K 37 15 | #define KEY_L 38 16 | #define KEY_M 50 17 | #define KEY_N 49 18 | #define KEY_O 24 19 | #define KEY_P 25 20 | #define KEY_Q 16 21 | #define KEY_R 19 22 | #define KEY_S 31 23 | #define KEY_T 20 24 | #define KEY_U 22 25 | #define KEY_V 47 26 | #define KEY_W 17 27 | #define KEY_X 45 28 | #define KEY_Y 21 29 | #define KEY_Z 44 30 | 31 | #define KEY_0 11 32 | #define KEY_1 2 33 | #define KEY_2 3 34 | #define KEY_3 4 35 | #define KEY_4 5 36 | #define KEY_5 6 37 | #define KEY_6 7 38 | #define KEY_7 8 39 | #define KEY_8 9 40 | #define KEY_9 10 41 | 42 | #define KEY_F1 59 43 | #define KEY_F2 60 44 | #define KEY_F3 61 45 | #define KEY_F4 62 46 | #define KEY_F5 63 47 | #define KEY_F6 64 48 | #define KEY_F7 65 49 | #define KEY_F8 66 50 | #define KEY_F9 67 51 | #define KEY_F10 68 52 | #define KEY_F11 87 53 | #define KEY_F12 88 54 | 55 | #define KEY_KP0 82 56 | #define KEY_KP1 79 57 | #define KEY_KP2 80 58 | #define KEY_KP3 81 59 | #define KEY_KP4 75 60 | #define KEY_KP5 76 61 | #define KEY_KP6 77 62 | #define KEY_KP7 71 63 | #define KEY_KP8 72 64 | #define KEY_KP9 73 65 | #define KEY_KPASTERISK 55 66 | #define KEY_KPMINUS 74 67 | #define KEY_KPPLUS 78 68 | #define KEY_KPDOT 83 69 | #define KEY_KPJPCOMMA 95 70 | #define KEY_KPENTER 96 71 | #define KEY_KPSLASH 98 72 | #define KEY_KPEQUAL 117 73 | #define KEY_KPPLUSMINUS 118 74 | 75 | #define KEY_ESC 1 76 | #define KEY_MINUS 12 77 | #define KEY_EQUAL 13 78 | #define KEY_BACKSPACE 14 79 | #define KEY_TAB 15 80 | #define KEY_LEFTBRACE 26 81 | #define KEY_RIGHTBRACE 27 82 | #define KEY_ENTER 28 83 | #define KEY_LEFTCTRL 29 84 | #define KEY_RIGHTCTRL 97 85 | #define KEY_SEMICOLON 39 86 | #define KEY_APOSTROPHE 40 87 | #define KEY_GRAVE 41 88 | #define KEY_LEFTSHIFT 42 89 | #define KEY_RIGHTSHIFT 54 90 | #define KEY_BACKSLASH 43 91 | #define KEY_COMMA 51 92 | #define KEY_DOT 52 93 | #define KEY_SLASH 53 94 | #define KEY_LEFTALT 56 95 | #define KEY_RIGHTALT 100 96 | #define KEY_SPACE 57 97 | #define KEY_CAPSLOCK 58 98 | #define KEY_NUMLOCK 69 99 | #define KEY_SCROLLLOCK 70 100 | #define KEY_HOME 102 101 | #define KEY_PAGEUP 104 102 | #define KEY_PAGEDOWN 109 103 | #define KEY_UP 103 104 | #define KEY_DOWN 108 105 | #define KEY_LEFT 105 106 | #define KEY_RIGHT 106 107 | #define KEY_END 107 108 | #define KEY_INSERT 110 109 | #define KEY_DELETE 111 110 | 111 | // Setup and initialize the Virtual Keyboard 112 | int vkey_init(); 113 | 114 | // Checks if the Virtual Keyboard interface is initialized 115 | char vkey_isInit(); 116 | 117 | // Gets the name of the virtual keyboard 118 | const char* vkey_getDeviceName(); 119 | 120 | // Sets the state of the given key 121 | void vkey_setKeyState(int code, char state); 122 | 123 | // Closes the Virtual Keyboard 124 | int vkey_close(); 125 | 126 | 127 | #endif /* VKEY_H */ 128 | -------------------------------------------------------------------------------- /source/core/wgc.c: -------------------------------------------------------------------------------- 1 | #include "wgc.h" 2 | #include "nrf.h" 3 | #include "vkey.h" 4 | #include 5 | #include 6 | #include 7 | 8 | #define POLLING_US 15000 9 | #define TIMEOUT_US 5000000 10 | 11 | #define POLLING_ONGOING 10 12 | 13 | #define WGC_KEY_B KEY_Z 14 | #define WGC_KEY_SL KEY_RIGHTSHIFT 15 | #define WGC_KEY_ST KEY_ENTER 16 | #define WGC_KEY_UP KEY_UP 17 | #define WGC_KEY_DN KEY_DOWN 18 | #define WGC_KEY_LF KEY_LEFT 19 | #define WGC_KEY_RT KEY_RIGHT 20 | #define WGC_KEY_A KEY_X 21 | #define WGC_KEY_L KEY_Q 22 | #define WGC_KEY_R KEY_W 23 | 24 | #define WGC_MASK_A 0x0001 25 | #define WGC_MASK_B 0x0002 26 | #define WGC_MASK_RT 0x0004 27 | #define WGC_MASK_LF 0x0008 28 | #define WGC_MASK_UP 0x0010 29 | #define WGC_MASK_DN 0x0020 30 | #define WGC_MASK_SL 0x0040 31 | #define WGC_MASK_ST 0x0080 32 | #define WGC_MASK_L 0x0100 33 | #define WGC_MASK_R 0x0200 34 | 35 | #define CTRL_UNKNOWN 0 36 | #define CTRL_SEARCHING 1 37 | #define CTRL_GBA 2 38 | #define CTRL_GB 3 39 | 40 | // Data 41 | static char wgc_isInitFlag = 0; 42 | static uint8_t wgc_isPolling = 0; 43 | static uint8_t wgc_nrfChannel = 0; 44 | static uint8_t wgc_nrfRx[6] = "wgbr"; 45 | static uint8_t wgc_nrfTx[6] = "wgbtx"; 46 | static uint8_t wgc_ctrlType = 0; 47 | static uint32_t wgc_timeout = 0; 48 | static pthread_t wgc_threadId = -1; 49 | static int wgc_state = 0x0000; 50 | 51 | // Helper Functions 52 | static void wgc_powerUpReceiver(); 53 | static void wgc_checkControllerType(); 54 | static void wgc_checkControllerData(); 55 | static void wgc_updateState(int data); 56 | 57 | // Util Functions 58 | static void wgc_sleep(long usec); 59 | 60 | // Controller state polling thread 61 | void* wgc_thread_statePolling(void* args) 62 | { 63 | while(wgc_isInitFlag > 0) { 64 | if(wgc_isPolling == 1) { 65 | wgc_isPolling = POLLING_ONGOING; 66 | wgc_checkControllerData(); 67 | wgc_isPolling = 1; 68 | 69 | wgc_timeout += POLLING_US; 70 | wgc_sleep(POLLING_US); 71 | 72 | } else { 73 | wgc_sleep(100*1000); 74 | } 75 | } 76 | return 0; 77 | } 78 | 79 | // Setup and initialize the Controller interface 80 | int wgc_init() 81 | { 82 | //already initialized? 83 | if(wgc_isInitFlag == 1) return 0; 84 | 85 | //check dependencies 86 | if(!nrf_isInit() || !vkey_isInit()) { 87 | if(!nrf_isInit()) fprintf(stderr, "wgc_init: nRF24L01 dependency is not initialized\n"); 88 | if(!vkey_isInit()) fprintf(stderr, "wgc_init: Virtual Keyboard dependency is not initialized\n"); 89 | wgc_close(); 90 | return 1; 91 | } 92 | 93 | //default data 94 | wgc_isPolling = 0; 95 | wgc_ctrlType = 0; 96 | wgc_timeout = 0; 97 | 98 | //start polling thread 99 | wgc_isInitFlag = 1; 100 | if(pthread_create(&wgc_threadId, NULL, wgc_thread_statePolling, NULL) > 0) { 101 | wgc_close(); 102 | return 1; 103 | } 104 | 105 | //set to channel 1 and address 1 106 | wgc_nrfChannel = 1; 107 | wgc_nrfRx[4] = 1; 108 | 109 | //configure nrf24l01 110 | nrf_configRegister(RF_CH, wgc_nrfChannel); //set RF channel 111 | nrf_configRegister(RX_PW_P0, 1); //set length of incoming payload 112 | nrf_configRegister(EN_AA, 0< -1) pthread_join(wgc_threadId, NULL); 150 | wgc_threadId = -1; 151 | return 0; 152 | } 153 | 154 | // Powers up the nrf receiver 155 | static void wgc_powerUpReceiver() { 156 | nrf_configRegister(CONFIG, (1< CTRL_SEARCHING) { 208 | 209 | //timeout? 210 | if(wgc_timeout >= TIMEOUT_US) { 211 | wgc_ctrlType = CTRL_UNKNOWN; 212 | //printf("Controller timed out\n"); 213 | } 214 | 215 | //check for payload 216 | else if(nrf_status() & (1<