Browser rewrite / Boot bug fixes

This commit is contained in:
Mateusz Faderewski 2023-07-02 21:52:58 +02:00
parent 1288d4fdcd
commit e0f0734e18
28 changed files with 935 additions and 520 deletions

View File

@ -1,4 +1,4 @@
FROM ubuntu:latest FROM debian:bookworm-slim
RUN apt-get update && \ RUN apt-get update && \
apt-get upgrade -y && \ apt-get upgrade -y && \
@ -6,8 +6,9 @@ RUN apt-get update && \
wget https://github.com/DragonMinded/libdragon/releases/download/toolchain-continuous-prerelease/gcc-toolchain-mips64-x86_64.deb && \ wget https://github.com/DragonMinded/libdragon/releases/download/toolchain-continuous-prerelease/gcc-toolchain-mips64-x86_64.deb && \
dpkg -i gcc-toolchain-mips64-x86_64.deb && \ dpkg -i gcc-toolchain-mips64-x86_64.deb && \
rm gcc-toolchain-mips64-x86_64.deb && \ rm gcc-toolchain-mips64-x86_64.deb && \
wget https://github.com/Polprzewodnikowy/SummerCart64/releases/download/v2.15.1/sc64-deployer-linux-v2.15.1.tar.gz && \ wget https://github.com/Polprzewodnikowy/SummerCart64/releases/download/v2.16.0/sc64-deployer-linux-v2.16.0.tar.gz && \
tar -xf sc64-deployer-linux-v2.15.1.tar.gz -C /usr/local/bin && \ tar -xf sc64-deployer-linux-v2.15.1.tar.gz -C /usr/local/bin && \
rm sc64-deployer-linux-v2.15.1.tar.gz && \ rm sc64-deployer-linux-v2.15.1.tar.gz && \
git config --global --add safe.directory "*" && \
SNIPPET="export PROMPT_COMMAND='history -a' && export HISTFILE=/commandhistory/.bash_history" && \ SNIPPET="export PROMPT_COMMAND='history -a' && export HISTFILE=/commandhistory/.bash_history" && \
echo "$SNIPPET" >> "/root/.bashrc" echo "$SNIPPET" >> "/root/.bashrc"

View File

@ -6,7 +6,7 @@
"mounts": [ "mounts": [
"source=n64flashcartmenu-bashhistory,target=/commandhistory,type=volume" "source=n64flashcartmenu-bashhistory,target=/commandhistory,type=volume"
], ],
"postCreateCommand": "cd ./libdragon && ./build.sh", "postCreateCommand": "git submodule update --init && cd ./libdragon && ./build.sh",
"customizations": { "customizations": {
"vscode": { "vscode": {
"extensions": [ "extensions": [

View File

@ -12,20 +12,26 @@ include $(N64_INST)/include/n64.mk
N64_CFLAGS += -iquote $(SOURCE_DIR) N64_CFLAGS += -iquote $(SOURCE_DIR)
SRCS = \ SRCS = \
main.c \
boot/boot.c \ boot/boot.c \
boot/crc32.c \ boot/crc32.c \
boot/ipl2.S \ boot/ipl2.S \
flashcart/flashcart.c \ flashcart/flashcart.c \
flashcart/sc64/sc64_internal.c \ flashcart/sc64/sc64_internal.c \
flashcart/sc64/sc64.c \ flashcart/sc64/sc64.c \
menu/menu_main.c \
menu/menu_info.c \
menu/menu_fileinfo.c \
menu/settings.c \
menu/rom_database.c \
utils/fs.c \
libs/toml/toml.c \ libs/toml/toml.c \
main.c menu/actions.c \
menu/menu.c \
menu/path.c \
menu/rom_database.c \
menu/settings.c \
menu/views/browser.c \
menu/views/credits.c \
menu/views/error.c \
menu/views/file_info.c \
menu/views/init.c \
menu/views/load.c \
utils/fs.c
OBJS = $(addprefix $(BUILD_DIR)/, $(addsuffix .o,$(basename $(SRCS)))) OBJS = $(addprefix $(BUILD_DIR)/, $(addsuffix .o,$(basename $(SRCS))))

View File

@ -17,7 +17,7 @@ static const ipl3_crc32_t ipl3_crc32[] = {
{ .crc32 = 0x587BD543, .seed = 0xAC }, // 5101 { .crc32 = 0x587BD543, .seed = 0xAC }, // 5101
{ .crc32 = 0x6170A4A1, .seed = 0x3F }, // 6101 { .crc32 = 0x6170A4A1, .seed = 0x3F }, // 6101
{ .crc32 = 0x009E9EA3, .seed = 0x3F }, // 7102 { .crc32 = 0x009E9EA3, .seed = 0x3F }, // 7102
{ .crc32 = 0x90BB6CB5, .seed = 0x3F }, // x102 { .crc32 = 0x90BB6CB5, .seed = 0x3F }, // 6102/7101
{ .crc32 = 0x0B050EE0, .seed = 0x78 }, // x103 { .crc32 = 0x0B050EE0, .seed = 0x78 }, // x103
{ .crc32 = 0x98BC2C86, .seed = 0x91 }, // x105 { .crc32 = 0x98BC2C86, .seed = 0x91 }, // x105
{ .crc32 = 0xACC8580A, .seed = 0x85 }, // x106 { .crc32 = 0xACC8580A, .seed = 0x85 }, // x106
@ -38,33 +38,6 @@ static io32_t *boot_get_device_base (boot_params_t *params) {
return device_base_address; return device_base_address;
} }
static bool boot_detect_tv_type (boot_params_t *params) {
io32_t *base = boot_get_device_base(params);
char region = ((io_read((uint32_t) (&base[15])) >> 8) & 0xFF);
switch (region) {
case 'P':
case 'U':
params->tv_type = BOOT_TV_TYPE_PAL;
break;
case 'E':
case 'J':
params->tv_type = BOOT_TV_TYPE_NTSC;
break;
case 'B':
params->tv_type = BOOT_TV_TYPE_MPAL;
break;
default:
return false;
}
return true;
}
static bool boot_detect_cic_seed (boot_params_t *params) { static bool boot_detect_cic_seed (boot_params_t *params) {
io32_t *base = boot_get_device_base(params); io32_t *base = boot_get_device_base(params);
@ -92,11 +65,9 @@ bool boot_is_warm (void) {
} }
void boot (boot_params_t *params) { void boot (boot_params_t *params) {
if (params->detect_tv_type) { if (params->tv_type == BOOT_TV_TYPE_PASSTHROUGH) {
if (!boot_detect_tv_type(params)) {
params->tv_type = OS_INFO->tv_type; params->tv_type = OS_INFO->tv_type;
} }
}
if (params->detect_cic_seed) { if (params->detect_cic_seed) {
if (!boot_detect_cic_seed(params)) { if (!boot_detect_cic_seed(params)) {
@ -104,6 +75,12 @@ void boot (boot_params_t *params) {
} }
} }
// asm volatile (
// "li $t1, %[status] \n"
// "mtc0 $t1, $12 \n" ::
// [status] "i" (C0_SR_CU1 | C0_SR_CU0 | C0_SR_FR)
// );
OS_INFO->mem_size_6105 = OS_INFO->mem_size; OS_INFO->mem_size_6105 = OS_INFO->mem_size;
while (!(cpu_io_read(&SP->SR) & SP_SR_HALT)); while (!(cpu_io_read(&SP->SR) & SP_SR_HALT));
@ -119,8 +96,21 @@ void boot (boot_params_t *params) {
cpu_io_write(&AI->MADDR, 0); cpu_io_write(&AI->MADDR, 0);
cpu_io_write(&AI->LEN, 0); cpu_io_write(&AI->LEN, 0);
io32_t *base = boot_get_device_base(params); while (cpu_io_read(&SP->SR) & SP_SR_DMA_BUSY);
uint32_t *ipl2_src = &ipl2;
io32_t *ipl2_dst = SP_MEM->IMEM;
for (int i = 0; i < 8; i++) {
cpu_io_write(&ipl2_dst[i], ipl2_src[i]);
}
cpu_io_write(&PI->DOM[0].LAT, 0xFF);
cpu_io_write(&PI->DOM[0].PWD, 0xFF);
cpu_io_write(&PI->DOM[0].PGS, 0x0F);
cpu_io_write(&PI->DOM[0].RLS, 0x03);
io32_t *base = boot_get_device_base(params);
uint32_t pi_config = io_read((uint32_t) (base)); uint32_t pi_config = io_read((uint32_t) (base));
cpu_io_write(&PI->DOM[0].LAT, pi_config & 0xFF); cpu_io_write(&PI->DOM[0].LAT, pi_config & 0xFF);
@ -132,13 +122,6 @@ void boot (boot_params_t *params) {
while (cpu_io_read(&DPC->SR) & DPC_SR_PIPE_BUSY); while (cpu_io_read(&DPC->SR) & DPC_SR_PIPE_BUSY);
} }
uint32_t *ipl2_src = &ipl2;
io32_t *ipl2_dst = SP_MEM->IMEM;
for (int i = 0; i < 8; i++) {
cpu_io_write(&ipl2_dst[i], ipl2_src[i]);
}
io32_t *ipl3_src = base; io32_t *ipl3_src = base;
io32_t *ipl3_dst = SP_MEM->DMEM; io32_t *ipl3_dst = SP_MEM->DMEM;
@ -159,7 +142,7 @@ void boot (boot_params_t *params) {
tv_type = (params->tv_type & 0x03); tv_type = (params->tv_type & 0x03);
reset_type = (params->reset_type & 0x01); reset_type = (params->reset_type & 0x01);
cic_seed = (params->cic_seed & 0xFF); cic_seed = (params->cic_seed & 0xFF);
version = 1; version = (params->tv_type == BOOT_TV_TYPE_PAL) ? 6 : 1;
stack_pointer = (void *) UNCACHED(&SP_MEM->IMEM[1020]); stack_pointer = (void *) UNCACHED(&SP_MEM->IMEM[1020]);
asm volatile ( asm volatile (

View File

@ -20,6 +20,7 @@ typedef enum {
BOOT_TV_TYPE_PAL = 0, BOOT_TV_TYPE_PAL = 0,
BOOT_TV_TYPE_NTSC = 1, BOOT_TV_TYPE_NTSC = 1,
BOOT_TV_TYPE_MPAL = 2, BOOT_TV_TYPE_MPAL = 2,
BOOT_TV_TYPE_PASSTHROUGH = 3,
} boot_tv_type_t; } boot_tv_type_t;
@ -28,7 +29,6 @@ typedef struct {
boot_reset_type_t reset_type; boot_reset_type_t reset_type;
boot_tv_type_t tv_type; boot_tv_type_t tv_type;
uint8_t cic_seed; uint8_t cic_seed;
bool detect_tv_type;
bool detect_cic_seed; bool detect_cic_seed;
} boot_params_t; } boot_params_t;

View File

@ -87,7 +87,12 @@ static flashcart_error_t sc64_load_rom (char *rom_path) {
return FLASHCART_ERROR_LOAD; return FLASHCART_ERROR_LOAD;
} }
size_t rom_size = ALIGN(f_size(&fil), FS_SECTOR_SIZE); // HACK: Align file size to the SD sector size to prevent FatFs from doing partial sector load.
// We are relying on direct transfer from SD to SDRAM without CPU intervention.
// Sending some extra bytes isn't an issue here.
fil.obj.objsize = ALIGN(f_size(&fil), FS_SECTOR_SIZE);
size_t rom_size = f_size(&fil);
if (rom_size > MiB(78)) { if (rom_size > MiB(78)) {
f_close(&fil); f_close(&fil);

View File

@ -5,8 +5,8 @@
#include "boot/boot.h" #include "boot/boot.h"
#include "flashcart/flashcart.h" #include "flashcart/flashcart.h"
#include "menu/menu.h"
#include "menu/settings.h" #include "menu/settings.h"
#include "menu/menu_main.h"
static void init (void) { static void init (void) {
@ -19,15 +19,12 @@ static void init (void) {
assertf(error == FLASHCART_OK, "Unknown error while initializing flashcart"); assertf(error == FLASHCART_OK, "Unknown error while initializing flashcart");
controller_init(); controller_init();
display_init(RESOLUTION_640x240, DEPTH_16_BPP, 2, GAMMA_NONE, ANTIALIAS_RESAMPLE);
display_close();
display_init(RESOLUTION_640x240, DEPTH_16_BPP, 3, GAMMA_NONE, ANTIALIAS_RESAMPLE);
graphics_set_color(0xFFFFFFFF, 0x00000000); graphics_set_color(0xFFFFFFFF, 0x00000000);
graphics_set_default_font(); graphics_set_default_font();
} }
static void deinit (void) { static void deinit (void) {
display_close();
flashcart_deinit(); flashcart_deinit();
rdpq_close(); rdpq_close();
rspq_close(); rspq_close();
@ -38,7 +35,6 @@ static void deinit (void) {
int main (void) { int main (void) {
init(); init();
settings_t settings; settings_t settings;
@ -49,7 +45,7 @@ int main (void) {
// menu_restore(&settings); // menu_restore(&settings);
// } // }
menu_main_init(&settings); menu_run(&settings);
deinit(); deinit();

66
src/menu/actions.c Normal file
View File

@ -0,0 +1,66 @@
#include <libdragon.h>
#include "actions.h"
#define ACTIONS_REPEAT_DELAY 20
#define ACTIONS_REPEAT_RATE 2
void actions_update (menu_t *menu) {
menu->actions.go_up = false;
menu->actions.go_down = false;
menu->actions.fast = false;
menu->actions.enter = false;
menu->actions.back = false;
menu->actions.info = false;
menu->actions.settings = false;
controller_scan();
struct controller_data down = get_keys_down();
struct controller_data held = get_keys_held();
if (down.c[0].err != 0) {
return;
}
if (down.c[0].up || down.c[0].C_up) {
menu->actions.go_up = true;
menu->actions.held_counter = 0;
if (down.c[0].C_up) {
menu->actions.fast = true;
}
} else if (down.c[0].down || down.c[0].C_down) {
menu->actions.go_down = true;
menu->actions.held_counter = 0;
if (down.c[0].C_down) {
menu->actions.fast = true;
}
} else if (held.c[0].up || held.c[0].C_up) {
menu->actions.held_counter += 1;
if ((menu->actions.held_counter >= ACTIONS_REPEAT_DELAY) && (menu->actions.held_counter % ACTIONS_REPEAT_RATE)) {
menu->actions.go_up = true;
if (held.c[0].C_up) {
menu->actions.fast = true;
}
}
} else if (held.c[0].down || held.c[0].C_down) {
menu->actions.held_counter += 1;
if ((menu->actions.held_counter >= ACTIONS_REPEAT_DELAY) && (menu->actions.held_counter % ACTIONS_REPEAT_RATE)) {
menu->actions.go_down = true;
if (held.c[0].C_down) {
menu->actions.fast = true;
}
}
}
if (down.c[0].A) {
menu->actions.enter = true;
} else if (down.c[0].B) {
menu->actions.back = true;
} else if (down.c[0].Z) {
menu->actions.info = true;
} else if (down.c[0].start) {
menu->actions.settings = true;
}
}

11
src/menu/actions.h Normal file
View File

@ -0,0 +1,11 @@
#ifndef ACTIONS_H__
#define ACTIONS_H__
#include "menu.h"
void actions_update (menu_t *menu);
#endif

104
src/menu/menu.c Normal file
View File

@ -0,0 +1,104 @@
#include <stdlib.h>
#include <libdragon.h>
#include "actions.h"
#include "menu.h"
#include "views.h"
static menu_t *menu_init (settings_t *settings) {
menu_t *menu = calloc(1, sizeof(menu_t));
menu->mode = MENU_MODE_INIT;
menu->next_mode = MENU_MODE_BROWSER;
menu->browser.valid = false;
menu->browser.directory = path_init(NULL); // TODO: load starting directory from settings
return menu;
}
static void menu_deinit (menu_t *menu) {
path_free(menu->browser.directory);
free(menu);
}
void menu_run (settings_t *settings) {
menu_t *menu = menu_init(settings);
bool running = true;
while (running) {
surface_t *display = display_try_get();
if (display != NULL) {
actions_update(menu);
switch (menu->mode) {
case MENU_MODE_INIT:
view_init_display(menu, display);
break;
case MENU_MODE_BROWSER:
view_browser_display(menu, display);
break;
case MENU_MODE_FILE_INFO:
view_file_info_display(menu, display);
break;
case MENU_MODE_CREDITS:
view_credits_display(menu, display);
break;
case MENU_MODE_LOAD:
view_load_display(menu, display);
break;
case MENU_MODE_ERROR:
view_error_display(menu, display);
break;
default:
break;
}
while (menu->mode != menu->next_mode) {
menu->mode = menu->next_mode;
switch (menu->next_mode) {
case MENU_MODE_BROWSER:
view_browser_init(menu);
break;
case MENU_MODE_FILE_INFO:
view_file_info_init(menu);
break;
case MENU_MODE_CREDITS:
view_credits_init(menu);
break;
case MENU_MODE_LOAD:
view_load_init(menu);
break;
case MENU_MODE_ERROR:
view_error_init(menu);
break;
case MENU_MODE_BOOT:
running = false;
break;
default:
break;
}
}
}
}
menu_deinit(menu);
}

62
src/menu/menu.h Normal file
View File

@ -0,0 +1,62 @@
#ifndef MENU_H__
#define MENU_H__
#include "path.h"
#include "settings.h"
#define BROWSER_LIST_SIZE 4096
typedef enum {
MENU_MODE_INIT,
MENU_MODE_BROWSER,
MENU_MODE_FILE_INFO,
MENU_MODE_CREDITS,
MENU_MODE_LOAD,
MENU_MODE_ERROR,
MENU_MODE_BOOT,
} menu_mode_t;
typedef enum {
ENTRY_TYPE_DIR,
ENTRY_TYPE_ROM,
ENTRY_TYPE_SAVE,
ENTRY_TYPE_UNKNOWN,
} entry_type_t;
typedef struct {
char *name;
entry_type_t type;
} entry_t;
typedef struct {
menu_mode_t mode;
menu_mode_t next_mode;
struct {
bool go_up;
bool go_down;
bool fast;
bool enter;
bool back;
bool info;
bool settings;
int held_counter;
} actions;
struct {
bool valid;
path_t *directory;
entry_t list[BROWSER_LIST_SIZE];
int entries;
int selected;
} browser;
} menu_t;
void menu_run (settings_t *settings);
#endif

View File

@ -1,114 +0,0 @@
#include <libdragon.h>
#include "menu_res_setup.h"
#include "menu_fileinfo.h"
#include "../utils/str_utils.h"
static char *get_file_type(FILINFO current_fileinfo) {
// TODO: should be at least a switch statement!
if (str_endswith(current_fileinfo.fname, ".z64") || str_endswith(current_fileinfo.fname, ".n64") || str_endswith(current_fileinfo.fname, ".v64") || str_endswith(current_fileinfo.fname, ".rom")) {
// TODO: check the necessary bytes in the header to ensure!
return "N64 ROM";
}
else if (str_endswith(current_fileinfo.fname, ".txt")) {
return "Text File";
}
else if (str_endswith(current_fileinfo.fname, ".ini")) {
return "INI File";
}
else if (str_endswith(current_fileinfo.fname, ".yml") || str_endswith(current_fileinfo.fname, ".yaml")) {
return "YAML File";
}
else if (str_endswith(current_fileinfo.fname, ".toml")) {
return "TOML File";
}
else if (str_endswith(current_fileinfo.fname, ".sav")) {
return "Save File";
}
else if (str_endswith(current_fileinfo.fname, ".emu")) {
return "Emulator File";
}
else {
return "Unknown File";
}
}
void menu_fileinfo_draw_n64_rom_info(surface_t *disp) {
// rom_header_t temp_header = file_read_rom_header(tmp_buffer);
// sprintf(buff, "ROM checksum: %llu\n", temp_header.checksum);
// sprintf(buff, "ROM title: %s\n", temp_header.title);
// sprintf(buff, "ROM media type: %c\n", temp_header.metadata.media_type);
// sprintf(buff, "ROM unique id: %.2s\n", (char*)&(temp_header.metadata.unique_identifier));
// sprintf(buff, "ROM dest market: %c\n", temp_header.metadata.destination_market);
// sprintf(buff, "ROM version: %hhu\n", temp_header.version);
}
void menu_fileinfo_draw_header(surface_t *disp) {
graphics_draw_text(disp, (disp->width / 2) - 64, vertical_start_position, "FILE INFORMATION"); // centre = numchars * font_horizontal_pixels / 2
graphics_draw_line(disp, 0, 30, disp->width, 30, 0xff);
}
void menu_fileinfo_draw_footer(surface_t *disp) {
graphics_draw_line(disp, 0, disp->height - overscan_vertical_pixels - font_vertical_pixels, disp->width,disp->height - overscan_vertical_pixels - font_vertical_pixels, 0xff);
graphics_draw_text(disp, (disp->width / 2) - 80,disp->height - overscan_vertical_pixels, "Press (B) to return!"); // centre = numchars * font_horizontal_pixels / 2
}
void menu_fileinfo(FILINFO current_fileinfo) {
char str_buffer[1024];
surface_t *disp = display_try_get();
graphics_fill_screen(disp, 0x00);
menu_fileinfo_draw_header(disp);
int16_t vertical_position = 40;
graphics_draw_text(disp, horizontal_start_position, vertical_position, "Name:");
graphics_draw_text(disp, horizontal_indent, vertical_position += font_vertical_pixels, current_fileinfo.fname);
vertical_position += (font_vertical_pixels * 2);
graphics_draw_text(disp, horizontal_start_position, vertical_position, "Size:");
sprintf(str_buffer, "%d %s", (int)current_fileinfo.fsize, "Bytes");
graphics_draw_text(disp, horizontal_indent, vertical_position += font_vertical_pixels, str_buffer);
vertical_position += (font_vertical_pixels * 2);
graphics_draw_text(disp, horizontal_start_position, vertical_position, "Attributes:");
sprintf(str_buffer, "%s%s%s%s%s\n",
((current_fileinfo.fattrib & AM_DIR) ? "Directory" : "File"),
((current_fileinfo.fattrib & AM_RDO) ? " | ReadOnly" : ""),
((current_fileinfo.fattrib & AM_SYS) ? " | System" : ""),
((current_fileinfo.fattrib & AM_ARC) ? " | Archive" : ""),
((current_fileinfo.fattrib & AM_HID) ? " | Hidden" : "")
);
graphics_draw_text(disp, horizontal_indent, vertical_position += font_vertical_pixels, str_buffer);
vertical_position += (font_vertical_pixels * 2);
graphics_draw_text(disp, horizontal_start_position, vertical_position, "Modified Timestamp:");
sprintf(str_buffer, "%u-%02u-%02u, %02u:%02u", (current_fileinfo.fdate >> 9) + 1980, current_fileinfo.fdate >> 5 & 15, current_fileinfo.fdate & 31, current_fileinfo.ftime >> 11, current_fileinfo.ftime >> 5 & 63);
graphics_draw_text(disp, horizontal_indent, vertical_position += font_vertical_pixels, str_buffer);
vertical_position += (font_vertical_pixels * 2);
graphics_draw_text(disp, horizontal_start_position, vertical_position, "Type:");
graphics_draw_text(disp, horizontal_indent, vertical_position += font_vertical_pixels, get_file_type(current_fileinfo));
//menu_fileinfo_draw_n64_rom_info(disp);
menu_fileinfo_draw_footer(disp);
display_show(disp);
for (;;) {
controller_scan();
struct controller_data ckeys = get_keys_down();
if (ckeys.c[0].B) {
break;
}
}
}

View File

@ -1,8 +0,0 @@
#ifndef MENU_FILEINFO_H__
#define MENU_FILEINFO_H__
#include <fatfs/ff.h>
void menu_fileinfo(FILINFO current_fileinfo);
#endif

View File

@ -1,55 +0,0 @@
#include <libdragon.h>
#include "menu_info.h"
#include "menu_res_setup.h"
void menu_info_draw_header(surface_t *disp) {
graphics_draw_text(disp, (disp->width / 2) - 64, vertical_start_position, "MENU INFORMATION"); // centre = numchars * font_horizontal_pixels / 2
graphics_draw_line(disp, 0, 30, disp->width, 30, 0xff);
}
void menu_info_draw_footer(surface_t *disp) {
graphics_draw_line(disp, 0, disp->height - overscan_vertical_pixels - font_vertical_pixels, disp->width,disp->height - overscan_vertical_pixels - font_vertical_pixels, 0xff);
graphics_draw_text(disp, (disp->width / 2) - 80,disp->height - overscan_vertical_pixels, "Press (B) to return!"); // centre = numchars * font_horizontal_pixels / 2
}
void menu_info(void) {
surface_t *disp = display_try_get();
graphics_fill_screen(disp, 0x00);
menu_info_draw_header(disp);
int16_t vertical_position = 40;
graphics_draw_text(disp, horizontal_start_position, vertical_position, "Menu Version:");
graphics_draw_text(disp, horizontal_indent,vertical_position += font_vertical_pixels, MENU_VERSION);
vertical_position += (font_vertical_pixels * 2);
graphics_draw_text(disp, horizontal_start_position, vertical_position, "Authors:");
graphics_draw_text(disp, horizontal_indent, vertical_position += font_vertical_pixels, "JonesAlmighty / NetworkFusion");
graphics_draw_text(disp, horizontal_indent, vertical_position += font_vertical_pixels, "korgeaux / Polprzewodnikowy");
vertical_position += (font_vertical_pixels * 2);
graphics_draw_text(disp, horizontal_start_position, vertical_position += font_vertical_pixels, "Github:");
// graphics_draw_text(disp, horizontal_indent, vertical_position += font_vertical_pixels, "https://github.com/Polprzewodnikowy/SummerCart64");
graphics_draw_text(disp, horizontal_indent, vertical_position += font_vertical_pixels, "https://github.com/Polprzewodnikowy/N64FlashcartMenu");
graphics_draw_text(disp, horizontal_indent, vertical_position += font_vertical_pixels, "https://github.com/NetworkFusion/N64FlashcartMenu");
vertical_position += (font_vertical_pixels * 2);
graphics_draw_text(disp, horizontal_start_position, vertical_position, "OSS licenses used:");
graphics_draw_text(disp, horizontal_indent,vertical_position += font_vertical_pixels, "UNLICENSE");
graphics_draw_text(disp, horizontal_indent,vertical_position += font_vertical_pixels, "MIT");
menu_info_draw_footer(disp);
display_show(disp);
for (;;) {
controller_scan();
struct controller_data ckeys = get_keys_down();
if (ckeys.c[0].B) {
break;
}
}
}

View File

@ -1,8 +0,0 @@
#ifndef MENU_INFO_H__
#define MENU_INFO_H__
#define MENU_VERSION "V0.0.0.3"
void menu_info(void);
#endif

View File

@ -1,265 +0,0 @@
#include <stdio.h>
#include <stdlib.h> // TODO: does this work... will unlock qsort!
#include <string.h>
#include <libdragon.h>
#include <fatfs/ff.h>
#include "flashcart/flashcart.h"
#include "settings.h"
#include "menu_main.h"
#include "menu_info.h"
#include "menu_fileinfo.h"
#include "rom_database.h"
#include "menu_res_setup.h"
#include "../utils/str_utils.h"
//const int max_files_on_screen = 16;
static int scroll_menu_position = 1;
static int items_in_dir = 1;
static FILINFO current_fileinfo;
void load_n64_rom() {
console_init();
console_clear();
char sd_path_buffer[1024];
sprintf(sd_path_buffer, "sd:/%s", current_fileinfo.fname);
rom_header_t temp_header = file_read_rom_header(sd_path_buffer);
printf("Loading N64 ROM type...\n");
printf("%s\n\n", current_fileinfo.fname);
printf("ROM title: %s\n\n", temp_header.title);
printf("ROM media type: %c\n", temp_header.metadata.media_type);
printf("ROM unique id: %.2s\n", (char*)&(temp_header.metadata.unique_identifier));
printf("uid as int: %d\n\n", temp_header.metadata.unique_identifier);
printf("ROM destination market: %c\n\n", temp_header.metadata.destination_market);
printf("ROM version: %hhu\n", temp_header.version);
printf("ROM checksum: %llu\n\n", temp_header.checksum);
// FIXME: if the ROM header does not make sense, it is an invalid ROM.
wait_ms(5000); // wait used for debugging. Can be removed later.
uint8_t save_type = rom_db_match_save_type(temp_header);
printf("save type: %d\n", save_type);
wait_ms(5000); // wait used for debugging. Can be removed later.
sprintf(sd_path_buffer, "%s.%llu.sav", current_fileinfo.fname, temp_header.checksum);
wait_ms(5000); // wait used for debugging. Can be removed later.
assertf(flashcart_load_save(sd_path_buffer, (flashcart_save_type_t)save_type, true) == FLASHCART_OK, "ROM load save error");
assertf(flashcart_load_rom(current_fileinfo.fname) == FLASHCART_OK, "ROM load error");
}
// FIXME: use newlib rather than fatfs to do this!
FRESULT scan_file_path (surface_t *disp, char *path) {
FRESULT res;
DIR dir;
char sfno[1024];
int counter = 0; //FIXME: we dont account for an empty dir or only one valid file!
int16_t vertical_position = 56;
char str_buffer[1036];
res = f_opendir(&dir, path);
if (res == FR_OK) {
for (;;) {
FILINFO file_info;
res = f_readdir(&dir, &file_info);
if ((res != FR_OK) || (file_info.fname[0] == 0)) {
break;
}
if (file_info.fattrib & AM_SYS) {
continue; // we do not want to show system files ever...
}
counter ++;
// TODO: convert these to icons...
sprintf(sfno, "| %c%c%c | %10d | %s",
((file_info.fattrib & AM_DIR) ? 'D' : '-'),
((file_info.fattrib & AM_RDO) ? 'R' : '-'),
((file_info.fattrib & AM_HID) ? 'H' : '-'),
(int)file_info.fsize, file_info.fname);
if (scroll_menu_position == counter) {
sprintf(str_buffer, "-> %s\n", sfno);
graphics_draw_text(disp, horizontal_indent, vertical_position += font_vertical_pixels, str_buffer);
current_fileinfo = file_info;
}
else {
sprintf(str_buffer, " %s\n", sfno);
graphics_draw_text(disp, horizontal_indent, vertical_position += font_vertical_pixels, str_buffer);
}
}
}
items_in_dir = counter;
f_closedir(&dir);
return res;
}
void menu_main_draw_header(surface_t *disp) {
graphics_draw_text(disp, (disp->width / 2) - 36, vertical_start_position, "FILE MENU"); // centre = numchars * font_horizontal_pixels / 2
graphics_draw_line(disp,0,30,disp->width,30, 0xff);
}
void menu_main_draw_footer(char *dir_path, surface_t *disp) {
graphics_draw_line(disp,0,disp->height - overscan_vertical_pixels - font_vertical_pixels, disp->width,disp->height - overscan_vertical_pixels - font_vertical_pixels, 0xff);
char str_buffer[1024];
sprintf(str_buffer, "Current Directory: SD:%s\nFile: %d of %d\n\n", dir_path, scroll_menu_position, items_in_dir);
graphics_draw_text(disp, (disp->width / 2) - 160,disp->height - overscan_vertical_pixels, str_buffer); // centre = numchars * font_horizontal_pixels / 2
}
void menu_main_refresh (char *dir_path) {
surface_t *disp = display_get();
graphics_fill_screen(disp, 0);
menu_main_draw_header(disp);
int16_t vertical_position = 40;
char str_buffer[1024];
sprintf(str_buffer, " | DRH | FILE SIZE | FILE NAME\n");
graphics_draw_text(disp, horizontal_indent, vertical_position += font_vertical_pixels, str_buffer);
sprintf(str_buffer, " |-----|------------|----------\n");
graphics_draw_text(disp, horizontal_indent, vertical_position += font_vertical_pixels, str_buffer);
scan_file_path(disp, dir_path);
menu_main_draw_footer(dir_path, disp);
display_show(disp);
}
void menu_main_init (settings_t *settings) {
char *current_dir = settings->last_state.current_directory;
char *last_dir = current_dir;
struct controller_data joypad = get_keys_down();
if ((settings->last_state.auto_load_last_rom) && !(joypad.c[0].B)) { // FIXME: the B button on any controller!
console_init();
console_clear();
printf("Loading last ROM: %s\n", settings->last_rom.rom_path);
assertf(flashcart_load_rom(settings->last_rom.rom_path) == FLASHCART_OK, "ROM load error");
printf("Loading save: %s, type: %d, writeback: %d\n", settings->last_rom.save_path, settings->last_rom.save_type, settings->last_rom.save_writeback);
assertf(flashcart_load_save(settings->last_rom.save_path, settings->last_rom.save_type, settings->last_rom.save_writeback) == FLASHCART_OK, "Save load error");
}
else {
settings->last_state.auto_load_last_rom = false;
menu_main_refresh(current_dir);
}
for (;;) {
controller_scan();
joypad = get_keys_down();
if (joypad.c[0].up) {
if (scroll_menu_position > 1 && scroll_menu_position <= items_in_dir) {
scroll_menu_position --;
}
else {
scroll_menu_position = items_in_dir;
}
menu_main_refresh(current_dir);
}
if (joypad.c[0].down) {
if (scroll_menu_position < items_in_dir) {
scroll_menu_position ++;
}
else {
scroll_menu_position = 1;
}
menu_main_refresh(current_dir);
}
if (joypad.c[0].A) {
// TODO: move this to a function and check that the ROM is valid by checking the header...
if (str_endswith(current_fileinfo.fname, ".z64")) {
load_n64_rom();
break; //required!
}
else if (str_endswith(current_fileinfo.fname, ".n64") || str_endswith(current_fileinfo.fname, ".v64") || str_endswith(current_fileinfo.fname, ".rom")) {
console_init();
console_clear();
printf("ROM : %s\n", current_fileinfo.fname);
printf("Not loading due to potential conversion issue.\n");
wait_ms(10000); // wait used for debugging. Can be removed later.
menu_main_refresh(current_dir);
}
else if (str_endswith(current_fileinfo.fname, ".zip")) {
console_init();
console_clear();
printf("ZIP : %s\n", current_fileinfo.fname);
printf("Not loading due to potential conversion issue.\n");
wait_ms(10000); // wait used for debugging. Can be removed later.
menu_main_refresh(current_dir);
}
else {
if (current_fileinfo.fattrib & AM_DIR) {
// if this is a directory we need to transverse to it!
items_in_dir = 1;
scroll_menu_position = 1;
last_dir = current_dir;
current_dir = current_fileinfo.fname;
menu_main_refresh(current_dir);
}
else {
menu_fileinfo(current_fileinfo);
menu_main_refresh(current_dir);
}
}
}
if (joypad.c[0].B) {
menu_main_refresh(current_dir);
current_dir = last_dir;
}
if (joypad.c[0].start) { // FIXME: the START button on any controller!
menu_info();
menu_main_refresh(current_dir);
}
if (joypad.c[0].Z) {
menu_fileinfo(current_fileinfo);
menu_main_refresh(current_dir);
}
}
// TODO: write menu state to SD card
}

View File

@ -1,6 +0,0 @@
#ifndef MENU_MAIN_H__
#define MENU_MAIN_H__
void menu_main_init (settings_t *settings);
#endif

102
src/menu/path.c Normal file
View File

@ -0,0 +1,102 @@
#include <libdragon.h>
#include <stdlib.h>
#include <string.h>
#include "path.h"
#define PATH_CAPACITY_INITIAL 255
#define PATH_CAPACITY_ALIGNMENT 32
static void path_resize (path_t *path, size_t min_length) {
path->capacity = min_length > PATH_CAPACITY_INITIAL ? min_length : PATH_CAPACITY_INITIAL;
size_t alignment = path->capacity % PATH_CAPACITY_ALIGNMENT;
if (alignment != (PATH_CAPACITY_ALIGNMENT - 1)) {
path->capacity += PATH_CAPACITY_ALIGNMENT - alignment;
}
path->buffer = realloc(path->buffer, (path->capacity + 1) * sizeof(char));
}
path_t *path_init (char *string) {
if (string == NULL) {
string = "";
}
path_t *path = calloc(1, sizeof(path_t));
path_resize(path, strlen(string));
memset(path->buffer, 0, path->capacity + 1);
strcpy(path->buffer, string);
return path;
}
void path_free (path_t *path) {
free(path->buffer);
free(path);
}
path_t *path_clone (path_t *path) {
return path_init(path->buffer);
}
char *path_get (path_t *path) {
return path->buffer;
}
char *path_last_get (path_t *path) {
char *last_slash = strrchr(path->buffer, '/');
return (last_slash == NULL) ? path->buffer : (last_slash + 1);
}
void path_append (path_t *path, char *string) {
size_t buffer_length = strlen(path->buffer);
size_t string_length = strlen(string);
size_t new_path_length = buffer_length + string_length;
if (new_path_length > path->capacity) {
path_resize(path, new_path_length);
}
strcat(path->buffer, string);
}
void path_concat (path_t *dst, path_t *src) {
path_append(dst, src->buffer);
}
void path_push (path_t *path, char *string) {
if (path->buffer[strlen(path->buffer) - 1] != '/') {
path_append(path, "/");
}
if (string[0] == '/') {
string += 1;
}
path_append(path, string);
}
void path_pop (path_t *path) {
char *last_slash = strrchr(path->buffer, '/');
if (last_slash != NULL) {
*last_slash = '\0';
}
}
char *path_ext_get (path_t *path) {
char *buffer = path_last_get(path);
char *last_dot = strrchr(buffer, '.');
if (last_dot != NULL) {
return last_dot + 1;
}
return NULL;
}
void path_ext_remove (path_t *path) {
char *buffer = path_last_get(path);
char *last_dot = strrchr(buffer, '.');
if (last_dot != NULL) {
*last_dot = '\0';
}
}
void path_ext_replace (path_t *path, char *ext) {
path_ext_remove(path);
path_append(path, ".");
path_append(path, ext);
}

25
src/menu/path.h Normal file
View File

@ -0,0 +1,25 @@
#ifndef PAHT_H__
#define PATH_H__
typedef struct {
char *buffer;
size_t capacity;
} path_t;
path_t *path_init (char *string);
void path_free (path_t *path);
path_t *path_clone (path_t *string);
char *path_get (path_t *path);
char *path_last_get (path_t *path);
void path_append (path_t *path, char *string);
void path_concat (path_t *dst, path_t *str);
void path_push (path_t *path, char *string);
void path_pop (path_t *path);
char *path_ext_get (path_t *path);
void path_ext_remove (path_t *path);
void path_ext_replace (path_t *path, char *ext);
#endif

View File

@ -1,7 +1,9 @@
#include <libdragon.h>
#include "rom_database.h" #include "rom_database.h"
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
uint8_t extract_homebrew_setting(uint8_t setting, uint8_t bit_position) { uint8_t extract_homebrew_setting(uint8_t setting, uint8_t bit_position) {
return (setting & (1 << bit_position)) ? 1 : 0; return (setting & (1 << bit_position)) ? 1 : 0;
@ -29,10 +31,14 @@ uint8_t extract_homebrew_save_type(uint8_t save_type) {
} }
rom_header_t file_read_rom_header(char *path) { rom_header_t file_read_rom_header(char *path) {
FILE *fp = fopen(path, "rb"); char *sd_path = calloc(4 + strlen(path) + 1, sizeof(char));
printf("loading path: %s\n", path); sprintf(sd_path, "sd:/%s", path);
FILE *fp = fopen(sd_path, "rb");
debugf("loading path: %s\n", sd_path);
if (!fp) { if (!fp) {
printf("Error loading rom file header\n"); debugf("Error loading rom file header\n");
} }
rom_header_t *rom_header = malloc(sizeof(rom_header_t)); rom_header_t *rom_header = malloc(sizeof(rom_header_t));
@ -53,6 +59,8 @@ rom_header_t file_read_rom_header(char *path) {
fclose(fp); fclose(fp);
free(sd_path);
return *rom_header; return *rom_header;
} }

View File

@ -162,7 +162,7 @@ void settings_load_default_state(settings_t *settings) {
settings->boot_params.device_type = BOOT_DEVICE_TYPE_ROM; settings->boot_params.device_type = BOOT_DEVICE_TYPE_ROM;
settings->boot_params.reset_type = BOOT_RESET_TYPE_NMI; settings->boot_params.reset_type = BOOT_RESET_TYPE_NMI;
settings->boot_params.detect_tv_type = true; settings->boot_params.tv_type = BOOT_TV_TYPE_PASSTHROUGH;
settings->boot_params.detect_cic_seed = true; settings->boot_params.detect_cic_seed = true;
// Initialize other default settings... // Initialize other default settings...

28
src/menu/views.h Normal file
View File

@ -0,0 +1,28 @@
#ifndef VIEWS_H__
#define VIEWS_H__
#include <surface.h>
#include "menu.h"
void view_init_display (menu_t *menu, surface_t *display);
void view_browser_init (menu_t *menu);
void view_browser_display (menu_t *menu, surface_t *display);
void view_file_info_init (menu_t *menu);
void view_file_info_display (menu_t *menu, surface_t *display);
void view_credits_init (menu_t *menu);
void view_credits_display (menu_t *menu, surface_t *display);
void view_load_init (menu_t *menu);
void view_load_display (menu_t *menu, surface_t *display);
void view_error_init (menu_t *menu);
void view_error_display (menu_t *menu, surface_t *display);
#endif

222
src/menu/views/browser.c Normal file
View File

@ -0,0 +1,222 @@
#include <fatfs/ff.h>
#include <libdragon.h>
#include <stdlib.h>
#include "../menu.h"
#include "../menu_res_setup.h"
#include "../../utils/str_utils.h"
#define BROWSER_LIST_ROWS 21
static int compare_entry (const void *pa, const void *pb) {
entry_t *a = (entry_t *) (pa);
entry_t *b = (entry_t *) (pb);
if (a->type != b->type) {
if (a->type == ENTRY_TYPE_DIR) {
return -1;
} else if (b->type == ENTRY_TYPE_DIR) {
return 1;
} else if (a->type == ENTRY_TYPE_ROM) {
return -1;
} else if (b->type == ENTRY_TYPE_ROM) {
return 1;
} else if (a->type == ENTRY_TYPE_SAVE) {
return -1;
} else if (b->type == ENTRY_TYPE_SAVE) {
return 1;
}
}
return strcasecmp((const char *) (a->name), (const char *) (b->name));
}
static void load_directory (menu_t *menu) {
DIR dir;
FILINFO info;
for (int i = 0; i < menu->browser.entries; i++) {
free(menu->browser.list[i].name);
}
menu->browser.entries = 0;
menu->browser.selected = -1;
if (f_opendir(&dir, path_get(menu->browser.directory)) != FR_OK) {
menu->next_mode = MENU_MODE_ERROR;
return;
}
while (true) {
if (f_readdir(&dir, &info) != FR_OK) {
menu->next_mode = MENU_MODE_ERROR;
return;
}
size_t length = strlen(info.fname);
if (length == 0) {
break;
}
if (info.fattrib & AM_SYS) {
continue;
}
entry_t *entry = &menu->browser.list[menu->browser.entries];
entry->name = malloc((length + 1) * sizeof(char));
strcpy(entry->name, info.fname);
if (info.fattrib & AM_DIR) {
entry->type = ENTRY_TYPE_DIR;
// TODO: use something like `ext_is_n64_rom(info.fname)` instead of `str_endswith(info.fname, ".xxx")`
} else if (str_endswith(info.fname, ".n64") || str_endswith(info.fname, ".z64") || str_endswith(info.fname, ".v64") || str_endswith(info.fname, ".N64")) {
entry->type = ENTRY_TYPE_ROM;
} else if (str_endswith(info.fname, ".sav")) {
entry->type = ENTRY_TYPE_SAVE;
} else {
entry->type = ENTRY_TYPE_UNKNOWN;
}
menu->browser.entries += 1;
if (menu->browser.entries == BROWSER_LIST_SIZE) {
break;
}
}
f_closedir(&dir);
if (menu->browser.entries > 0) {
menu->browser.selected = 0;
}
qsort(menu->browser.list, menu->browser.entries, sizeof(entry_t), compare_entry);
}
void push_directory (menu_t *menu, char *directory) {
path_push(menu->browser.directory, directory);
load_directory(menu);
}
void pop_directory (menu_t *menu) {
path_t *current_directory = path_clone(menu->browser.directory);
path_pop(menu->browser.directory);
load_directory(menu);
for (int i = 0; i < menu->browser.entries; i++) {
if (strcmp(menu->browser.list[i].name, path_last_get(current_directory)) == 0) {
menu->browser.selected = i;
break;
}
}
path_free(current_directory);
}
static void process (menu_t *menu) {
int scroll_speed = menu->actions.fast ? BROWSER_LIST_ROWS : 1;
if (menu->browser.entries > 1) {
if (menu->actions.go_up) {
menu->browser.selected -= scroll_speed;
if (menu->browser.selected < 0) {
menu->browser.selected = 0;
}
} else if (menu->actions.go_down) {
menu->browser.selected += scroll_speed;
if (menu->browser.selected >= menu->browser.entries) {
menu->browser.selected = menu->browser.entries - 1;
}
}
}
if (menu->actions.enter) {
entry_t *entry = &menu->browser.list[menu->browser.selected];
switch (entry->type) {
case ENTRY_TYPE_DIR:
push_directory(menu, entry->name);
break;
case ENTRY_TYPE_ROM:
menu->next_mode = MENU_MODE_LOAD;
break;
default:
menu->next_mode = MENU_MODE_FILE_INFO;
break;
}
} else if (menu->actions.back) {
pop_directory(menu);
} else if (menu->actions.info) {
menu->next_mode = MENU_MODE_FILE_INFO;
} else if (menu->actions.settings) {
menu->next_mode = MENU_MODE_CREDITS;
}
}
static void draw (menu_t *menu, surface_t *d) {
int x = 24;
int y = 35;
int starting_position = 0;
int entries_drawn = 0;
if (menu->browser.entries > BROWSER_LIST_ROWS && menu->browser.selected >= (BROWSER_LIST_ROWS / 2)) {
starting_position = menu->browser.selected - (BROWSER_LIST_ROWS / 2);
if (starting_position >= menu->browser.entries - BROWSER_LIST_ROWS) {
starting_position = menu->browser.entries - BROWSER_LIST_ROWS;
}
}
graphics_fill_screen(d, graphics_make_color(0, 0, 0, 255));
graphics_draw_text(d, (d->width / 2) - 36, vertical_start_position, "FILE MENU");
graphics_draw_line(d, 0, 30, d->width, 30, 0xff);
char str_buffer[1024];
for (int i = starting_position; i < menu->browser.entries; i++) {
if (i == menu->browser.selected) {
uint32_t color;
switch (menu->browser.list[i].type) {
case ENTRY_TYPE_ROM:
color = graphics_make_color(0, 64, 0, 0);
break;
default:
color = graphics_make_color(64, 64, 64, 0);
break;
}
graphics_draw_box(d, x, y, (640 - x * 2), font_vertical_pixels, color);
}
snprintf(str_buffer, 1024, "%.74s", menu->browser.list[i].name);
graphics_draw_text(d, x, y, str_buffer);
y += font_vertical_pixels;
entries_drawn += 1;
if (entries_drawn == BROWSER_LIST_ROWS) {
break;
}
}
graphics_draw_line(d, 0, d->height - overscan_vertical_pixels - font_vertical_pixels, d->width, d->height - overscan_vertical_pixels - font_vertical_pixels, 0xff);
sprintf(str_buffer, "Current Directory: SD:%s\nFile: %d of %d\n\n", path_get(menu->browser.directory), menu->browser.selected + 1, menu->browser.entries);
graphics_draw_text(d, (d->width / 2) - 160, d->height - overscan_vertical_pixels, str_buffer);
display_show(d);
}
void view_browser_init (menu_t *menu) {
if (!menu->browser.valid) {
menu->browser.valid = true;
load_directory(menu);
}
}
void view_browser_display (menu_t *menu, surface_t *display) {
process(menu);
draw(menu, display);
}

53
src/menu/views/credits.c Normal file
View File

@ -0,0 +1,53 @@
#include <libdragon.h>
#include "../menu.h"
#include "../menu_res_setup.h"
#define MENU_VERSION "V0.0.0.3"
static void process (menu_t *menu) {
if (menu->actions.back) {
menu->next_mode = MENU_MODE_BROWSER;
}
}
static void draw (menu_t *menu, surface_t *d) {
graphics_fill_screen(d, 0x00);
graphics_draw_text(d, (d->width / 2) - 64, vertical_start_position, "MENU INFORMATION"); // centre = numchars * font_horizontal_pixels / 2
graphics_draw_line(d, 0, 30, d->width, 30, 0xff);
int16_t vertical_position = 40;
graphics_draw_text(d, horizontal_start_position, vertical_position, "Menu Version:");
graphics_draw_text(d, horizontal_indent,vertical_position += font_vertical_pixels, MENU_VERSION);
vertical_position += (font_vertical_pixels * 2);
graphics_draw_text(d, horizontal_start_position, vertical_position, "Authors:");
graphics_draw_text(d, horizontal_indent, vertical_position += font_vertical_pixels, "JonesAlmighty / NetworkFusion");
graphics_draw_text(d, horizontal_indent, vertical_position += font_vertical_pixels, "korgeaux / Polprzewodnikowy");
vertical_position += (font_vertical_pixels * 2);
graphics_draw_text(d, horizontal_start_position, vertical_position += font_vertical_pixels, "Github:");
// graphics_draw_text(d, horizontal_indent, vertical_position += font_vertical_pixels, "https://github.com/Polprzewodnikowy/SummerCart64");
graphics_draw_text(d, horizontal_indent, vertical_position += font_vertical_pixels, "https://github.com/Polprzewodnikowy/N64FlashcartMenu");
graphics_draw_text(d, horizontal_indent, vertical_position += font_vertical_pixels, "https://github.com/NetworkFusion/N64FlashcartMenu");
vertical_position += (font_vertical_pixels * 2);
graphics_draw_text(d, horizontal_start_position, vertical_position, "OSS licenses used:");
graphics_draw_text(d, horizontal_indent,vertical_position += font_vertical_pixels, "UNLICENSE");
graphics_draw_text(d, horizontal_indent,vertical_position += font_vertical_pixels, "MIT");
graphics_draw_line(d, 0, d->height - overscan_vertical_pixels - font_vertical_pixels, d->width,d->height - overscan_vertical_pixels - font_vertical_pixels, 0xff);
graphics_draw_text(d, (d->width / 2) - 80,d->height - overscan_vertical_pixels, "Press (B) to return!"); // centre = numchars * font_horizontal_pixels / 2
display_show(d);
}
void view_credits_init (menu_t *menu) {
// Nothing to initialize (yet)
}
void view_credits_display (menu_t *menu, surface_t *display) {
process(menu);
draw(menu, display);
}

27
src/menu/views/error.c Normal file
View File

@ -0,0 +1,27 @@
#include <libdragon.h>
#include "../menu.h"
static void process (menu_t *menu) {
if (menu->actions.back) {
menu->next_mode = MENU_MODE_BROWSER;
}
}
static void draw (menu_t *menu, surface_t *d) {
graphics_fill_screen(d, graphics_make_color(0, 0, 0, 255));
graphics_draw_text(d, 24, 36, "ERROR!");
display_show(d);
}
void view_error_init (menu_t *menu) {
// Nothing to initialize (yet)
}
void view_error_display (menu_t *menu, surface_t *display) {
process(menu);
draw(menu, display);
}

106
src/menu/views/file_info.c Normal file
View File

@ -0,0 +1,106 @@
#include <fatfs/ff.h>
#include <libdragon.h>
#include "../menu.h"
#include "../menu_res_setup.h"
#include "../../utils/str_utils.h"
static FILINFO info;
static char *get_file_type (void) {
// TODO: should be at least a switch statement!
if (str_endswith(info.fname, ".z64") || str_endswith(info.fname, ".n64") || str_endswith(info.fname, ".v64") || str_endswith(info.fname, ".rom")) {
// TODO: check the necessary bytes in the header to ensure!
return "N64 ROM";
}
else if (str_endswith(info.fname, ".txt")) {
return "Text File";
}
else if (str_endswith(info.fname, ".ini")) {
return "INI File";
}
else if (str_endswith(info.fname, ".yml") || str_endswith(info.fname, ".yaml")) {
return "YAML File";
}
else if (str_endswith(info.fname, ".toml")) {
return "TOML File";
}
else if (str_endswith(info.fname, ".sav")) {
return "Save File";
}
else if (str_endswith(info.fname, ".emu")) {
return "Emulator File";
}
else {
return "Unknown File";
}
}
static void process (menu_t *menu) {
if (menu->actions.back) {
menu->next_mode = MENU_MODE_BROWSER;
}
}
static void draw (menu_t *menu, surface_t *d) {
char str_buffer[1024];
graphics_fill_screen(d, 0x00);
graphics_draw_text(d, (d->width / 2) - 64, vertical_start_position, "FILE INFORMATION"); // centre = numchars * font_horizontal_pixels / 2
graphics_draw_line(d, 0, 30, d->width, 30, 0xff);
int16_t vertical_position = 40;
graphics_draw_text(d, horizontal_start_position, vertical_position, "Name:");
graphics_draw_text(d, horizontal_indent, vertical_position += font_vertical_pixels, info.fname);
vertical_position += (font_vertical_pixels * 2);
graphics_draw_text(d, horizontal_start_position, vertical_position, "Size:");
sprintf(str_buffer, "%d %s", (int)info.fsize, "Bytes");
graphics_draw_text(d, horizontal_indent, vertical_position += font_vertical_pixels, str_buffer);
vertical_position += (font_vertical_pixels * 2);
graphics_draw_text(d, horizontal_start_position, vertical_position, "Attributes:");
sprintf(str_buffer, "%s%s%s%s%s\n",
((info.fattrib & AM_DIR) ? "Directory" : "File"),
((info.fattrib & AM_RDO) ? " | ReadOnly" : ""),
((info.fattrib & AM_SYS) ? " | System" : ""),
((info.fattrib & AM_ARC) ? " | Archive" : ""),
((info.fattrib & AM_HID) ? " | Hidden" : "")
);
graphics_draw_text(d, horizontal_indent, vertical_position += font_vertical_pixels, str_buffer);
vertical_position += (font_vertical_pixels * 2);
graphics_draw_text(d, horizontal_start_position, vertical_position, "Modified Timestamp:");
sprintf(str_buffer, "%u-%02u-%02u, %02u:%02u", (info.fdate >> 9) + 1980, info.fdate >> 5 & 15, info.fdate & 31, info.ftime >> 11, info.ftime >> 5 & 63);
graphics_draw_text(d, horizontal_indent, vertical_position += font_vertical_pixels, str_buffer);
vertical_position += (font_vertical_pixels * 2);
graphics_draw_text(d, horizontal_start_position, vertical_position, "Type:");
graphics_draw_text(d, horizontal_indent, vertical_position += font_vertical_pixels, get_file_type());
//menu_fileinfo_draw_n64_rom_info(d);
graphics_draw_line(d, 0, d->height - overscan_vertical_pixels - font_vertical_pixels, d->width,d->height - overscan_vertical_pixels - font_vertical_pixels, 0xff);
graphics_draw_text(d, (d->width / 2) - 80,d->height - overscan_vertical_pixels, "Press (B) to return!"); // centre = numchars * font_horizontal_pixels / 2
display_show(d);
}
void view_file_info_init (menu_t *menu) {
path_t *file = path_clone(menu->browser.directory);
path_push(file, menu->browser.list[menu->browser.selected].name);
if (f_stat(path_get(file), &info) != FR_OK) {
menu->next_mode = MENU_MODE_ERROR;
}
path_free(file);
}
void view_file_info_display (menu_t *menu, surface_t *display) {
process(menu);
draw(menu, display);
}

13
src/menu/views/init.c Normal file
View File

@ -0,0 +1,13 @@
#include <libdragon.h>
#include "../menu.h"
static void draw (menu_t *menu, surface_t *d) {
graphics_fill_screen(d, graphics_make_color(0, 0, 0, 255));
display_show(d);
}
void view_init_display (menu_t *menu, surface_t *display) {
draw(menu, display);
}

53
src/menu/views/load.c Normal file
View File

@ -0,0 +1,53 @@
#include <libdragon.h>
#include "../menu.h"
#include "../rom_database.h"
#include "../../flashcart/flashcart.h"
static void draw (menu_t *menu, surface_t *d) {
int x = 24;
int y = 36;
graphics_fill_screen(d, graphics_make_color(0, 0, 0, 255));
graphics_draw_text(d, x, y, "booting...");
display_show(d);
}
static void load (menu_t *menu) {
menu->next_mode = MENU_MODE_BOOT;
path_t *path = path_clone(menu->browser.directory);
path_push(path, menu->browser.list[menu->browser.selected].name);
rom_header_t temp_header = file_read_rom_header(path_get(path));
uint8_t save_type = rom_db_match_save_type(temp_header);
if (flashcart_load_rom(path_get(path)) != FLASHCART_OK) {
menu->next_mode = MENU_MODE_ERROR;
path_free(path);
return;
}
path_ext_replace(path, "sav");
if (flashcart_load_save(path_get(path), (flashcart_save_type_t) (save_type), true) != FLASHCART_OK) {
menu->next_mode = MENU_MODE_ERROR;
path_free(path);
return;
}
path_free(path);
}
void view_load_init (menu_t *menu) {
// Nothing to initialize (yet)
}
void view_load_display (menu_t *menu, surface_t *display) {
draw(menu, display);
load(menu);
}