├── 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<