Skip to content

Commit

Permalink
Merge pull request #13 from rodri042/v1.1
Browse files Browse the repository at this point in the history
v1.1: overclock mod, runtime config, key mappings, 3d-printed case
  • Loading branch information
afska committed Nov 19, 2021
2 parents f391064 + 8dbac48 commit 2e88c7c
Show file tree
Hide file tree
Showing 35 changed files with 1,046 additions and 294 deletions.
1 change: 0 additions & 1 deletion .gitattributes
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
*.exe filter=lfs diff=lfs merge=lfs -text
*.tool filter=lfs diff=lfs merge=lfs -text
*.zip filter=lfs diff=lfs merge=lfs -text
*.gif filter=lfs diff=lfs merge=lfs -text
Binary file added 3d/bottom.3mf
Binary file not shown.
Binary file added 3d/link.3mf
Binary file not shown.
Binary file added 3d/top.3mf
Binary file not shown.
220 changes: 137 additions & 83 deletions README.md

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion gba/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ Before compiling, you can comment/uncomment these build parameters in `src/Build
Name | Description
--- | ---
`WITH_AUDIO` | Enables GSM audio decoding.
`BENCHMARK` | Replaces all the code with an SPI speed benchmark.

## Commands

Expand Down
9 changes: 5 additions & 4 deletions gba/src/Benchmark.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "BuildConfig.h"
#ifndef BENCHMARK_H
#define BENCHMARK_H

#ifdef BENCHMARK
#include "BuildConfig.h"

#include "SPISlave.h"
#include "Utils.h"
Expand All @@ -13,7 +14,7 @@ typedef struct {
u32 badPackets;
} State;

inline void onVBlank(State& state) {
ALWAYS_INLINE void onVBlank(State& state) {
state.frame++;
if (state.frame >= 60) {
m3_plot(20, 80, state.goodPackets >= 40000 ? CLR_GREEN : CLR_RED);
Expand Down Expand Up @@ -59,7 +60,7 @@ CODE_IWRAM void mainLoop() {
}
}

inline void init() {
ALWAYS_INLINE void init() {
REG_DISPCNT = DCNT_MODE3 | DCNT_BG2;
}

Expand Down
2 changes: 0 additions & 2 deletions gba/src/BuildConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,4 @@

// #define WITH_AUDIO

// #define BENCHMARK

#endif // BUILD_CONFIG_H
77 changes: 58 additions & 19 deletions gba/src/Protocol.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,10 @@
#include <stdint.h>

// RENDER
#define RENDER_WIDTH 120
#define RENDER_HEIGHT 80
#define TOTAL_PIXELS (RENDER_WIDTH * RENDER_HEIGHT)
#define DRAW_SCALE_X 2
#define DRAW_SCALE_Y 2
#define DRAW_SCANLINES true
#define DRAW_WIDTH (RENDER_WIDTH * DRAW_SCALE_X)
#define DRAW_HEIGHT (RENDER_HEIGHT * DRAW_SCALE_Y)
#define TOTAL_SCREEN_PIXELS (DRAW_WIDTH * DRAW_HEIGHT)
#define DRAW_WIDTH 240
#define DRAW_HEIGHT 160
#define PALETTE_COLORS 256
#define TOTAL_SCREEN_PIXELS (DRAW_WIDTH * DRAW_HEIGHT)

// TRANSFER
#define PACKET_SIZE 4
Expand All @@ -26,26 +20,24 @@
#define TRANSFER_SYNC_PERIOD 32
#define COLORS_PER_PACKET (PACKET_SIZE / COLOR_SIZE)
#define PIXELS_PER_PACKET (PACKET_SIZE / PIXEL_SIZE)
#define MAX_PIXELS_SIZE (TOTAL_PIXELS / PIXELS_PER_PACKET)
#define MAX_PIXELS_SIZE (TOTAL_SCREEN_PIXELS / PIXELS_PER_PACKET)
#define AUDIO_PADDED_SIZE (AUDIO_CHUNK_SIZE + AUDIO_CHUNK_PADDING)

// DIFFS
#define TEMPORAL_DIFF_MAX_SIZE (TOTAL_PIXELS / 8)
#define TEMPORAL_DIFF_MAX_PADDED_SIZE (TEMPORAL_DIFF_MAX_SIZE + 4)
#define TEMPORAL_DIFF_MAX_PACKETS (TEMPORAL_DIFF_MAX_SIZE / PACKET_SIZE)
#define TEMPORAL_DIFF_MAX_SIZE(TOTAL_PIXELS) (TOTAL_PIXELS / 8)
#define TEMPORAL_DIFF_MAX_PADDED_SIZE(TOTAL_PIXELS) \
(TEMPORAL_DIFF_MAX_SIZE(TOTAL_PIXELS) + 4)
#define TEMPORAL_DIFF_MAX_PACKETS(TOTAL_PIXELS) \
(TEMPORAL_DIFF_MAX_SIZE(TOTAL_PIXELS) / PACKET_SIZE)
#define MAX_RLE 255

// FILES
#define CONFIG_FILENAME "config.cfg"
#define CONTROLS_FILENAME "controls.cfg"
#define PALETTE_CACHE_FILENAME "palette.cache"

// COMMANDS
#define AUDIO_BIT_MASK 0b10000000000000000000000000000000
#define COMPR_BIT_MASK 0b01000000000000000000000000000000
#define PACKS_BIT_MASK 0b00000000000000000011111111111111
#define START_BIT_MASK 0b00000000000000001111111111111111
#define PACKS_BIT_OFFSET 16
#define CMD_RESET 0x99887766
#define CMD_RESET 0x99887000
#define CMD_RPI_OFFSET 1
#define CMD_GBA_OFFSET 2
#define CMD_FRAME_START 0x12345610
Expand All @@ -54,4 +46,51 @@
#define CMD_FRAME_END 0x12345640
#define CMD_RECOVERY 0x98765490

// RESET PACKET
#define RESET_PACKET_MASK 0b11111111111111111111000000000000
#define RENDER_MODE_BIT_MASK 0b1111
#define CONTROLS_BIT_MASK 0b1111
#define COMPRESSION_BIT_MASK 0b111
#define CPU_OVERCLOCK_BIT_MASK 0b1
#define CONTROLS_BIT_OFFSET 4
#define COMPRESSION_BIT_OFFSET 8
#define CPU_OVERCLOCK_BIT_OFFSET 11
#define IS_RESET(VALUE) (((VALUE)&RESET_PACKET_MASK) == CMD_RESET)

// METADATA PACKET
#define AUDIO_BIT_MASK 0b10000000000000000000000000000000
#define COMPR_BIT_MASK 0b01000000000000000000000000000000
#define PACKS_BIT_MASK 0b00000000000000000011111111111111
#define START_BIT_MASK 0b00000000000000001111111111111111
#define PACKS_BIT_OFFSET 16

// RENDER MODES
#define RENDER_MODES 9
#define RENDER_MODE_BENCHMARK_1 9
#define RENDER_MODE_BENCHMARK_2 10
#define RENDER_MODE_IS_BENCHMARK(MODE) \
(MODE == RENDER_MODE_BENCHMARK_1 || MODE == RENDER_MODE_BENCHMARK_2)
#define DEFAULT_RENDER_MODE 4
#define COMPRESSION_LEVELS 6

#ifdef WITH_AUDIO
#define RENDER_MODE_IS_INVALID(MODE) \
((MODE) == 1 || (MODE) == 2 || (MODE) == 3 || (MODE) == 5 || (MODE) == 6)
#endif
#ifndef WITH_AUDIO
#define RENDER_MODE_IS_INVALID(MODE) (false)
#endif

const uint32_t RENDER_MODE_WIDTH[RENDER_MODES] = {60, 60, 60, 120, 120,
120, 240, 240, 240};
const uint32_t RENDER_MODE_HEIGHT[RENDER_MODES] = {40, 80, 160, 40, 80,
160, 40, 80, 160};
const uint32_t RENDER_MODE_SCALEX[RENDER_MODES] = {4, 4, 4, 2, 2, 2, 1, 1, 1};
const uint32_t RENDER_MODE_SCALEY[RENDER_MODES] = {4, 2, 1, 4, 2, 1, 4, 2, 1};
const uint32_t RENDER_MODE_PIXELS[RENDER_MODES] = {
2400, 4800, 9600, 4800, 9600, 19200, 9600, 19200, 38400};

const uint32_t DIFF_THRESHOLDS[COMPRESSION_LEVELS] = {0, 500, 1000,
1500, 3000, 6000};

#endif // PROTOCOL_H
232 changes: 232 additions & 0 deletions gba/src/RuntimeConfig.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,232 @@
#ifndef RUNTIME_CONFIG_H
#define RUNTIME_CONFIG_H

#include <tonc.h>
#include "Protocol.h"
#include "Utils.h"
#include "_state.h"

#define CONFIG_ITEMS 11
#define CONFIG_PERCENTAGE_ITEMS 3
#define CONFIG_BOOLEAN_ITEMS 2
#define CONFIG_NUMERIC_ITEMS 9
#define CONFIG_COMPRESSION_ITEMS 6
#define CONFIG_MENU_KEY_ITEMS 2

const char* const CONFIG_PERCENTAGE_OPTIONS[CONFIG_PERCENTAGE_ITEMS] = {
" <25%>", " <50%>", "<100%>"};
const char* const CONFIG_BOOLEAN_OPTIONS[CONFIG_BOOLEAN_ITEMS] = {"<OFF>",
" <ON>"};
const char* const CONFIG_COMPRESSION_OPTIONS[CONFIG_COMPRESSION_ITEMS] = {
"<-->", "<LO>", "<MD>", "<HI>", "<EX>", "<!!>"};
const char* const CONFIG_MENU_KEY_OPTIONS[CONFIG_MENU_KEY_ITEMS] = {
"<A+B+L+R>", " <START>"};
const char* const CONFIG_NUMERIC_OPTIONS[CONFIG_NUMERIC_ITEMS] = {
"<01>", "<02>", "<03>", "<04>", "<05>", "<06>", "<07>", "<08>", "<09>"};

typedef struct Config {
u32 renderMode;

u8 frameWidthIndex;
u8 frameHeightIndex;
bool scanlines;
u8 compression;
bool cpuOverclock;
bool ewramOverclock;
bool exitWithStart;
u8 controls;

bool isBenchmark() { return RENDER_MODE_IS_BENCHMARK(renderMode); }
void update() {
renderMode = frameWidthIndex * CONFIG_PERCENTAGE_ITEMS + frameHeightIndex;
}
} Config;

extern Config config;

namespace RuntimeConfig {

enum Option {
FRAME_WIDTH,
FRAME_HEIGHT,
SCANLINES,
COMPRESSION,
CPU_OVERCLOCK,
EWRAM_OVERCLOCK,
EXIT_WITH_START_KEY,
CONTROLS,
BENCHMARK,
DEFAULTS,
START
};

inline void drawMenu(u32 option) {
#define SELECTION(ID) (option == ID ? ">" : " ")

tte_erase_screen();
tte_write("#{P:0,0}");
tte_write(" gba-remote-play (^_^)\n\n");
tte_write(SELECTION(Option::FRAME_WIDTH));
tte_write("Frame width ");
tte_write(CONFIG_PERCENTAGE_OPTIONS[config.frameWidthIndex]);
tte_write("\n");
tte_write(SELECTION(Option::FRAME_HEIGHT));
tte_write("Frame height ");
tte_write(CONFIG_PERCENTAGE_OPTIONS[config.frameHeightIndex]);
tte_write("\n");
tte_write(SELECTION(Option::SCANLINES));
tte_write("Scanlines ");
tte_write(CONFIG_BOOLEAN_OPTIONS[config.scanlines]);
tte_write("\n");
tte_write(SELECTION(Option::COMPRESSION));
tte_write("Compression ");
tte_write(CONFIG_COMPRESSION_OPTIONS[config.compression]);
tte_write("\n");
tte_write(SELECTION(Option::CPU_OVERCLOCK));
tte_write("CPU Overclock ");
tte_write(CONFIG_BOOLEAN_OPTIONS[config.cpuOverclock]);
tte_write("\n");
tte_write(SELECTION(Option::EWRAM_OVERCLOCK));
tte_write("EWRAM Overclock ");
tte_write(CONFIG_BOOLEAN_OPTIONS[config.ewramOverclock]);
tte_write("\n");
tte_write(SELECTION(Option::EXIT_WITH_START_KEY));
tte_write("Menu key ");
tte_write(CONFIG_MENU_KEY_OPTIONS[config.exitWithStart]);
tte_write("\n");
tte_write(SELECTION(Option::CONTROLS));
tte_write("Controls ");
tte_write(CONFIG_NUMERIC_OPTIONS[config.controls]);
tte_write("\n\n");
tte_write(SELECTION(Option::BENCHMARK));
tte_write("[BENCHMARK]\n");
tte_write(SELECTION(Option::DEFAULTS));
tte_write("[RESET OPTIONS]\n");
tte_write(SELECTION(Option::START));
tte_write(RENDER_MODE_IS_INVALID(config.renderMode)
? "<This mode is not supported>"
: "[START STREAMING]");
}

ALWAYS_INLINE void initialize() {
config.frameWidthIndex = 1;
config.frameHeightIndex = 1;
config.scanlines = true;
config.compression = 2;
config.cpuOverclock = false;
config.exitWithStart = false;
config.controls = 0;
config.update();
}

ALWAYS_INLINE void show() {
u32 option = 0;
u32 keys = 0, previousKeys = pressedKeys();

#define IS_PRESSED(KEY) (keys & KEY && !(previousKeys & KEY))
#define CYCLE_OPTIONS(N, LIMIT) ((N) < 0 ? ((LIMIT)-1) : ((N) % LIMIT))

REG_DISPCNT = DCNT_MODE0 | DCNT_BG0;
tte_init_se(0, BG_CBB(0) | BG_SBB(31), 0xF000, CLR_WHITE, 0, &fwf_default,
NULL);

drawMenu(option);

while (true) {
keys = pressedKeys();

if (IS_PRESSED(KEY_DOWN)) {
option = (option + 1) % CONFIG_ITEMS;
drawMenu(option);
} else if (IS_PRESSED(KEY_UP)) {
option = option == 0 ? CONFIG_ITEMS - 1 : option - 1;
drawMenu(option);
} else if (IS_PRESSED(KEY_A) || IS_PRESSED(KEY_RIGHT) ||
IS_PRESSED(KEY_LEFT)) {
s8 direction = (IS_PRESSED(KEY_LEFT) ? -1 : 1);

switch (option) {
case Option::FRAME_WIDTH: {
config.frameWidthIndex = CYCLE_OPTIONS(
config.frameWidthIndex + direction, CONFIG_PERCENTAGE_ITEMS);
config.update();
break;
}
case Option::FRAME_HEIGHT: {
config.frameHeightIndex = CYCLE_OPTIONS(
config.frameHeightIndex + direction, CONFIG_PERCENTAGE_ITEMS);
config.update();
break;
}
case Option::SCANLINES: {
config.scanlines = !config.scanlines;
break;
}
case Option::COMPRESSION: {
config.compression = CYCLE_OPTIONS(config.compression + direction,
CONFIG_COMPRESSION_ITEMS);
break;
}
case Option::CPU_OVERCLOCK: {
config.cpuOverclock = !config.cpuOverclock;
break;
}
case Option::EWRAM_OVERCLOCK: {
overclockEWRAM();
config.ewramOverclock = true;
break;
}
case Option::EXIT_WITH_START_KEY: {
config.exitWithStart = !config.exitWithStart;
break;
}
case Option::CONTROLS: {
config.controls =
CYCLE_OPTIONS(config.controls + direction, CONFIG_NUMERIC_ITEMS);
break;
}
case Option::BENCHMARK: {
if (IS_PRESSED(KEY_A)) {
tte_erase_screen();
tte_write("#{P:0,0}");
tte_write(
"\n L - Benchmark: safe/slow\n R - Benchmark: one-way/fast");

while (true) {
if (pressedKeys() & KEY_L) {
config.renderMode = RENDER_MODE_BENCHMARK_1;
return;
}
if (pressedKeys() & KEY_R) {
config.renderMode = RENDER_MODE_BENCHMARK_2;
return;
}
}
}
break;
}
case Option::DEFAULTS: {
if (IS_PRESSED(KEY_A))
initialize();
break;
}
case Option::START: {
if (IS_PRESSED(KEY_A) && !RENDER_MODE_IS_INVALID(config.renderMode))
return;
break;
}
}
drawMenu(option);
} else if (IS_PRESSED(KEY_START) &&
!RENDER_MODE_IS_INVALID(config.renderMode)) {
return;
}

previousKeys = keys;
vid_vsync();
}
}

} // namespace RuntimeConfig

#endif // RUNTIME_CONFIG_H
Loading

0 comments on commit 2e88c7c

Please sign in to comment.