diff --git a/Makefile b/Makefile index 487447bd..9392bd07 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,8 @@ FILESYSTEM_DIR = filesystem BUILD_DIR = build OUTPUT_DIR = output -FLAGS += -DMENU_VERSION=\"0.0.1.$(shell date +%Y-%m-%dT%H:%M:%SZ).ALPHA\" +MENU_VERSION ?= "Rolling release" +BUILD_TIMESTAMP = "$(shell TZ='UTC' date "+%Y-%m-%d %H:%M:%S %:z")" include $(N64_INST)/include/n64.mk @@ -55,6 +56,7 @@ SRCS = \ menu/views/fault.c \ menu/views/file_info.c \ menu/views/image_viewer.c \ + menu/views/text_viewer.c \ menu/views/load_disk.c \ menu/views/load_emulator.c \ menu/views/load_rom.c \ @@ -63,6 +65,7 @@ SRCS = \ menu/views/system_info.c \ menu/views/settings_editor.c \ menu/views/rtc.c \ + menu/views/flashcart_info.c \ utils/fs.c FONTS = \ @@ -88,6 +91,9 @@ $(FILESYSTEM_DIR)/%.font64: $(ASSETS_DIR)/%.ttf $(BUILD_DIR)/$(PROJECT_NAME).dfs: $(FILESYSTEM) +$(BUILD_DIR)/menu/views/credits.o: .FORCE +$(BUILD_DIR)/menu/views/credits.o: FLAGS+=-DMENU_VERSION=\"$(MENU_VERSION)\" -DBUILD_TIMESTAMP=\"$(BUILD_TIMESTAMP)\" + $(BUILD_DIR)/$(PROJECT_NAME).elf: $(OBJS) disassembly: $(BUILD_DIR)/$(PROJECT_NAME).elf @@ -149,4 +155,6 @@ debug-gdb: $(OUTPUT_DIR)/$(PROJECT_NAME).n64 # test: # TODO: run tests +.FORCE: + -include $(DEPS) diff --git a/libdragon b/libdragon index 6323128d..185c4a34 160000 --- a/libdragon +++ b/libdragon @@ -1 +1 @@ -Subproject commit 6323128d72fdf32dfaa134f40191ba72e5527076 +Subproject commit 185c4a34f265c90d027f4054024cff1675529d7f diff --git a/src/boot/cic.c b/src/boot/cic.c index 58f03fbc..990e95ca 100644 --- a/src/boot/cic.c +++ b/src/boot/cic.c @@ -102,7 +102,7 @@ cic_type_t cic_detect (uint8_t *ipl3) { switch (cic_calculate_ipl3_checksum(ipl3, 0x3F)) { case 0x45CC73EE317AULL: return CIC_6101; // 6101 case 0x44160EC5D9AFULL: return CIC_7102; // 7102 - case 0xA536C0F1D859ULL: return CIC_6102_7101; // 6102 / 7101 + case 0xA536C0F1D859ULL: return CIC_x102; // 6102 / 7101 } switch (cic_calculate_ipl3_checksum(ipl3, 0x78)) { case 0x586FD4709867ULL: return CIC_x103; // 6103 / 7103 @@ -133,7 +133,7 @@ uint8_t cic_get_seed (cic_type_t cic_type) { case CIC_5167: return 0xDD; case CIC_6101: return 0x3F; case CIC_7102: return 0x3F; - case CIC_6102_7101: return 0x3F; + case CIC_x102: return 0x3F; case CIC_x103: return 0x78; case CIC_x105: return 0x91; case CIC_x106: return 0x85; diff --git a/src/boot/cic.h b/src/boot/cic.h index 4f97c6c4..3de811bb 100644 --- a/src/boot/cic.h +++ b/src/boot/cic.h @@ -13,7 +13,7 @@ typedef enum { CIC_5167, CIC_6101, CIC_7102, - CIC_6102_7101, + CIC_x102, CIC_x103, CIC_x105, CIC_x106, diff --git a/src/flashcart/64drive/64drive.c b/src/flashcart/64drive/64drive.c index 6bcee6cb..9b0b8b08 100644 --- a/src/flashcart/64drive/64drive.c +++ b/src/flashcart/64drive/64drive.c @@ -73,6 +73,8 @@ static flashcart_err_t d64_deinit (void) { static bool d64_has_feature (flashcart_features_t feature) { switch (feature) { case FLASHCART_FEATURE_64DD: return false; + case FLASHCART_FEATURE_RTC: return true; + case FLASHCART_FEATURE_USB: return true; default: return false; } } @@ -96,7 +98,7 @@ static flashcart_err_t d64_load_rom (char *rom_path, flashcart_progress_callback size_t sdram_size = MiB(64); - size_t chunk_size = MiB(1); + size_t chunk_size = KiB(128); for (int offset = 0; offset < sdram_size; offset += chunk_size) { size_t block_size = MIN(sdram_size - offset, chunk_size); if (f_read(&fil, (void *) (ROM_ADDRESS + offset), block_size, &br) != FR_OK) { diff --git a/src/flashcart/flashcart.h b/src/flashcart/flashcart.h index 0e97e807..001516bb 100644 --- a/src/flashcart/flashcart.h +++ b/src/flashcart/flashcart.h @@ -27,6 +27,8 @@ typedef enum { /** @brief List of optional supported flashcart features */ typedef enum { FLASHCART_FEATURE_64DD, + FLASHCART_FEATURE_RTC, + FLASHCART_FEATURE_USB, } flashcart_features_t; /** @brief Flashcart save type enumeration */ diff --git a/src/flashcart/sc64/sc64.c b/src/flashcart/sc64/sc64.c index a0878c9d..b7febf16 100644 --- a/src/flashcart/sc64/sc64.c +++ b/src/flashcart/sc64/sc64.c @@ -260,6 +260,8 @@ static flashcart_err_t sc64_deinit (void) { static bool sc64_has_feature (flashcart_features_t feature) { switch (feature) { case FLASHCART_FEATURE_64DD: return true; + case FLASHCART_FEATURE_RTC: return true; + case FLASHCART_FEATURE_USB: return true; default: return false; } } @@ -288,7 +290,7 @@ static flashcart_err_t sc64_load_rom (char *rom_path, flashcart_progress_callbac size_t shadow_size = shadow_enabled ? MIN(rom_size - sdram_size, KiB(128)) : 0; size_t extended_size = extended_enabled ? rom_size - MiB(64) : 0; - size_t chunk_size = MiB(1); + size_t chunk_size = KiB(128); for (int offset = 0; offset < sdram_size; offset += chunk_size) { size_t block_size = MIN(sdram_size - offset, chunk_size); if (f_read(&fil, (void *) (ROM_ADDRESS + offset), block_size, &br) != FR_OK) { @@ -450,7 +452,7 @@ static flashcart_err_t sc64_load_64dd_ipl (char *ipl_path, flashcart_progress_ca return FLASHCART_ERR_LOAD; } - size_t chunk_size = KiB(256); + size_t chunk_size = KiB(128); for (int offset = 0; offset < ipl_size; offset += chunk_size) { size_t block_size = MIN(ipl_size - offset, chunk_size); if (f_read(&fil, (void *) (IPL_ADDRESS + offset), block_size, &br) != FR_OK) { diff --git a/src/menu/components.h b/src/menu/components.h index 127c1d7b..a8cecb51 100644 --- a/src/menu/components.h +++ b/src/menu/components.h @@ -45,7 +45,8 @@ typedef struct component_context_menu { struct component_context_menu *submenu; struct { const char *text; - void (*action) (menu_t *menu); + void (*action) (menu_t *menu, void *arg); + void *arg; struct component_context_menu *submenu; } list[]; } component_context_menu_t; diff --git a/src/menu/components/context_menu.c b/src/menu/components/context_menu.c index 82b3daa0..f2e32c42 100644 --- a/src/menu/components/context_menu.c +++ b/src/menu/components/context_menu.c @@ -48,7 +48,7 @@ bool component_context_menu_process (menu_t *menu, component_context_menu_t *cm) cm->submenu->selected = 0; cm->submenu->parent = cm; } else if (cm->list[cm->selected].action) { - cm->list[cm->selected].action(menu); + cm->list[cm->selected].action(menu, cm->list[cm->selected].arg); top->hide_pending = true; } } else if (menu->actions.go_up) { diff --git a/src/menu/menu.c b/src/menu/menu.c index 7cd3758a..1b8832cb 100644 --- a/src/menu/menu.c +++ b/src/menu/menu.c @@ -20,6 +20,7 @@ #include "views/views.h" +#define MENU_DIRECTORY "sd:/menu" #define CACHE_DIRECTORY "sd:/menu/cache" #define BACKGROUND_CACHE "sd:/menu/cache/background.data" @@ -77,6 +78,8 @@ static void menu_init (boot_params_t *boot_params) { menu->error_message = NULL; + directory_create(MENU_DIRECTORY); + settings_load(&menu->settings); directory_create(CACHE_DIRECTORY); @@ -133,30 +136,41 @@ static void menu_deinit (menu_t *menu) { display_close(); } - -// NOTE: Keep this array in sync with menu_mode_t -static struct views_s { +typedef const struct { + menu_mode_t id; void (*init) (menu_t *menu); void (*show) (menu_t *menu, surface_t *display); -} views[__MENU_MODE_COUNT] = { - { NULL, NULL }, // MENU_MODE_NONE - { view_startup_init, view_startup_display }, // MENU_MODE_STARTUP - { view_browser_init, view_browser_display }, // MENU_MODE_BROWSER - { view_file_info_init, view_file_info_display }, // MENU_MODE_FILE_INFO - { view_system_info_init, view_system_info_display }, // MENU_MODE_SYSTEM_INFO - { view_image_viewer_init, view_image_viewer_display }, // MENU_MODE_IMAGE_VIEWER - { view_music_player_init, view_music_player_display }, // MENU_MODE_MUSIC_PLAYER - { view_credits_init, view_credits_display }, // MENU_MODE_CREDITS - { view_settings_init, view_settings_display }, // MENU_MODE_SETTINGS_EDITOR - { view_rtc_init, view_rtc_display }, // MENU_MODE_RTC - { view_load_rom_init, view_load_rom_display }, // MENU_MODE_LOAD_ROM - { view_load_disk_init, view_load_disk_display }, // MENU_MODE_LOAD_DISK - { view_load_emulator_init, view_load_emulator_display }, // MENU_MODE_LOAD_EMULATOR - { view_error_init, view_error_display }, // MENU_MODE_ERROR - { view_fault_init, view_fault_display }, // MENU_MODE_FAULT - { NULL, NULL }, // MENU_MODE_BOOT +} view_t; + +static view_t menu_views[] = { + { MENU_MODE_STARTUP, view_startup_init, view_startup_display }, + { MENU_MODE_BROWSER, view_browser_init, view_browser_display }, + { MENU_MODE_FILE_INFO, view_file_info_init, view_file_info_display }, + { MENU_MODE_SYSTEM_INFO, view_system_info_init, view_system_info_display }, + { MENU_MODE_IMAGE_VIEWER, view_image_viewer_init, view_image_viewer_display }, + { MENU_MODE_TEXT_VIEWER, view_text_viewer_init, view_text_viewer_display }, + { MENU_MODE_MUSIC_PLAYER, view_music_player_init, view_music_player_display }, + { MENU_MODE_CREDITS, view_credits_init, view_credits_display }, + { MENU_MODE_SETTINGS_EDITOR, view_settings_init, view_settings_display }, + { MENU_MODE_RTC, view_rtc_init, view_rtc_display }, + { MENU_MODE_FLASHCART, view_flashcart_info_init, view_flashcart_info_display }, + { MENU_MODE_LOAD_ROM, view_load_rom_init, view_load_rom_display }, + { MENU_MODE_LOAD_DISK, view_load_disk_init, view_load_disk_display }, + { MENU_MODE_LOAD_EMULATOR, view_load_emulator_init, view_load_emulator_display }, + { MENU_MODE_ERROR, view_error_init, view_error_display }, + { MENU_MODE_FAULT, view_fault_init, view_fault_display }, }; +static view_t *menu_get_view (menu_mode_t id) { + for (int i = 0; i < sizeof(menu_views) / sizeof(view_t); i++) { + if (menu_views[i].id == id) { + return &menu_views[i]; + } + } + return NULL; +} + + void menu_run (boot_params_t *boot_params) { menu_init(boot_params); @@ -168,8 +182,9 @@ void menu_run (boot_params_t *boot_params) { actions_update(menu); - if (views[menu->mode].show) { - views[menu->mode].show(menu, display); + view_t *view = menu_get_view(menu->mode); + if (view && view->show) { + view->show(menu, display); } else { rdpq_attach_clear(display, NULL); rdpq_detach_wait(); @@ -183,8 +198,9 @@ void menu_run (boot_params_t *boot_params) { while (menu->mode != menu->next_mode) { menu->mode = menu->next_mode; - if (views[menu->mode].init) { - views[menu->mode].init(menu); + view_t *next_view = menu_get_view(menu->next_mode); + if (next_view && next_view->init) { + next_view->init(menu); } } diff --git a/src/menu/menu_state.h b/src/menu/menu_state.h index d29573d4..f0d93492 100644 --- a/src/menu/menu_state.h +++ b/src/menu/menu_state.h @@ -29,17 +29,18 @@ typedef enum { MENU_MODE_FILE_INFO, MENU_MODE_SYSTEM_INFO, MENU_MODE_IMAGE_VIEWER, + MENU_MODE_TEXT_VIEWER, MENU_MODE_MUSIC_PLAYER, MENU_MODE_CREDITS, MENU_MODE_SETTINGS_EDITOR, MENU_MODE_RTC, + MENU_MODE_FLASHCART, MENU_MODE_LOAD_ROM, MENU_MODE_LOAD_DISK, MENU_MODE_LOAD_EMULATOR, MENU_MODE_ERROR, MENU_MODE_FAULT, MENU_MODE_BOOT, - __MENU_MODE_COUNT, } menu_mode_t; /** @brief File entry type enumeration */ @@ -50,6 +51,7 @@ typedef enum { ENTRY_TYPE_EMULATOR, ENTRY_TYPE_SAVE, ENTRY_TYPE_IMAGE, + ENTRY_TYPE_TEXT, ENTRY_TYPE_MUSIC, ENTRY_TYPE_OTHER, } entry_type_t; diff --git a/src/menu/mp3_player.c b/src/menu/mp3_player.c index 3dfbd7da..87109a3e 100644 --- a/src/menu/mp3_player.c +++ b/src/menu/mp3_player.c @@ -27,7 +27,7 @@ typedef struct { mp3dec_t dec; mp3dec_frame_info_t info; - uint8_t buffer[MAX_FREE_FORMAT_FRAME_SIZE]; + uint8_t buffer[16 * 1024]; uint8_t *buffer_ptr; size_t buffer_left; @@ -54,6 +54,10 @@ static void mp3player_fill_buffer (void) { return; } + if (p->buffer_left >= ALIGN(MAX_FREE_FORMAT_FRAME_SIZE, FS_SECTOR_SIZE)) { + return; + } + if ((p->buffer_ptr != p->buffer) && (p->buffer_left > 0)) { memmove(p->buffer, p->buffer_ptr, p->buffer_left); p->buffer_ptr = p->buffer; diff --git a/src/menu/png_decoder.c b/src/menu/png_decoder.c index 951057b6..54d185d3 100644 --- a/src/menu/png_decoder.c +++ b/src/menu/png_decoder.c @@ -4,6 +4,7 @@ #include "png_decoder.h" #include "utils/fs.h" + /** @brief PNG File Information Structure. */ typedef struct { FIL fil; diff --git a/src/menu/rom_info.c b/src/menu/rom_info.c index 8d8f1f49..6a2223c5 100644 --- a/src/menu/rom_info.c +++ b/src/menu/rom_info.c @@ -3,6 +3,7 @@ #include #include +#include "boot/cic.h" #include "rom_info.h" #include "utils/fs.h" @@ -16,6 +17,7 @@ #define CLOCK_RATE_DEFAULT (0x0000000F) + /** @brief ROM File Information Structure. */ typedef struct __attribute__((packed)) { uint32_t pi_dom1_config; @@ -652,15 +654,34 @@ static match_t find_rom_in_database (rom_header_t *rom_header) { return *match; } -static uint32_t fix_boot_address (cic_type_t cic_type, uint32_t boot_address) { +static rom_cic_type_t detect_cic_type (uint8_t *ipl3) { + switch (cic_detect(ipl3)) { + case CIC_5101: return ROM_CIC_TYPE_5101; + case CIC_5167: return ROM_CIC_TYPE_5167; + case CIC_6101: return ROM_CIC_TYPE_6101; + case CIC_7102: return ROM_CIC_TYPE_7102; + case CIC_x102: return ROM_CIC_TYPE_x102; + case CIC_x103: return ROM_CIC_TYPE_x103; + case CIC_x105: return ROM_CIC_TYPE_x105; + case CIC_x106: return ROM_CIC_TYPE_x106; + case CIC_8301: return ROM_CIC_TYPE_8301; + case CIC_8302: return ROM_CIC_TYPE_8302; + case CIC_8303: return ROM_CIC_TYPE_8303; + case CIC_8401: return ROM_CIC_TYPE_8401; + case CIC_8501: return ROM_CIC_TYPE_8501; + default: return ROM_CIC_TYPE_UNKNOWN; + } +} + +static uint32_t fix_boot_address (rom_cic_type_t cic_type, uint32_t boot_address) { switch (cic_type) { - case CIC_x103: return (boot_address - 0x100000); - case CIC_x106: return (boot_address - 0x200000); + case ROM_CIC_TYPE_x103: return (boot_address - 0x100000); + case ROM_CIC_TYPE_x106: return (boot_address - 0x200000); default: return boot_address; } } -static rom_tv_type_t determine_tv_type (destination_type_t rom_destination_code) { +static rom_tv_type_t determine_tv_type (rom_destination_type_t rom_destination_code) { // check the market type from the ROM destination_code and return best guess! switch (rom_destination_code) { case MARKET_NORTH_AMERICA: @@ -695,7 +716,7 @@ static rom_tv_type_t determine_tv_type (destination_type_t rom_destination_code) } static void extract_rom_info (match_t *match, rom_header_t *rom_header, rom_info_t *rom_info) { - rom_info->cic_type = cic_detect(rom_header->ipl3); + rom_info->cic_type = detect_cic_type(rom_header->ipl3); if (match->type == MATCH_TYPE_HOMEBREW_HEADER) { if (rom_header->version & (1 << 0)) { @@ -746,63 +767,72 @@ static void extract_rom_info (match_t *match, rom_header_t *rom_header, rom_info } static void load_overrides (path_t *path, rom_info_t *rom_info) { + path_t *overrides_path = path_clone(path); + + path_ext_replace(overrides_path, "ini"); + + mini_t *ini = mini_load(path_get(overrides_path)); + + rom_info->override.cic = false; rom_info->override.save = false; rom_info->override.tv = false; - path_t *overrides_path = path_clone(path); + if (ini) { + rom_info->override.cic_type = mini_get_int(ini, NULL, "cic_type", ROM_CIC_TYPE_AUTOMATIC); + if (rom_info->override.cic_type != ROM_CIC_TYPE_AUTOMATIC) { + rom_info->override.cic = true; + } - path_ext_replace(overrides_path, "ini"); + rom_info->override.save_type = mini_get_int(ini, NULL, "save_type", SAVE_TYPE_AUTOMATIC); + if (rom_info->override.save_type != SAVE_TYPE_AUTOMATIC) { + rom_info->override.save = true; + } - if (!file_exists(path_get(overrides_path))) { - path_free(overrides_path); - return; + rom_info->override.tv_type = mini_get_int(ini, NULL, "tv_type", ROM_TV_TYPE_AUTOMATIC); + if (rom_info->override.tv_type != ROM_TV_TYPE_AUTOMATIC) { + rom_info->override.tv = true; + } + + mini_free(ini); } - mini_t *ini = mini_try_load(path_get(overrides_path)); - - rom_info->override.save_type = mini_get_int(ini, NULL, "save_type", SAVE_TYPE_AUTOMATIC); - if (rom_info->override.save_type != SAVE_TYPE_AUTOMATIC) { - rom_info->override.save = true; - } - - rom_info->override.tv_type = mini_get_int(ini, NULL, "tv_type", ROM_TV_TYPE_AUTOMATIC); - if (rom_info->override.tv_type != ROM_TV_TYPE_AUTOMATIC) { - rom_info->override.tv = true; - } - - mini_free(ini); - path_free(overrides_path); } - -rom_err_t rom_info_override_save_type (path_t *path, rom_info_t *rom_info, rom_save_type_t save_type) { +static rom_err_t save_override (path_t *path, const char *id, int value, int default_value) { path_t *overrides_path = path_clone(path); path_ext_replace(overrides_path, "ini"); mini_t *ini = mini_try_load(path_get(overrides_path)); - rom_info->override.save_type = save_type; - - if (rom_info->override.save_type == SAVE_TYPE_AUTOMATIC) { - rom_info->override.save = false; - mini_delete_value(ini, NULL, "save_type"); - } else { - rom_info->override.save = true; - mini_set_int(ini, NULL, "save_type", rom_info->override.save_type); + if (!ini) { + return ROM_ERR_IO; } - bool empty_override_file = mini_empty(ini); + if (value == default_value) { + mini_delete_value(ini, NULL, id); + } else { + mini_set_int(ini, NULL, id, value); + } - if (!empty_override_file) { - mini_save(ini, MINI_FLAGS_NONE); + bool empty = mini_empty(ini); + + if (!empty) { + if (mini_save(ini, MINI_FLAGS_NONE) != MINI_OK) { + path_free(overrides_path); + mini_free(ini); + return ROM_ERR_IO; + } } mini_free(ini); - if (empty_override_file) { - file_delete(path_get(overrides_path)); + if (empty) { + if (file_delete(path_get(overrides_path))) { + path_free(overrides_path); + return ROM_ERR_IO; + } } path_free(overrides_path); @@ -810,38 +840,45 @@ rom_err_t rom_info_override_save_type (path_t *path, rom_info_t *rom_info, rom_s return ROM_OK; } -rom_err_t rom_info_override_tv_type (path_t *path, rom_info_t *rom_info, rom_tv_type_t tv_type) { - path_t *overrides_path = path_clone(path); - path_ext_replace(overrides_path, "ini"); - - mini_t *ini = mini_try_load(path_get(overrides_path)); - - rom_info->override.tv_type = tv_type; - - if (rom_info->override.tv_type == ROM_TV_TYPE_AUTOMATIC) { - rom_info->override.tv = false; - mini_delete_value(ini, NULL, "tv_type"); +rom_cic_type_t rom_info_get_cic_type (rom_info_t *rom_info) { + if (rom_info->override.cic) { + return rom_info->override.cic_type; } else { - rom_info->override.tv = true; - mini_set_int(ini, NULL, "tv_type", rom_info->override.tv_type); + return rom_info->cic_type; + } +} + +bool rom_info_get_cic_seed (rom_info_t *rom_info, uint8_t *seed) { + cic_type_t cic_type; + + switch (rom_info_get_cic_type(rom_info)) { + case ROM_CIC_TYPE_5101: cic_type = CIC_5101; break; + case ROM_CIC_TYPE_5167: cic_type = CIC_5167; break; + case ROM_CIC_TYPE_6101: cic_type = CIC_6101; break; + case ROM_CIC_TYPE_7102: cic_type = CIC_7102; break; + case ROM_CIC_TYPE_x102: cic_type = CIC_x102; break; + case ROM_CIC_TYPE_x103: cic_type = CIC_x103; break; + case ROM_CIC_TYPE_x105: cic_type = CIC_x105; break; + case ROM_CIC_TYPE_x106: cic_type = CIC_x106; break; + case ROM_CIC_TYPE_8301: cic_type = CIC_8301; break; + case ROM_CIC_TYPE_8302: cic_type = CIC_8302; break; + case ROM_CIC_TYPE_8303: cic_type = CIC_8303; break; + case ROM_CIC_TYPE_8401: cic_type = CIC_8401; break; + case ROM_CIC_TYPE_8501: cic_type = CIC_8501; break; + default: cic_type = CIC_UNKNOWN; break; } - bool empty_override_file = mini_empty(ini); + *seed = cic_get_seed(cic_type); - if (!empty_override_file) { - mini_save(ini, MINI_FLAGS_NONE); - } + return (!rom_info->override.cic); +} - mini_free(ini); +rom_err_t rom_info_override_cic_type (path_t *path, rom_info_t *rom_info, rom_cic_type_t cic_type) { + rom_info->override.cic = (cic_type != ROM_CIC_TYPE_AUTOMATIC); + rom_info->override.cic_type = cic_type; - if (empty_override_file) { - file_delete(path_get(overrides_path)); - } - - path_free(overrides_path); - - return ROM_OK; + return save_override(path, "cic_type", rom_info->override.cic_type, ROM_CIC_TYPE_AUTOMATIC); } rom_save_type_t rom_info_get_save_type (rom_info_t *rom_info) { @@ -852,6 +889,13 @@ rom_save_type_t rom_info_get_save_type (rom_info_t *rom_info) { } } +rom_err_t rom_info_override_save_type (path_t *path, rom_info_t *rom_info, rom_save_type_t save_type) { + rom_info->override.save = (save_type != SAVE_TYPE_AUTOMATIC); + rom_info->override.save_type = save_type; + + return save_override(path, "save_type", rom_info->override.save_type, SAVE_TYPE_AUTOMATIC); +} + rom_tv_type_t rom_info_get_tv_type (rom_info_t *rom_info) { if (rom_info->override.tv) { return rom_info->override.tv_type; @@ -860,6 +904,13 @@ rom_tv_type_t rom_info_get_tv_type (rom_info_t *rom_info) { } } +rom_err_t rom_info_override_tv_type (path_t *path, rom_info_t *rom_info, rom_tv_type_t tv_type) { + rom_info->override.tv = (tv_type != ROM_TV_TYPE_AUTOMATIC); + rom_info->override.tv_type = tv_type; + + return save_override(path, "tv_type", rom_info->override.tv_type, ROM_TV_TYPE_AUTOMATIC); +} + rom_err_t rom_info_load (path_t *path, rom_info_t *rom_info) { FIL fil; UINT br; diff --git a/src/menu/rom_info.h b/src/menu/rom_info.h index a4088c64..cb241a2e 100644 --- a/src/menu/rom_info.h +++ b/src/menu/rom_info.h @@ -1,7 +1,7 @@ /** * @file rom_info.h * @brief N64 ROM Database. - * @note Only works with N64 ROM's by checking the first 1024 bytes of the file. + * @note Only works with N64 ROM's by checking the first 4096 bytes of the file. * @ingroup menu */ @@ -12,7 +12,6 @@ #include #include -#include "boot/cic.h" #include "path.h" @@ -31,7 +30,7 @@ typedef enum { ENDIANNESS_LITTLE, /** @brief Is Byte Swapped Endian. */ ENDIANNESS_BYTE_SWAP, -} endianness_t; +} rom_endianness_t; /** @brief ROM media type enumeration. */ typedef enum { @@ -45,7 +44,7 @@ typedef enum { N64_DISK_EXPANDABLE = 'E', /** @brief Is an Aleck64 program. */ N64_ALECK64 = 'Z' -} category_type_t; +} rom_category_type_t; /** @brief ROM market region & language type enumeration. */ typedef enum { @@ -89,27 +88,46 @@ typedef enum { MARKET_OTHER_Y = 'Y', // many EU ROM's uses this. /** @brief The ROM is designed for an undefined region and TBD language(s). */ MARKET_OTHER_Z = 'Z' // no known ROM's use this. -} destination_type_t; +} rom_destination_type_t; + +/** @brief ROM CIC type enumeration. */ +typedef enum { + ROM_CIC_TYPE_UNKNOWN = 0, // No known CIC type detected + ROM_CIC_TYPE_5101 = 5101, // Aleck64 CIC-5101 + ROM_CIC_TYPE_5167 = 5167, // 64DD ROM conversion CIC-5167 + ROM_CIC_TYPE_6101 = 6101, // NTSC CIC-6101 + ROM_CIC_TYPE_7102 = 7102, // PAL CIC-7102 + ROM_CIC_TYPE_x102 = 6102, // NTSC CIC-6102 / PAL CIC-7101 + ROM_CIC_TYPE_x103 = 6103, // NTSC CIC-6103 / PAL CIC-7103 + ROM_CIC_TYPE_x105 = 6105, // NTSC CIC-6105 / PAL CIC-7105 + ROM_CIC_TYPE_x106 = 6106, // NTSC CIC-6106 / PAL CIC-7106 + ROM_CIC_TYPE_8301 = 8301, // NDDJ0 64DD IPL + ROM_CIC_TYPE_8302 = 8302, // NDDJ1 64DD IPL + ROM_CIC_TYPE_8303 = 8303, // NDDJ2 64DD IPL + ROM_CIC_TYPE_8401 = 8401, // NDXJ0 64DD IPL + ROM_CIC_TYPE_8501 = 8501, // NDDE0 64DD IPL + ROM_CIC_TYPE_AUTOMATIC = -1, // Guess CIC from IPL3 +} rom_cic_type_t; /** @brief ROM save type enumeration. */ typedef enum { /** @brief There is no expected save type. */ - SAVE_TYPE_NONE, - SAVE_TYPE_EEPROM_4K, - SAVE_TYPE_EEPROM_16K, - SAVE_TYPE_SRAM, - SAVE_TYPE_SRAM_BANKED, - SAVE_TYPE_SRAM_128K, - SAVE_TYPE_FLASHRAM, - SAVE_TYPE_FLASHRAM_PKST2, + SAVE_TYPE_NONE = 0, + SAVE_TYPE_EEPROM_4K = 1, + SAVE_TYPE_EEPROM_16K = 2, + SAVE_TYPE_SRAM = 3, + SAVE_TYPE_SRAM_BANKED = 4, + SAVE_TYPE_SRAM_128K = 5, + SAVE_TYPE_FLASHRAM = 6, + SAVE_TYPE_FLASHRAM_PKST2 = 7, SAVE_TYPE_AUTOMATIC = -1, } rom_save_type_t; typedef enum { - ROM_TV_TYPE_PAL, - ROM_TV_TYPE_NTSC, - ROM_TV_TYPE_MPAL, - ROM_TV_TYPE_UNKNOWN, + ROM_TV_TYPE_PAL = 0, + ROM_TV_TYPE_NTSC = 1, + ROM_TV_TYPE_MPAL = 2, + ROM_TV_TYPE_UNKNOWN = 3, ROM_TV_TYPE_AUTOMATIC = -1, } rom_tv_type_t; @@ -129,49 +147,62 @@ typedef enum { /** @brief The ROM is faulty when using 8MB of memory. */ EXPANSION_PAK_FAULTY, -} expansion_pak_t; +} rom_expansion_pak_t; /** @brief ROM Information Structure. */ typedef struct { /** @brief The file endian. */ - endianness_t endianness; + rom_endianness_t endianness; + /** @brief The clock rate defined in the ROM's header. */ float clock_rate; + /** @brief The boot address defined in the ROM's header. */ uint32_t boot_address; + struct { /** @brief The SDK version defined in the ROM's header. */ uint8_t version; /** @brief The SDK revision defined in the ROM's header. */ char revision; } libultra; + /** @brief The check code defined in the ROM's header. */ uint64_t check_code; + /** @brief The title defined in the ROM's header. */ char title[20]; + union { /** @brief The game code defined in the ROM's header. */ char game_code[4]; struct { /** @brief The game media type. */ - category_type_t category_code : 8; + rom_category_type_t category_code : 8; /** @brief The game unique identifier. */ char unique_code[2]; /** @brief The game region and or market. */ - destination_type_t destination_code : 8; + rom_destination_type_t destination_code : 8; }; }; + /** @brief The ROM version defined in the ROM's header. */ uint8_t version; - cic_type_t cic_type; + /** @brief The CIC type required by the ROM. */ + rom_cic_type_t cic_type; /** @brief The save type required by the ROM. */ rom_save_type_t save_type; + /** @brief The TV type required by the ROM. */ rom_tv_type_t tv_type; + /** @brief Overrides of auto-detected CIC/save/TV types. */ struct { + bool cic; + rom_cic_type_t cic_type; + bool save; rom_save_type_t save_type; @@ -188,15 +219,21 @@ typedef struct { bool real_time_clock; bool disk_conversion; bool combo_rom_disk_game; - expansion_pak_t expansion_pak; + rom_expansion_pak_t expansion_pak; } features; } rom_info_t; -rom_err_t rom_info_override_save_type (path_t *path, rom_info_t *rom_info, rom_save_type_t save_type); -rom_err_t rom_info_override_tv_type (path_t *path, rom_info_t *rom_info, rom_tv_type_t tv_type); +rom_cic_type_t rom_info_get_cic_type (rom_info_t *rom_info); +bool rom_info_get_cic_seed (rom_info_t *rom_info, uint8_t *seed); +rom_err_t rom_info_override_cic_type (path_t *path, rom_info_t *rom_info, rom_cic_type_t cic_type); + rom_save_type_t rom_info_get_save_type (rom_info_t *rom_info); +rom_err_t rom_info_override_save_type (path_t *path, rom_info_t *rom_info, rom_save_type_t save_type); + rom_tv_type_t rom_info_get_tv_type (rom_info_t *rom_info); +rom_err_t rom_info_override_tv_type (path_t *path, rom_info_t *rom_info, rom_tv_type_t tv_type); + rom_err_t rom_info_load (path_t *path, rom_info_t *rom_info); diff --git a/src/menu/sound.c b/src/menu/sound.c index d613b4f2..9e58d001 100644 --- a/src/menu/sound.c +++ b/src/menu/sound.c @@ -6,7 +6,7 @@ #define DEFAULT_FREQUENCY (44100) -#define NUM_BUFFERS (2) +#define NUM_BUFFERS (4) #define NUM_CHANNELS (2) diff --git a/src/menu/usb_comm.c b/src/menu/usb_comm.c index c823a3bd..fd218cd3 100644 --- a/src/menu/usb_comm.c +++ b/src/menu/usb_comm.c @@ -12,10 +12,12 @@ #define MAX_FILE_SIZE MiB(4) + /** @brief The supported USB commands structure. */ typedef struct { /** @brief The command identifier. */ const char *id; + /** @brief The command operation. */ void (*op) (menu_t *menu); } usb_comm_command_t; diff --git a/src/menu/views/browser.c b/src/menu/views/browser.c index 75ab0a4a..01cdb41b 100644 --- a/src/menu/views/browser.c +++ b/src/menu/views/browser.c @@ -14,6 +14,7 @@ static const char *disk_extensions[] = { "ndd", NULL }; static const char *emulator_extensions[] = { "nes", "sfc", "smc", "gb", "gbc", "sms", "gg", "sg", NULL }; static const char *save_extensions[] = { "sav", NULL }; // TODO: "eep", "sra", "srm", "fla" could be used if transfered from different flashcarts. static const char *image_extensions[] = { "png", NULL }; +static const char *text_extensions[] = { "txt", "ini", "yml", "yaml", NULL }; static const char *music_extensions[] = { "mp3", NULL }; @@ -46,6 +47,10 @@ static int compare_entry (const void *pa, const void *pb) { return -1; } else if (b->type == ENTRY_TYPE_IMAGE) { return 1; + } else if (a->type == ENTRY_TYPE_TEXT) { + return -1; + } else if (b->type == ENTRY_TYPE_TEXT) { + return 1; } else if (a->type == ENTRY_TYPE_MUSIC) { return -1; } else if (b->type == ENTRY_TYPE_MUSIC) { @@ -110,6 +115,8 @@ static bool load_directory (menu_t *menu) { entry->type = ENTRY_TYPE_SAVE; } else if (file_has_extensions(info.fname, image_extensions)) { entry->type = ENTRY_TYPE_IMAGE; + } else if (file_has_extensions(info.fname, text_extensions)) { + entry->type = ENTRY_TYPE_TEXT; } else if (file_has_extensions(info.fname, music_extensions)) { entry->type = ENTRY_TYPE_MUSIC; } else { @@ -135,6 +142,22 @@ static bool load_directory (menu_t *menu) { return false; } +static bool reload_directory (menu_t *menu) { + int selected = menu->browser.selected; + + if (load_directory(menu)) { + return true; + } + + menu->browser.selected = selected; + if (menu->browser.selected >= menu->browser.entries) { + menu->browser.selected = menu->browser.entries - 1; + } + menu->browser.entry = menu->browser.selected >= 0 ? &menu->browser.list[menu->browser.selected] : NULL; + + return false; +} + static bool push_directory (menu_t *menu, char *directory) { path_t *previous_directory = path_clone(menu->browser.directory); @@ -175,13 +198,11 @@ static bool pop_directory (menu_t *menu) { return false; } -static void show_properties (menu_t *menu) { +static void show_properties (menu_t *menu, void *arg) { menu->next_mode = MENU_MODE_FILE_INFO; } -static void delete_entry (menu_t *menu) { - int selected = menu->browser.selected; - +static void delete_entry (menu_t *menu, void *arg) { path_t *path = path_clone_push(menu->browser.directory, menu->browser.entry->name); if (menu->browser.entry->type == ENTRY_TYPE_DIR) { @@ -200,20 +221,13 @@ static void delete_entry (menu_t *menu) { path_free(path); - if (load_directory(menu)) { + if (reload_directory(menu)) { menu->browser.valid = false; menu_show_error(menu, "Couldn't refresh directory contents after delete operation"); - return; } - - menu->browser.selected = selected; - if (menu->browser.selected >= menu->browser.entries) { - menu->browser.selected = menu->browser.entries - 1; - } - menu->browser.entry = menu->browser.selected >= 0 ? &menu->browser.list[menu->browser.selected] : NULL; } -static void set_default_directory (menu_t *menu) { +static void set_default_directory (menu_t *menu, void *arg) { free(menu->settings.default_directory); menu->settings.default_directory = strdup(strip_sd_prefix(path_get(menu->browser.directory))); settings_save(&menu->settings); @@ -228,28 +242,18 @@ static component_context_menu_t entry_context_menu = { } }; -static void edit_settings (menu_t *menu) { - menu->next_mode = MENU_MODE_SETTINGS_EDITOR; -} - -static void show_system_info (menu_t *menu) { - menu->next_mode = MENU_MODE_SYSTEM_INFO; -} - -static void show_credits (menu_t *menu) { - menu->next_mode = MENU_MODE_CREDITS; -} - -static void edit_rtc (menu_t *menu) { - menu->next_mode = MENU_MODE_RTC; +static void set_menu_next_mode (menu_t *menu, void *arg) { + menu_mode_t next_mode = (menu_mode_t) (arg); + menu->next_mode = next_mode; } static component_context_menu_t settings_context_menu = { .list = { - { .text = "Edit settings", .action = edit_settings }, - { .text = "Show system info", .action = show_system_info }, - { .text = "Show credits", .action = show_credits }, - { .text = "Adjust RTC", .action = edit_rtc }, + { .text = "Edit settings", .action = set_menu_next_mode, .arg = (void *) (MENU_MODE_SETTINGS_EDITOR) }, + { .text = "Show system info", .action = set_menu_next_mode, .arg = (void *) (MENU_MODE_SYSTEM_INFO) }, + { .text = "Show credits", .action = set_menu_next_mode, .arg = (void *) (MENU_MODE_CREDITS) }, + { .text = "Adjust RTC", .action = set_menu_next_mode, .arg = (void *) (MENU_MODE_RTC) }, + { .text = "Show cart info", .action = set_menu_next_mode, .arg = (void *) (MENU_MODE_FLASHCART) }, COMPONENT_CONTEXT_MENU_LIST_END, } }; @@ -300,6 +304,9 @@ static void process (menu_t *menu) { case ENTRY_TYPE_IMAGE: menu->next_mode = MENU_MODE_IMAGE_VIEWER; break; + case ENTRY_TYPE_TEXT: + menu->next_mode = MENU_MODE_TEXT_VIEWER; + break; case ENTRY_TYPE_MUSIC: menu->next_mode = MENU_MODE_MUSIC_PLAYER; break; @@ -337,6 +344,7 @@ static void draw (menu_t *menu, surface_t *d) { case ENTRY_TYPE_ROM: action = "A: Load"; break; case ENTRY_TYPE_DISK: action = "A: Load"; break; case ENTRY_TYPE_IMAGE: action = "A: Show"; break; + case ENTRY_TYPE_TEXT: action = "A: View"; break; case ENTRY_TYPE_MUSIC: action = "A: Play"; break; default: action = "A: Info"; break; } @@ -386,18 +394,12 @@ void view_browser_init (menu_t *menu) { menu->browser.valid = true; } } + if (menu->browser.reload) { menu->browser.reload = false; - int selected = menu->browser.selected; - if (load_directory(menu)) { + if (reload_directory(menu)) { menu_show_error(menu, "Error while reloading current directory"); menu->browser.valid = false; - } else { - menu->browser.selected = selected; - if (menu->browser.selected >= menu->browser.entries) { - menu->browser.selected = menu->browser.entries - 1; - } - menu->browser.entry = menu->browser.selected >= 0 ? &menu->browser.list[menu->browser.selected] : NULL; } } } diff --git a/src/menu/views/credits.c b/src/menu/views/credits.c index a6e42a9a..dc1d0665 100644 --- a/src/menu/views/credits.c +++ b/src/menu/views/credits.c @@ -2,7 +2,11 @@ #ifndef MENU_VERSION -#define MENU_VERSION "0.0.0.6.ALPHA" +#define MENU_VERSION "Unknown" +#endif + +#ifndef BUILD_TIMESTAMP +#define BUILD_TIMESTAMP "Unknown" #endif @@ -28,7 +32,8 @@ static void draw (menu_t *menu, surface_t *d) { ALIGN_LEFT, VALIGN_TOP, "\n" "\n" - "Menu Revision: V%s\n" + "Menu version: %s\n" + "Build timestamp: %s\n" "\n" "Github:\n" " https://github.com/Polprzewodnikowy/N64FlashcartMenu\n" @@ -44,7 +49,8 @@ static void draw (menu_t *menu, surface_t *d) { " mini.c (BSD 2-Clause License)\n" " minimp3 (CC0 1.0 Universal)\n" " miniz (MIT License)", - MENU_VERSION + MENU_VERSION, + BUILD_TIMESTAMP ); component_actions_bar_text_draw( diff --git a/src/menu/views/flashcart_info.c b/src/menu/views/flashcart_info.c new file mode 100644 index 00000000..084cc073 --- /dev/null +++ b/src/menu/views/flashcart_info.c @@ -0,0 +1,46 @@ +#include "views.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) { + rdpq_attach(d, NULL); + + component_background_draw(); + + component_layout_draw(); + + component_main_text_draw( + ALIGN_CENTER, VALIGN_TOP, + "FLASHCART INFORMATION\n" + ); + + component_main_text_draw( + ALIGN_LEFT, VALIGN_TOP, + "\n" + "\n" + ); + + + component_actions_bar_text_draw( + ALIGN_LEFT, VALIGN_TOP, + "\n" + "B: Back" + ); + + rdpq_detach_show(); +} + + +void view_flashcart_info_init (menu_t *menu) { + // Nothing to initialize (yet) +} + +void view_flashcart_info_display (menu_t *menu, surface_t *display) { + process(menu); + draw(menu, display); +} diff --git a/src/menu/views/load_disk.c b/src/menu/views/load_disk.c index 14d9d80b..0a8ebb62 100644 --- a/src/menu/views/load_disk.c +++ b/src/menu/views/load_disk.c @@ -126,9 +126,21 @@ static void load (menu_t *menu) { } menu->next_mode = MENU_MODE_BOOT; - menu->boot_params->device_type = load_rom ? BOOT_DEVICE_TYPE_ROM : BOOT_DEVICE_TYPE_64DD; - menu->boot_params->tv_type = BOOT_TV_TYPE_PASSTHROUGH; - menu->boot_params->detect_cic_seed = true; + + if (load_rom) { + menu->boot_params->device_type = BOOT_DEVICE_TYPE_ROM; + menu->boot_params->detect_cic_seed = rom_info_get_cic_seed(&menu->load.rom_info, &menu->boot_params->cic_seed); + switch (rom_info_get_tv_type(&menu->load.rom_info)) { + case ROM_TV_TYPE_PAL: menu->boot_params->tv_type = BOOT_TV_TYPE_PAL; break; + case ROM_TV_TYPE_NTSC: menu->boot_params->tv_type = BOOT_TV_TYPE_NTSC; break; + case ROM_TV_TYPE_MPAL: menu->boot_params->tv_type = BOOT_TV_TYPE_MPAL; break; + default: menu->boot_params->tv_type = BOOT_TV_TYPE_PASSTHROUGH; break; + } + } else { + menu->boot_params->device_type = BOOT_DEVICE_TYPE_64DD; + menu->boot_params->tv_type = BOOT_TV_TYPE_NTSC; + menu->boot_params->detect_cic_seed = true; + } } diff --git a/src/menu/views/load_rom.c b/src/menu/views/load_rom.c index 6beeaa0f..c5da6ed4 100644 --- a/src/menu/views/load_rom.c +++ b/src/menu/views/load_rom.c @@ -8,15 +8,15 @@ static bool load_pending; static component_boxart_t *boxart; -static char *convert_error_message (disk_err_t err) { +static char *convert_error_message (rom_err_t err) { switch (err) { - case ROM_ERR_IO: return "I/O error during loading ROM information"; + case ROM_ERR_IO: return "I/O error during loading/storing ROM information"; case ROM_ERR_NO_FILE: return "Couldn't open ROM file"; default: return "Unknown ROM info load error"; } } -static const char *format_rom_endianness (endianness_t endianness) { +static const char *format_rom_endianness (rom_endianness_t endianness) { switch (endianness) { case ENDIANNESS_BIG: return "Big (default)"; case ENDIANNESS_LITTLE: return "Little (unsupported)"; @@ -25,7 +25,7 @@ static const char *format_rom_endianness (endianness_t endianness) { } } -static const char *format_rom_media_type (category_type_t media_type) { +static const char *format_rom_media_type (rom_category_type_t media_type) { switch (media_type) { case N64_CART: return "Cartridge"; case N64_DISK: return "Disk"; @@ -36,7 +36,7 @@ static const char *format_rom_media_type (category_type_t media_type) { } } -static const char *format_rom_destination_market (destination_type_t market_type) { +static const char *format_rom_destination_market (rom_destination_type_t market_type) { // TODO: These are all assumptions and should be corrected if required. // From http://n64devkit.square7.ch/info/submission/pal/01-01.html switch (market_type) { @@ -87,7 +87,7 @@ static const char *format_rom_tv_type (rom_tv_type_t tv_type) { } } -static char *format_rom_expansion_pak_info (expansion_pak_t expansion_pak_info) { +static const char *format_rom_expansion_pak_info (rom_expansion_pak_t expansion_pak_info) { switch (expansion_pak_info) { case EXPANSION_PAK_REQUIRED: return "Required"; case EXPANSION_PAK_RECOMMENDED: return "Recommended"; @@ -97,72 +97,94 @@ static char *format_rom_expansion_pak_info (expansion_pak_t expansion_pak_info) } } -static const char *format_cic_type (cic_type_t cic_type) { +static const char *format_cic_type (rom_cic_type_t cic_type) { switch (cic_type) { - case CIC_5101: return "5101"; - case CIC_5167: return "5167"; - case CIC_6101: return "6101"; - case CIC_7102: return "7102"; - case CIC_6102_7101: return "6102 / 7101"; - case CIC_x103: return "6103 / 7103"; - case CIC_x105: return "6105 / 7105"; - case CIC_x106: return "6106 / 7106"; - case CIC_8301: return "8301"; - case CIC_8302: return "8302"; - case CIC_8303: return "8303"; - case CIC_8401: return "8401"; - case CIC_8501: return "8501"; + case ROM_CIC_TYPE_5101: return "5101"; + case ROM_CIC_TYPE_5167: return "5167"; + case ROM_CIC_TYPE_6101: return "6101"; + case ROM_CIC_TYPE_7102: return "7102"; + case ROM_CIC_TYPE_x102: return "6102 / 7101"; + case ROM_CIC_TYPE_x103: return "6103 / 7103"; + case ROM_CIC_TYPE_x105: return "6105 / 7105"; + case ROM_CIC_TYPE_x106: return "6106 / 7106"; + case ROM_CIC_TYPE_8301: return "8301"; + case ROM_CIC_TYPE_8302: return "8302"; + case ROM_CIC_TYPE_8303: return "8303"; + case ROM_CIC_TYPE_8401: return "8401"; + case ROM_CIC_TYPE_8501: return "8501"; default: return "Unknown"; } } -static void set_save_type (menu_t *menu, rom_save_type_t save_type) { - rom_info_override_save_type(menu->load.rom_path, &menu->load.rom_info, save_type); +static void set_cic_type (menu_t *menu, void *arg) { + rom_cic_type_t cic_type = (rom_cic_type_t) (arg); + rom_err_t err = rom_info_override_cic_type(menu->load.rom_path, &menu->load.rom_info, cic_type); + if (err != ROM_OK) { + menu_show_error(menu, convert_error_message(err)); + } menu->browser.reload = true; } -static void set_save_type_automatic (menu_t *menu) { set_save_type(menu, SAVE_TYPE_AUTOMATIC); } -static void set_save_type_none (menu_t *menu) { set_save_type(menu, SAVE_TYPE_NONE); } -static void set_save_type_eeprom_4kbit (menu_t *menu) { set_save_type(menu, SAVE_TYPE_EEPROM_4K); } -static void set_save_type_eeprom_16kbit (menu_t *menu) { set_save_type(menu, SAVE_TYPE_EEPROM_16K); } -static void set_save_type_sram_256kbit (menu_t *menu) { set_save_type(menu, SAVE_TYPE_SRAM); } -static void set_save_type_sram_768kbit (menu_t *menu) { set_save_type(menu, SAVE_TYPE_SRAM_BANKED); } -static void set_save_type_sram_1mbit (menu_t *menu) { set_save_type(menu, SAVE_TYPE_SRAM_128K); } -static void set_save_type_flash_ram_1mbit (menu_t *menu) { set_save_type(menu, SAVE_TYPE_FLASHRAM); } +static void set_save_type (menu_t *menu, void *arg) { + rom_save_type_t save_type = (rom_save_type_t) (arg); + rom_err_t err = rom_info_override_save_type(menu->load.rom_path, &menu->load.rom_info, save_type); + if (err != ROM_OK) { + menu_show_error(menu, convert_error_message(err)); + } + menu->browser.reload = true; +} -static component_context_menu_t set_save_type_context_menu = { .list = { - { .text = "Automatic", .action = set_save_type_automatic }, - { .text = "None", .action = set_save_type_none }, - { .text = "EEPROM 4kbit", .action = set_save_type_eeprom_4kbit }, - { .text = "EEPROM 16kbit", .action = set_save_type_eeprom_16kbit }, - { .text = "SRAM 256kbit", .action = set_save_type_sram_256kbit }, - { .text = "SRAM 768kbit", .action = set_save_type_sram_768kbit }, - { .text = "SRAM 1Mbit", .action = set_save_type_sram_1mbit }, - { .text = "FlashRAM 1Mbit", .action = set_save_type_flash_ram_1mbit }, +static void set_tv_type (menu_t *menu, void *arg) { + rom_tv_type_t tv_type = (rom_tv_type_t) (arg); + rom_err_t err = rom_info_override_tv_type(menu->load.rom_path, &menu->load.rom_info, tv_type); + if (err != ROM_OK) { + menu_show_error(menu, convert_error_message(err)); + } + menu->browser.reload = true; +} + +static component_context_menu_t set_cic_type_context_menu = { .list = { + {.text = "Automatic", .action = set_cic_type, .arg = (void *) (ROM_CIC_TYPE_AUTOMATIC) }, + {.text = "CIC-6101", .action = set_cic_type, .arg = (void *) (ROM_CIC_TYPE_6101) }, + {.text = "CIC-7102", .action = set_cic_type, .arg = (void *) (ROM_CIC_TYPE_7102) }, + {.text = "CIC-6102 / CIC-7101", .action = set_cic_type, .arg = (void *) (ROM_CIC_TYPE_x102) }, + {.text = "CIC-6103 / CIC-7103", .action = set_cic_type, .arg = (void *) (ROM_CIC_TYPE_x103) }, + {.text = "CIC-6105 / CIC-7105", .action = set_cic_type, .arg = (void *) (ROM_CIC_TYPE_x105) }, + {.text = "CIC-6106 / CIC-7106", .action = set_cic_type, .arg = (void *) (ROM_CIC_TYPE_x106) }, + {.text = "Aleck64 CIC-5101", .action = set_cic_type, .arg = (void *) (ROM_CIC_TYPE_5101) }, + {.text = "64DD ROM conversion CIC-5167", .action = set_cic_type, .arg = (void *) (ROM_CIC_TYPE_5167) }, + {.text = "NDDJ0 64DD IPL", .action = set_cic_type, .arg = (void *) (ROM_CIC_TYPE_8301) }, + {.text = "NDDJ1 64DD IPL", .action = set_cic_type, .arg = (void *) (ROM_CIC_TYPE_8302) }, + {.text = "NDDJ2 64DD IPL", .action = set_cic_type, .arg = (void *) (ROM_CIC_TYPE_8303) }, + {.text = "NDXJ0 64DD IPL", .action = set_cic_type, .arg = (void *) (ROM_CIC_TYPE_8401) }, + {.text = "NDDE0 64DD IPL", .action = set_cic_type, .arg = (void *) (ROM_CIC_TYPE_8501) }, COMPONENT_CONTEXT_MENU_LIST_END, }}; -static void set_tv_type (menu_t *menu, rom_tv_type_t tv_type) { - rom_info_override_tv_type(menu->load.rom_path, &menu->load.rom_info, tv_type); - menu->browser.reload = true; -} - -static void set_tv_type_automatic (menu_t *menu) { set_tv_type(menu, ROM_TV_TYPE_AUTOMATIC); } -static void set_tv_type_pal (menu_t *menu) { set_tv_type(menu, ROM_TV_TYPE_PAL); } -static void set_tv_type_ntsc (menu_t *menu) { set_tv_type(menu, ROM_TV_TYPE_NTSC); } -static void set_tv_type_mpal (menu_t *menu) { set_tv_type(menu, ROM_TV_TYPE_MPAL); } +static component_context_menu_t set_save_type_context_menu = { .list = { + { .text = "Automatic", .action = set_save_type, .arg = (void *) (SAVE_TYPE_AUTOMATIC) }, + { .text = "None", .action = set_save_type, .arg = (void *) (SAVE_TYPE_NONE) }, + { .text = "EEPROM 4kbit", .action = set_save_type, .arg = (void *) (SAVE_TYPE_EEPROM_4K) }, + { .text = "EEPROM 16kbit", .action = set_save_type, .arg = (void *) (SAVE_TYPE_EEPROM_16K) }, + { .text = "SRAM 256kbit", .action = set_save_type, .arg = (void *) (SAVE_TYPE_SRAM) }, + { .text = "SRAM 768kbit", .action = set_save_type, .arg = (void *) (SAVE_TYPE_SRAM_BANKED) }, + { .text = "SRAM 1Mbit", .action = set_save_type, .arg = (void *) (SAVE_TYPE_SRAM_128K) }, + { .text = "FlashRAM 1Mbit", .action = set_save_type, .arg = (void *) (SAVE_TYPE_FLASHRAM) }, + COMPONENT_CONTEXT_MENU_LIST_END, +}}; static component_context_menu_t set_tv_type_context_menu = { .list = { - { .text = "Automatic", .action = set_tv_type_automatic }, - { .text = "PAL", .action = set_tv_type_pal }, - { .text = "NTSC", .action = set_tv_type_ntsc }, - { .text = "MPAL", .action = set_tv_type_mpal }, + { .text = "Automatic", .action = set_tv_type, .arg = (void *) (ROM_TV_TYPE_AUTOMATIC) }, + { .text = "PAL", .action = set_tv_type, .arg = (void *) (ROM_TV_TYPE_PAL) }, + { .text = "NTSC", .action = set_tv_type, .arg = (void *) (ROM_TV_TYPE_NTSC) }, + { .text = "MPAL", .action = set_tv_type, .arg = (void *) (ROM_TV_TYPE_MPAL) }, COMPONENT_CONTEXT_MENU_LIST_END, }}; static component_context_menu_t options_context_menu = { .list = { - { .text = "Set save type", .submenu = &set_save_type_context_menu }, - { .text = "Set TV type", .submenu = &set_tv_type_context_menu }, + { .text = "Set CIC Type", .submenu = &set_cic_type_context_menu }, + { .text = "Set Save Type", .submenu = &set_save_type_context_menu }, + { .text = "Set TV Type", .submenu = &set_tv_type_context_menu }, COMPONENT_CONTEXT_MENU_LIST_END, }}; @@ -230,7 +252,7 @@ static void draw (menu_t *menu, surface_t *d) { format_rom_save_type(rom_info_get_save_type(&menu->load.rom_info)), format_rom_tv_type(rom_info_get_tv_type(&menu->load.rom_info)), format_rom_expansion_pak_info(menu->load.rom_info.features.expansion_pak), - format_cic_type(menu->load.rom_info.cic_type), + format_cic_type(rom_info_get_cic_type(&menu->load.rom_info)), menu->load.rom_info.boot_address, (menu->load.rom_info.libultra.version / 10.0f), menu->load.rom_info.libultra.revision, menu->load.rom_info.clock_rate @@ -281,8 +303,8 @@ static void load (menu_t *menu) { menu->next_mode = MENU_MODE_BOOT; menu->boot_params->device_type = BOOT_DEVICE_TYPE_ROM; - menu->boot_params->detect_cic_seed = true; - switch(rom_info_get_tv_type(&menu->load.rom_info)) { + menu->boot_params->detect_cic_seed = rom_info_get_cic_seed(&menu->load.rom_info, &menu->boot_params->cic_seed); + switch (rom_info_get_tv_type(&menu->load.rom_info)) { case ROM_TV_TYPE_PAL: menu->boot_params->tv_type = BOOT_TV_TYPE_PAL; break; case ROM_TV_TYPE_NTSC: menu->boot_params->tv_type = BOOT_TV_TYPE_NTSC; break; case ROM_TV_TYPE_MPAL: menu->boot_params->tv_type = BOOT_TV_TYPE_MPAL; break; @@ -296,18 +318,20 @@ static void deinit (void) { void view_load_rom_init (menu_t *menu) { + load_pending = false; + if (menu->load.rom_path) { path_free(menu->load.rom_path); - menu->load.rom_path = NULL; } - load_pending = false; - menu->load.rom_path = path_clone_push(menu->browser.directory, menu->browser.entry->name); rom_err_t err = rom_info_load(menu->load.rom_path, &menu->load.rom_info); if (err != ROM_OK) { + path_free(menu->load.rom_path); + menu->load.rom_path = NULL; menu_show_error(menu, convert_error_message(err)); + return; } boxart = component_boxart_init(menu->load.rom_info.game_code); diff --git a/src/menu/views/settings_editor.c b/src/menu/views/settings_editor.c index c624ba1a..7158a0b3 100644 --- a/src/menu/views/settings_editor.c +++ b/src/menu/views/settings_editor.c @@ -1,13 +1,14 @@ #include "views.h" -static char *format_boolean_type (int state) { + +static const char *format_switch (bool state) { switch (state) { - case 0: return "Off"; - case 1: return "On"; - default: return "Unknown"; + case true: return "On"; + case false: return "Off"; } } + static void process (menu_t *menu) { if (menu->actions.back) { menu->next_mode = MENU_MODE_BROWSER; @@ -40,16 +41,15 @@ static void draw (menu_t *menu, surface_t *d) { "bgm_enabled: %s\n" "sound_enabled: %s\n" "rumble_enabled: %s\n", - format_boolean_type(menu->settings.pal60_enabled), - format_boolean_type(menu->settings.hidden_files_enabled), + format_switch(menu->settings.pal60_enabled), + format_switch(menu->settings.hidden_files_enabled), menu->settings.default_directory, - format_boolean_type(menu->settings.use_saves_folder), - format_boolean_type(menu->settings.bgm_enabled), - format_boolean_type(menu->settings.sound_enabled), - format_boolean_type(menu->settings.rumble_enabled) + format_switch(menu->settings.use_saves_folder), + format_switch(menu->settings.bgm_enabled), + format_switch(menu->settings.sound_enabled), + format_switch(menu->settings.rumble_enabled) ); - component_actions_bar_text_draw( ALIGN_LEFT, VALIGN_TOP, "\n" @@ -66,5 +66,6 @@ void view_settings_init (menu_t *menu) { void view_settings_display (menu_t *menu, surface_t *display) { process(menu); + draw(menu, display); } diff --git a/src/menu/views/system_info.c b/src/menu/views/system_info.c index a0ebfcad..02b78f72 100644 --- a/src/menu/views/system_info.c +++ b/src/menu/views/system_info.c @@ -7,27 +7,25 @@ static int joypad[4]; static int accessory[4]; -static char *format_accessory (int joypad) { +static const char *format_accessory (int joypad) { switch (accessory[joypad]) { - case JOYPAD_ACCESSORY_TYPE_RUMBLE_PAK: - return "[Rumble Pak is inserted]"; - case JOYPAD_ACCESSORY_TYPE_CONTROLLER_PAK: - return "[Controller Pak is inserted]"; - case JOYPAD_ACCESSORY_TYPE_TRANSFER_PAK: - return "[Transfer Pak is inserted]"; - case JOYPAD_ACCESSORY_TYPE_BIO_SENSOR: - return "[BIO Sensor is inserted]"; - case JOYPAD_ACCESSORY_TYPE_SNAP_STATION: - return "[Snap Station is inserted]"; - case JOYPAD_ACCESSORY_TYPE_NONE: - return ""; - default: - return "[unknown accessory inserted]"; + case JOYPAD_ACCESSORY_TYPE_RUMBLE_PAK: return "[Rumble Pak is inserted]"; + case JOYPAD_ACCESSORY_TYPE_CONTROLLER_PAK: return "[Controller Pak is inserted]"; + case JOYPAD_ACCESSORY_TYPE_TRANSFER_PAK: return "[Transfer Pak is inserted]"; + case JOYPAD_ACCESSORY_TYPE_BIO_SENSOR: return "[BIO Sensor is inserted]"; + case JOYPAD_ACCESSORY_TYPE_SNAP_STATION: return "[Snap Station is inserted]"; + case JOYPAD_ACCESSORY_TYPE_NONE: return ""; + default: return "[unknown accessory inserted]"; } } static void process (menu_t *menu) { + JOYPAD_PORT_FOREACH (port) { + joypad[port] = (joypad_get_style(port) != JOYPAD_STYLE_NONE); + accessory[port] = joypad_get_accessory_type(port); + } + if (menu->actions.back) { menu->next_mode = MENU_MODE_BROWSER; } @@ -53,10 +51,10 @@ static void draw (menu_t *menu, surface_t *d) { "\n" "Expansion PAK is %sinserted\n" "\n" - "JoyPad 1 is %sconnected %s\n" - "JoyPad 2 is %sconnected %s\n" - "JoyPad 3 is %sconnected %s\n" - "JoyPad 4 is %sconnected %s\n", + "Joypad 1 is %sconnected %s\n" + "Joypad 2 is %sconnected %s\n" + "Joypad 3 is %sconnected %s\n" + "Joypad 4 is %sconnected %s\n", menu->current_time >= 0 ? ctime(&menu->current_time) : "Unknown\n", is_memory_expanded() ? "" : "not ", (joypad[0]) ? "" : "not ", format_accessory(0), @@ -76,10 +74,7 @@ static void draw (menu_t *menu, surface_t *d) { void view_system_info_init (menu_t *menu) { - JOYPAD_PORT_FOREACH (port) { - joypad[port] = (joypad_get_style(port) != JOYPAD_STYLE_NONE); - accessory[port] = joypad_get_accessory_type(port); - } + // Nothing to initialize (yet) } void view_system_info_display (menu_t *menu, surface_t *display) { diff --git a/src/menu/views/text_viewer.c b/src/menu/views/text_viewer.c new file mode 100644 index 00000000..adef2df9 --- /dev/null +++ b/src/menu/views/text_viewer.c @@ -0,0 +1,78 @@ +#include + +#include "utils/fs.h" +#include "views.h" + +static char *file_content; + +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) { + rdpq_attach(d, NULL); + + component_background_draw(); + + component_layout_draw(); + + component_main_text_draw( + ALIGN_CENTER, VALIGN_TOP, + "TEXT VIEWER\n" + "\n" + ); + + component_main_text_draw( + ALIGN_LEFT, VALIGN_TOP, + "\n" + "\n" + "%s\n", + file_content + ); + + + component_actions_bar_text_draw( + ALIGN_LEFT, VALIGN_TOP, + "\n" + "B: Back" + ); + + rdpq_detach_show(); +} + + +void view_text_viewer_init (menu_t *menu) { + path_t *path = path_clone_push(menu->browser.directory, menu->browser.entry->name); + + uint32_t file_size = file_get_size(path_get(path)); + + if (file_size > 1024) { // FIXME: this is just a placeholder until scrolling is implemented. + file_size = 1024; // For the moment, we just set it to that, since any more would be a waste. + } + + file_content = calloc(file_size, 1); + + // read file content + FIL fil; + UINT br; + + if (f_open(&fil, strip_sd_prefix(path_get(path)), FA_READ) != FR_OK) { + debugf("Error loading file\n"); + } + if (f_read(&fil, file_content, file_size, &br) != FR_OK) { + f_close(&fil); + debugf("Error loading file content\n"); + } + if (f_close(&fil) != FR_OK) { + debugf("Error closing file\n"); + } + + path_free(path); +} + +void view_text_viewer_display (menu_t *menu, surface_t *display) { + process(menu); + draw(menu, display); +} diff --git a/src/menu/views/views.h b/src/menu/views/views.h index 2b7e0660..8da900dc 100644 --- a/src/menu/views/views.h +++ b/src/menu/views/views.h @@ -23,33 +23,39 @@ void view_startup_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_system_info_init (menu_t *menu); -void view_system_info_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_system_info_init (menu_t *menu); +void view_system_info_display (menu_t *menu, surface_t *display); + void view_image_viewer_init (menu_t *menu); void view_image_viewer_display (menu_t *menu, surface_t *display); +void view_text_viewer_init (menu_t *menu); +void view_text_viewer_display (menu_t *menu, surface_t *display); + void view_music_player_init (menu_t *menu); void view_music_player_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_rom_init (menu_t *menu); -void view_load_rom_display (menu_t *menu, surface_t *display); - -void view_load_disk_init (menu_t *menu); -void view_load_disk_display (menu_t *menu, surface_t *display); - void view_settings_init (menu_t *menu); void view_settings_display (menu_t *menu, surface_t *display); void view_rtc_init (menu_t *menu); void view_rtc_display (menu_t *menu, surface_t *display); +void view_flashcart_info_init (menu_t *menu); +void view_flashcart_info_display (menu_t *menu, surface_t *display); + +void view_load_rom_init (menu_t *menu); +void view_load_rom_display (menu_t *menu, surface_t *display); + +void view_load_disk_init (menu_t *menu); +void view_load_disk_display (menu_t *menu, surface_t *display); + void view_load_emulator_init (menu_t *menu); void view_load_emulator_display (menu_t *menu, surface_t *display);