diff --git a/CHANGELOG.md b/CHANGELOG.md index 2f66b9533..473bcc2a5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,12 @@ +# Retro-Go 1.36.2 (2022-12-07) +- SNES: Fixed crash in controls menu +- Launcher: Start wifi access point + + +# Retro-Go 1.36.1 (2022-11-29) +- Fixed MRGC/esplay builds + + # Retro-Go 1.36 (2022-11-28) - GBC: Fixed Pokemon Trading Card Game - SNES: Added support for ROMs with extra headers diff --git a/components/retro-go/rg_gui.c b/components/retro-go/rg_gui.c index a7d2d30a3..cb80e02b0 100644 --- a/components/retro-go/rg_gui.c +++ b/components/retro-go/rg_gui.c @@ -803,6 +803,7 @@ int rg_gui_dialog(const char *title, const rg_gui_option_t *options_const, int s } rg_task_delay(20); + rg_system_tick(0); } rg_input_wait_for_key(joystick, false); @@ -1051,7 +1052,7 @@ static rg_gui_event_t theme_cb(rg_gui_option_t *option, rg_gui_event_t event) return RG_DIALOG_VOID; } -int rg_gui_options_menu(void) +void rg_gui_options_menu(void) { rg_gui_option_t options[24]; rg_gui_option_t *opt = &options[0]; @@ -1085,16 +1086,14 @@ int rg_gui_options_menu(void) rg_audio_set_mute(true); - int sel = rg_gui_dialog("Options", options, 0); + rg_gui_dialog("Options", options, 0); rg_settings_commit(); rg_system_save_time(); rg_audio_set_mute(false); - - return sel; } -int rg_gui_about_menu(const rg_gui_option_t *extra_options) +void rg_gui_about_menu(const rg_gui_option_t *extra_options) { char build_ver[32], build_date[32], build_user[32], network_str[64]; @@ -1164,11 +1163,9 @@ int rg_gui_about_menu(const rg_gui_option_t *extra_options) rg_gui_debug_menu(NULL); break; } - - return sel; } -int rg_gui_debug_menu(const rg_gui_option_t *extra_options) +void rg_gui_debug_menu(const rg_gui_option_t *extra_options) { char screen_res[20], source_res[20], scaled_res[20]; char stack_hwm[20], heap_free[20], block_free[20]; @@ -1206,22 +1203,18 @@ int rg_gui_debug_menu(const rg_gui_option_t *extra_options) snprintf(block_free, 20, "%d+%d", stats.freeBlockInt, stats.freeBlockExt); snprintf(uptime, 20, "%ds", (int)(rg_system_timer() / 1000000)); - int sel = rg_gui_dialog("Debugging", options, 0); - - if (sel == 1000) + switch (rg_gui_dialog("Debugging", options, 0)) { + case 1000: rg_emu_screenshot(RG_STORAGE_ROOT "/screenshot.png", 0, 0); - } - else if (sel == 2000) - { + break; + case 2000: rg_system_save_trace(RG_STORAGE_ROOT "/trace.txt", 0); - } - else if (sel == 4000) - { + break; + case 4000: RG_PANIC("Crash test!"); + break; } - - return sel; } static rg_emu_state_t *savestate; @@ -1282,10 +1275,13 @@ int rg_gui_savestate_menu(const char *title, const char *rom_path, bool quick_re free(savestate); + if (sel == RG_DIALOG_CANCELLED) + return -1; + return sel; } -int rg_gui_game_menu(void) +void rg_gui_game_menu(void) { const rg_gui_option_t choices[] = { {1000, "Save & Continue", NULL, 1, NULL}, @@ -1338,6 +1334,4 @@ int rg_gui_game_menu(void) } rg_audio_set_mute(false); - - return sel; } diff --git a/components/retro-go/rg_gui.h b/components/retro-go/rg_gui.h index bbaba8a26..fdd4938d9 100644 --- a/components/retro-go/rg_gui.h +++ b/components/retro-go/rg_gui.h @@ -71,6 +71,8 @@ struct rg_gui_option_s #define RG_DIALOG_CHOICE_LAST {0, NULL, NULL, 0, NULL} #define RG_DIALOG_SEPARATOR {0, "----------", NULL, RG_DIALOG_FLAG_SKIP, NULL} +#define RG_DIALOG_CANCELLED -0x7654321 + #define TEXT_RECT(text, max) rg_gui_draw_text(-(max), 0, 0, (text), 0, 0, RG_TEXT_MULTILINE|RG_TEXT_DUMMY_DRAW) void rg_gui_init(void); @@ -98,10 +100,10 @@ void rg_gui_alert(const char *title, const char *message); char *rg_gui_file_picker(const char *title, const char *path, bool (*validator)(const char *path)); int rg_gui_savestate_menu(const char *title, const char *rom_path, bool quick_return); -int rg_gui_options_menu(void); -int rg_gui_game_menu(void); -int rg_gui_about_menu(const rg_gui_option_t *extra_options); -int rg_gui_debug_menu(const rg_gui_option_t *extra_options); +void rg_gui_options_menu(void); +void rg_gui_game_menu(void); +void rg_gui_about_menu(const rg_gui_option_t *extra_options); +void rg_gui_debug_menu(const rg_gui_option_t *extra_options); // Creates a 565LE color from C_RGB(255, 255, 255) #define C_RGB(r, g, b) ((((r) >> 3) << 11) | (((g) >> 2) << 5) | (((b) & 0x1F))) diff --git a/components/retro-go/rg_input.c b/components/retro-go/rg_input.c index b6b9b0933..e6cd8d6c0 100644 --- a/components/retro-go/rg_input.c +++ b/components/retro-go/rg_input.c @@ -17,7 +17,6 @@ #endif static bool input_task_running = false; -static int64_t last_gamepad_read = 0; static uint32_t gamepad_state = -1; // _Atomic static int battery_level = -1; #if defined(RG_BATTERY_ADC_CHANNEL) @@ -327,16 +326,8 @@ void rg_input_deinit(void) RG_LOGI("Input terminated.\n"); } -long rg_input_gamepad_last_read(void) -{ - if (!last_gamepad_read) - return 0; - return rg_system_timer() - last_gamepad_read; -} - uint32_t rg_input_read_gamepad(void) { - last_gamepad_read = rg_system_timer(); #ifdef RG_TARGET_SDL2 SDL_PumpEvents(); #endif @@ -351,7 +342,10 @@ bool rg_input_key_is_pressed(rg_key_t key) void rg_input_wait_for_key(rg_key_t key, bool pressed) { while (rg_input_key_is_pressed(key) != pressed) - rg_task_delay(1); + { + rg_task_delay(10); + rg_system_tick(0); + } } bool rg_input_read_battery(float *percent, float *volts) diff --git a/components/retro-go/rg_input.h b/components/retro-go/rg_input.h index 568353bec..fd3a9096a 100644 --- a/components/retro-go/rg_input.h +++ b/components/retro-go/rg_input.h @@ -26,7 +26,6 @@ typedef enum void rg_input_init(void); void rg_input_deinit(void); -long rg_input_gamepad_last_read(void); bool rg_input_key_is_pressed(rg_key_t key); void rg_input_wait_for_key(rg_key_t key, bool pressed); uint32_t rg_input_read_gamepad(void); diff --git a/components/retro-go/rg_network.c b/components/retro-go/rg_network.c index bf293e75c..d53ad4787 100644 --- a/components/retro-go/rg_network.c +++ b/components/retro-go/rg_network.c @@ -158,6 +158,7 @@ bool rg_network_wifi_start(void) { memcpy(config.ap.ssid, wifi_config.ssid, 32); memcpy(config.ap.password, wifi_config.password, 64); + config.ap.authmode = wifi_config.password[0] ? WIFI_AUTH_WPA2_PSK : WIFI_AUTH_OPEN; config.ap.channel = wifi_config.channel; config.ap.max_connection = 1; TRY(esp_wifi_set_mode(WIFI_MODE_AP)); diff --git a/components/retro-go/rg_storage.c b/components/retro-go/rg_storage.c index de3b7faa8..6197f60c7 100644 --- a/components/retro-go/rg_storage.c +++ b/components/retro-go/rg_storage.c @@ -280,6 +280,7 @@ static int scandir_natural_sort(const void *a, const void *b) return 0; } +// FIXME: rg_scandir_t should probably be {count, items[]} to avoid walking the array to get the count... rg_scandir_t *rg_storage_scandir(const char *path, bool (*validator)(const char *path), uint32_t flags) { DIR *dir = opendir(path); diff --git a/components/retro-go/rg_system.c b/components/retro-go/rg_system.c index bb0becabf..b6579471a 100644 --- a/components/retro-go/rg_system.c +++ b/components/retro-go/rg_system.c @@ -249,7 +249,7 @@ static void system_monitor_task(void *arg) if ((wdtCounter -= loopTime_us) <= 0) { - if (rg_input_gamepad_last_read() > WDT_TIMEOUT) + if ((lastLoop - statistics.lastTick) > WDT_TIMEOUT) { #ifdef RG_ENABLE_PROFILING RG_LOGW("Application unresponsive!\n"); @@ -544,6 +544,7 @@ rg_stats_t rg_system_get_counters(void) IRAM_ATTR void rg_system_tick(int busyTime) { + statistics.lastTick = rg_system_timer(); statistics.busyTime += busyTime; statistics.ticks++; // WDT_RELOAD(WDT_TIMEOUT); diff --git a/components/retro-go/rg_system.h b/components/retro-go/rg_system.h index 6d36bf187..fe696d8c3 100644 --- a/components/retro-go/rg_system.h +++ b/components/retro-go/rg_system.h @@ -176,6 +176,7 @@ typedef struct float totalFPS; float busyPercent; int64_t busyTime; + int64_t lastTick; int ticks; int totalMemoryInt; int totalMemoryExt; diff --git a/components/retro-go/targets/esplay-s3/env.py b/components/retro-go/targets/esplay-s3/env.py index 6167332f0..17cc5de0c 100644 --- a/components/retro-go/targets/esplay-s3/env.py +++ b/components/retro-go/targets/esplay-s3/env.py @@ -1,4 +1,4 @@ import os -os.environ["IDF_TARGET"] = "esp32" +os.environ["IDF_TARGET"] = "esp32s3" os.environ["FW_FORMAT"] = "esplay" diff --git a/launcher/main/CMakeLists.txt b/launcher/main/CMakeLists.txt index 7b2ed4904..b18e8c0b8 100644 --- a/launcher/main/CMakeLists.txt +++ b/launcher/main/CMakeLists.txt @@ -1,4 +1,4 @@ set(COMPONENT_SRCDIRS ". libs") set(COMPONENT_ADD_INCLUDEDIRS ". libs") register_component() -rg_setup_compile_options(-O2) +rg_setup_compile_options(-O2 -mfix-esp32-psram-cache-issue) diff --git a/launcher/main/applications.c b/launcher/main/applications.c index cf2bd4c87..ccc5d0d37 100644 --- a/launcher/main/applications.c +++ b/launcher/main/applications.c @@ -65,26 +65,27 @@ static void scan_folder(retro_app_t *app, const char* path, void *parent) if (!is_valid) continue; - app->files[app->files_count++] = (retro_file_t) { - .name = strdup(entry->name), - .folder = folder, - .app = (void*)app, - .type = type, - .is_valid = true, - }; - - if ((app->files_count % 10) == 0) + if (app->files_count + 1 > app->files_capacity) { - size_t new_size = (app->files_count + 10 + 2) * sizeof(retro_file_t); - retro_file_t *new_buf = realloc(app->files, new_size); + size_t new_capacity = app->files_capacity * 1.5; + retro_file_t *new_buf = realloc(app->files, new_capacity * sizeof(retro_file_t)); if (!new_buf) { RG_LOGW("Ran out of memory, file scanning stopped at %d entries ...\n", app->files_count); break; } app->files = new_buf; + app->files_capacity = new_capacity; } + app->files[app->files_count++] = (retro_file_t) { + .name = strdup(entry->name), + .folder = folder, + .app = (void*)app, + .type = type, + .is_valid = true, + }; + if (type == 0xFF) { retro_file_t *file = &app->files[app->files_count-1]; @@ -291,6 +292,7 @@ void crc_cache_idle_task(tab_t *tab) gui_set_status(tab, "", ""); gui_redraw(); // gui_draw_status(tab); + rg_system_tick(0); } } @@ -667,7 +669,8 @@ static void application(const char *desc, const char *name, const char *exts, co snprintf(app->paths.saves, RG_PATH_MAX, RG_BASE_PATH_SAVES "/%s", app->short_name); snprintf(app->paths.roms, RG_PATH_MAX, RG_BASE_PATH_ROMS "/%s", app->short_name); app->available = rg_system_have_app(app->partition); - app->files = calloc(10, sizeof(retro_file_t)); + app->files = calloc(100, sizeof(retro_file_t)); + app->files_capacity = 100; app->crc_offset = crc_offset; gui_add_tab(app->short_name, app->description, app, event_handler); diff --git a/launcher/main/applications.h b/launcher/main/applications.h index 1ba1e4fbd..bb0be3b1b 100644 --- a/launcher/main/applications.h +++ b/launcher/main/applications.h @@ -31,6 +31,7 @@ typedef struct retro_app_s } paths; size_t crc_offset; retro_file_t *files; + size_t files_capacity; size_t files_count; bool use_crc_covers; bool crc_scan_done; diff --git a/launcher/main/main.c b/launcher/main/main.c index 63fa2f91f..c494e23b3 100644 --- a/launcher/main/main.c +++ b/launcher/main/main.c @@ -6,6 +6,10 @@ #include #include +#ifdef CONFIG_IDF_TARGET +#include +#endif + #include "applications.h" #include "bookmarks.h" #include "music.h" @@ -57,7 +61,7 @@ static rg_gui_event_t timezone_cb(rg_gui_option_t *option, rg_gui_event_t event) options[timezones_count] = (rg_gui_option_t)RG_DIALOG_CHOICE_LAST; int sel = rg_gui_dialog("Timezone", options, 0); - if (sel >= 0 && sel < timezones_count) + if (sel != RG_DIALOG_CANCELLED) rg_system_set_timezone(timezones[sel].TZ); gui_redraw(); } @@ -128,15 +132,14 @@ static rg_gui_event_t wifi_select_cb(rg_gui_option_t *option, rg_gui_event_t eve options[index++] = (rg_gui_option_t){i, ap_name ?: "(empty)", NULL, ap_name ? 1 : 0, NULL}; } char *ap_name = rg_settings_get_string(NS_WIFI, "ssid", NULL); - options[index++] = (rg_gui_option_t){999, ap_name ?: "(empty)", NULL, ap_name ? 1 : 0, NULL}; + options[index++] = (rg_gui_option_t){-1, ap_name ?: "(empty)", NULL, ap_name ? 1 : 0, NULL}; options[index++] = (rg_gui_option_t)RG_DIALOG_CHOICE_LAST; int sel = rg_gui_dialog("Select saved AP", options, rg_settings_get_number(NS_WIFI, SETTING_WIFI_SLOT, 0)); - if (sel >= 0) + if (sel != RG_DIALOG_CANCELLED) { - int slot = (sel == 999) ? -1 : sel; - rg_settings_set_number(NS_WIFI, SETTING_WIFI_SLOT, slot); - if (rg_network_wifi_load_config(slot)) + rg_settings_set_number(NS_WIFI, SETTING_WIFI_SLOT, sel); + if (rg_network_wifi_load_config(sel)) { rg_network_wifi_stop(); rg_network_wifi_start(); @@ -156,6 +159,20 @@ static rg_gui_event_t webui_switch_cb(rg_gui_option_t *option, rg_gui_event_t ev return RG_DIALOG_VOID; } +static rg_gui_event_t wifi_access_point_cb(rg_gui_option_t *option, rg_gui_event_t event) +{ + if (event == RG_DIALOG_ENTER) + { + if (rg_gui_confirm("Wi-Fi AP", "Start access point?\n\nSSID: retro-go\nPassword: retro-go", true)) + { + rg_network_wifi_stop(); + rg_network_wifi_set_config("retro-go", "retro-go", 6, 1); + rg_network_wifi_start(); + } + } + return RG_DIALOG_VOID; +} + static rg_gui_event_t wifi_options_cb(rg_gui_option_t *option, rg_gui_event_t event) { if (event == RG_DIALOG_ENTER) @@ -163,6 +180,8 @@ static rg_gui_event_t wifi_options_cb(rg_gui_option_t *option, rg_gui_event_t ev const rg_gui_option_t options[] = { {0, "Wi-Fi" , "...", 1, &wifi_switch_cb}, {0, "Wi-Fi select", "...", 1, &wifi_select_cb}, + {0, "Wi-Fi Access Point", NULL, 1, &wifi_access_point_cb}, + RG_DIALOG_SEPARATOR, {0, "File server" , "...", 1, &webui_switch_cb}, {0, "Time sync" , "On", 0, NULL}, RG_DIALOG_CHOICE_LAST, @@ -239,6 +258,19 @@ static void retro_loop(void) while (true) { + // At the moment the HTTP server has absolute priority because it may change UI elements. + // It's also risky to let the user do file accesses at the same time (thread safety, SPI, etc)... + if (gui.http_lock) + { + rg_gui_draw_dialog("HTTP Server Busy...", NULL, 0); + redraw_pending = true; + while (gui.http_lock) + { + rg_task_delay(100); + rg_system_tick(0); + } + } + if (!tab->enabled && !change_tab) { change_tab = 1; @@ -359,12 +391,6 @@ static void retro_loop(void) gui.idle_counter = 0; next_idle_event = rg_system_timer() + 100000; } - else if (gui.http_lock) - { - rg_gui_draw_dialog("HTTP Server Busy...", NULL, 0); - while (gui.http_lock) // Note: Maybe we should yield on user action, even if risky? - usleep(100 * 1000); - } else if (rg_system_timer() >= next_idle_event) { gui.idle_counter++; @@ -378,6 +404,8 @@ static void retro_loop(void) { usleep(10000); } + + rg_system_tick(0); } } @@ -451,5 +479,12 @@ void app_main(void) try_migrate(); } +#ifdef CONFIG_IDF_TARGET + // The launcher makes a lot of small allocations and it sometimes fills internal RAM, causing the SD Card driver to + // stop working. Lowering CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL and manually using rg_alloc to do internal allocs when + // needed is a better solution, but that would have to be done for every app. This is a good workaround for now. + heap_caps_malloc_extmem_enable(1024); +#endif + retro_loop(); } diff --git a/snes9x-go/main/main.c b/snes9x-go/main/main.c index 233e59ffa..fe1a38d8f 100644 --- a/snes9x-go/main/main.c +++ b/snes9x-go/main/main.c @@ -128,8 +128,8 @@ static rg_gui_event_t menu_keymap_cb(rg_gui_option_t *option, rg_gui_event_t eve { if (event == RG_DIALOG_ENTER) { - rg_gui_option_t options[keymap.size + 4]; - char values[keymap.size][16]; + rg_gui_option_t options[RG_COUNT(keymap.keys) + 4]; + char values[RG_COUNT(keymap.keys)][16]; char profile[32]; bool dismissed = false; @@ -177,7 +177,7 @@ static rg_gui_event_t menu_keymap_cb(rg_gui_option_t *option, rg_gui_event_t eve *option++ = (rg_gui_option_t)RG_DIALOG_CHOICE_LAST; - dismissed = rg_gui_dialog("Controls", options, 0) == -1; + dismissed = rg_gui_dialog("Controls", options, 0) == RG_DIALOG_CANCELLED; rg_display_queue_update(currentUpdate, NULL); rg_display_sync(); }