From a35c6bdec7bf340d6a5638d07eb83c30c4d71c58 Mon Sep 17 00:00:00 2001 From: Robin Jones Date: Sun, 18 Aug 2024 19:10:33 +0100 Subject: [PATCH 01/47] Update libdragon --- libdragon | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libdragon b/libdragon index 9bae4999..d25c4a6b 160000 --- a/libdragon +++ b/libdragon @@ -1 +1 @@ -Subproject commit 9bae49994bf1c796f9939ea1aa7c133813b9053f +Subproject commit d25c4a6bb22abb93a29049e9d1b4438c93dcb9a3 From 08a42ddb329a66627f2a61a49658d21355d13a6c Mon Sep 17 00:00:00 2001 From: Robin Jones Date: Sun, 18 Aug 2024 20:18:30 +0100 Subject: [PATCH 02/47] Update miniz submodule (#136) ## Description Updates the miniz git submodule ## Motivation and Context keep it up-to-date ## How Has This Been Tested? Assuming it is used for PNG conversion. Tested changing backgrounds locally on an SC64, which still works. ## Screenshots ## Types of changes - [ ] Improvement (non-breaking change that adds a new feature) - [ ] Bug fix (fixes an issue) - [ ] Breaking change (breaking change) - [ ] Documentation Improvement - [ ] Config and build (change in the configuration and build system, has no impact on code or features) ## Checklist: - [ ] My code follows the code style of this project. - [ ] My change requires a change to the documentation. - [ ] I have updated the documentation accordingly. - [ ] I have added tests to cover my changes. - [ ] All new and existing tests passed. Signed-off-by: GITHUB_USER ## Summary by CodeRabbit - **Chores** - Updated the reference to a newer version of a subproject, potentially incorporating various enhancements and bug fixes. No changes were made to the existing functionality. --- src/libs/miniz | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/miniz b/src/libs/miniz index 16413c21..1ff82be7 160000 --- a/src/libs/miniz +++ b/src/libs/miniz @@ -1 +1 @@ -Subproject commit 16413c213de38e703d883006193734e8b1178d5d +Subproject commit 1ff82be7d67f5c2f8b5497f538eea247861e0717 From 4e4c109bd7b66881fcf602a7dc04155f2726edfc Mon Sep 17 00:00:00 2001 From: Robin Jones Date: Sun, 18 Aug 2024 22:13:22 +0100 Subject: [PATCH 03/47] Update libdragon --- libdragon | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libdragon b/libdragon index d25c4a6b..70ce3223 160000 --- a/libdragon +++ b/libdragon @@ -1 +1 @@ -Subproject commit d25c4a6bb22abb93a29049e9d1b4438c93dcb9a3 +Subproject commit 70ce32232a9a89a92be032d19b01ba9d8dd6cf2f From f2fa7d0dbad55f480c6dbb3701e92e26e1fef972 Mon Sep 17 00:00:00 2001 From: Robin Jones Date: Fri, 30 Aug 2024 20:44:20 +0100 Subject: [PATCH 04/47] Add flashcart features for CIC and Region (#138) ## Description ## Motivation and Context Some flashcarts may be old (which would include old 64drive's), and not use the Ultra CIC, or old one that does not handle auto switching of regions, we should have them as a feature switch. ## How Has This Been Tested? ## Screenshots ## Types of changes - [x] Improvement (non-breaking change that adds a new feature) - [ ] Bug fix (fixes an issue) - [ ] Breaking change (breaking change) - [ ] Documentation Improvement - [ ] Config and build (change in the configuration and build system, has no impact on code or features) ## Checklist: - [ ] My code follows the code style of this project. - [ ] My change requires a change to the documentation. - [ ] I have updated the documentation accordingly. - [ ] I have added tests to cover my changes. - [ ] All new and existing tests passed. Signed-off-by: GITHUB_USER --- src/flashcart/64drive/64drive.c | 2 ++ src/flashcart/flashcart.h | 2 ++ src/flashcart/sc64/sc64.c | 2 ++ 3 files changed, 6 insertions(+) diff --git a/src/flashcart/64drive/64drive.c b/src/flashcart/64drive/64drive.c index 0fd47bef..3997bf80 100644 --- a/src/flashcart/64drive/64drive.c +++ b/src/flashcart/64drive/64drive.c @@ -75,6 +75,8 @@ static bool d64_has_feature (flashcart_features_t feature) { case FLASHCART_FEATURE_64DD: return false; case FLASHCART_FEATURE_RTC: return true; case FLASHCART_FEATURE_USB: return true; + case FLASHCART_FEATURE_AUTO_CIC: return true; + case FLASHCART_FEATURE_AUTO_REGION: return true; default: return false; } } diff --git a/src/flashcart/flashcart.h b/src/flashcart/flashcart.h index b4996f36..ade09eaa 100644 --- a/src/flashcart/flashcart.h +++ b/src/flashcart/flashcart.h @@ -29,6 +29,8 @@ typedef enum { FLASHCART_FEATURE_64DD, FLASHCART_FEATURE_RTC, FLASHCART_FEATURE_USB, + FLASHCART_FEATURE_AUTO_CIC, + FLASHCART_FEATURE_AUTO_REGION, } flashcart_features_t; /** @brief Flashcart save type enumeration */ diff --git a/src/flashcart/sc64/sc64.c b/src/flashcart/sc64/sc64.c index 7119a271..bcab63f0 100644 --- a/src/flashcart/sc64/sc64.c +++ b/src/flashcart/sc64/sc64.c @@ -254,6 +254,8 @@ static bool sc64_has_feature (flashcart_features_t feature) { case FLASHCART_FEATURE_64DD: return true; case FLASHCART_FEATURE_RTC: return true; case FLASHCART_FEATURE_USB: return true; + case FLASHCART_FEATURE_AUTO_CIC: return true; + case FLASHCART_FEATURE_AUTO_REGION: return true; default: return false; } } From 83ed01a0432c9785e822093655a576fcb519047b Mon Sep 17 00:00:00 2001 From: Robin Jones Date: Fri, 30 Aug 2024 21:02:59 +0100 Subject: [PATCH 05/47] Update libdragon --- libdragon | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libdragon b/libdragon index 70ce3223..e1eb9283 160000 --- a/libdragon +++ b/libdragon @@ -1 +1 @@ -Subproject commit 70ce32232a9a89a92be032d19b01ba9d8dd6cf2f +Subproject commit e1eb9283e6feeb37a66797fa538ae7883d73227c From 3b2fddcc2a5a774cf02fd82982155989d2002ee7 Mon Sep 17 00:00:00 2001 From: Robin Jones Date: Mon, 2 Sep 2024 19:06:51 +0100 Subject: [PATCH 06/47] Fix Perfect Dark JP DB entry (#139) ## Description Perfect Dark (JP) release. ## Motivation and Context Database entry (requires Expansion Pak). ## How Has This Been Tested? ## Screenshots https://imgur.com/a/perfect-dark-without-expansion-vPOYVMB ## Types of changes - [x] Improvement (non-breaking change that adds a new feature) - [ ] Bug fix (fixes an issue) - [ ] Breaking change (breaking change) - [ ] Documentation Improvement - [ ] Config and build (change in the configuration and build system, has no impact on code or features) ## Checklist: - [ ] My code follows the code style of this project. - [ ] My change requires a change to the documentation. - [ ] I have updated the documentation accordingly. - [ ] I have added tests to cover my changes. - [ ] All new and existing tests passed. Signed-off-by: GITHUB_USER ## Summary by CodeRabbit - **New Features** - Added detailed match information for the game "Perfect Dark," enhancing recognition and handling by the system. - **Improvements** - Updated the entry for "Perfect Dark" to improve database organization and clarity. --- src/menu/rom_info.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/menu/rom_info.c b/src/menu/rom_info.c index 25f07832..e5b750ce 100644 --- a/src/menu/rom_info.c +++ b/src/menu/rom_info.c @@ -186,6 +186,9 @@ static const match_t database[] = { MATCH_ID_REGION("NDKJ", SAVE_TYPE_EEPROM_4KBIT, FEAT_NONE), // Dark Rift [Space Dynamites (J)] + MATCH_ID_REGION("NPDJ", SAVE_TYPE_EEPROM_16KBIT, FEAT_CPAK | FEAT_RPAK | FEAT_TPAK | FEAT_EXP_PAK_REQUIRED),// Perfect Dark (J) + MATCH_ID("NPD", SAVE_TYPE_EEPROM_16KBIT, FEAT_CPAK | FEAT_RPAK | FEAT_TPAK | FEAT_EXP_PAK_RECOMMENDED), // Perfect Dark + MATCH_ID_REGION("NSVE", SAVE_TYPE_EEPROM_4KBIT, FEAT_RPAK), // Space Station Silicon Valley MATCH_ID("NSV", SAVE_TYPE_EEPROM_4KBIT, FEAT_RPAK | FEAT_EXP_PAK_BROKEN), // Space Station Silicon Valley @@ -305,7 +308,6 @@ static const match_t database[] = { MATCH_ID("NMV", SAVE_TYPE_EEPROM_16KBIT, FEAT_RPAK), // Mario Party 3 MATCH_ID("NMX", SAVE_TYPE_EEPROM_16KBIT, FEAT_CPAK | FEAT_RPAK), // Excitebike 64 MATCH_ID("NNB", SAVE_TYPE_EEPROM_16KBIT, FEAT_CPAK | FEAT_RPAK), // Kobe Bryant in NBA Courtside - MATCH_ID("NPD", SAVE_TYPE_EEPROM_16KBIT, FEAT_CPAK | FEAT_RPAK | FEAT_TPAK | FEAT_EXP_PAK_RECOMMENDED), // Perfect Dark MATCH_ID("NPP", SAVE_TYPE_EEPROM_16KBIT, FEAT_CPAK), // Parlor! Pro 64: Pachinko Jikki Simulation Game MATCH_ID("NR7", SAVE_TYPE_EEPROM_16KBIT, FEAT_TPAK), // Robot Poncots 64: 7tsu no Umi no Caramel MATCH_ID("NRZ", SAVE_TYPE_EEPROM_16KBIT, FEAT_RPAK), // Ridge Racer 64 From 305a15d11427654075ff55ac2ed6fe28b68d9e03 Mon Sep 17 00:00:00 2001 From: Robin Jones Date: Mon, 2 Sep 2024 20:13:17 +0100 Subject: [PATCH 07/47] Update 00_getting_started_sd.md Fix missing backslash --- docs/00_getting_started_sd.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/00_getting_started_sd.md b/docs/00_getting_started_sd.md index 4ee6e763..af937dfe 100644 --- a/docs/00_getting_started_sd.md +++ b/docs/00_getting_started_sd.md @@ -36,7 +36,7 @@ SD:\ │ │ ├── NDDJ2.n64 │ │ └── NDXJ0.n64 │ │ -│ └── emulators +│ └── emulators\ │ ├── neon64bu.rom │ ├── sodium64.z64 │ ├── gb.v64 From 2116f6e26b4f1a29ea52d68c097f9c159c2e49fe Mon Sep 17 00:00:00 2001 From: Fazana <52551480+FazanaJ@users.noreply.github.com> Date: Mon, 16 Sep 2024 21:48:28 +0100 Subject: [PATCH 08/47] Add support for inputs from controller ports 2-4 (#141) Title sums it up ## Description Adds some extra logic in the controller polling to read from ports 2-4, letting those controllers input on the menu. ## Motivation and Context Port 1 no longer feels alone in the dark, cold world of menu selection. ## How Has This Been Tested? Same method I used for libdragon's error screen which had the same issue. Tested on a system with four controllers inserted. ## Screenshots ## Types of changes - [x] Improvement (non-breaking change that adds a new feature) - [ ] Bug fix (fixes an issue) - [ ] Breaking change (breaking change) - [ ] Documentation Improvement - [ ] Config and build (change in the configuration and build system, has no impact on code or features) ## Checklist: - [x] My code follows the code style of this project. - [ ] My change requires a change to the documentation. - [ ] I have updated the documentation accordingly. - [ ] I have added tests to cover my changes. - [ ] All new and existing tests passed. Signed-off-by: FazanaJ --------- Co-authored-by: Robin Jones --- docs/00_getting_started_sd.md | 2 +- src/menu/actions.c | 22 +++++++++++++++++++--- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/docs/00_getting_started_sd.md b/docs/00_getting_started_sd.md index 4ee6e763..af937dfe 100644 --- a/docs/00_getting_started_sd.md +++ b/docs/00_getting_started_sd.md @@ -36,7 +36,7 @@ SD:\ │ │ ├── NDDJ2.n64 │ │ └── NDXJ0.n64 │ │ -│ └── emulators +│ └── emulators\ │ ├── neon64bu.rom │ ├── sodium64.z64 │ ├── gb.v64 diff --git a/src/menu/actions.c b/src/menu/actions.c index 14c87fb6..9c44c23e 100644 --- a/src/menu/actions.c +++ b/src/menu/actions.c @@ -25,8 +25,17 @@ static void actions_clear (menu_t *menu) { } static void actions_update_direction (menu_t *menu) { - joypad_8way_t held_dir = joypad_get_direction(JOYPAD_PORT_1, JOYPAD_2D_DPAD | JOYPAD_2D_STICK); - joypad_8way_t fast_dir = joypad_get_direction(JOYPAD_PORT_1, JOYPAD_2D_C); + joypad_8way_t held_dir; + joypad_8way_t fast_dir; + + JOYPAD_PORT_FOREACH (i) { + held_dir = joypad_get_direction(i, JOYPAD_2D_DPAD | JOYPAD_2D_STICK); + fast_dir = joypad_get_direction(i, JOYPAD_2D_C); + if (held_dir != JOYPAD_8WAY_NONE || fast_dir != JOYPAD_8WAY_NONE) { + break; + } + } + if (fast_dir != JOYPAD_8WAY_NONE) { held_dir = fast_dir; @@ -82,7 +91,14 @@ static void actions_update_direction (menu_t *menu) { } static void actions_update_buttons (menu_t *menu) { - joypad_buttons_t pressed = joypad_get_buttons_pressed(JOYPAD_PORT_1); + joypad_buttons_t pressed; + + JOYPAD_PORT_FOREACH (i) { + pressed = joypad_get_buttons_pressed(i); + if (pressed.raw) { + break; + } + } if (pressed.a) { menu->actions.enter = true; From 10a8fcab9e2231b9fa2fb9e7bbd48bd4a96fe475 Mon Sep 17 00:00:00 2001 From: Mateusz Faderewski Date: Tue, 17 Sep 2024 00:11:51 +0200 Subject: [PATCH 09/47] libdragon update + reorganized menu init + bug fixes --- Makefile | 1 - libdragon | 2 +- src/menu/actions.c | 7 ++- src/menu/actions.h | 1 + src/menu/components/background.c | 13 ++-- src/menu/menu.c | 102 ++++++++++--------------------- 6 files changed, 45 insertions(+), 81 deletions(-) diff --git a/Makefile b/Makefile index ae6e6961..70255c60 100644 --- a/Makefile +++ b/Makefile @@ -98,7 +98,6 @@ $(SPNG_OBJS): N64_CFLAGS+=-isystem $(SOURCE_DIR)/libs/miniz -DSPNG_USE_MINIZ -fc $(FILESYSTEM_DIR)/FiraMonoBold.font64: MKFONT_FLAGS+=-c 1 --size 16 -r 20-7F -r 80-1FF -r 2026-2026 --ellipsis 2026,1 $(FILESYSTEM_DIR)/%.wav64: AUDIOCONV_FLAGS=--wav-compress 1 - $(@info $(shell mkdir -p ./$(FILESYSTEM_DIR) &> /dev/null)) $(FILESYSTEM_DIR)/%.font64: $(ASSETS_DIR)/%.ttf diff --git a/libdragon b/libdragon index e1eb9283..9dd99415 160000 --- a/libdragon +++ b/libdragon @@ -1 +1 @@ -Subproject commit e1eb9283e6feeb37a66797fa538ae7883d73227c +Subproject commit 9dd994151ae3f3709f1f80224e6b654aac8be6b4 diff --git a/src/menu/actions.c b/src/menu/actions.c index 9c44c23e..00317168 100644 --- a/src/menu/actions.c +++ b/src/menu/actions.c @@ -36,7 +36,6 @@ static void actions_update_direction (menu_t *menu) { } } - if (fast_dir != JOYPAD_8WAY_NONE) { held_dir = fast_dir; menu->actions.go_fast = true; @@ -114,6 +113,12 @@ static void actions_update_buttons (menu_t *menu) { } +void actions_init (void) { + JOYPAD_PORT_FOREACH (port) { + joypad_set_rumble_active(port, false); + } +} + void actions_update (menu_t *menu) { joypad_poll(); diff --git a/src/menu/actions.h b/src/menu/actions.h index f890b55c..e02e35af 100644 --- a/src/menu/actions.h +++ b/src/menu/actions.h @@ -11,6 +11,7 @@ #include "menu_state.h" +void actions_init (void); void actions_update (menu_t *menu); diff --git a/src/menu/components/background.c b/src/menu/components/background.c index 45119107..525fb0c8 100644 --- a/src/menu/components/background.c +++ b/src/menu/components/background.c @@ -98,9 +98,6 @@ static void prepare_background (component_background_t *c) { return; } - uint16_t image_center_x = (c->image->width / 2); - uint16_t image_center_y = (c->image->height / 2); - // Darken the image rdpq_attach(c->image, NULL); rdpq_mode_push(); @@ -108,15 +105,13 @@ static void prepare_background (component_background_t *c) { rdpq_set_prim_color(BACKGROUND_OVERLAY_COLOR); rdpq_mode_combiner(RDPQ_COMBINER_FLAT); rdpq_mode_blender(RDPQ_BLENDER_MULTIPLY); - rdpq_fill_rectangle( - 0 - (DISPLAY_CENTER_X - image_center_x), - 0 - (DISPLAY_CENTER_Y - image_center_y), - DISPLAY_WIDTH - (DISPLAY_CENTER_X - image_center_x), - DISPLAY_HEIGHT - (DISPLAY_CENTER_Y - image_center_y) - ); + rdpq_fill_rectangle(0, 0, c->image->width, c->image->height); rdpq_mode_pop(); rdpq_detach(); + uint16_t image_center_x = (c->image->width / 2); + uint16_t image_center_y = (c->image->height / 2); + // Prepare display list rspq_block_begin(); rdpq_mode_push(); diff --git a/src/menu/menu.c b/src/menu/menu.c index 479d9cfd..5e2b2168 100644 --- a/src/menu/menu.c +++ b/src/menu/menu.c @@ -27,53 +27,19 @@ #define MENU_CACHE_DIRECTORY "cache" #define BACKGROUND_CACHE_FILE "background.data" -#define FRAMERATE_DIVIDER (2) -#define LAG_REPORT (false) +#define INTERLACED (true) +#define FPS_LIMIT (30.0f) static menu_t *menu; -static tv_type_t tv_type; -static volatile int frame_counter = 0; - -extern tv_type_t __boot_tvtype; -static void frame_counter_handler (void) { - frame_counter += 1; -} - -static void frame_counter_reset (void) { -#if LAG_REPORT - static int accumulated = 0; - if (frame_counter > FRAMERATE_DIVIDER) { - accumulated += frame_counter - FRAMERATE_DIVIDER; - debugf( - "LAG: %d additional frame(s) displayed since last draw (accumulated: %d)\n", - frame_counter - FRAMERATE_DIVIDER, - accumulated - ); - } -#endif - frame_counter = 0; -} - -static void menu_init (boot_params_t *boot_params) { - joypad_init(); - timer_init(); - rtc_init(); - rspq_init(); - rdpq_init(); - dfs_init(DFS_DEFAULT_LOCATION); - - sound_init_default(); - - JOYPAD_PORT_FOREACH (port) { - joypad_set_rumble_active(port, false); - } - +static void menu_init (boot_params_t *boot_params) { menu = calloc(1, sizeof(menu_t)); assert(menu != NULL); + menu->boot_params = boot_params; + menu->mode = MENU_MODE_NONE; menu->next_mode = MENU_MODE_STARTUP; @@ -82,6 +48,19 @@ static void menu_init (boot_params_t *boot_params) { menu->next_mode = MENU_MODE_FAULT; } + joypad_init(); + timer_init(); + rtc_init(); + rspq_init(); + rdpq_init(); + dfs_init(DFS_DEFAULT_LOCATION); + + actions_init(); + sound_init_default(); + sound_init_sfx(); + + hdmi_clear_game_id(); + path_t *path = path_init(menu->storage_prefix, MENU_DIRECTORY); directory_create(path_get(path)); @@ -91,6 +70,15 @@ static void menu_init (boot_params_t *boot_params) { settings_load(&menu->settings); path_pop(path); + resolution_t resolution = { + .width = 640, + .height = 480, + .interlaced = INTERLACED ? INTERLACE_HALF : INTERLACE_OFF, + .pal60 = menu->settings.pal60_enabled, + }; + display_init(resolution, DEPTH_16_BPP, 2, GAMMA_NONE, INTERLACED ? FILTERS_DISABLED : FILTERS_RESAMPLE); + display_set_fps_limit(FPS_LIMIT); + path_push(path, MENU_CUSTOM_FONT_FILE); fonts_init(path_get(path)); path_pop(path); @@ -103,40 +91,20 @@ static void menu_init (boot_params_t *boot_params) { path_free(path); - menu->boot_params = boot_params; + sound_use_sfx(menu->settings.sound_enabled); menu->browser.directory = path_init(menu->storage_prefix, menu->settings.default_directory); if (!directory_exists(path_get(menu->browser.directory))) { path_free(menu->browser.directory); menu->browser.directory = path_init(menu->storage_prefix, "/"); } - - hdmi_clear_game_id(); - - tv_type = get_tv_type(); - if ((tv_type == TV_PAL) && menu->settings.pal60_enabled) { - // HACK: Set TV type to NTSC, so PAL console would output 60 Hz signal instead. - __boot_tvtype = TV_NTSC; - } - - sound_init_sfx(); - if (menu->settings.sound_enabled) { - sound_use_sfx(true); - } - - display_init(RESOLUTION_640x480, DEPTH_16_BPP, 2, GAMMA_NONE, FILTERS_DISABLED); - - register_VI_handler(frame_counter_handler); } static void menu_deinit (menu_t *menu) { - unregister_VI_handler(frame_counter_handler); - - // NOTE: Restore previous TV type so boot procedure wouldn't passthrough wrong value. - __boot_tvtype = tv_type; - hdmi_send_game_id(menu->boot_params); + component_background_free(); + path_free(menu->load.disk_path); path_free(menu->load.rom_path); for (int i = 0; i < menu->browser.entries; i++) { @@ -146,9 +114,7 @@ static void menu_deinit (menu_t *menu) { path_free(menu->browser.directory); free(menu); - component_background_free(); - - flashcart_deinit(); + display_close(); sound_deinit(); @@ -158,7 +124,7 @@ static void menu_deinit (menu_t *menu) { timer_close(); joypad_close(); - display_close(); + flashcart_deinit(); } typedef const struct { @@ -200,11 +166,9 @@ void menu_run (boot_params_t *boot_params) { menu_init(boot_params); while (true) { - surface_t *display = (frame_counter >= FRAMERATE_DIVIDER) ? display_try_get() : NULL; + surface_t *display = display_try_get(); if (display != NULL) { - frame_counter_reset(); - actions_update(menu); view_t *view = menu_get_view(menu->mode); From 269a8ae94d45e766a0bbe6cf97dddd77964754dd Mon Sep 17 00:00:00 2001 From: Robin Jones Date: Sat, 28 Sep 2024 20:47:53 +0100 Subject: [PATCH 10/47] Optimize boxart image load (#130) ## Description Improves boxart image loading by using directory file paths. It also adds matching by full game ID's (for compatibility), but notes in the readme that it is slow. ## Motivation and Context Loading boxart was slow in certain circumstances. ## How Has This Been Tested? Locally on an SC64. ## Screenshots ## Types of changes - [x] Improvement (non-breaking change that adds a new feature) - [ ] Bug fix (fixes an issue) - [ ] Breaking change (breaking change) - [ ] Documentation Improvement - [ ] Config and build (change in the configuration and build system, has no impact on code or features) ## Checklist: - [ ] My code follows the code style of this project. - [ ] My change requires a change to the documentation. - [ ] I have updated the documentation accordingly. - [ ] I have added tests to cover my changes. - [ ] All new and existing tests passed. Signed-off-by: GITHUB_USER ## Summary by CodeRabbit - **New Features** - Introduced a new image type enumeration for boxart components, enhancing image management. - Updated boxart initialization to allow for specific image views, improving flexibility in image retrieval. - Enhanced instructions for setting up boxart images with clearer directory structures and simplified naming conventions. - **Bug Fixes** - Improved the logic for loading boxart images, enabling better fallback options in case of missing files. --- README.md | 48 +++++++++++++----- src/menu/components.h | 37 +++++++++++++- src/menu/components/boxart.c | 94 ++++++++++++++++++++++++++++++------ src/menu/views/load_disk.c | 2 +- src/menu/views/load_rom.c | 2 +- 5 files changed, 151 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index 703804cc..26af0067 100644 --- a/README.md +++ b/README.md @@ -49,22 +49,44 @@ An open source menu for N64 flashcarts. ## Experimental features These features are subject to change: -### ROM Boxart -To use boxart, place PNG files in the `/menu/boxart` folder on the SD card with the following dimensions: -* Standard covers: 158x112 -* 64DD covers: 129x112 -* Japanese covers: 112x158 - -Each file must be named according to the 2 letter ROM ID, or 3 letter ROM ID including media type. -i.e. for GoldenEye 2 letters, this would be `GE.png`. -i.e. for GoldenEye 3 letters, this would be `NGE.png`. -You can download these boxart packs: -[American Boxart](https://mega.nz/file/6cNGwSqI#8X5ukb65n3YMlGaUtSOGXkKo9HxVnnMOgqn94Epcr7w) +### GamePak sprites +To use N64 `GamePak` sprites, place `PNG` files within the `sd:/menu/boxart/` folder. -[European Boxart](https://mega.nz/file/O7AjDbRJ#VnVU10dq8HQvBUQptppI6PAcQMb8-Zembqav8WtAQ_M) -[64DD Boxart](https://mega.nz/file/O3JzwD7B#BYl1aV-pbrJ-MxWUbM_K0yGVIRbmSoxJJZqQInRzZyM) +#### Supported sprites +These must be `PNG` files that use the following dimensions: +* Standard N64 GamePak boxart sprites: 158x112 +* Japanese N64 GamePak boxart sprites: 112x158 +* 64DD boxart sprites: 129x112 + +They will be loaded by directories using each character of the full 4 character Game Code (as identified in the menus ROM information). +i.e. for GoldenEye NTSC USA (NGEE), this would be `sd:/menu/boxart/N/G/E/E/boxart_front.png`. +i.e. for GoldenEye PAL (NGEP), this would be `sd:/menu/boxart/N/G/E/P/boxart_front.png`. + +To improve compatibility between regions (as a fallback), you may exclude the region ID (last matched directory) for GamePaks to match with 3 letter IDs instead: +i.e. for GoldenEye, this would be `sd:/menu/boxart/N/G/E/boxart_front.png`. + +**Note1:** Excluding the region ID may show the wrong boxart. +**Note2:** For future support, boxart sprites should also include: `boxart_back.png`, `boxart_top.png`, `boxart_bottom.png`, `boxart_left.png`, `boxart_right.png`. + + +#### Compatibilty mode +If you cannot yet satisfy the correct boxart layout, The menu still has **deprecated** support for filenames containing the Game ID. + +**Note:** This will add a noticeable delay for displaying parts of the menu. + +Each file must be named according to the 2,3 or 4 letter GamePak ID (matched in this order). +i.e. +* for GoldenEye 4 letters, this would be `sd:/menu/boxart/NGEE.png` and/or `sd:/menu/boxart/NGEP.png`. +* for GoldenEye 3 letters, this would be `sd:/menu/boxart/NGE.png`. +* for GoldenEye 2 letters, this would be `sd:/menu/boxart/GE.png`. + + +As a starting point, here are some links to boxart packs: +* [American GamePak Boxart](https://mega.nz/file/6cNGwSqI#8X5ukb65n3YMlGaUtSOGXkKo9HxVnnMOgqn94Epcr7w) +* [European GamePak Boxart](https://mega.nz/file/O7AjDbRJ#VnVU10dq8HQvBUQptppI6PAcQMb8-Zembqav8WtAQ_M) +* [64DD Boxart](https://mega.nz/file/O3JzwD7B#BYl1aV-pbrJ-MxWUbM_K0yGVIRbmSoxJJZqQInRzZyM) ### Menu Settings diff --git a/src/menu/components.h b/src/menu/components.h index 4925ee5b..67fde2d3 100644 --- a/src/menu/components.h +++ b/src/menu/components.h @@ -11,6 +11,41 @@ #include #include "menu_state.h" +/** @brief File image Enumeration. */ +typedef enum { + + /** @brief Boxart image from the front */ + IMAGE_BOXART_FRONT, + + /** @brief Boxart image from the back */ + IMAGE_BOXART_BACK, + + /** @brief Boxart image from the top */ + IMAGE_BOXART_TOP, + + /** @brief Boxart image from the bottom */ + IMAGE_BOXART_BOTTOM, + + /** @brief Boxart image from the left side */ + IMAGE_BOXART_LEFT, + + /** @brief Boxart image from the right side */ + IMAGE_BOXART_RIGHT, + + /** @brief GamePak image from the front */ + IMAGE_GAMEPAK_FRONT, + + /** @brief GamePak image from the back */ + IMAGE_GAMEPAK_BACK, + + /** @brief File image thumbnail */ + IMAGE_THUMBNAIL, + + /** @brief List end marker */ + IMAGE_TYPE_END + +} file_image_type_t; + /** * @addtogroup @@ -64,7 +99,7 @@ typedef struct { surface_t *image; } component_boxart_t; -component_boxart_t *component_boxart_init (const char *storage_prefix, char *game_code); +component_boxart_t *component_boxart_init (const char *storage_prefix, char *game_code, file_image_type_t current_image_view); void component_boxart_free (component_boxart_t *b); void component_boxart_draw (component_boxart_t *b); diff --git a/src/menu/components/boxart.c b/src/menu/components/boxart.c index f50294ee..2535068c 100644 --- a/src/menu/components/boxart.c +++ b/src/menu/components/boxart.c @@ -17,9 +17,9 @@ static void png_decoder_callback (png_err_t err, surface_t *decoded_image, void } -component_boxart_t *component_boxart_init (const char *storage_prefix, char *game_code) { +component_boxart_t *component_boxart_init (const char *storage_prefix, char *game_code, file_image_type_t current_image_view) { component_boxart_t *b; - char file_name[8]; + char boxart_id_path[8]; if ((b = calloc(1, sizeof(component_boxart_t))) == NULL) { return NULL; @@ -29,22 +29,84 @@ component_boxart_t *component_boxart_init (const char *storage_prefix, char *gam path_t *path = path_init(storage_prefix, BOXART_DIRECTORY); - sprintf(file_name, "%.3s.png", game_code); - path_push(path, file_name); - if (png_decoder_start(path_get(path), BOXART_WIDTH_MAX, BOXART_HEIGHT_MAX, png_decoder_callback, b) == PNG_OK) { - path_free(path); - return b; - } - path_pop(path); + sprintf(boxart_id_path, "%c/%c/%c/%c", game_code[0], game_code[1], game_code[2], game_code[3]); + path_push(path, boxart_id_path); - // TODO: This is bad, we should only check for 3 letter codes - sprintf(file_name, "%.2s.png", game_code + 1); - path_push(path, file_name); - if (png_decoder_start(path_get(path), BOXART_WIDTH_MAX, BOXART_HEIGHT_MAX, png_decoder_callback, b) == PNG_OK) { - path_free(path); - return b; + if (!directory_exists(path_get(path))) { // Allow boxart to not specify the region code. + path_pop(path); } + if (directory_exists(path_get(path))) { + switch (current_image_view) { + case IMAGE_GAMEPAK_FRONT: + path_push(path, "gamepak_front.png"); + case IMAGE_GAMEPAK_BACK: + path_push(path, "gamepak_back.png"); + case IMAGE_BOXART_BACK: + path_push(path, "boxart_back.png"); + case IMAGE_BOXART_LEFT: + path_push(path, "boxart_left.png"); + case IMAGE_BOXART_RIGHT: + path_push(path, "boxart_right.png"); + case IMAGE_BOXART_BOTTOM: + path_push(path, "boxart_bottom.png"); + case IMAGE_BOXART_TOP: + path_push(path, "boxart_top.png"); + default: + path_push(path, "boxart_front.png"); + } + + if (file_exists(path_get(path))) { + if (png_decoder_start(path_get(path), BOXART_WIDTH_MAX, BOXART_HEIGHT_MAX, png_decoder_callback, b) == PNG_OK) { + path_free(path); + return b; + } + } + } + else { // compatibility mode + + char file_name[8]; + + // reset the directory path used for boxart. + path = path_init(storage_prefix, BOXART_DIRECTORY); + + sprintf(file_name, "%c%c%c%c.png", game_code[0], game_code[1], game_code[2], game_code[3]); + path_push(path, file_name); + + if (file_exists(path_get(path))) { + if (png_decoder_start(path_get(path), BOXART_WIDTH_MAX, BOXART_HEIGHT_MAX, png_decoder_callback, b) == PNG_OK) { + path_free(path); + return b; + } + } + + path_pop(path); + sprintf(file_name, "%c%c%c.png", game_code[0], game_code[1], game_code[2]); + path_push(path, file_name); + + if (file_exists(path_get(path))) { + if (file_exists(path_get(path))) { + if (png_decoder_start(path_get(path), BOXART_WIDTH_MAX, BOXART_HEIGHT_MAX, png_decoder_callback, b) == PNG_OK) { + path_free(path); + return b; + } + } + } + else { + path_pop(path); + + sprintf(file_name, "%c%c.png", game_code[1], game_code[2]); + path_push(path, file_name); + if (file_exists(path_get(path))) { + if (png_decoder_start(path_get(path), BOXART_WIDTH_MAX, BOXART_HEIGHT_MAX, png_decoder_callback, b) == PNG_OK) { + path_free(path); + return b; + } + } + } + } + // TODO: return default image. + path_free(path); free(b); @@ -89,4 +151,4 @@ void component_boxart_draw (component_boxart_t *b) { BOXART_LOADING_COLOR ); } -} \ No newline at end of file +} diff --git a/src/menu/views/load_disk.c b/src/menu/views/load_disk.c index 0165bdc9..39957fcf 100644 --- a/src/menu/views/load_disk.c +++ b/src/menu/views/load_disk.c @@ -170,7 +170,7 @@ void view_load_disk_init (menu_t *menu) { menu_show_error(menu, convert_error_message(err)); } - boxart = component_boxart_init(menu->storage_prefix, menu->load.disk_info.id); + boxart = component_boxart_init(menu->storage_prefix, menu->load.disk_info.id, IMAGE_BOXART_FRONT); } void view_load_disk_display (menu_t *menu, surface_t *display) { diff --git a/src/menu/views/load_rom.c b/src/menu/views/load_rom.c index c408b47c..36933b92 100644 --- a/src/menu/views/load_rom.c +++ b/src/menu/views/load_rom.c @@ -355,7 +355,7 @@ void view_load_rom_init (menu_t *menu) { return; } - boxart = component_boxart_init(menu->storage_prefix, menu->load.rom_info.game_code); + boxart = component_boxart_init(menu->storage_prefix, menu->load.rom_info.game_code, IMAGE_BOXART_FRONT); component_context_menu_init(&options_context_menu); } From 55e7663baea4b43293b258a93c07c74950129baf Mon Sep 17 00:00:00 2001 From: Suprapote <111246491+Suprapote@users.noreply.github.com> Date: Sat, 28 Sep 2024 21:57:45 +0200 Subject: [PATCH 11/47] New boxart links (#135) ## Description Improve the gamepak boxart links with better sprite matching. ## Motivation and Context Games were not always matched correctly. Works towards a boxart pack for every region of every game. ## How Has This Been Tested? ## Screenshots ## Types of changes - [ ] Improvement (non-breaking change that adds a new feature) - [ ] Bug fix (fixes an issue) - [ ] Breaking change (breaking change) - [x] Documentation Improvement - [ ] Config and build (change in the configuration and build system, has no impact on code or features) ## Checklist: - [ ] My code follows the code style of this project. - [ ] My change requires a change to the documentation. - [ ] I have updated the documentation accordingly. - [ ] I have added tests to cover my changes. - [ ] All new and existing tests passed. Signed-off-by: GITHUB_USER --------- Co-authored-by: Robin Jones --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 26af0067..de3d030c 100644 --- a/README.md +++ b/README.md @@ -84,9 +84,10 @@ i.e. As a starting point, here are some links to boxart packs: -* [American GamePak Boxart](https://mega.nz/file/6cNGwSqI#8X5ukb65n3YMlGaUtSOGXkKo9HxVnnMOgqn94Epcr7w) -* [European GamePak Boxart](https://mega.nz/file/O7AjDbRJ#VnVU10dq8HQvBUQptppI6PAcQMb8-Zembqav8WtAQ_M) -* [64DD Boxart](https://mega.nz/file/O3JzwD7B#BYl1aV-pbrJ-MxWUbM_K0yGVIRbmSoxJJZqQInRzZyM) +* [Japan Boxart](https://mega.nz/file/KyJR0B6B#ERabLautAVPaqJTIdBSv4ghbudNhK7hnEr2ZS1Q6ub0) +* [American Boxart](https://mega.nz/file/rugAFYSQ#JHfgCU2amzNVpC4S6enP3vg--wtAAwsziKa7cej6QCc) +* [European Boxart](https://mega.nz/file/OmIV3aAK#kOWdutK1_41ffN64R6thbU7HEPR_M9qO0YM2mNG6RbQ) +* [64DD Boxart](https://mega.nz/file/ay5wQIxJ#k3PF-VMLrZJxJTr-BOaOKa2TBIK7c2t4zwbdshsQl40) ### Menu Settings From c49b9ed33027e66ef656182f098e925622795e18 Mon Sep 17 00:00:00 2001 From: Robin Jones Date: Mon, 30 Sep 2024 22:16:40 +0100 Subject: [PATCH 12/47] Update docs for newer firmware (#143) ## Description Update the "supported" SC64 firmware version. ## Motivation and Context Although the latest firmware is not "required", it is best to keep it aligned. ## How Has This Been Tested? ## Screenshots ## Types of changes - [ ] Improvement (non-breaking change that adds a new feature) - [ ] Bug fix (fixes an issue) - [ ] Breaking change (breaking change) - [ ] Documentation Improvement - [ ] Config and build (change in the configuration and build system, has no impact on code or features) ## Checklist: - [ ] My code follows the code style of this project. - [ ] My change requires a change to the documentation. - [ ] I have updated the documentation accordingly. - [ ] I have added tests to cover my changes. - [ ] All new and existing tests passed. Signed-off-by: GITHUB_USER ## Summary by CodeRabbit - **New Features** - Updated the supported firmware version for "SummerCart64" to 2.20.0+ in error messages. - **Documentation** - Revised developer documentation to reflect the upgrade of the SC64 deployer to v2.20.0, including updated links and compatibility requirements. - Clarified instructions for using the dev container and added a workaround for USB device communication. - Expanded guidance on generating and serving documentation locally. --- .devcontainer/Dockerfile | 2 +- docs/99_developer_guide.md | 6 +++--- src/menu/views/fault.c | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 116f0cb9..e5a3ad30 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,6 +1,6 @@ FROM debian:bookworm-slim -ARG SC64_DEPLOYER_VERSION=v2.18.0 +ARG SC64_DEPLOYER_VERSION=v2.20.0 RUN apt-get update && \ apt-get upgrade -y && \ apt-get install build-essential doxygen git python3 wget -y && \ diff --git a/docs/99_developer_guide.md b/docs/99_developer_guide.md index ff6ad67c..ab148140 100644 --- a/docs/99_developer_guide.md +++ b/docs/99_developer_guide.md @@ -8,11 +8,11 @@ You can use a dev container in VSCode to ease development. ### To deploy: #### SC64 -* Download the deployer [here](https://github.com/Polprzewodnikowy/SummerCart64/releases/download/v2.18.0/sc64-deployer-windows-v2.18.0.zip) +* Download the deployer [here](https://github.com/Polprzewodnikowy/SummerCart64/releases/download/v2.20.0/sc64-deployer-windows-v2.20.0.zip) * Extract and place `sc64deployer.exe` in the `tools/sc64` directory. -Make sure that your firmware is compatible (currently v2.18.0+) -See: [here](https://github.com/Polprzewodnikowy/SummerCart64/blob/v2.18.0/docs/00_quick_startup_guide.md#firmware-backupupdate) +Make sure that your firmware is compatible (currently v2.20.0+) +See: [here](https://github.com/Polprzewodnikowy/SummerCart64/blob/v2.20.0/docs/00_quick_startup_guide.md#firmware-backupupdate) ##### From the devcontainer It is not currently possible to directly communicate with USB devices. diff --git a/src/menu/views/fault.c b/src/menu/views/fault.c index 7128f666..6ec767a4 100644 --- a/src/menu/views/fault.c +++ b/src/menu/views/fault.c @@ -7,7 +7,7 @@ static void draw (menu_t *menu, surface_t *d) { rdpq_clear(RGBA32(0x7F, 0x00, 0x00, 0xFF)); const char *firmware_message = ( - "Supported firmware versions:\n" + "Minimum supported firmware versions:\n" "64drive: 2.05+\n" "EverDrive-64: ???+\n" "SummerCart64: 2.17.0+" From b8fa9e287d515c1159f8385d0fdf29fda3b4a572 Mon Sep 17 00:00:00 2001 From: Robin Jones Date: Mon, 30 Sep 2024 22:16:40 +0100 Subject: [PATCH 13/47] Update docs for newer firmware (#143) ## Description Update the "supported" SC64 firmware version. ## Motivation and Context Although the latest firmware is not "required", it is best to keep it aligned. ## How Has This Been Tested? ## Screenshots ## Types of changes - [ ] Improvement (non-breaking change that adds a new feature) - [ ] Bug fix (fixes an issue) - [ ] Breaking change (breaking change) - [ ] Documentation Improvement - [ ] Config and build (change in the configuration and build system, has no impact on code or features) ## Checklist: - [ ] My code follows the code style of this project. - [ ] My change requires a change to the documentation. - [ ] I have updated the documentation accordingly. - [ ] I have added tests to cover my changes. - [ ] All new and existing tests passed. Signed-off-by: GITHUB_USER ## Summary by CodeRabbit - **New Features** - Updated the supported firmware version for "SummerCart64" to 2.20.0+ in error messages. - **Documentation** - Revised developer documentation to reflect the upgrade of the SC64 deployer to v2.20.0, including updated links and compatibility requirements. - Clarified instructions for using the dev container and added a workaround for USB device communication. - Expanded guidance on generating and serving documentation locally. --- .devcontainer/Dockerfile | 2 +- docs/99_developer_guide.md | 6 +++--- src/menu/views/fault.c | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 116f0cb9..e5a3ad30 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,6 +1,6 @@ FROM debian:bookworm-slim -ARG SC64_DEPLOYER_VERSION=v2.18.0 +ARG SC64_DEPLOYER_VERSION=v2.20.0 RUN apt-get update && \ apt-get upgrade -y && \ apt-get install build-essential doxygen git python3 wget -y && \ diff --git a/docs/99_developer_guide.md b/docs/99_developer_guide.md index ff6ad67c..ab148140 100644 --- a/docs/99_developer_guide.md +++ b/docs/99_developer_guide.md @@ -8,11 +8,11 @@ You can use a dev container in VSCode to ease development. ### To deploy: #### SC64 -* Download the deployer [here](https://github.com/Polprzewodnikowy/SummerCart64/releases/download/v2.18.0/sc64-deployer-windows-v2.18.0.zip) +* Download the deployer [here](https://github.com/Polprzewodnikowy/SummerCart64/releases/download/v2.20.0/sc64-deployer-windows-v2.20.0.zip) * Extract and place `sc64deployer.exe` in the `tools/sc64` directory. -Make sure that your firmware is compatible (currently v2.18.0+) -See: [here](https://github.com/Polprzewodnikowy/SummerCart64/blob/v2.18.0/docs/00_quick_startup_guide.md#firmware-backupupdate) +Make sure that your firmware is compatible (currently v2.20.0+) +See: [here](https://github.com/Polprzewodnikowy/SummerCart64/blob/v2.20.0/docs/00_quick_startup_guide.md#firmware-backupupdate) ##### From the devcontainer It is not currently possible to directly communicate with USB devices. diff --git a/src/menu/views/fault.c b/src/menu/views/fault.c index 7128f666..6ec767a4 100644 --- a/src/menu/views/fault.c +++ b/src/menu/views/fault.c @@ -7,7 +7,7 @@ static void draw (menu_t *menu, surface_t *d) { rdpq_clear(RGBA32(0x7F, 0x00, 0x00, 0xFF)); const char *firmware_message = ( - "Supported firmware versions:\n" + "Minimum supported firmware versions:\n" "64drive: 2.05+\n" "EverDrive-64: ???+\n" "SummerCart64: 2.17.0+" From 4d311ffcd89946e1ff41a34b9ff54dcf18d6b955 Mon Sep 17 00:00:00 2001 From: Robin Jones Date: Wed, 2 Oct 2024 21:11:58 +0100 Subject: [PATCH 14/47] Update 00_getting_started_sd.md --- docs/00_getting_started_sd.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/docs/00_getting_started_sd.md b/docs/00_getting_started_sd.md index af937dfe..f2f75de8 100644 --- a/docs/00_getting_started_sd.md +++ b/docs/00_getting_started_sd.md @@ -1,11 +1,19 @@ ## First time setup of SD card -Using your PC, insert the SD card and ensure it is formatted for compatibility with your flashcart (*FAT32 and EXFAT are fully supported on the SC64*). +Using your PC, insert the SD card and ensure it is formatted for compatibility with your flashcart +#### SC64 +- FAT32 and EXFAT are fully supported. +- An SD formatted with 128 kiB cluster size is recommended. - Download the latest `sc64menu.n64` (assuming you are using an *sc64*) file from the [releases](https://github.com/Polprzewodnikowy/N64FlashcartMenu/releases/) page, then put it in the root directory of your SD card. - Create a folder in the root of your SD card called `menu`. - Place your ROMs on the SD Card, in any folder (**except for `menu`**). +#### Other supported flashcarts +- FAT32 recommended. +- An SD formatted with default cluster size is recommended. + + ### Emulator support Emulators should be added to the `/menu/emulators` directory on the SD card. From 49ea127dd76f7a84696be212e9a187a3827c244f Mon Sep 17 00:00:00 2001 From: Robin Jones Date: Sun, 20 Oct 2024 15:52:02 +0100 Subject: [PATCH 15/47] Integer type fixes (#145) ## Description Improve integer type under certain conditions. ## Motivation and Context When running the flags `-Wall -Wextra`. ## How Has This Been Tested? ## Screenshots ## Types of changes - [x] Improvement (non-breaking change that adds a new feature) - [ ] Bug fix (fixes an issue) - [ ] Breaking change (breaking change) - [ ] Documentation Improvement - [ ] Config and build (change in the configuration and build system, has no impact on code or features) ## Checklist: - [ ] My code follows the code style of this project. - [ ] My change requires a change to the documentation. - [ ] I have updated the documentation accordingly. - [ ] I have added tests to cover my changes. - [ ] All new and existing tests passed. Signed-off-by: GITHUB_USER ## Summary by CodeRabbit - **Bug Fixes** - Improved handling of loop variables to prevent negative overflow in various functions, enhancing stability and reliability when processing larger values. - **Refactor** - Updated loop variable types to `unsigned int` for better performance and accuracy in ROM data handling across multiple components. --- src/boot/boot.c | 2 +- src/flashcart/64drive/64drive.c | 2 +- src/flashcart/sc64/sc64.c | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/boot/boot.c b/src/boot/boot.c index 9aaac778..2fc0a889 100644 --- a/src/boot/boot.c +++ b/src/boot/boot.c @@ -95,7 +95,7 @@ void boot (boot_params_t *params) { io32_t *reboot_dst = SP_MEM->IMEM; size_t reboot_instructions = (size_t) (&reboot_size) / sizeof(uint32_t); - for (int i = 0; i < reboot_instructions; i++) { + for (unsigned int i = 0; i < reboot_instructions; i++) { cpu_io_write(&reboot_dst[i], reboot_src[i]); } diff --git a/src/flashcart/64drive/64drive.c b/src/flashcart/64drive/64drive.c index 0fd47bef..61af404d 100644 --- a/src/flashcart/64drive/64drive.c +++ b/src/flashcart/64drive/64drive.c @@ -99,7 +99,7 @@ static flashcart_err_t d64_load_rom (char *rom_path, flashcart_progress_callback size_t sdram_size = MiB(64); size_t chunk_size = KiB(128); - for (int offset = 0; offset < sdram_size; offset += chunk_size) { + for (unsigned 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) { f_close(&fil); diff --git a/src/flashcart/sc64/sc64.c b/src/flashcart/sc64/sc64.c index 7119a271..57bb7e73 100644 --- a/src/flashcart/sc64/sc64.c +++ b/src/flashcart/sc64/sc64.c @@ -232,7 +232,7 @@ static flashcart_err_t sc64_init (void) { { CFG_ID_ROM_EXTENDED_ENABLE, false }, }; - for (int i = 0; i < sizeof(default_config) / sizeof(default_config[0]); i++) { + for (unsigned int i = 0; i < sizeof(default_config) / sizeof(default_config[0]); i++) { if (sc64_ll_set_config(default_config[i].id, default_config[i].value) != SC64_OK) { return FLASHCART_ERR_INT; } @@ -283,7 +283,7 @@ static flashcart_err_t sc64_load_rom (char *rom_path, flashcart_progress_callbac size_t extended_size = extended_enabled ? rom_size - MiB(64) : 0; size_t chunk_size = KiB(128); - for (int offset = 0; offset < sdram_size; offset += chunk_size) { + for (unsigned 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) { f_close(&fil); @@ -445,7 +445,7 @@ static flashcart_err_t sc64_load_64dd_ipl (char *ipl_path, flashcart_progress_ca } size_t chunk_size = KiB(128); - for (int offset = 0; offset < ipl_size; offset += chunk_size) { + for (unsigned 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) { f_close(&fil); @@ -499,7 +499,7 @@ static flashcart_err_t sc64_load_64dd_disk (char *disk_path, flashcart_disk_para { CFG_ID_BUTTON_MODE, BUTTON_MODE_DD_DISK_SWAP }, }; - for (int i = 0; i < sizeof(config) / sizeof(config[0]); i++) { + for (unsigned int i = 0; i < sizeof(config) / sizeof(config[0]); i++) { if (sc64_ll_set_config(config[i].id, config[i].value) != SC64_OK) { return FLASHCART_ERR_INT; } From f01fb77db347694e3e7ecdb7f31ed99d1178ff9d Mon Sep 17 00:00:00 2001 From: Robin Jones Date: Wed, 23 Oct 2024 12:58:21 +0100 Subject: [PATCH 16/47] Minor comment improvements --- docs/99_developer_guide.md | 2 ++ src/menu/actions.h | 4 +++- src/menu/sound.h | 17 +++++++++++++++++ 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/docs/99_developer_guide.md b/docs/99_developer_guide.md index ab148140..1734b8d9 100644 --- a/docs/99_developer_guide.md +++ b/docs/99_developer_guide.md @@ -57,6 +57,8 @@ Generated documentation is located in the `output/docs` folder and auto-publishe Once merged, they can be viewed [here](https://polprzewodnikowy.github.io/N64FlashcartMenu/) ### Test generated docs in the dev-container +Testing the documentation locally allows you to preview changes and ensure everything renders correctly before submitting your changes. + Install Prerequisites: ```bash apt-get install ruby-full build-essential zlib1g-dev diff --git a/src/menu/actions.h b/src/menu/actions.h index e02e35af..f10a83ce 100644 --- a/src/menu/actions.h +++ b/src/menu/actions.h @@ -10,7 +10,9 @@ #include "menu_state.h" - +/** + * @brief Initialize the actions module + */ void actions_init (void); void actions_update (menu_t *menu); diff --git a/src/menu/sound.h b/src/menu/sound.h index 8752a9b9..e086a362 100644 --- a/src/menu/sound.h +++ b/src/menu/sound.h @@ -12,6 +12,9 @@ #define SOUND_MP3_PLAYER_CHANNEL (0) #define SOUND_SFX_CHANNEL (2) +/** + * @brief Enumeration of available sound effects for menu interactions. + */ typedef enum { SFX_CURSOR, SFX_ERROR, @@ -23,8 +26,22 @@ typedef enum { void sound_init_default (void); void sound_init_mp3_playback (void); + +/** + * @brief Initialize sound effects system. + */ void sound_init_sfx (void); + +/** + * @brief Enable or disable sound effects. + * @param enable True to enable sound effects, false to disable. + */ void sound_use_sfx(bool); + +/** + * @brief Play a specified sound effect. + * @param sfx The sound effect to play, as defined in sound_effect_t. + */ void sound_play_effect(sound_effect_t sfx); void sound_deinit (void); void sound_poll (void); From 9020445c17ac2b25c8ac691f734f495b717d8ca4 Mon Sep 17 00:00:00 2001 From: Robin Jones Date: Wed, 23 Oct 2024 13:46:29 +0100 Subject: [PATCH 17/47] Improve boxart Minor fixes for: * menu error SFX * RTC text --- src/menu/components/boxart.c | 25 ++++++++++++++++--------- src/menu/views/error.c | 2 +- src/menu/views/load_disk.c | 4 +++- src/menu/views/load_rom.c | 5 ++++- src/menu/views/rtc.c | 2 +- 5 files changed, 25 insertions(+), 13 deletions(-) diff --git a/src/menu/components/boxart.c b/src/menu/components/boxart.c index 2535068c..d663230a 100644 --- a/src/menu/components/boxart.c +++ b/src/menu/components/boxart.c @@ -40,20 +40,28 @@ component_boxart_t *component_boxart_init (const char *storage_prefix, char *gam switch (current_image_view) { case IMAGE_GAMEPAK_FRONT: path_push(path, "gamepak_front.png"); + break; case IMAGE_GAMEPAK_BACK: path_push(path, "gamepak_back.png"); + break; case IMAGE_BOXART_BACK: path_push(path, "boxart_back.png"); + break; case IMAGE_BOXART_LEFT: path_push(path, "boxart_left.png"); + break; case IMAGE_BOXART_RIGHT: path_push(path, "boxart_right.png"); + break; case IMAGE_BOXART_BOTTOM: path_push(path, "boxart_bottom.png"); + break; case IMAGE_BOXART_TOP: path_push(path, "boxart_top.png"); + break; default: path_push(path, "boxart_front.png"); + break; } if (file_exists(path_get(path))) { @@ -65,12 +73,13 @@ component_boxart_t *component_boxart_init (const char *storage_prefix, char *gam } else { // compatibility mode - char file_name[8]; + char file_name[9]; // reset the directory path used for boxart. + path_free(path); path = path_init(storage_prefix, BOXART_DIRECTORY); - sprintf(file_name, "%c%c%c%c.png", game_code[0], game_code[1], game_code[2], game_code[3]); + snprintf(file_name, sizeof(file_name), "%c%c%c%c.png", game_code[0], game_code[1], game_code[2], game_code[3]); path_push(path, file_name); if (file_exists(path_get(path))) { @@ -81,21 +90,19 @@ component_boxart_t *component_boxart_init (const char *storage_prefix, char *gam } path_pop(path); - sprintf(file_name, "%c%c%c.png", game_code[0], game_code[1], game_code[2]); + snprintf(file_name, sizeof(file_name), "%c%c%c.png", game_code[0], game_code[1], game_code[2]); path_push(path, file_name); if (file_exists(path_get(path))) { - if (file_exists(path_get(path))) { - if (png_decoder_start(path_get(path), BOXART_WIDTH_MAX, BOXART_HEIGHT_MAX, png_decoder_callback, b) == PNG_OK) { - path_free(path); - return b; - } + if (png_decoder_start(path_get(path), BOXART_WIDTH_MAX, BOXART_HEIGHT_MAX, png_decoder_callback, b) == PNG_OK) { + path_free(path); + return b; } } else { path_pop(path); - sprintf(file_name, "%c%c.png", game_code[1], game_code[2]); + snprintf(file_name, sizeof(file_name), "%c%c.png", game_code[1], game_code[2]); path_push(path, file_name); if (file_exists(path_get(path))) { if (png_decoder_start(path_get(path), BOXART_WIDTH_MAX, BOXART_HEIGHT_MAX, png_decoder_callback, b) == PNG_OK) { diff --git a/src/menu/views/error.c b/src/menu/views/error.c index 07eb70d4..7cb4f7d2 100644 --- a/src/menu/views/error.c +++ b/src/menu/views/error.c @@ -4,8 +4,8 @@ static void process (menu_t *menu) { if (menu->actions.back) { - menu->next_mode = MENU_MODE_BROWSER; sound_play_effect(SFX_EXIT); + menu->next_mode = MENU_MODE_BROWSER; } } diff --git a/src/menu/views/load_disk.c b/src/menu/views/load_disk.c index 39957fcf..f4140781 100644 --- a/src/menu/views/load_disk.c +++ b/src/menu/views/load_disk.c @@ -94,7 +94,9 @@ static void draw (menu_t *menu, surface_t *d) { ); } - component_boxart_draw(boxart); + if (boxart != NULL) { + component_boxart_draw(boxart); + } } rdpq_detach_show(); diff --git a/src/menu/views/load_rom.c b/src/menu/views/load_rom.c index 36933b92..4fb9d710 100644 --- a/src/menu/views/load_rom.c +++ b/src/menu/views/load_rom.c @@ -262,7 +262,9 @@ static void draw (menu_t *menu, surface_t *d) { "R: Options" ); - component_boxart_draw(boxart); + if (boxart != NULL) { + component_boxart_draw(boxart); + } if (show_extra_info_message) { component_messagebox_draw( @@ -335,6 +337,7 @@ static void load (menu_t *menu) { static void deinit (void) { component_boxart_free(boxart); + boxart = NULL; } diff --git a/src/menu/views/rtc.c b/src/menu/views/rtc.c index ae56fd8b..da595f6f 100644 --- a/src/menu/views/rtc.c +++ b/src/menu/views/rtc.c @@ -36,7 +36,7 @@ static void draw (menu_t *menu, surface_t *d) { "\n" "\n" "To set the date and time, please use the PC terminal\n" - "application and set via USB or a game that uses it.\n\n" + "application and set via USB,\n or a N64 game with RTC support.\n\n" "Current date & time: %s\n", menu->current_time >= 0 ? ctime(&menu->current_time) : "Unknown\n" ); From 4732981f88f8916a92b9e4dcfaf2785c39d75748 Mon Sep 17 00:00:00 2001 From: Robin Jones Date: Wed, 23 Oct 2024 14:19:59 +0100 Subject: [PATCH 18/47] Correctly init joypay vars Correctly free overrides path --- src/menu/actions.c | 6 +++--- src/menu/rom_info.c | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/menu/actions.c b/src/menu/actions.c index 00317168..4cafbce7 100644 --- a/src/menu/actions.c +++ b/src/menu/actions.c @@ -25,8 +25,8 @@ static void actions_clear (menu_t *menu) { } static void actions_update_direction (menu_t *menu) { - joypad_8way_t held_dir; - joypad_8way_t fast_dir; + joypad_8way_t held_dir = JOYPAD_8WAY_NONE; + joypad_8way_t fast_dir = JOYPAD_8WAY_NONE; JOYPAD_PORT_FOREACH (i) { held_dir = joypad_get_direction(i, JOYPAD_2D_DPAD | JOYPAD_2D_STICK); @@ -90,7 +90,7 @@ static void actions_update_direction (menu_t *menu) { } static void actions_update_buttons (menu_t *menu) { - joypad_buttons_t pressed; + joypad_buttons_t pressed = {0}; JOYPAD_PORT_FOREACH (i) { pressed = joypad_get_buttons_pressed(i); diff --git a/src/menu/rom_info.c b/src/menu/rom_info.c index e5b750ce..b313950c 100644 --- a/src/menu/rom_info.c +++ b/src/menu/rom_info.c @@ -835,6 +835,7 @@ static rom_err_t save_override (path_t *path, const char *id, int value, int def mini_t *ini = mini_try_load(path_get(overrides_path)); if (!ini) { + path_free(overrides_path); return ROM_ERR_SAVE_IO; } From a6465787ded3fff24681e76da656e861bec83fa5 Mon Sep 17 00:00:00 2001 From: Robin Jones Date: Wed, 23 Oct 2024 15:29:46 +0100 Subject: [PATCH 19/47] Improve sound_deinit Close sound effects properly. --- src/menu/sound.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/menu/sound.c b/src/menu/sound.c index 98d62748..c439c4f9 100644 --- a/src/menu/sound.c +++ b/src/menu/sound.c @@ -19,10 +19,7 @@ static bool sfx_enabled = false; static void sound_reconfigure (int frequency) { if ((frequency > 0) && (audio_get_frequency() != frequency)) { - if (sound_initialized) { - mixer_close(); - audio_close(); - } + sound_deinit(); audio_init(frequency, NUM_BUFFERS); mixer_init(NUM_CHANNELS); mp3player_mixer_init(); @@ -86,6 +83,13 @@ void sound_play_effect(sound_effect_t sfx) { void sound_deinit (void) { if (sound_initialized) { + if (sfx_enabled) { + wav64_close(&sfx_cursor); + wav64_close(&sfx_exit); + wav64_close(&sfx_setting); + wav64_close(&sfx_enter); + wav64_close(&sfx_error); + } mixer_close(); audio_close(); sound_initialized = false; From 0116c1466745d52f130251c3501135f528ffbf21 Mon Sep 17 00:00:00 2001 From: Robin Jones Date: Wed, 23 Oct 2024 16:12:49 +0100 Subject: [PATCH 20/47] Update 99_developer_guide.md Improve submodule docs --- docs/99_developer_guide.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/docs/99_developer_guide.md b/docs/99_developer_guide.md index 1734b8d9..8aa62879 100644 --- a/docs/99_developer_guide.md +++ b/docs/99_developer_guide.md @@ -45,10 +45,13 @@ For ease of development and debugging, the menu ROM can run in the [Ares emulato * Add the required file to the correct folder on your SD card. -## Update Libdragon submodule -This repo currently uses the `preview` branch as a submodule at a specific commit. +## Update submodules To update to the latest version, use `git submodule update --remote` from the terminal. +### libdragon +This repo currently uses the `preview` branch as a submodule at a specific commit. +* To ensure your local instance is building against it, use `cd ./libdragon && make clobber -j && make libdragon tools -j && make install tools-install -j && cd ..` + ## Generate documentation Run `doxygen` from the dev container terminal. Make sure you fix the warnings before creating a PR! From 329ba270ff9a9698b918c7672fd8dec7d9c7f891 Mon Sep 17 00:00:00 2001 From: Robin Jones Date: Wed, 23 Oct 2024 20:14:25 +0100 Subject: [PATCH 21/47] Improve flashcart info SC64 only. Other flashcarts may show wrong info (but they are not yet supported anyway). --- src/menu/views/flashcart_info.c | 38 +++++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 9 deletions(-) diff --git a/src/menu/views/flashcart_info.c b/src/menu/views/flashcart_info.c index 41c1f443..fa1f6eb5 100644 --- a/src/menu/views/flashcart_info.c +++ b/src/menu/views/flashcart_info.c @@ -2,6 +2,10 @@ #include "../sound.h" +static inline const char *format_boolean_type (bool bool_value) { + return bool_value ? "Supported" : "Unsupported"; +} + static void process (menu_t *menu) { if (menu->actions.back) { menu->next_mode = MENU_MODE_BROWSER; @@ -18,10 +22,33 @@ static void draw (menu_t *menu, surface_t *d) { component_main_text_draw( ALIGN_CENTER, VALIGN_TOP, - "FLASHCART INFORMATION\n" + "FLASHCART INFORMATION" "\n" "\n" - "This feature is not yet supported.\n\n" + ); + + component_main_text_draw( + ALIGN_LEFT, VALIGN_TOP, + "\n" + "\n" + "Type:\n" + " %s\n\n" + "Firmware:\n" + " %s\n\n" + "Features:\n" + " Virtual 64DD: %s.\n" + " Real Time Clock: %s.\n" + " USB Debugging: %s.\n" + " CIC Detection: %s.\n" + " Region Detection: %s.\n" + "\n\n", + "SummerCart64", + "V?.?.?", + format_boolean_type(true), + format_boolean_type(true), + format_boolean_type(true), + format_boolean_type(true), + format_boolean_type(true) ); // FIXME: Display: @@ -30,13 +57,6 @@ static void draw (menu_t *menu, surface_t *d) { // * supported features (flashcart_features_t) - component_main_text_draw( - ALIGN_LEFT, VALIGN_TOP, - "\n" - "\n" - ); - - component_actions_bar_text_draw( ALIGN_LEFT, VALIGN_TOP, "\n" From 004f182e29e728e92912c5f9d966849c1b493b62 Mon Sep 17 00:00:00 2001 From: Robin Jones Date: Wed, 23 Oct 2024 20:45:47 +0100 Subject: [PATCH 22/47] Avoid casting void* to bool directly --- src/menu/views/settings_editor.c | 34 ++++++++++++++++---------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/menu/views/settings_editor.c b/src/menu/views/settings_editor.c index 55feffea..41d96407 100644 --- a/src/menu/views/settings_editor.c +++ b/src/menu/views/settings_editor.c @@ -12,36 +12,36 @@ static const char *format_switch (bool state) { } static void set_pal60_type (menu_t *menu, void *arg) { - menu->settings.pal60_enabled = (bool) (arg); + menu->settings.pal60_enabled = (bool)(uintptr_t)(arg); settings_save(&menu->settings); } static void set_protected_entries_type (menu_t *menu, void *arg) { - menu->settings.show_protected_entries = (bool) (arg); + menu->settings.show_protected_entries = (bool)(uintptr_t)(arg); settings_save(&menu->settings); menu->browser.reload = true; } static void set_use_saves_folder_type (menu_t *menu, void *arg) { - menu->settings.use_saves_folder = (bool) (arg); + menu->settings.use_saves_folder = (bool)(uintptr_t)(arg); settings_save(&menu->settings); } static void set_sound_enabled_type (menu_t *menu, void *arg) { - menu->settings.sound_enabled = (bool) (arg); + menu->settings.sound_enabled = (bool)(uintptr_t)(arg); sound_use_sfx(menu->settings.sound_enabled); settings_save(&menu->settings); } #ifdef BETA_SETTINGS static void set_bgm_enabled_type (menu_t *menu, void *arg) { - menu->settings.bgm_enabled = (bool) (arg); + menu->settings.bgm_enabled = (bool)(uintptr_t)(arg); settings_save(&menu->settings); } static void set_rumble_enabled_type (menu_t *menu, void *arg) { - menu->settings.rumble_enabled = (bool) (arg); + menu->settings.rumble_enabled = (bool)(uintptr_t)(arg); settings_save(&menu->settings); } @@ -53,39 +53,39 @@ static void set_rumble_enabled_type (menu_t *menu, void *arg) { static component_context_menu_t set_pal60_type_context_menu = { .list = { - {.text = "On", .action = set_pal60_type, .arg = (void *) (true) }, + {.text = "On", .action = set_pal60_type, .arg = (void *)(uintptr_t)(true) }, {.text = "Off", .action = set_pal60_type, .arg = (void *) (false) }, COMPONENT_CONTEXT_MENU_LIST_END, }}; static component_context_menu_t set_protected_entries_type_context_menu = { .list = { - {.text = "On", .action = set_protected_entries_type, .arg = (void *) (true) }, - {.text = "Off", .action = set_protected_entries_type, .arg = (void *) (false) }, + {.text = "On", .action = set_protected_entries_type, .arg = (void *)(uintptr_t)(true) }, + {.text = "Off", .action = set_protected_entries_type, .arg = (void *)(uintptr_t)(false) }, COMPONENT_CONTEXT_MENU_LIST_END, }}; static component_context_menu_t set_sound_enabled_type_context_menu = { .list = { - {.text = "On", .action = set_sound_enabled_type, .arg = (void *) (true) }, - {.text = "Off", .action = set_sound_enabled_type, .arg = (void *) (false) }, + {.text = "On", .action = set_sound_enabled_type, .arg = (void *)(uintptr_t)(true) }, + {.text = "Off", .action = set_sound_enabled_type, .arg = (void *)(uintptr_t)(false) }, COMPONENT_CONTEXT_MENU_LIST_END, }}; static component_context_menu_t set_use_saves_folder_type_context_menu = { .list = { - {.text = "On", .action = set_use_saves_folder_type, .arg = (void *) (true) }, - {.text = "Off", .action = set_use_saves_folder_type, .arg = (void *) (false) }, + {.text = "On", .action = set_use_saves_folder_type, .arg = (void *)(uintptr_t)(true) }, + {.text = "Off", .action = set_use_saves_folder_type, .arg = (void *)(uintptr_t)(false) }, COMPONENT_CONTEXT_MENU_LIST_END, }}; #ifdef BETA_SETTINGS static component_context_menu_t set_bgm_enabled_type_context_menu = { .list = { - {.text = "On", .action = set_bgm_enabled_type, .arg = (void *) (true) }, - {.text = "Off", .action = set_bgm_enabled_type, .arg = (void *) (false) }, + {.text = "On", .action = set_bgm_enabled_type, .arg = (void *)(uintptr_t)(true) }, + {.text = "Off", .action = set_bgm_enabled_type, .arg = (void *)(uintptr_t)(false) }, COMPONENT_CONTEXT_MENU_LIST_END, }}; static component_context_menu_t set_rumble_enabled_type_context_menu = { .list = { - {.text = "On", .action = set_rumble_enabled_type, .arg = (void *) (true) }, - {.text = "Off", .action = set_rumble_enabled_type, .arg = (void *) (false) }, + {.text = "On", .action = set_rumble_enabled_type, .arg = (void *)(uintptr_t)(true) }, + {.text = "Off", .action = set_rumble_enabled_type, .arg = (void *)(uintptr_t)(false) }, COMPONENT_CONTEXT_MENU_LIST_END, }}; #endif From a1f2a5d56b7bebdad59f94b9d5d2702e75f06e18 Mon Sep 17 00:00:00 2001 From: Robin Jones Date: Fri, 25 Oct 2024 13:11:29 +0100 Subject: [PATCH 23/47] Improve sound_poll --- src/menu/sound.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/menu/sound.c b/src/menu/sound.c index c439c4f9..08c5996f 100644 --- a/src/menu/sound.c +++ b/src/menu/sound.c @@ -97,9 +97,7 @@ void sound_deinit (void) { } void sound_poll (void) { - if (sound_initialized && audio_can_write()) { - short *audio_buffer = audio_write_begin(); - mixer_poll(audio_buffer, audio_get_buffer_length()); - audio_write_end(); + if (sound_initialized) { + mixer_try_play(); } } From 3e37991b73853cee865be609de57ed31b0077ade Mon Sep 17 00:00:00 2001 From: Robin Jones Date: Fri, 25 Oct 2024 13:21:49 +0100 Subject: [PATCH 24/47] Improve context menu vars --- src/menu/components.h | 4 +-- src/menu/components/context_menu.c | 40 +++++++++++++++--------------- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/menu/components.h b/src/menu/components.h index 67fde2d3..6d31a3d3 100644 --- a/src/menu/components.h +++ b/src/menu/components.h @@ -73,8 +73,8 @@ void component_background_draw (void); void component_file_list_draw (entry_t *list, int entries, int selected); typedef struct component_context_menu { - int count; - int selected; + int row_count; + int row_selected; bool hide_pending; struct component_context_menu *parent; struct component_context_menu *submenu; diff --git a/src/menu/components/context_menu.c b/src/menu/components/context_menu.c index c4d0364a..abf1947e 100644 --- a/src/menu/components/context_menu.c +++ b/src/menu/components/context_menu.c @@ -13,22 +13,22 @@ static component_context_menu_t *get_current_submenu (component_context_menu_t * void component_context_menu_init (component_context_menu_t *cm) { - cm->selected = -1; - cm->count = 0; + cm->row_selected = -1; + cm->row_count = 0; cm->hide_pending = false; cm->parent = NULL; for (int i = 0; (cm->list[i].text) != NULL; i++) { - cm->count += 1; + cm->row_count += 1; } } void component_context_menu_show (component_context_menu_t *cm) { - cm->selected = 0; + cm->row_selected = 0; cm->submenu = NULL; } bool component_context_menu_process (menu_t *menu, component_context_menu_t *cm) { - if (!cm || (cm->selected < 0)) { + if (!cm || (cm->row_selected < 0)) { return false; } @@ -44,26 +44,26 @@ bool component_context_menu_process (menu_t *menu, component_context_menu_t *cm) } sound_play_effect(SFX_EXIT); } else if (menu->actions.enter) { - if (cm->list[cm->selected].submenu) { - cm->submenu = cm->list[cm->selected].submenu; + if (cm->list[cm->row_selected].submenu) { + cm->submenu = cm->list[cm->row_selected].submenu; component_context_menu_init(cm->submenu); - cm->submenu->selected = 0; + cm->submenu->row_selected = 0; cm->submenu->parent = cm; - } else if (cm->list[cm->selected].action) { - cm->list[cm->selected].action(menu, cm->list[cm->selected].arg); + } else if (cm->list[cm->row_selected].action) { + cm->list[cm->row_selected].action(menu, cm->list[cm->row_selected].arg); top->hide_pending = true; } sound_play_effect(SFX_ENTER); } else if (menu->actions.go_up) { - cm->selected -= 1; - if (cm->selected < 0) { - cm->selected = 0; + cm->row_selected -= 1; + if (cm->row_selected < 0) { + cm->row_selected = 0; } sound_play_effect(SFX_CURSOR); } else if (menu->actions.go_down) { - cm->selected += 1; - if (cm->selected >= cm->count) { - cm->selected = (cm->count - 1); + cm->row_selected += 1; + if (cm->row_selected >= cm->row_count) { + cm->row_selected = (cm->row_count - 1); } sound_play_effect(SFX_CURSOR); } @@ -72,7 +72,7 @@ bool component_context_menu_process (menu_t *menu, component_context_menu_t *cm) } void component_context_menu_draw (component_context_menu_t *cm) { - if (!cm || (cm->selected < 0)) { + if (!cm || (cm->row_selected < 0)) { return; } @@ -92,7 +92,7 @@ void component_context_menu_draw (component_context_menu_t *cm) { NULL ); - for (int i = 0; i < cm->count; i++) { + for (int i = 0; i < cm->row_count; i++) { const char *text = cm->list[i].text; rdpq_paragraph_builder_span(text, strlen(text)); if (cm->list[i + 1].text != NULL) { @@ -110,7 +110,7 @@ void component_context_menu_draw (component_context_menu_t *cm) { int highlight_x0 = DISPLAY_CENTER_X - (width / 2); int highlight_x1 = DISPLAY_CENTER_X + (width / 2); int highlight_height = (layout->bbox.y1 - layout->bbox.y0) / layout->nlines; - int highlight_y = VISIBLE_AREA_Y0 + layout->bbox.y0 + ((cm->selected) * highlight_height); + int highlight_y = VISIBLE_AREA_Y0 + layout->bbox.y0 + ((cm->row_selected) * highlight_height); component_box_draw( highlight_x0, @@ -126,6 +126,6 @@ void component_context_menu_draw (component_context_menu_t *cm) { if (top->hide_pending) { top->hide_pending = false; - top->selected = -1; + top->row_selected = -1; } } From f5521031e43e0e6bbdfff2a185c12599cec09926 Mon Sep 17 00:00:00 2001 From: Robin Jones Date: Fri, 25 Oct 2024 13:49:56 +0100 Subject: [PATCH 25/47] Revert change to sound_reconfigure that caused a de reference exception after MP3 playback. --- src/menu/sound.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/menu/sound.c b/src/menu/sound.c index 08c5996f..ea088447 100644 --- a/src/menu/sound.c +++ b/src/menu/sound.c @@ -19,7 +19,10 @@ static bool sfx_enabled = false; static void sound_reconfigure (int frequency) { if ((frequency > 0) && (audio_get_frequency() != frequency)) { - sound_deinit(); + if (sound_initialized) { + mixer_close(); + audio_close(); + } audio_init(frequency, NUM_BUFFERS); mixer_init(NUM_CHANNELS); mp3player_mixer_init(); From 819e27784baad3f926bbe40e5f0023890263b6d5 Mon Sep 17 00:00:00 2001 From: Robin Jones Date: Fri, 25 Oct 2024 14:00:56 +0100 Subject: [PATCH 26/47] Update miniz --- src/libs/miniz | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/miniz b/src/libs/miniz index 1ff82be7..35528ad7 160000 --- a/src/libs/miniz +++ b/src/libs/miniz @@ -1 +1 @@ -Subproject commit 1ff82be7d67f5c2f8b5497f538eea247861e0717 +Subproject commit 35528ad769143b9ed38a95a22d460b963e39f278 From 6eb6991ca02edd82b1b9ce45af4673db13f61631 Mon Sep 17 00:00:00 2001 From: Robin Jones Date: Fri, 25 Oct 2024 14:48:21 +0100 Subject: [PATCH 27/47] Detect and display flashcart features correctly --- src/menu/views/flashcart_info.c | 40 ++++++++++++++++++++++----------- 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/src/menu/views/flashcart_info.c b/src/menu/views/flashcart_info.c index fa1f6eb5..aa50b74e 100644 --- a/src/menu/views/flashcart_info.c +++ b/src/menu/views/flashcart_info.c @@ -1,11 +1,31 @@ #include "views.h" #include "../sound.h" +#include static inline const char *format_boolean_type (bool bool_value) { return bool_value ? "Supported" : "Unsupported"; } +static const char *format_cart_type () { + switch (cart_type) { + case CART_CI: + return "64drive"; + + case CART_EDX: + return "Series X EverDrive-64"; + + case CART_ED: + return "Series V EverDrive-64"; + + case CART_SC: + return "SummerCart64"; + + default: // Probably emulator + return "Emulator?"; + } +} + static void process (menu_t *menu) { if (menu->actions.back) { menu->next_mode = MENU_MODE_BROWSER; @@ -42,21 +62,15 @@ static void draw (menu_t *menu, surface_t *d) { " CIC Detection: %s.\n" " Region Detection: %s.\n" "\n\n", - "SummerCart64", - "V?.?.?", - format_boolean_type(true), - format_boolean_type(true), - format_boolean_type(true), - format_boolean_type(true), - format_boolean_type(true) + format_cart_type(), + "Not Available", + format_boolean_type(flashcart_has_feature(FLASHCART_FEATURE_64DD)), + format_boolean_type(flashcart_has_feature(FLASHCART_FEATURE_RTC)), + format_boolean_type(flashcart_has_feature(FLASHCART_FEATURE_USB)), + format_boolean_type(flashcart_has_feature(FLASHCART_FEATURE_AUTO_CIC)), + format_boolean_type(flashcart_has_feature(FLASHCART_FEATURE_AUTO_REGION)) ); - // FIXME: Display: - // * cart_type - // * Firmware version - // * supported features (flashcart_features_t) - - component_actions_bar_text_draw( ALIGN_LEFT, VALIGN_TOP, "\n" From f5dd0ae3360f45d6df8dec7d3109d34677880d67 Mon Sep 17 00:00:00 2001 From: Robin Jones Date: Fri, 25 Oct 2024 15:09:12 +0100 Subject: [PATCH 28/47] Improve consistency of sound_play_effect --- src/menu/views/credits.c | 2 +- src/menu/views/file_info.c | 2 +- src/menu/views/flashcart_info.c | 2 +- src/menu/views/load_disk.c | 2 +- src/menu/views/load_emulator.c | 2 +- src/menu/views/load_rom.c | 2 +- src/menu/views/music_player.c | 2 +- src/menu/views/rtc.c | 2 +- src/menu/views/settings_editor.c | 2 +- src/menu/views/system_info.c | 2 +- src/menu/views/text_viewer.c | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/menu/views/credits.c b/src/menu/views/credits.c index fb068e6b..1889232a 100644 --- a/src/menu/views/credits.c +++ b/src/menu/views/credits.c @@ -12,8 +12,8 @@ static void process (menu_t *menu) { if (menu->actions.back) { - menu->next_mode = MENU_MODE_BROWSER; sound_play_effect(SFX_EXIT); + menu->next_mode = MENU_MODE_BROWSER; } } diff --git a/src/menu/views/file_info.c b/src/menu/views/file_info.c index 496c07f4..1b4609c4 100644 --- a/src/menu/views/file_info.c +++ b/src/menu/views/file_info.c @@ -50,8 +50,8 @@ static char *format_file_type (char *name, bool is_directory) { static void process (menu_t *menu) { if (menu->actions.back) { - menu->next_mode = MENU_MODE_BROWSER; sound_play_effect(SFX_EXIT); + menu->next_mode = MENU_MODE_BROWSER; } } diff --git a/src/menu/views/flashcart_info.c b/src/menu/views/flashcart_info.c index aa50b74e..01bfe81f 100644 --- a/src/menu/views/flashcart_info.c +++ b/src/menu/views/flashcart_info.c @@ -28,8 +28,8 @@ static const char *format_cart_type () { static void process (menu_t *menu) { if (menu->actions.back) { - menu->next_mode = MENU_MODE_BROWSER; sound_play_effect(SFX_EXIT); + menu->next_mode = MENU_MODE_BROWSER; } } diff --git a/src/menu/views/load_disk.c b/src/menu/views/load_disk.c index f4140781..be95010a 100644 --- a/src/menu/views/load_disk.c +++ b/src/menu/views/load_disk.c @@ -38,8 +38,8 @@ static void process (menu_t *menu) { load_rom = true; sound_play_effect(SFX_SETTING); } else if (menu->actions.back) { - menu->next_mode = MENU_MODE_BROWSER; sound_play_effect(SFX_EXIT); + menu->next_mode = MENU_MODE_BROWSER; } } diff --git a/src/menu/views/load_emulator.c b/src/menu/views/load_emulator.c index 589a6a59..9cfaeb48 100644 --- a/src/menu/views/load_emulator.c +++ b/src/menu/views/load_emulator.c @@ -36,8 +36,8 @@ static void process (menu_t *menu) { if (menu->actions.enter) { load_pending = true; } else if (menu->actions.back) { - menu->next_mode = MENU_MODE_BROWSER; sound_play_effect(SFX_EXIT); + menu->next_mode = MENU_MODE_BROWSER; } } diff --git a/src/menu/views/load_rom.c b/src/menu/views/load_rom.c index 4fb9d710..18acd7e6 100644 --- a/src/menu/views/load_rom.c +++ b/src/menu/views/load_rom.c @@ -198,8 +198,8 @@ static void process (menu_t *menu) { if (menu->actions.enter) { load_pending = true; } else if (menu->actions.back) { - menu->next_mode = MENU_MODE_BROWSER; sound_play_effect(SFX_EXIT); + menu->next_mode = MENU_MODE_BROWSER; } else if (menu->actions.options) { component_context_menu_show(&options_context_menu); sound_play_effect(SFX_SETTING); diff --git a/src/menu/views/music_player.c b/src/menu/views/music_player.c index 4de00756..c540bfab 100644 --- a/src/menu/views/music_player.c +++ b/src/menu/views/music_player.c @@ -41,8 +41,8 @@ static void process (menu_t *menu) { if (err != MP3PLAYER_OK) { menu_show_error(menu, convert_error_message(err)); } else if (menu->actions.back) { - menu->next_mode = MENU_MODE_BROWSER; sound_play_effect(SFX_EXIT); + menu->next_mode = MENU_MODE_BROWSER; } else if (menu->actions.enter) { err = mp3player_toggle(); if (err != MP3PLAYER_OK) { diff --git a/src/menu/views/rtc.c b/src/menu/views/rtc.c index da595f6f..6be481a3 100644 --- a/src/menu/views/rtc.c +++ b/src/menu/views/rtc.c @@ -18,8 +18,8 @@ static void process (menu_t *menu) { if (menu->actions.back) { - menu->next_mode = MENU_MODE_BROWSER; sound_play_effect(SFX_EXIT); + menu->next_mode = MENU_MODE_BROWSER; } } diff --git a/src/menu/views/settings_editor.c b/src/menu/views/settings_editor.c index 41d96407..41dfa0a9 100644 --- a/src/menu/views/settings_editor.c +++ b/src/menu/views/settings_editor.c @@ -114,8 +114,8 @@ static void process (menu_t *menu) { component_context_menu_show(&options_context_menu); sound_play_effect(SFX_SETTING); } else if (menu->actions.back) { - menu->next_mode = MENU_MODE_BROWSER; sound_play_effect(SFX_EXIT); + menu->next_mode = MENU_MODE_BROWSER; } } diff --git a/src/menu/views/system_info.c b/src/menu/views/system_info.c index 74ed4cbd..2dea476d 100644 --- a/src/menu/views/system_info.c +++ b/src/menu/views/system_info.c @@ -28,8 +28,8 @@ static void process (menu_t *menu) { } if (menu->actions.back) { - menu->next_mode = MENU_MODE_BROWSER; sound_play_effect(SFX_EXIT); + menu->next_mode = MENU_MODE_BROWSER; } } diff --git a/src/menu/views/text_viewer.c b/src/menu/views/text_viewer.c index cf8b505f..0339ba37 100644 --- a/src/menu/views/text_viewer.c +++ b/src/menu/views/text_viewer.c @@ -55,8 +55,8 @@ static void perform_vertical_scroll (int lines) { static void process (menu_t *menu) { if (menu->actions.back) { - menu->next_mode = MENU_MODE_BROWSER; sound_play_effect(SFX_EXIT); + menu->next_mode = MENU_MODE_BROWSER; } else if (text) { if (menu->actions.go_up) { perform_vertical_scroll(menu->actions.go_fast ? -10 : -1); From b07364aa3f7a893bb93d48e66f860ce871ee9862 Mon Sep 17 00:00:00 2001 From: Robin Jones Date: Fri, 25 Oct 2024 15:28:52 +0100 Subject: [PATCH 29/47] Update flashcart features --- src/flashcart/64drive/64drive.c | 1 + src/flashcart/flashcart.h | 3 +++ src/flashcart/sc64/sc64.c | 2 ++ src/menu/views/flashcart_info.c | 8 +++++++- 4 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/flashcart/64drive/64drive.c b/src/flashcart/64drive/64drive.c index 363b3bcf..5b4b5d22 100644 --- a/src/flashcart/64drive/64drive.c +++ b/src/flashcart/64drive/64drive.c @@ -77,6 +77,7 @@ static bool d64_has_feature (flashcart_features_t feature) { case FLASHCART_FEATURE_USB: return true; case FLASHCART_FEATURE_AUTO_CIC: return true; case FLASHCART_FEATURE_AUTO_REGION: return true; + case FLASHCART_FEATURE_SAVE_WRITEBACK: return true; default: return false; } } diff --git a/src/flashcart/flashcart.h b/src/flashcart/flashcart.h index ade09eaa..bd568968 100644 --- a/src/flashcart/flashcart.h +++ b/src/flashcart/flashcart.h @@ -31,6 +31,9 @@ typedef enum { FLASHCART_FEATURE_USB, FLASHCART_FEATURE_AUTO_CIC, FLASHCART_FEATURE_AUTO_REGION, + FLASHCART_FEATURE_BATTERY_HEALTH, + FLASHCART_FEATURE_BIOS_UPDATE_FROM_MENU, + FLASHCART_FEATURE_SAVE_WRITEBACK } flashcart_features_t; /** @brief Flashcart save type enumeration */ diff --git a/src/flashcart/sc64/sc64.c b/src/flashcart/sc64/sc64.c index 927843a3..c0597057 100644 --- a/src/flashcart/sc64/sc64.c +++ b/src/flashcart/sc64/sc64.c @@ -256,6 +256,8 @@ static bool sc64_has_feature (flashcart_features_t feature) { case FLASHCART_FEATURE_USB: return true; case FLASHCART_FEATURE_AUTO_CIC: return true; case FLASHCART_FEATURE_AUTO_REGION: return true; + case FLASHCART_FEATURE_BATTERY_HEALTH: return true; + case FLASHCART_FEATURE_SAVE_WRITEBACK: return true; default: return false; } } diff --git a/src/menu/views/flashcart_info.c b/src/menu/views/flashcart_info.c index 01bfe81f..bf4ddb29 100644 --- a/src/menu/views/flashcart_info.c +++ b/src/menu/views/flashcart_info.c @@ -61,6 +61,9 @@ static void draw (menu_t *menu, surface_t *d) { " USB Debugging: %s.\n" " CIC Detection: %s.\n" " Region Detection: %s.\n" + " Battery Health: %s.\n" + " Save Writeback: %s.\n" + " Update from menu: %s.\n" "\n\n", format_cart_type(), "Not Available", @@ -68,7 +71,10 @@ static void draw (menu_t *menu, surface_t *d) { format_boolean_type(flashcart_has_feature(FLASHCART_FEATURE_RTC)), format_boolean_type(flashcart_has_feature(FLASHCART_FEATURE_USB)), format_boolean_type(flashcart_has_feature(FLASHCART_FEATURE_AUTO_CIC)), - format_boolean_type(flashcart_has_feature(FLASHCART_FEATURE_AUTO_REGION)) + format_boolean_type(flashcart_has_feature(FLASHCART_FEATURE_AUTO_REGION)), + format_boolean_type(flashcart_has_feature(FLASHCART_FEATURE_BATTERY_HEALTH)), + format_boolean_type(flashcart_has_feature(FLASHCART_FEATURE_SAVE_WRITEBACK)), + format_boolean_type(flashcart_has_feature(FLASHCART_FEATURE_BIOS_UPDATE_FROM_MENU)) ); component_actions_bar_text_draw( From f1238debb1531193a14f37f2a747da17cd215e73 Mon Sep 17 00:00:00 2001 From: Robin Jones Date: Fri, 25 Oct 2024 16:40:24 +0100 Subject: [PATCH 30/47] Improve fileinfo stat st_mtime will expand to st_mtim.tv_sec using a macro --- src/menu/views/file_info.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/menu/views/file_info.c b/src/menu/views/file_info.c index 1b4609c4..9d45574b 100644 --- a/src/menu/views/file_info.c +++ b/src/menu/views/file_info.c @@ -84,7 +84,7 @@ static void draw (menu_t *menu, surface_t *d) { S_ISDIR(st.st_mode) ? "Directory" : "File", st.st_mode & S_IWUSR ? "" : "(Read only)", format_file_type(menu->browser.entry->name, S_ISDIR(st.st_mode)), - ctime(&st.st_mtim.tv_sec) + ctime(&st.st_mtime) ); component_actions_bar_text_draw( From dd3ce84a4695826267ba623ecf0b6f464b5428a1 Mon Sep 17 00:00:00 2001 From: Robin Jones Date: Fri, 25 Oct 2024 17:16:10 +0100 Subject: [PATCH 31/47] Improve flashcart features --- src/flashcart/flashcart.h | 2 +- src/flashcart/sc64/sc64.c | 2 +- src/menu/views/flashcart_info.c | 9 +++++---- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/flashcart/flashcart.h b/src/flashcart/flashcart.h index bd568968..fcbcf606 100644 --- a/src/flashcart/flashcart.h +++ b/src/flashcart/flashcart.h @@ -31,7 +31,7 @@ typedef enum { FLASHCART_FEATURE_USB, FLASHCART_FEATURE_AUTO_CIC, FLASHCART_FEATURE_AUTO_REGION, - FLASHCART_FEATURE_BATTERY_HEALTH, + FLASHCART_FEATURE_DIAGNOSTIC_DATA, FLASHCART_FEATURE_BIOS_UPDATE_FROM_MENU, FLASHCART_FEATURE_SAVE_WRITEBACK } flashcart_features_t; diff --git a/src/flashcart/sc64/sc64.c b/src/flashcart/sc64/sc64.c index c0597057..605ae419 100644 --- a/src/flashcart/sc64/sc64.c +++ b/src/flashcart/sc64/sc64.c @@ -256,7 +256,7 @@ static bool sc64_has_feature (flashcart_features_t feature) { case FLASHCART_FEATURE_USB: return true; case FLASHCART_FEATURE_AUTO_CIC: return true; case FLASHCART_FEATURE_AUTO_REGION: return true; - case FLASHCART_FEATURE_BATTERY_HEALTH: return true; + case FLASHCART_FEATURE_DIAGNOSTIC_DATA: return true; case FLASHCART_FEATURE_SAVE_WRITEBACK: return true; default: return false; } diff --git a/src/menu/views/flashcart_info.c b/src/menu/views/flashcart_info.c index bf4ddb29..635ef2ca 100644 --- a/src/menu/views/flashcart_info.c +++ b/src/menu/views/flashcart_info.c @@ -59,22 +59,23 @@ static void draw (menu_t *menu, surface_t *d) { " Virtual 64DD: %s.\n" " Real Time Clock: %s.\n" " USB Debugging: %s.\n" - " CIC Detection: %s.\n" + " Automatic CIC: %s.\n" " Region Detection: %s.\n" - " Battery Health: %s.\n" " Save Writeback: %s.\n" " Update from menu: %s.\n" "\n\n", format_cart_type(), - "Not Available", + "Not Available", // TODO get cart firmware version(s). format_boolean_type(flashcart_has_feature(FLASHCART_FEATURE_64DD)), format_boolean_type(flashcart_has_feature(FLASHCART_FEATURE_RTC)), format_boolean_type(flashcart_has_feature(FLASHCART_FEATURE_USB)), format_boolean_type(flashcart_has_feature(FLASHCART_FEATURE_AUTO_CIC)), format_boolean_type(flashcart_has_feature(FLASHCART_FEATURE_AUTO_REGION)), - format_boolean_type(flashcart_has_feature(FLASHCART_FEATURE_BATTERY_HEALTH)), format_boolean_type(flashcart_has_feature(FLASHCART_FEATURE_SAVE_WRITEBACK)), format_boolean_type(flashcart_has_feature(FLASHCART_FEATURE_BIOS_UPDATE_FROM_MENU)) + + //TODO: display the battery and temperature information (if available). + //format_diagnostic_data(flashcart_has_feature(FLASHCART_FEATURE_DIAGNOSTIC_DATA)) ); component_actions_bar_text_draw( From 9c0a4b86a2b8dd970b400b846a5592fe2413f6b4 Mon Sep 17 00:00:00 2001 From: Robin Jones Date: Fri, 25 Oct 2024 19:27:06 +0100 Subject: [PATCH 32/47] Improve settings editor text --- src/menu/views/settings_editor.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/menu/views/settings_editor.c b/src/menu/views/settings_editor.c index 41dfa0a9..64bed3b9 100644 --- a/src/menu/views/settings_editor.c +++ b/src/menu/views/settings_editor.c @@ -145,8 +145,9 @@ static void draw (menu_t *menu, surface_t *d) { " Background Music : %s\n" " Rumble Feedback : %s\n" #endif - "Note: Certain settings have the following caveats:\n\n" - "* Requires a flashcart reboot.\n", + "\n\n" + "Note: Certain settings have the following caveats:\n" + "* Requires rebooting the N64 Console.\n", menu->settings.default_directory, format_switch(menu->settings.pal60_enabled), format_switch(menu->settings.show_protected_entries), From f65b345859f01ef953be5923ec1410af86ff375e Mon Sep 17 00:00:00 2001 From: Robin Jones Date: Fri, 25 Oct 2024 19:36:04 +0100 Subject: [PATCH 33/47] Updated doxygen action version use the new tag alias --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b7da2151..7f88be12 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -113,7 +113,7 @@ jobs: - uses: actions/checkout@v4 - name: Run Doxygen - uses: mattnotmitt/doxygen-action@1.9.5 + uses: mattnotmitt/doxygen-action@v1 with: doxyfile-path: './Doxyfile' From 7b1cf8f2ed5f858287c0a09bffa5b3dbd2d29e97 Mon Sep 17 00:00:00 2001 From: Robin Jones Date: Fri, 25 Oct 2024 23:00:55 +0100 Subject: [PATCH 34/47] Update README.md Improve Gamepak sprite info --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index de3d030c..6c4474fe 100644 --- a/README.md +++ b/README.md @@ -60,7 +60,7 @@ These must be `PNG` files that use the following dimensions: * Japanese N64 GamePak boxart sprites: 112x158 * 64DD boxart sprites: 129x112 -They will be loaded by directories using each character of the full 4 character Game Code (as identified in the menus ROM information). +They will be loaded by directories using each character (case-sensitive) of the full 4 character Game Code (as identified in the menu ROM information). i.e. for GoldenEye NTSC USA (NGEE), this would be `sd:/menu/boxart/N/G/E/E/boxart_front.png`. i.e. for GoldenEye PAL (NGEP), this would be `sd:/menu/boxart/N/G/E/P/boxart_front.png`. From 13caeee7a614afa2de792ce41e77fd8c56e9b23f Mon Sep 17 00:00:00 2001 From: Robin Jones Date: Thu, 31 Oct 2024 14:36:11 +0000 Subject: [PATCH 35/47] Update Libdragon submodule (#153) ## Description Update submodules libdragon. ## Motivation and Context keeps libs up-to-date. ## How Has This Been Tested? ## Screenshots ## Types of changes - [ ] Improvement (non-breaking change that adds a new feature) - [ ] Bug fix (fixes an issue) - [ ] Breaking change (breaking change) - [ ] Documentation Improvement - [ ] Config and build (change in the configuration and build system, has no impact on code or features) ## Checklist: - [ ] My code follows the code style of this project. - [ ] My change requires a change to the documentation. - [ ] I have updated the documentation accordingly. - [ ] I have added tests to cover my changes. - [ ] All new and existing tests passed. Signed-off-by: GITHUB_USER ## Summary by CodeRabbit - **Chores** - Updated the subproject commit identifier to a newer version. --- libdragon | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libdragon b/libdragon index 9dd99415..e93802ae 160000 --- a/libdragon +++ b/libdragon @@ -1 +1 @@ -Subproject commit 9dd994151ae3f3709f1f80224e6b654aac8be6b4 +Subproject commit e93802aec7e7839710281824ce2e9e4689b3a01d From 6cb3019c76bab79132a5d067b4bb1fce65db2ef5 Mon Sep 17 00:00:00 2001 From: Robin Jones Date: Thu, 31 Oct 2024 20:23:25 +0000 Subject: [PATCH 36/47] Display Entire Filename on ROM Information Page #101 --- src/menu/components/common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/menu/components/common.c b/src/menu/components/common.c index d0fce75f..29a97ada 100644 --- a/src/menu/components/common.c +++ b/src/menu/components/common.c @@ -151,7 +151,7 @@ void component_main_text_draw (rdpq_align_t align, rdpq_valign_t valign, char *f .height = LAYOUT_ACTIONS_SEPARATOR_Y - OVERSCAN_HEIGHT - (TEXT_MARGIN_VERTICAL * 2), .align = align, .valign = valign, - .wrap = WRAP_ELLIPSES, + .wrap = WRAP_WORD, .line_spacing = TEXT_LINE_SPACING_ADJUST, }, FNT_DEFAULT, From b5f6adc1ea537c7c55b1884cb9bfde6d3b4d52ce Mon Sep 17 00:00:00 2001 From: Robin Jones Date: Thu, 31 Oct 2024 21:26:33 +0000 Subject: [PATCH 37/47] Improve load_pending naming Make their actions clear. Works towards the ability to autoload ROMs. --- src/menu/views/load_disk.c | 24 ++++++++++++------------ src/menu/views/load_emulator.c | 12 ++++++------ src/menu/views/load_rom.c | 12 ++++++------ 3 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/menu/views/load_disk.c b/src/menu/views/load_disk.c index be95010a..580401eb 100644 --- a/src/menu/views/load_disk.c +++ b/src/menu/views/load_disk.c @@ -5,8 +5,8 @@ #include "views.h" -static bool load_pending; -static bool load_rom; +static bool load_disk_file_boot_pending; +static bool load_disk_with_rom; static component_boxart_t *boxart; @@ -31,11 +31,11 @@ static char *format_disk_region (disk_region_t region) { static void process (menu_t *menu) { if (menu->actions.enter) { - load_pending = true; - load_rom = false; + load_disk_file_boot_pending = true; + load_disk_with_rom = false; } else if (menu->actions.options && menu->load.rom_path) { - load_pending = true; - load_rom = true; + load_disk_file_boot_pending = true; + load_disk_with_rom = true; sound_play_effect(SFX_SETTING); } else if (menu->actions.back) { sound_play_effect(SFX_EXIT); @@ -48,7 +48,7 @@ static void draw (menu_t *menu, surface_t *d) { component_background_draw(); - if (load_pending) { + if (load_disk_file_boot_pending) { component_loader_draw(0.0f); } else { component_layout_draw(); @@ -119,7 +119,7 @@ static void draw_progress (float progress) { static void load (menu_t *menu) { cart_load_err_t err; - if (menu->load.rom_path && load_rom) { + if (menu->load.rom_path && load_disk_with_rom) { err = cart_load_n64_rom_and_save(menu, draw_progress); if (err != CART_LOAD_OK) { menu_show_error(menu, cart_load_convert_error_message(err)); @@ -135,7 +135,7 @@ static void load (menu_t *menu) { menu->next_mode = MENU_MODE_BOOT; - if (load_rom) { + if (load_disk_with_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)) { @@ -163,7 +163,7 @@ void view_load_disk_init (menu_t *menu) { menu->load.disk_path = NULL; } - load_pending = false; + load_disk_file_boot_pending = false; menu->load.disk_path = path_clone_push(menu->browser.directory, menu->browser.entry->name); @@ -180,8 +180,8 @@ void view_load_disk_display (menu_t *menu, surface_t *display) { draw(menu, display); - if (load_pending) { - load_pending = false; + if (load_disk_file_boot_pending) { + load_disk_file_boot_pending = false; load(menu); } diff --git a/src/menu/views/load_emulator.c b/src/menu/views/load_emulator.c index 9cfaeb48..5b13ba24 100644 --- a/src/menu/views/load_emulator.c +++ b/src/menu/views/load_emulator.c @@ -11,7 +11,7 @@ static const char *emu_gameboy_rom_extensions[] = { "gb", NULL }; static const char *emu_gameboy_color_rom_extensions[] = { "gbc", NULL }; static const char *emu_sega_8bit_rom_extensions[] = { "sms", "gg", "sg", NULL }; -static bool load_pending; +static bool load_emulator_file_boot_pending; static cart_load_emu_type_t emu_type; static char *format_emulator_name (cart_load_emu_type_t emulator_info) { @@ -34,7 +34,7 @@ static char *format_emulator_name (cart_load_emu_type_t emulator_info) { static void process (menu_t *menu) { if (menu->actions.enter) { - load_pending = true; + load_emulator_file_boot_pending = true; } else if (menu->actions.back) { sound_play_effect(SFX_EXIT); menu->next_mode = MENU_MODE_BROWSER; @@ -46,7 +46,7 @@ static void draw (menu_t *menu, surface_t *d) { component_background_draw(); - if (load_pending) { + if (load_emulator_file_boot_pending) { component_loader_draw(0.0f); } else { component_layout_draw(); @@ -107,7 +107,7 @@ static void load (menu_t *menu) { void view_load_emulator_init (menu_t *menu) { - load_pending = false; + load_emulator_file_boot_pending = false; path_t *path = path_clone_push(menu->browser.directory, menu->browser.entry->name); @@ -133,8 +133,8 @@ void view_load_emulator_display (menu_t *menu, surface_t *display) { draw(menu, display); - if (load_pending) { - load_pending = false; + if (load_emulator_file_boot_pending) { + load_emulator_file_boot_pending = false; load(menu); } } diff --git a/src/menu/views/load_rom.c b/src/menu/views/load_rom.c index 18acd7e6..ef2d26bd 100644 --- a/src/menu/views/load_rom.c +++ b/src/menu/views/load_rom.c @@ -5,7 +5,7 @@ #include "views.h" static bool show_extra_info_message = false; -static bool load_pending; +static bool load_rom_file_boot_pending; static component_boxart_t *boxart; @@ -196,7 +196,7 @@ static void process (menu_t *menu) { } if (menu->actions.enter) { - load_pending = true; + load_rom_file_boot_pending = true; } else if (menu->actions.back) { sound_play_effect(SFX_EXIT); menu->next_mode = MENU_MODE_BROWSER; @@ -218,7 +218,7 @@ static void draw (menu_t *menu, surface_t *d) { component_background_draw(); - if (load_pending) { + if (load_rom_file_boot_pending) { component_loader_draw(0.0f); } else { component_layout_draw(); @@ -342,7 +342,7 @@ static void deinit (void) { void view_load_rom_init (menu_t *menu) { - load_pending = false; + load_rom_file_boot_pending = false; if (menu->load.rom_path) { path_free(menu->load.rom_path); @@ -368,8 +368,8 @@ void view_load_rom_display (menu_t *menu, surface_t *display) { draw(menu, display); - if (load_pending) { - load_pending = false; + if (load_rom_file_boot_pending) { + load_rom_file_boot_pending = false; load(menu); } From 4eca91798c7513216d13048083023416617ddd30 Mon Sep 17 00:00:00 2001 From: Robin Jones Date: Thu, 31 Oct 2024 21:54:14 +0000 Subject: [PATCH 38/47] move boot_pending vars to menu_state works towards ability to autoload ROMs --- src/menu/menu_state.h | 6 ++++++ src/menu/views/load_disk.c | 13 ++++++------- src/menu/views/load_emulator.c | 11 +++++------ src/menu/views/load_rom.c | 12 +++++------- 4 files changed, 22 insertions(+), 20 deletions(-) diff --git a/src/menu/menu_state.h b/src/menu/menu_state.h index 0d6aa459..eaeb83ec 100644 --- a/src/menu/menu_state.h +++ b/src/menu/menu_state.h @@ -104,6 +104,12 @@ typedef struct { path_t *disk_path; disk_info_t disk_info; } load; + + struct { + bool rom_file; + bool disk_file; + bool emulator_file; + } boot_pending; } menu_t; diff --git a/src/menu/views/load_disk.c b/src/menu/views/load_disk.c index 580401eb..781ebe27 100644 --- a/src/menu/views/load_disk.c +++ b/src/menu/views/load_disk.c @@ -5,7 +5,6 @@ #include "views.h" -static bool load_disk_file_boot_pending; static bool load_disk_with_rom; static component_boxart_t *boxart; @@ -31,10 +30,10 @@ static char *format_disk_region (disk_region_t region) { static void process (menu_t *menu) { if (menu->actions.enter) { - load_disk_file_boot_pending = true; + menu->boot_pending.disk_file = true; load_disk_with_rom = false; } else if (menu->actions.options && menu->load.rom_path) { - load_disk_file_boot_pending = true; + menu->boot_pending.disk_file = true; load_disk_with_rom = true; sound_play_effect(SFX_SETTING); } else if (menu->actions.back) { @@ -48,7 +47,7 @@ static void draw (menu_t *menu, surface_t *d) { component_background_draw(); - if (load_disk_file_boot_pending) { + if (menu->boot_pending.disk_file) { component_loader_draw(0.0f); } else { component_layout_draw(); @@ -163,7 +162,7 @@ void view_load_disk_init (menu_t *menu) { menu->load.disk_path = NULL; } - load_disk_file_boot_pending = false; + menu->boot_pending.disk_file = false; menu->load.disk_path = path_clone_push(menu->browser.directory, menu->browser.entry->name); @@ -180,8 +179,8 @@ void view_load_disk_display (menu_t *menu, surface_t *display) { draw(menu, display); - if (load_disk_file_boot_pending) { - load_disk_file_boot_pending = false; + if (menu->boot_pending.disk_file) { + menu->boot_pending.disk_file = false; load(menu); } diff --git a/src/menu/views/load_emulator.c b/src/menu/views/load_emulator.c index 5b13ba24..3a131722 100644 --- a/src/menu/views/load_emulator.c +++ b/src/menu/views/load_emulator.c @@ -11,7 +11,6 @@ static const char *emu_gameboy_rom_extensions[] = { "gb", NULL }; static const char *emu_gameboy_color_rom_extensions[] = { "gbc", NULL }; static const char *emu_sega_8bit_rom_extensions[] = { "sms", "gg", "sg", NULL }; -static bool load_emulator_file_boot_pending; static cart_load_emu_type_t emu_type; static char *format_emulator_name (cart_load_emu_type_t emulator_info) { @@ -34,7 +33,7 @@ static char *format_emulator_name (cart_load_emu_type_t emulator_info) { static void process (menu_t *menu) { if (menu->actions.enter) { - load_emulator_file_boot_pending = true; + menu->boot_pending.emulator_file = true; } else if (menu->actions.back) { sound_play_effect(SFX_EXIT); menu->next_mode = MENU_MODE_BROWSER; @@ -46,7 +45,7 @@ static void draw (menu_t *menu, surface_t *d) { component_background_draw(); - if (load_emulator_file_boot_pending) { + if (menu->boot_pending.emulator_file) { component_loader_draw(0.0f); } else { component_layout_draw(); @@ -107,7 +106,7 @@ static void load (menu_t *menu) { void view_load_emulator_init (menu_t *menu) { - load_emulator_file_boot_pending = false; + menu->boot_pending.emulator_file = false; path_t *path = path_clone_push(menu->browser.directory, menu->browser.entry->name); @@ -133,8 +132,8 @@ void view_load_emulator_display (menu_t *menu, surface_t *display) { draw(menu, display); - if (load_emulator_file_boot_pending) { - load_emulator_file_boot_pending = false; + if (menu->boot_pending.emulator_file) { + menu->boot_pending.emulator_file = false; load(menu); } } diff --git a/src/menu/views/load_rom.c b/src/menu/views/load_rom.c index ef2d26bd..1e8c4dc1 100644 --- a/src/menu/views/load_rom.c +++ b/src/menu/views/load_rom.c @@ -5,10 +5,8 @@ #include "views.h" static bool show_extra_info_message = false; -static bool load_rom_file_boot_pending; static component_boxart_t *boxart; - static char *convert_error_message (rom_err_t err) { switch (err) { case ROM_ERR_LOAD_IO: return "I/O error during loading ROM information and/or options"; @@ -196,7 +194,7 @@ static void process (menu_t *menu) { } if (menu->actions.enter) { - load_rom_file_boot_pending = true; + menu->boot_pending.rom_file = true; } else if (menu->actions.back) { sound_play_effect(SFX_EXIT); menu->next_mode = MENU_MODE_BROWSER; @@ -218,7 +216,7 @@ static void draw (menu_t *menu, surface_t *d) { component_background_draw(); - if (load_rom_file_boot_pending) { + if (menu->boot_pending.rom_file) { component_loader_draw(0.0f); } else { component_layout_draw(); @@ -342,7 +340,7 @@ static void deinit (void) { void view_load_rom_init (menu_t *menu) { - load_rom_file_boot_pending = false; + menu->boot_pending.rom_file = false; if (menu->load.rom_path) { path_free(menu->load.rom_path); @@ -368,8 +366,8 @@ void view_load_rom_display (menu_t *menu, surface_t *display) { draw(menu, display); - if (load_rom_file_boot_pending) { - load_rom_file_boot_pending = false; + if (menu->boot_pending.rom_file) { + menu->boot_pending.rom_file = false; load(menu); } From 36647ebdecd2bfbb590740e85970964751eb5dc0 Mon Sep 17 00:00:00 2001 From: Robin Jones Date: Tue, 5 Nov 2024 09:27:44 +0000 Subject: [PATCH 39/47] N64 Rom autoload (#150) ## Description Allows the ability to autoload a specified ROM instead of the menu, taking into account the ROM database. If enabled, you can currently fallback to the menu by holding joypad start on console reset. ## Motivation and Context This is a better implementation of #140. ## How Has This Been Tested? ## Screenshots ## Types of changes - [x] Improvement (non-breaking change that adds a new feature) - [ ] Bug fix (fixes an issue) - [ ] Breaking change (breaking change) - [ ] Documentation Improvement - [ ] Config and build (change in the configuration and build system, has no impact on code or features) ## Checklist: - [ ] My code follows the code style of this project. - [ ] My change requires a change to the documentation. - [ ] I have updated the documentation accordingly. - [ ] I have added tests to cover my changes. - [ ] All new and existing tests passed. Signed-off-by: GITHUB_USER ## Summary by CodeRabbit ## Release Notes - **New Features** - Introduced ROM autoloading functionality, allowing users to enable automatic loading of ROMs with specified paths and filenames. - Added a settings option for managing ROM autoload preferences in the menu. - **User Interface Enhancements** - Updated settings menu to display the state of the "Autoload ROM" setting. - Improved context menus for toggling various settings. - **Bug Fixes** - Enhanced memory management by ensuring proper resource deallocation for settings. - **Documentation** - Added documentation for new functions and settings related to ROM autoloading. --- README.md | 4 ++++ src/menu/settings.c | 12 +++++++++++- src/menu/settings.h | 11 ++++++++++- src/menu/views/load_rom.c | 31 +++++++++++++++++++++++-------- src/menu/views/settings_editor.c | 2 ++ src/menu/views/startup.c | 21 +++++++++++++++++++++ 6 files changed, 71 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 6c4474fe..8fae66a3 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,7 @@ An open source menu for N64 flashcarts. * Real Time Clock support. * Music playback (MP3). * Menu sound effects. +* N64 ROM autoload. ## Documentation @@ -49,6 +50,9 @@ An open source menu for N64 flashcarts. ## Experimental features These features are subject to change: +### N64 ROM autoload +To use the autoload function, while on the `N64 ROM information` display, press the `R` button on your joypad and select the `Set ROM to autoload` option. When you restart the console, it will now only load the selected ROM rather than the menu. +NOTE: to return to the menu, hold joypad `start` button whilst powering on the console. ### GamePak sprites To use N64 `GamePak` sprites, place `PNG` files within the `sd:/menu/boxart/` folder. diff --git a/src/menu/settings.c b/src/menu/settings.c index 0b372531..5361f0a6 100644 --- a/src/menu/settings.c +++ b/src/menu/settings.c @@ -14,7 +14,10 @@ static settings_t init = { .default_directory = "/", .use_saves_folder = true, .sound_enabled = true, - + .rom_autoload_enabled = false, + .rom_autoload_path = "", + .rom_autoload_filename = "", + /* Beta feature flags (should always init to off) */ .bgm_enabled = false, .rumble_enabled = false, @@ -41,6 +44,10 @@ void settings_load (settings_t *settings) { settings->use_saves_folder = mini_get_bool(ini, "menu", "use_saves_folder", init.use_saves_folder); settings->sound_enabled = mini_get_bool(ini, "menu", "sound_enabled", init.sound_enabled); + settings->rom_autoload_enabled = mini_get_bool(ini, "menu", "autoload_rom_enabled", init.rom_autoload_enabled); + settings->rom_autoload_path = strdup(mini_get_string(ini, "autoload", "rom_path", init.rom_autoload_path)); + settings->rom_autoload_filename = strdup(mini_get_string(ini, "autoload", "rom_filename", init.rom_autoload_filename)); + /* Beta feature flags, they might not be in the file */ settings->bgm_enabled = mini_get_bool(ini, "menu_beta_flag", "bgm_enabled", init.bgm_enabled); settings->rumble_enabled = mini_get_bool(ini, "menu_beta_flag", "rumble_enabled", init.rumble_enabled); @@ -56,6 +63,9 @@ void settings_save (settings_t *settings) { mini_set_string(ini, "menu", "default_directory", settings->default_directory); mini_set_bool(ini, "menu", "use_saves_folder", settings->use_saves_folder); mini_set_bool(ini, "menu", "sound_enabled", settings->sound_enabled); + mini_set_bool(ini, "menu", "autoload_rom_enabled", settings->rom_autoload_enabled); + mini_set_string(ini, "autoload", "rom_path", settings->rom_autoload_path); + mini_set_string(ini, "autoload", "rom_filename", settings->rom_autoload_filename); /* Beta feature flags, they should not save until production ready! */ // mini_set_bool(ini, "menu_beta_flag", "bgm_enabled", settings->bgm_enabled); diff --git a/src/menu/settings.h b/src/menu/settings.h index e9931b05..471879eb 100644 --- a/src/menu/settings.h +++ b/src/menu/settings.h @@ -30,6 +30,16 @@ typedef struct { /** @brief Enable rumble feedback */ bool rumble_enabled; + + /** @brief Enable the ability to bypass the menu and instantly load a ROM */ + bool rom_autoload_enabled; + + /** @brief A path to the autoloaded ROM */ + char *rom_autoload_path; + + /** @brief A filename of the autoloaded ROM */ + char *rom_autoload_filename; + } settings_t; @@ -40,5 +50,4 @@ void settings_load (settings_t *settings); /** @brief The settings to save */ void settings_save (settings_t *settings); - #endif diff --git a/src/menu/views/load_rom.c b/src/menu/views/load_rom.c index 1e8c4dc1..2a4ce34d 100644 --- a/src/menu/views/load_rom.c +++ b/src/menu/views/load_rom.c @@ -3,6 +3,8 @@ #include "boot/boot.h" #include "../sound.h" #include "views.h" +#include +#include "utils/fs.h" static bool show_extra_info_message = false; static component_boxart_t *boxart; @@ -143,6 +145,17 @@ static void set_tv_type (menu_t *menu, void *arg) { menu->browser.reload = true; } +static void set_autoload_type (menu_t *menu, void *arg) { + free(menu->settings.rom_autoload_path); + menu->settings.rom_autoload_path = strdup(strip_fs_prefix(path_get(menu->browser.directory))); + free(menu->settings.rom_autoload_filename); + menu->settings.rom_autoload_filename = strdup(menu->browser.entry->name); + // FIXME: add a confirmation box here! (press start on reboot) + menu->settings.rom_autoload_enabled = true; + settings_save(&menu->settings); + 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) }, @@ -185,6 +198,7 @@ static component_context_menu_t options_context_menu = { .list = { { .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 }, + { .text = "Set ROM to autoload", .action = set_autoload_type }, COMPONENT_CONTEXT_MENU_LIST_END, }}; @@ -340,14 +354,14 @@ static void deinit (void) { void view_load_rom_init (menu_t *menu) { - menu->boot_pending.rom_file = false; + if (!menu->settings.rom_autoload_enabled) { + if (menu->load.rom_path) { + path_free(menu->load.rom_path); + } - if (menu->load.rom_path) { - path_free(menu->load.rom_path); + menu->load.rom_path = path_clone_push(menu->browser.directory, menu->browser.entry->name); } - 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); @@ -356,9 +370,10 @@ void view_load_rom_init (menu_t *menu) { return; } - boxart = component_boxart_init(menu->storage_prefix, menu->load.rom_info.game_code, IMAGE_BOXART_FRONT); - - component_context_menu_init(&options_context_menu); + if (!menu->settings.rom_autoload_enabled) { + boxart = component_boxart_init(menu->storage_prefix, menu->load.rom_info.game_code, IMAGE_BOXART_FRONT); + component_context_menu_init(&options_context_menu); + } } void view_load_rom_display (menu_t *menu, surface_t *display) { diff --git a/src/menu/views/settings_editor.c b/src/menu/views/settings_editor.c index 64bed3b9..068b4675 100644 --- a/src/menu/views/settings_editor.c +++ b/src/menu/views/settings_editor.c @@ -136,6 +136,7 @@ static void draw (menu_t *menu, surface_t *d) { ALIGN_LEFT, VALIGN_TOP, "\n\n" " Default Directory : %s\n\n" + " Autoload ROM : %s\n" "To change the following menu settings, press 'A':\n" "* PAL60 Mode : %s\n" " Show Hidden Files : %s\n" @@ -149,6 +150,7 @@ static void draw (menu_t *menu, surface_t *d) { "Note: Certain settings have the following caveats:\n" "* Requires rebooting the N64 Console.\n", menu->settings.default_directory, + format_switch(menu->settings.rom_autoload_enabled), format_switch(menu->settings.pal60_enabled), format_switch(menu->settings.show_protected_entries), format_switch(menu->settings.use_saves_folder), diff --git a/src/menu/views/startup.c b/src/menu/views/startup.c index 118d20dc..c12a9045 100644 --- a/src/menu/views/startup.c +++ b/src/menu/views/startup.c @@ -9,6 +9,27 @@ static void draw (menu_t *menu, surface_t *d) { void view_startup_init (menu_t *menu) { + // FIXME: rather than use a controller button, would it be better to use the cart button? + JOYPAD_PORT_FOREACH (port) { + joypad_poll(); + joypad_buttons_t b_held = joypad_get_buttons_held(port); + + if (menu->settings.rom_autoload_enabled && b_held.start) { + menu->settings.rom_autoload_enabled = false; + menu->settings.rom_autoload_path = ""; + menu->settings.rom_autoload_filename = ""; + settings_save(&menu->settings); + } + } + if (menu->settings.rom_autoload_enabled) { + menu->browser.directory = path_init(menu->storage_prefix, menu->settings.rom_autoload_path); + menu->load.rom_path = path_clone_push(menu->browser.directory, menu->settings.rom_autoload_filename); + menu->boot_pending.rom_file = true; + menu->next_mode = MENU_MODE_LOAD_ROM; + + return; + } + menu->next_mode = MENU_MODE_BROWSER; } From e8c16a7af62a2886117c65fd34397126059b2af5 Mon Sep 17 00:00:00 2001 From: Guillermo Horacio Romero Villa <65469983+E1ite007@users.noreply.github.com> Date: Tue, 5 Nov 2024 04:36:36 -0600 Subject: [PATCH 40/47] Added new boxart following the pre-release folder structure (#152) ## Description Following #130 and with #135 efforts, I created this new database following the newer folder structure. ## Motivation and Context Adding compatibility for the newest `rolling pre-release`. ## How Has This Been Tested? ## Screenshots ## Types of changes - [x] Improvement (non-breaking change that adds a new feature) - [ ] Bug fix (fixes an issue) - [ ] Breaking change (breaking change) - [ ] Documentation Improvement - [ ] Config and build (change in the configuration and build system, has no impact on code or features) ## Checklist: - [x] My code follows the code style of this project. - [ ] My change requires a change to the documentation. - [x] I have updated the documentation accordingly. - [ ] I have added tests to cover my changes. - [ ] All new and existing tests passed. Signed-off-by: E1ite007 ## Summary by CodeRabbit - **New Features** - Introduced a "GamePak sprites" section with guidelines for using N64 GamePak sprites. - Added a "Compatibility mode" subsection detailing deprecated filename support. - Included a "Sounds" subsection listing sound effects and their licenses. - Provided a link to a boxart pack that adheres to the new structure. - **Documentation** - Enhanced readability with formatting updates and additional examples. --------- Co-authored-by: Robin Jones --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 8fae66a3..c44efae5 100644 --- a/README.md +++ b/README.md @@ -74,6 +74,9 @@ i.e. for GoldenEye, this would be `sd:/menu/boxart/N/G/E/boxart_front.png`. **Note1:** Excluding the region ID may show the wrong boxart. **Note2:** For future support, boxart sprites should also include: `boxart_back.png`, `boxart_top.png`, `boxart_bottom.png`, `boxart_left.png`, `boxart_right.png`. +As a starting point, here is a link to a boxart pack following the new structure, including `boxart_front.png` and failback images: +* [Link](https://drive.google.com/file/d/1IpCmFqmGgGwKKmlRBxYObfFR9XywaC6n/view?usp=drive_link) + #### Compatibilty mode If you cannot yet satisfy the correct boxart layout, The menu still has **deprecated** support for filenames containing the Game ID. From 2fc4a6a6c12a6151edb77daaed102203317e8c31 Mon Sep 17 00:00:00 2001 From: Robin Jones Date: Tue, 5 Nov 2024 18:20:35 +0000 Subject: [PATCH 41/47] Update libdragon --- libdragon | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libdragon b/libdragon index e93802ae..52950162 160000 --- a/libdragon +++ b/libdragon @@ -1 +1 @@ -Subproject commit e93802aec7e7839710281824ce2e9e4689b3a01d +Subproject commit 5295016230d657cd6c7fce5b6ed4a342538e09f5 From fb0a04e048ed78a96c32d59397b1894f9b4aec61 Mon Sep 17 00:00:00 2001 From: Robin Jones Date: Tue, 5 Nov 2024 21:32:17 +0000 Subject: [PATCH 42/47] header documentation improvements --- src/boot/boot_io.h | 77 ++++++++++++------ src/boot/vr4300_asm.h | 52 +++++++----- src/menu/mp3_player.h | 181 ++++++++++++++++++++++++++++++++++++------ 3 files changed, 240 insertions(+), 70 deletions(-) diff --git a/src/boot/boot_io.h b/src/boot/boot_io.h index 6923e4df..eb9f5cc6 100644 --- a/src/boot/boot_io.h +++ b/src/boot/boot_io.h @@ -7,41 +7,79 @@ #ifndef BOOT_IO_H__ #define BOOT_IO_H__ - #include #include - +/** + * @typedef io8_t + * @brief 8-bit volatile IO type. + */ typedef volatile uint8_t io8_t; + +/** + * @typedef io32_t + * @brief 32-bit volatile IO type. + */ typedef volatile uint32_t io32_t; - +/** + * @brief Convert an address to its uncached equivalent. + * + * This macro takes an address and converts it to its uncached equivalent + * by setting the appropriate bits. + * + * @param address The address to convert. + * @return The uncached equivalent of the address. + */ #define UNCACHED(address) ((typeof(address)) (((io32_t) (address)) | (0xA0000000UL))) -/** @brief Memory Structure. */ +/** + * @brief Memory Structure. + * + * This structure represents the memory layout for the SP (Signal Processor), + * containing both Data Memory (DMEM) and Instruction Memory (IMEM). + */ typedef struct { - io32_t DMEM[1024]; - io32_t IMEM[1024]; + io32_t DMEM[1024]; /**< Data Memory (DMEM) array of 1024 32-bit words. */ + io32_t IMEM[1024]; /**< Instruction Memory (IMEM) array of 1024 32-bit words. */ } sp_mem_t; +/** + * @brief Base address for SP memory. + */ #define SP_MEM_BASE (0x04000000UL) + +/** + * @brief Pointer to the SP memory structure. + */ #define SP_MEM ((sp_mem_t *) SP_MEM_BASE) -/** @brief SP Registers Structure. */ +/** + * @brief SP Registers Structure. + * + * This structure represents the registers for the SP (Signal Processor). + */ typedef struct { - io32_t PADDR; - io32_t MADDR; - io32_t RD_LEN; - io32_t WR_LEN; - io32_t SR; - io32_t DMA_FULL; - io32_t DMA_BUSY; - io32_t SEMAPHORE; + io32_t PADDR; /**< Physical Address Register. */ + io32_t MADDR; /**< Memory Address Register. */ + io32_t RD_LEN; /**< Read Length Register. */ + io32_t WR_LEN; /**< Write Length Register. */ + io32_t SR; /**< Status Register. */ + io32_t DMA_FULL; /**< DMA Full Register. */ + io32_t DMA_BUSY; /**< DMA Busy Register. */ + io32_t SEMAPHORE; /**< Semaphore Register. */ io32_t __reserved[0xFFF8]; io32_t PC; } sp_regs_t; +/** + * @brief Base address for SP registers. + */ #define SP_BASE (0x04040000UL) + +/** + * @brief Pointer to the SP registers structure. + */ #define SP ((sp_regs_t *) SP_BASE) #define SP_SR_HALT (1 << 0) @@ -85,7 +123,6 @@ typedef struct { #define SP_SR_CLR_SIG7 (1 << 23) #define SP_SR_SET_SIG7 (1 << 24) - /** @brief DPC Registers Structure. */ typedef struct { io32_t START; @@ -123,7 +160,6 @@ typedef struct { #define DPC_SR_CLR_CMD_CTR (1 << 8) #define DPC_SR_CLR_CLOCK_CTR (1 << 9) - /** @brief Video Interface Registers Structure. */ typedef struct { /** @brief The Control Register. */ @@ -198,7 +234,6 @@ typedef struct { #define AI_SR_FIFO_FULL (1 << 31) #define AI_CR_DMA_ON (1 << 0) - /** @brief Peripheral Interface Register Structure. */ typedef struct { /** @brief The Memory Address. */ @@ -233,15 +268,12 @@ typedef struct { #define PI_SR_RESET (1 << 0) #define PI_SR_CLR_INTR (1 << 1) - #define ROM_DDIPL_BASE (0x06000000UL) #define ROM_DDIPL ((io32_t *) ROM_DDIPL_BASE) - #define ROM_CART_BASE (0x10000000UL) #define ROM_CART ((io32_t *) ROM_CART_BASE) - static inline uint32_t cpu_io_read (io32_t *address) { io32_t *uncached = UNCACHED(address); uint32_t value = *uncached; @@ -253,5 +285,4 @@ static inline void cpu_io_write (io32_t *address, uint32_t value) { *uncached = value; } - -#endif +#endif /* BOOT_IO_H__ */ diff --git a/src/boot/vr4300_asm.h b/src/boot/vr4300_asm.h index 59dfd77c..b2736e21 100644 --- a/src/boot/vr4300_asm.h +++ b/src/boot/vr4300_asm.h @@ -3,37 +3,47 @@ #include +/** + * @brief VR4300 Instruction Structure + * + * This structure represents a VR4300 instruction, which can be of different types (R-type, I-type, J-type, etc.). + */ typedef union { - uint32_t raw; + uint32_t raw; /**< Raw 32-bit instruction */ struct { - uint32_t op : 6; - uint32_t rs : 5; - uint32_t rt : 5; - uint32_t imm : 16; - } i_type; + uint32_t op : 6; /**< Opcode field */ + uint32_t rs : 5; /**< Source register */ + uint32_t rt : 5; /**< Target register */ + uint32_t imm : 16; /**< Immediate value */ + } i_type; /**< I-type instruction format */ struct { - uint32_t op : 6; - uint32_t target : 26; - } j_type; + uint32_t op : 6; /**< Opcode field */ + uint32_t target : 26; /**< Target Address field */ + } j_type; /**< J-type instruction format */ struct { - uint32_t op : 6; - uint32_t rs : 5; - uint32_t rt : 5; - uint32_t rd : 5; - uint32_t sa : 5; - uint32_t funct : 6; - } r_type; + uint32_t op : 6; /**< Opcode field */ + uint32_t rs : 5; /**< Source register */ + uint32_t rt : 5; /**< Target register */ + uint32_t rd : 5; /**< Destination register */ + uint32_t sa : 5; /**< Shift amount */ + uint32_t funct : 6; /**< Function field */ + } r_type; /**< Alternate R-type instruction format */ struct { - uint32_t op : 6; - uint32_t co : 1; - uint32_t funct : 25; - } c_type; + uint32_t op : 6; /**< Opcode field */ + uint32_t co : 1; /**< Coprocessor operation bit */ + uint32_t funct : 25; /**< Function field */ + } c_type; /**< C-type instruction format */ } vr4300_instruction_t; +/** + * @brief VR4300 Opcode Enumeration + * + * Enumeration for different opcodes used in VR4300 instructions. + */ typedef enum { OP_SPECIAL, OP_REGIMM, @@ -394,4 +404,4 @@ typedef enum { #define I_SRL(rd, rt, sa) __ASM_R_INST(OP_SPECIAL, 0, rt, rd, sa, FUNCT_SRL) #define I_SW(rt, offset, base) __ASM_I_INST(OP_SW, base, rt, offset) -#endif +#endif /* VR4300_ASM_H__ */ diff --git a/src/menu/mp3_player.h b/src/menu/mp3_player.h index baea06bf..20f6c485 100644 --- a/src/menu/mp3_player.h +++ b/src/menu/mp3_player.h @@ -7,37 +7,166 @@ #ifndef MP3_PLAYER_H__ #define MP3_PLAYER_H__ - #include - -/** @brief MP3 file error enumeration */ +/** + * @brief MP3 file error enumeration. + * + * Enumeration for different types of errors that can occur in the MP3 player. + */ typedef enum { - MP3PLAYER_OK, - MP3PLAYER_ERR_OUT_OF_MEM, - MP3PLAYER_ERR_IO, - MP3PLAYER_ERR_NO_FILE, - MP3PLAYER_ERR_INVALID_FILE, + MP3PLAYER_OK, /**< No error */ + MP3PLAYER_ERR_OUT_OF_MEM, /**< Out of memory error */ + MP3PLAYER_ERR_IO, /**< Input/Output error */ + MP3PLAYER_ERR_NO_FILE, /**< No file found error */ + MP3PLAYER_ERR_INVALID_FILE, /**< Invalid file error */ } mp3player_err_t; +/** + * @brief Initialize the MP3 player mixer. + * + * This function initializes the mixer for the MP3 player. + */ +void mp3player_mixer_init(void); -void mp3player_mixer_init (void); -mp3player_err_t mp3player_init (void); -void mp3player_deinit (void); -mp3player_err_t mp3player_load (char *path); -void mp3player_unload (void); -mp3player_err_t mp3player_process (void); -bool mp3player_is_playing (void); -bool mp3player_is_finished (void); -mp3player_err_t mp3player_play (void); -void mp3player_stop (void); -mp3player_err_t mp3player_toggle (void); -void mp3player_mute (bool mute); -mp3player_err_t mp3player_seek (int seconds); -float mp3player_get_duration (void); -float mp3player_get_bitrate (void); -int mp3player_get_samplerate (void); -float mp3player_get_progress (void); +/** + * @brief Initialize the MP3 player. + * + * This function initializes the MP3 player and prepares it for playback. + * + * @return mp3player_err_t Error code indicating the result of the initialization. + */ +mp3player_err_t mp3player_init(void); +/** + * @brief Deinitialize the MP3 player. + * + * This function deinitializes the MP3 player and releases any resources. + */ +void mp3player_deinit(void); -#endif +/** + * @brief Load an MP3 file. + * + * This function loads an MP3 file from the specified path. + * + * @param path Path to the MP3 file. + * @return mp3player_err_t Error code indicating the result of the load operation. + */ +mp3player_err_t mp3player_load(char *path); + +/** + * @brief Unload the current MP3 file. + * + * This function unloads the currently loaded MP3 file. + */ +void mp3player_unload(void); + +/** + * @brief Process the MP3 player. + * + * This function processes the MP3 player, handling playback and other operations. + * + * @return mp3player_err_t Error code indicating the result of the process operation. + */ +mp3player_err_t mp3player_process(void); + +/** + * @brief Check if the MP3 player is playing. + * + * This function checks if the MP3 player is currently playing. + * + * @return true if the MP3 player is playing, false otherwise. + */ +bool mp3player_is_playing(void); + +/** + * @brief Check if the MP3 player has finished playing. + * + * This function checks if the MP3 player has finished playing the current file. + * + * @return true if the MP3 player has finished playing, false otherwise. + */ +bool mp3player_is_finished(void); + +/** + * @brief Start playback of the MP3 file. + * + * This function starts playback of the currently loaded MP3 file. + * + * @return mp3player_err_t Error code indicating the result of the play operation. + */ +mp3player_err_t mp3player_play(void); + +/** + * @brief Stop playback of the MP3 file. + * + * This function stops playback of the currently loaded MP3 file. + */ +void mp3player_stop(void); + +/** + * @brief Toggle playback of the MP3 file. + * + * This function toggles playback of the currently loaded MP3 file. + * + * @return mp3player_err_t Error code indicating the result of the toggle operation. + */ +mp3player_err_t mp3player_toggle(void); + +/** + * @brief Mute or unmute the MP3 player. + * + * This function mutes or unmutes the MP3 player. + * + * @param mute true to mute, false to unmute. + */ +void mp3player_mute(bool mute); + +/** + * @brief Seek to a specific position in the MP3 file. + * + * This function seeks to a specific position in the currently loaded MP3 file. + * + * @param seconds Number of seconds to seek. + * @return mp3player_err_t Error code indicating the result of the seek operation. + */ +mp3player_err_t mp3player_seek(int seconds); + +/** + * @brief Get the duration of the MP3 file. + * + * This function gets the duration of the currently loaded MP3 file. + * + * @return float Duration of the MP3 file in seconds. + */ +float mp3player_get_duration(void); + +/** + * @brief Get the bitrate of the MP3 file. + * + * This function gets the bitrate of the currently loaded MP3 file. + * + * @return float Bitrate of the MP3 file in kbps. + */ +float mp3player_get_bitrate(void); + +/** + * @brief Get the sample rate of the MP3 file. + * + * This function gets the sample rate of the currently loaded MP3 file. + * + * @return int Sample rate of the MP3 file in Hz. + */ +int mp3player_get_samplerate(void); + +/** + * @brief Get the current playback progress. + * + * This function gets the current playback progress of the MP3 file. + * + * @return float Current playback progress as a percentage (0.0 to 100.0). + */ +float mp3player_get_progress(void); + +#endif /* MP3_PLAYER_H__ */ From 1e51108b0d9f2e9d2d242c03093f4dc39cc5406f Mon Sep 17 00:00:00 2001 From: Robin Jones Date: Tue, 5 Nov 2024 22:41:19 +0000 Subject: [PATCH 43/47] Further header documentation improvements --- src/menu/fonts.h | 42 ++++++++++++++++++--------- src/menu/png_decoder.h | 65 ++++++++++++++++++++++++++++++++++-------- src/menu/sound.h | 44 +++++++++++++++++++--------- src/menu/usb_comm.h | 26 +++++++++++++---- 4 files changed, 134 insertions(+), 43 deletions(-) diff --git a/src/menu/fonts.h b/src/menu/fonts.h index 9fb00092..97dd54bd 100644 --- a/src/menu/fonts.h +++ b/src/menu/fonts.h @@ -7,23 +7,39 @@ #ifndef FONTS_H__ #define FONTS_H__ -/** @brief Font type enumeration. */ +/** + * @brief Font type enumeration. + * + * This enumeration defines the different types of fonts that can be used + * in the menu system. + */ typedef enum { - FNT_DEFAULT = 1, + FNT_DEFAULT = 1, /**< Default font type */ } menu_font_type_t; -/** @brief Font style enumeration. */ +/** + * @brief Font style enumeration. + * + * This enumeration defines the different styles of fonts that can be used + * in the menu system. + */ typedef enum { - STL_DEFAULT = 0, - STL_GREEN, - STL_BLUE, - STL_YELLOW, - STL_ORANGE, - STL_GRAY, + STL_DEFAULT = 0, /**< Default font style */ + STL_GREEN, /**< Green font style */ + STL_BLUE, /**< Blue font style */ + STL_YELLOW, /**< Yellow font style */ + STL_ORANGE, /**< Orange font style */ + STL_GRAY, /**< Gray font style */ } menu_font_style_t; +/** + * @brief Initialize fonts. + * + * This function initializes the fonts used in the menu system. It can load + * custom fonts from the specified path. + * + * @param custom_font_path Path to the custom font file. + */ +void fonts_init(char *custom_font_path); -void fonts_init (char *custom_font_path); - - -#endif +#endif /* FONTS_H__ */ diff --git a/src/menu/png_decoder.h b/src/menu/png_decoder.h index ea7977f7..a506e136 100644 --- a/src/menu/png_decoder.h +++ b/src/menu/png_decoder.h @@ -7,27 +7,68 @@ #ifndef PNG_DECODER_H__ #define PNG_DECODER_H__ - #include - -/** @brief PNG decoder errors */ +/** + * @brief PNG decoder errors + * + * Enumeration for different types of errors that can occur in the PNG decoder. + */ typedef enum { - PNG_OK, - PNG_ERR_INT, - PNG_ERR_BUSY, - PNG_ERR_OUT_OF_MEM, - PNG_ERR_NO_FILE, - PNG_ERR_BAD_FILE, + PNG_OK, /**< No error */ + PNG_ERR_INT, /**< Internal error */ + PNG_ERR_BUSY, /**< Decoder is busy */ + PNG_ERR_OUT_OF_MEM, /**< Out of memory error */ + PNG_ERR_NO_FILE, /**< No file found error */ + PNG_ERR_BAD_FILE, /**< Bad file error */ } png_err_t; +/** + * @brief PNG decoder callback type. + * + * This typedef defines the callback function type used by the PNG decoder. + * + * @param err Error code indicating the result of the decoding process. + * @param decoded_image Pointer to the decoded image surface. + * @param callback_data User-defined data passed to the callback function. + */ typedef void png_callback_t (png_err_t err, surface_t *decoded_image, void *callback_data); - +/** + * @brief Start the PNG decoding process. + * + * This function starts the PNG decoding process for the specified file. + * + * @param path Path to the PNG file. + * @param max_width Maximum width of the decoded image. + * @param max_height Maximum height of the decoded image. + * @param callback Callback function to be called when decoding is complete. + * @param callback_data User-defined data to be passed to the callback function. + * @return png_err_t Error code indicating the result of the start operation. + */ png_err_t png_decoder_start (char *path, int max_width, int max_height, png_callback_t *callback, void *callback_data); + +/** + * @brief Abort the PNG decoding process. + * + * This function aborts the ongoing PNG decoding process. + */ void png_decoder_abort (void); + +/** + * @brief Get the progress of the PNG decoding process. + * + * This function returns the current progress of the PNG decoding process as a percentage. + * + * @return float Current progress of the decoding process (0.0 to 100.0). + */ float png_decoder_get_progress (void); + +/** + * @brief Poll the PNG decoder. + * + * This function polls the PNG decoder to handle any ongoing decoding tasks. + */ void png_decoder_poll (void); - -#endif +#endif /* PNG_DECODER_H__ */ diff --git a/src/menu/sound.h b/src/menu/sound.h index e086a362..97d83d23 100644 --- a/src/menu/sound.h +++ b/src/menu/sound.h @@ -9,28 +9,46 @@ #include -#define SOUND_MP3_PLAYER_CHANNEL (0) -#define SOUND_SFX_CHANNEL (2) +#define SOUND_MP3_PLAYER_CHANNEL (0) /**< Channel for MP3 player sound */ +#define SOUND_SFX_CHANNEL (2) /**< Channel for sound effects */ /** * @brief Enumeration of available sound effects for menu interactions. + * + * This enumeration defines the different sound effects that can be used + * for menu interactions. */ typedef enum { - SFX_CURSOR, - SFX_ERROR, - SFX_ENTER, - SFX_EXIT, - SFX_SETTING, + SFX_CURSOR, /**< Sound effect for cursor movement */ + SFX_ERROR, /**< Sound effect for error */ + SFX_ENTER, /**< Sound effect for entering a menu */ + SFX_EXIT, /**< Sound effect for exiting a menu */ + SFX_SETTING, /**< Sound effect for changing a setting */ } sound_effect_t; - -void sound_init_default (void); -void sound_init_mp3_playback (void); +/** + * @brief Initialize the default sound system. + * + * This function initializes the default sound system, setting up + * necessary resources and configurations. + */ +void sound_init_default(void); /** - * @brief Initialize sound effects system. + * @brief Initialize the MP3 playback system. + * + * This function initializes the MP3 playback system, preparing it + * for playing MP3 files. */ -void sound_init_sfx (void); +void sound_init_mp3_playback(void); + +/** + * @brief Initialize the sound effects system. + * + * This function initializes the sound effects system, setting up + * necessary resources and configurations for playing sound effects. + */ +void sound_init_sfx(void); /** * @brief Enable or disable sound effects. @@ -46,4 +64,4 @@ void sound_play_effect(sound_effect_t sfx); void sound_deinit (void); void sound_poll (void); -#endif +#endif /* SOUND_H__ */ diff --git a/src/menu/usb_comm.h b/src/menu/usb_comm.h index c7f9a9ed..0b914643 100644 --- a/src/menu/usb_comm.h +++ b/src/menu/usb_comm.h @@ -2,20 +2,36 @@ * @file usb_comm.h * @brief USB communication subsystem * @ingroup menu + * + * This file contains the declarations for the USB communication subsystem + * used in the menu system. */ #ifndef USB_COMM_H__ #define USB_COMM_H__ - #include "menu_state.h" - #ifndef NDEBUG -void usb_comm_poll (menu_t *menu); +/** + * @brief Poll the USB communication subsystem. + * + * This function polls the USB communication subsystem to handle any + * incoming or outgoing data. It is only available in debug builds. + * + * @param menu Pointer to the menu structure. + */ +void usb_comm_poll(menu_t *menu); #else +/** + * @brief Poll the USB communication subsystem (no-op in release builds). + * + * This macro is a no-op in release builds, where USB communication polling + * is disabled. + * + * @param menu Pointer to the menu structure. + */ #define usb_comm_poll(menu) #endif - -#endif +#endif /* USB_COMM_H__ */ From 527e27525d2e793c010b323dd37027e2584f9727 Mon Sep 17 00:00:00 2001 From: Robin Jones Date: Tue, 5 Nov 2024 23:10:29 +0000 Subject: [PATCH 44/47] Further header documentation improvements --- src/flashcart/64drive/README.md | 2 +- src/flashcart/sc64/README.md | 2 +- src/menu/disk_info.h | 12 +++++++++++- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/flashcart/64drive/README.md b/src/flashcart/64drive/README.md index 6809afcc..6c6859c0 100644 --- a/src/flashcart/64drive/README.md +++ b/src/flashcart/64drive/README.md @@ -1,4 +1,4 @@ -## 64drive developer notes +# 64drive developer notes ### Official documentation diff --git a/src/flashcart/sc64/README.md b/src/flashcart/sc64/README.md index 5071466f..fe313411 100644 --- a/src/flashcart/sc64/README.md +++ b/src/flashcart/sc64/README.md @@ -1,4 +1,4 @@ -## SummerCart64 developer notes +# SummerCart64 developer notes ### Official documentation diff --git a/src/menu/disk_info.h b/src/menu/disk_info.h index fe5175ec..656768ff 100644 --- a/src/menu/disk_info.h +++ b/src/menu/disk_info.h @@ -52,7 +52,17 @@ typedef struct { } disk_info_t; +/** + * @brief Loads disk information from the specified path. + * + * This function reads the disk information from the given path and populates + * the provided disk_info structure with the relevant data. + * + * @param path A pointer to a path_t structure that specifies the path to the disk. + * @param disk_info A pointer to a disk_info_t structure where the disk information will be stored. + * @return A disk_err_t value indicating the success or failure of the operation. + */ disk_err_t disk_info_load (path_t *path, disk_info_t *disk_info); -#endif +#endif /* DISK_INFO_H__ */ From 0d2deaa4f4b277f6b7e7d79c956e78ac820497ec Mon Sep 17 00:00:00 2001 From: Robin Jones Date: Tue, 5 Nov 2024 23:34:14 +0000 Subject: [PATCH 45/47] Further header documentation improvements --- src/menu/components.h | 312 +++++++++++++++++++++++++++++++----------- 1 file changed, 232 insertions(+), 80 deletions(-) diff --git a/src/menu/components.h b/src/menu/components.h index 6d31a3d3..f15a6ba5 100644 --- a/src/menu/components.h +++ b/src/menu/components.h @@ -1,109 +1,261 @@ /** * @file components.h - * @brief Menu Components + * @brief Menu Graphical User Interface Components * @ingroup menu */ #ifndef COMPONENTS_H__ #define COMPONENTS_H__ - #include #include "menu_state.h" -/** @brief File image Enumeration. */ -typedef enum { - - /** @brief Boxart image from the front */ - IMAGE_BOXART_FRONT, - - /** @brief Boxart image from the back */ - IMAGE_BOXART_BACK, - - /** @brief Boxart image from the top */ - IMAGE_BOXART_TOP, - - /** @brief Boxart image from the bottom */ - IMAGE_BOXART_BOTTOM, - - /** @brief Boxart image from the left side */ - IMAGE_BOXART_LEFT, - - /** @brief Boxart image from the right side */ - IMAGE_BOXART_RIGHT, - - /** @brief GamePak image from the front */ - IMAGE_GAMEPAK_FRONT, - - /** @brief GamePak image from the back */ - IMAGE_GAMEPAK_BACK, - - /** @brief File image thumbnail */ - IMAGE_THUMBNAIL, - - /** @brief List end marker */ - IMAGE_TYPE_END - -} file_image_type_t; - - /** - * @addtogroup - * @{ menu_components + * @addtogroup menu_ui_components + * @{ */ -void component_box_draw (int x0, int y0, int x1, int y1, color_t color); -void component_border_draw (int x0, int y0, int x1, int y1); -void component_layout_draw (void); -void component_progressbar_draw (int x0, int y0, int x1, int y1, float progress); -void component_seekbar_draw (float progress); -void component_loader_draw (float position); -void component_scrollbar_draw (int x, int y, int width, int height, int position, int items, int visible_items); -void component_list_scrollbar_draw (int position, int items, int visible_items); -void component_dialog_draw (int width, int height); -void component_messagebox_draw (char *fmt, ...); -void component_main_text_draw (rdpq_align_t align, rdpq_valign_t valign, char *fmt, ...); -void component_actions_bar_text_draw (rdpq_align_t align, rdpq_valign_t valign, char *fmt, ...); +/** + * @brief File image Enumeration. + * + * Enumeration for different types of file images used in the GUI. + */ +typedef enum { + IMAGE_BOXART_FRONT, /**< Boxart image from the front */ + IMAGE_BOXART_BACK, /**< Boxart image from the back */ + IMAGE_BOXART_TOP, /**< Boxart image from the top */ + IMAGE_BOXART_BOTTOM, /**< Boxart image from the bottom */ + IMAGE_BOXART_LEFT, /**< Boxart image from the left side */ + IMAGE_BOXART_RIGHT, /**< Boxart image from the right side */ + IMAGE_GAMEPAK_FRONT, /**< GamePak image from the front */ + IMAGE_GAMEPAK_BACK, /**< GamePak image from the back */ + IMAGE_THUMBNAIL, /**< File image thumbnail */ + IMAGE_TYPE_END /**< List end marker */ +} file_image_type_t; -void component_background_init (char *cache_location); -void component_background_free (void); -void component_background_replace_image (surface_t *image); -void component_background_draw (void); +/** + * @brief Draw a box component. + * + * @param x0 Starting x-coordinate. + * @param y0 Starting y-coordinate. + * @param x1 Ending x-coordinate. + * @param y1 Ending y-coordinate. + * @param color Color of the box. + */ +void component_box_draw(int x0, int y0, int x1, int y1, color_t color); -void component_file_list_draw (entry_t *list, int entries, int selected); +/** + * @brief Draw a border component. + * + * @param x0 Starting x-coordinate. + * @param y0 Starting y-coordinate. + * @param x1 Ending x-coordinate. + * @param y1 Ending y-coordinate. + */ +void component_border_draw(int x0, int y0, int x1, int y1); +/** + * @brief Draw the layout component. + */ +void component_layout_draw(void); + +/** + * @brief Draw a progress bar component. + * + * @param x0 Starting x-coordinate. + * @param y0 Starting y-coordinate. + * @param x1 Ending x-coordinate. + * @param y1 Ending y-coordinate. + * @param progress Progress value (0.0 to 1.0). + */ +void component_progressbar_draw(int x0, int y0, int x1, int y1, float progress); + +/** + * @brief Draw a seek bar component. + * + * @param progress Progress value (0.0 to 1.0). + */ +void component_seekbar_draw(float progress); + +/** + * @brief Draw a loader component. + * + * @param position Position value (0.0 to 1.0). + */ +void component_loader_draw(float position); + +/** + * @brief Draw a scrollbar component. + * + * @param x Starting x-coordinate. + * @param y Starting y-coordinate. + * @param width Width of the scrollbar. + * @param height Height of the scrollbar. + * @param position Current position. + * @param items Total number of items. + * @param visible_items Number of visible items. + */ +void component_scrollbar_draw(int x, int y, int width, int height, int position, int items, int visible_items); + +/** + * @brief Draw a list scrollbar component. + * + * @param position Current position. + * @param items Total number of items. + * @param visible_items Number of visible items. + */ +void component_list_scrollbar_draw(int position, int items, int visible_items); + +/** + * @brief Draw a dialog component. + * + * @param width Width of the dialog. + * @param height Height of the dialog. + */ +void component_dialog_draw(int width, int height); + +/** + * @brief Draw a message box component. + * + * @param fmt Format string for the message. + * @param ... Additional arguments for the format string. + */ +void component_messagebox_draw(char *fmt, ...); + +/** + * @brief Draw the main text component. + * + * @param align Horizontal alignment. + * @param valign Vertical alignment. + * @param fmt Format string for the text. + * @param ... Additional arguments for the format string. + */ +void component_main_text_draw(rdpq_align_t align, rdpq_valign_t valign, char *fmt, ...); + +/** + * @brief Draw the actions bar text component. + * + * @param align Horizontal alignment. + * @param valign Vertical alignment. + * @param fmt Format string for the text. + * @param ... Additional arguments for the format string. + */ +void component_actions_bar_text_draw(rdpq_align_t align, rdpq_valign_t valign, char *fmt, ...); + +/** + * @brief Initialize the background component. + * + * @param cache_location Location of the cache. + */ +void component_background_init(char *cache_location); + +/** + * @brief Free the background component resources. + */ +void component_background_free(void); + +/** + * @brief Replace the background image. + * + * @param image New background image. + */ +void component_background_replace_image(surface_t *image); + +/** + * @brief Draw the background component. + */ +void component_background_draw(void); + +/** + * @brief Draw the file list component. + * + * @param list List of entries. + * @param entries Number of entries. + * @param selected Index of the selected entry. + */ +void component_file_list_draw(entry_t *list, int entries, int selected); + +/** + * @brief Context menu structure. + */ typedef struct component_context_menu { - int row_count; - int row_selected; - bool hide_pending; - struct component_context_menu *parent; - struct component_context_menu *submenu; + int row_count; /**< Number of rows in the context menu */ + int row_selected; /**< Index of the selected row */ + bool hide_pending; /**< Flag to indicate if hiding is pending */ + struct component_context_menu *parent; /**< Pointer to the parent context menu */ + struct component_context_menu *submenu; /**< Pointer to the submenu */ struct { - const char *text; - void (*action) (menu_t *menu, void *arg); - void *arg; - struct component_context_menu *submenu; - } list[]; + const char *text; /**< Text of the menu item */ + void (*action)(menu_t *menu, void *arg); /**< Action function for the menu item */ + void *arg; /**< Argument for the action function */ + struct component_context_menu *submenu; /**< Pointer to the submenu */ + } list[]; /**< List of menu items */ } component_context_menu_t; -#define COMPONENT_CONTEXT_MENU_LIST_END { .text = NULL } +#define COMPONENT_CONTEXT_MENU_LIST_END { .text = NULL } /**< End marker for the context menu list */ -void component_context_menu_init (component_context_menu_t *cm); -void component_context_menu_show (component_context_menu_t *cm); -bool component_context_menu_process (menu_t *menu, component_context_menu_t *cm); -void component_context_menu_draw (component_context_menu_t *cm); +/** + * @brief Initialize the context menu component. + * + * @param cm Pointer to the context menu structure. + */ +void component_context_menu_init(component_context_menu_t *cm); -/** @brief Box Art Structure. */ +/** + * @brief Show the context menu component. + * + * @param cm Pointer to the context menu structure. + */ +void component_context_menu_show(component_context_menu_t *cm); + +/** + * @brief Process the context menu component. + * + * @param menu Pointer to the menu structure. + * @param cm Pointer to the context menu structure. + * @return True if the context menu was processed, false otherwise. + */ +bool component_context_menu_process(menu_t *menu, component_context_menu_t *cm); + +/** + * @brief Draw the context menu component. + * + * @param cm Pointer to the context menu structure. + */ +void component_context_menu_draw(component_context_menu_t *cm); + +/** + * @brief Box Art Structure. + */ typedef struct { - bool loading; - surface_t *image; + bool loading; /**< Flag to indicate if the box art is loading */ + surface_t *image; /**< Pointer to the box art image */ } component_boxart_t; -component_boxart_t *component_boxart_init (const char *storage_prefix, char *game_code, file_image_type_t current_image_view); -void component_boxart_free (component_boxart_t *b); -void component_boxart_draw (component_boxart_t *b); +/** + * @brief Initialize the box art component. + * + * @param storage_prefix Prefix for the storage location. + * @param game_code Game code for the box art. + * @param current_image_view Current image view type. + * @return Pointer to the initialized box art component. + */ +component_boxart_t *component_boxart_init(const char *storage_prefix, char *game_code, file_image_type_t current_image_view); -/** @} */ /* menu_components */ +/** + * @brief Free the box art component resources. + * + * @param b Pointer to the box art component. + */ +void component_boxart_free(component_boxart_t *b); +/** + * @brief Draw the box art component. + * + * @param b Pointer to the box art component. + */ +void component_boxart_draw(component_boxart_t *b); -#endif +/** @} */ /* menu_ui_components */ + +#endif /* COMPONENTS_H__ */ From 17c214537ffa555900af3d72d348d27419612ac4 Mon Sep 17 00:00:00 2001 From: Robin Jones Date: Tue, 5 Nov 2024 23:40:42 +0000 Subject: [PATCH 46/47] Minor fix for disk load error Don't bother to load boxart after. --- src/menu/views/load_disk.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/menu/views/load_disk.c b/src/menu/views/load_disk.c index 781ebe27..9ba914d9 100644 --- a/src/menu/views/load_disk.c +++ b/src/menu/views/load_disk.c @@ -169,6 +169,7 @@ void view_load_disk_init (menu_t *menu) { disk_err_t err = disk_info_load(menu->load.disk_path, &menu->load.disk_info); if (err != DISK_OK) { menu_show_error(menu, convert_error_message(err)); + return; } boxart = component_boxart_init(menu->storage_prefix, menu->load.disk_info.id, IMAGE_BOXART_FRONT); From e7608dc557d9f46bd0439d2dd03c42550f04cfe4 Mon Sep 17 00:00:00 2001 From: Robin Jones Date: Thu, 7 Nov 2024 20:16:35 +0000 Subject: [PATCH 47/47] Add ability to adjust RTC (#107) ## Description This PR adds the ability to set the time from the menu. The underlying logic is sound given what is currently available within libdragon, but expected changes are noted (like `settimeofday`) for future improvement and will need to be revisited once available. A future PR will need to add better GUI components for numeric control. ## Motivation and Context #106 ## How Has This Been Tested? locally on a SC64 ## Screenshots ## Types of changes - [x] Improvement (non-breaking change that adds a new feature) - [ ] Bug fix (fixes an issue) - [ ] Breaking change (breaking change) - [ ] Config and build (change in the configuration and build system, has no impact on code or features) ## Checklist: - [ ] My code follows the code style of this project. - [ ] My change requires a change to the documentation. - [ ] I have updated the documentation accordingly. - [ ] I have added tests to cover my changes. - [ ] All new and existing tests passed. Signed-off-by: GITHUB_USER --- src/menu/views/rtc.c | 212 ++++++++++++++++++++++++++++++----- src/menu/views/system_info.c | 2 +- 2 files changed, 184 insertions(+), 30 deletions(-) diff --git a/src/menu/views/rtc.c b/src/menu/views/rtc.c index 6be481a3..c93d7aa2 100644 --- a/src/menu/views/rtc.c +++ b/src/menu/views/rtc.c @@ -1,26 +1,165 @@ -#include +#include +#include +#include +#include #include "../sound.h" #include "views.h" -// FIXME: add implementation! -// struct { -// uint16_t seconds; -// uint16_t minutes; -// uint16_t hours; -// uint16_t day; -// uint16_t month; -// uint16_t year; -// } adjusted_datetime; +#define MAX(a,b) ({ typeof(a) _a = a; typeof(b) _b = b; _a > _b ? _a : _b; }) +#define MIN(a,b) ({ typeof(a) _a = a; typeof(b) _b = b; _a < _b ? _a : _b; }) +#define CLAMP(x, min, max) (MIN(MAX((x), (min)), (max))) -// static void save_adjusted_datetime () { +#define YEAR_MIN 1996 +#define YEAR_MAX 2095 -// } +typedef enum { + RTC_EDIT_YEAR, + RTC_EDIT_MONTH, + RTC_EDIT_DAY, + RTC_EDIT_HOUR, + RTC_EDIT_MIN, + RTC_EDIT_SEC, +} rtc_field_t; + +static const char* const DAYS_OF_WEEK[7] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; + +static struct tm rtc_tm = {0}; +static bool is_editing_mode; +static rtc_field_t editing_field_type; + +int wrap( uint16_t val, uint16_t min, uint16_t max ) { + if( val < min ) return max; + if( val > max ) return min; + return val; +} + +rtc_time_t rtc_time_from_tm( struct tm *time ) { + return(rtc_time_t){ + .year = CLAMP(time->tm_year + 1900, YEAR_MIN, YEAR_MAX), + .month = CLAMP(time->tm_mon, 1, 12), + .day = CLAMP(time->tm_mday, 1, 31), + .hour = CLAMP(time->tm_hour, 0, 23), + .min = CLAMP(time->tm_min, 0, 59), + .sec = CLAMP(time->tm_sec, 0, 59), + .week_day = CLAMP(time->tm_wday, 0, 6), + }; +} + +void adjust_rtc_time( struct tm *t, int incr ) { + switch(editing_field_type) + { + case RTC_EDIT_YEAR: + t->tm_year = wrap( t->tm_year + incr, YEAR_MIN - 1900, YEAR_MAX - 1900 ); + break; + case RTC_EDIT_MONTH: + t->tm_mon = wrap( t->tm_mon + incr, 0, 11 ); + break; + case RTC_EDIT_DAY: + t->tm_mday = wrap( t->tm_mday + incr, 1, 31 ); + break; + case RTC_EDIT_HOUR: + t->tm_hour = wrap( t->tm_hour + incr, 0, 23 ); + break; + case RTC_EDIT_MIN: + t->tm_min = wrap( t->tm_min + incr, 0, 59 ); + break; + case RTC_EDIT_SEC: + t->tm_sec = wrap( t->tm_sec + incr, 0, 59 ); + break; + } + // Recalculate day-of-week and day-of-year + time_t timestamp = mktime( t ); + *t = *gmtime( ×tamp ); +} + +void component_editdatetime_draw ( struct tm t, rtc_field_t selected_field ) { + // FIXME: move this to components.c once improved. + /* Format RTC date/time as strings */ + char full_dt[30]; + char current_selection_chars[30]; + + snprintf( full_dt, sizeof(full_dt), ">%04d|%02d|%02d|%02d|%02d|%02d< %s", + t.tm_year + 1900, + t.tm_mon + 1, + t.tm_mday, + t.tm_hour, + t.tm_min, + t.tm_sec, + DAYS_OF_WEEK[t.tm_wday] + ); + + switch(selected_field) + { + // Note: for what ever reason, hat chars need to be duplicated to display correctly. This will be solved when there is a decent UI for it. + case RTC_EDIT_YEAR: + snprintf( current_selection_chars, sizeof(current_selection_chars), "*^^^^^^^^********************"); + break; + case RTC_EDIT_MONTH: + snprintf( current_selection_chars, sizeof(current_selection_chars), "******^^^^*****************"); + break; + case RTC_EDIT_DAY: + snprintf( current_selection_chars, sizeof(current_selection_chars), "*********^^^^**************"); + break; + case RTC_EDIT_HOUR: + snprintf( current_selection_chars, sizeof(current_selection_chars), "************^^^^***********"); + break; + case RTC_EDIT_MIN: + snprintf( current_selection_chars, sizeof(current_selection_chars), "***************^^^^********"); + break; + case RTC_EDIT_SEC: + snprintf( current_selection_chars, sizeof(current_selection_chars), "******************^^^^*****"); + break; + } + component_messagebox_draw( + "|YYYY|MM|DD|HH|MM|SS| DOW\n%s\n%s\n", full_dt, current_selection_chars); +} static void process (menu_t *menu) { - if (menu->actions.back) { + if (menu->actions.back && !is_editing_mode) { sound_play_effect(SFX_EXIT); menu->next_mode = MENU_MODE_BROWSER; } + else if (menu->actions.enter && !is_editing_mode) { + rtc_tm = *gmtime(&menu->current_time); + is_editing_mode = true; + } + + if (is_editing_mode) { + if (menu->actions.go_left) { + if ( editing_field_type <= RTC_EDIT_YEAR ) { editing_field_type = RTC_EDIT_SEC; } + else { editing_field_type = editing_field_type - 1; } + } + else if (menu->actions.go_right) { + if ( editing_field_type >= RTC_EDIT_SEC ) { editing_field_type = RTC_EDIT_YEAR; } + else { editing_field_type = editing_field_type + 1; } + } + else if (menu->actions.go_up) { + adjust_rtc_time( &rtc_tm, +1 ); + } + else if (menu->actions.go_down) { + adjust_rtc_time( &rtc_tm, -1 ); + } + else if (menu->actions.options) { // R button = save + if(rtc_is_writable()) { + // FIXME: settimeofday is not available in libdragon yet. + // struct timeval new_time = { .tv_sec = mktime(&rtc_tm) }; + // int res = settimeofday(&new_time, NULL); + + rtc_time_t rtc_time = rtc_time_from_tm(&rtc_tm); + int res = rtc_set(&rtc_time); + if (res != 1) { + menu_show_error(menu, "Failed to set RTC time"); + } + } + else { + menu_show_error(menu, "RTC is not writable"); + } + is_editing_mode = false; + } + else if (menu->actions.back) { // cancel + is_editing_mode = false; + } + } } static void draw (menu_t *menu, surface_t *d) { @@ -30,36 +169,51 @@ static void draw (menu_t *menu, surface_t *d) { component_layout_draw(); - component_main_text_draw( + component_main_text_draw( ALIGN_CENTER, VALIGN_TOP, "ADJUST REAL TIME CLOCK\n" "\n" "\n" - "To set the date and time, please use the PC terminal\n" - "application and set via USB,\n or a N64 game with RTC support.\n\n" - "Current date & time: %s\n", - menu->current_time >= 0 ? ctime(&menu->current_time) : "Unknown\n" - ); - - component_main_text_draw( - ALIGN_LEFT, VALIGN_TOP, - "\n" + "To set the RTC date and time, Press A.\n" + "You can also use the PC terminal application via USB,\n" + "or even an N64 game with RTC support.\n" "\n" + "Current date & time: %s\n" + "\n", + menu->current_time >= 0 ? ctime(&menu->current_time) : "Unknown" ); + if (!is_editing_mode) { + component_actions_bar_text_draw( + ALIGN_LEFT, VALIGN_TOP, + "A: Change\n" + "B: Back" + ); + } + else { + component_actions_bar_text_draw( + ALIGN_RIGHT, VALIGN_TOP, + "Up/Down: Adjust Field\n" + "Left/Right: Switch Field" + ); + component_actions_bar_text_draw( + ALIGN_LEFT, VALIGN_TOP, + "R: Save\n" + "B: Back" + ); + } - component_actions_bar_text_draw( - ALIGN_LEFT, VALIGN_TOP, - "\n" // "A: Save\n" - "B: Back" - ); + if (is_editing_mode) { + component_editdatetime_draw(rtc_tm, editing_field_type); + } rdpq_detach_show(); } void view_rtc_init (menu_t *menu) { - // Nothing to initialize (yet) + is_editing_mode = false; + editing_field_type = RTC_EDIT_YEAR; } void view_rtc_display (menu_t *menu, surface_t *display) { diff --git a/src/menu/views/system_info.c b/src/menu/views/system_info.c index 2dea476d..18cffb0d 100644 --- a/src/menu/views/system_info.c +++ b/src/menu/views/system_info.c @@ -57,7 +57,7 @@ static void draw (menu_t *menu, surface_t *d) { "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", + menu->current_time >= 0 ? ctime(&menu->current_time) : "Unknown", is_memory_expanded() ? "" : "not ", (joypad[0]) ? "" : "not ", format_accessory(0), (joypad[1]) ? "" : "not ", format_accessory(1),