diff --git a/CHANGELOG.md b/CHANGELOG.md index 952d7b026..ee110b6c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +# Retro-Go 1.37 (2022-12-30) +- SNES: Fixed controls menu labels +- GEN: Small performance improvement +- Launcher: Added tool to download updates + + # Retro-Go 1.36.3 (2022-12-14) - SNES: Fixed freeze in controls menu (hopefully for real this time...) diff --git a/README.md b/README.md index 0471d110e..9f0531bd7 100644 --- a/README.md +++ b/README.md @@ -80,8 +80,7 @@ The roms must be packed with [LCD-Game-Shrinker](https://github.com/bzhxx/LCD-Ga ## Wifi -To use wifi you will need to add your config to `/retro-go/config/wifi.json` file. -It should look like this: +To use wifi you will need to create a `/retro-go/config/wifi.json` config file. Its content should look like this: ````json { @@ -90,6 +89,18 @@ It should look like this: } ```` +Multiple networks can be defined using the following format (then selectable in the Options menu): +````json +{ + "ssid0": "my-network", + "password0": "my-password", + "ssid1": "my-network", + "password1": "my-password", + "ssid2": "my-network", + "password2": "my-password" +} +```` + ### Time synchronization Time synchronization happens in the launcher immediately after a successful connection to the network. This is done via NTP by contacting `pool.ntp.org` and cannot be disabled at this time. diff --git a/base.sdkconfig b/base.sdkconfig index 314c5a765..483afb399 100644 --- a/base.sdkconfig +++ b/base.sdkconfig @@ -156,3 +156,9 @@ CONFIG_HTTPD_PURGE_BUF_LEN=32 # CONFIG_HTTPD_LOG_PURGE_DATA is not set # CONFIG_HTTPD_WS_SUPPORT is not set # end of HTTP Server + + +# TLS +# Not ideal but I don't want to deal with CAs right now :( +CONFIG_ESP_TLS_INSECURE=y +CONFIG_ESP_TLS_SKIP_SERVER_CERT_VERIFY=y diff --git a/components/retro-go/CMakeLists.txt b/components/retro-go/CMakeLists.txt index ae2d63c91..596a2ea14 100644 --- a/components/retro-go/CMakeLists.txt +++ b/components/retro-go/CMakeLists.txt @@ -1,9 +1,9 @@ set(COMPONENT_SRCDIRS ". fonts libs/netplay libs/lodepng") set(COMPONENT_ADD_INCLUDEDIRS ". libs/netplay libs/lodepng") -if("${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR}" VERSION_GREATER_EQUAL "5.0") - set(COMPONENT_REQUIRES "spi_flash fatfs nvs_flash app_update driver esp_timer esp_adc json") +if($ENV{RG_ENABLE_NETWORKING}) + set(COMPONENT_REQUIRES "spi_flash fatfs nvs_flash esp_http_client app_update esp_adc_cal esp32 json") else() - set(COMPONENT_REQUIRES "spi_flash fatfs nvs_flash app_update esp_adc_cal esp32 json") + set(COMPONENT_REQUIRES "spi_flash fatfs app_update esp_adc_cal esp32 json") endif() register_component() diff --git a/components/retro-go/rg_audio.c b/components/retro-go/rg_audio.c index e059c6b68..58b749772 100644 --- a/components/retro-go/rg_audio.c +++ b/components/retro-go/rg_audio.c @@ -31,7 +31,9 @@ #endif static const rg_audio_sink_t sinks[] = { +#if !RG_AUDIO_USE_INT_DAC && !RG_AUDIO_USE_EXT_DAC {RG_AUDIO_SINK_DUMMY, 0, "Dummy" }, +#endif #if RG_AUDIO_USE_INT_DAC {RG_AUDIO_SINK_I2S_DAC, 0, "Speaker"}, #endif @@ -77,7 +79,7 @@ void rg_audio_init(int sampleRate) ACQUIRE_DEVICE(1000); - int sinkType = (int)rg_settings_get_number(NS_GLOBAL, SETTING_OUTPUT, sinks[RG_COUNT(sinks) > 1 ? 1 : 0].type); + int sinkType = (int)rg_settings_get_number(NS_GLOBAL, SETTING_OUTPUT, sinks[0].type); for (size_t i = 0; i < RG_COUNT(sinks); ++i) { if (!audio.sink || sinks[i].type == sinkType) diff --git a/components/retro-go/rg_gui.c b/components/retro-go/rg_gui.c index 0dea4fe58..9e33549a5 100644 --- a/components/retro-go/rg_gui.c +++ b/components/retro-go/rg_gui.c @@ -31,8 +31,8 @@ static struct bool initialized; } gui; -static const char *SETTING_FONTTYPE = "FontType"; -static const char *SETTING_THEME = "Theme"; +static const char *SETTING_FONTTYPE = "FontType"; +static const char *SETTING_THEME = "Theme"; void rg_gui_init(void) @@ -131,7 +131,7 @@ void rg_gui_copy_buffer(int left, int top, int width, int height, int stride, co for (int y = 0; y < height; ++y) { uint16_t *dst = gui.screen_buffer + (top + y) * gui.screen_width + left; - const uint16_t *src = (void*)buffer + y * stride; + const uint16_t *src = (void *)buffer + y * stride; for (int x = 0; x < width; ++x) if (src[x] != C_TRANSPARENT) dst[x] = src[x]; @@ -707,11 +707,13 @@ int rg_gui_dialog(const char *title, const rg_gui_option_t *options_const, int s for (size_t i = 0; i < options_count; i++) { rg_gui_option_t *option = &options[i]; - if (option->value && text_buffer) { + if (option->value && text_buffer) + { option->value = strcpy(text_buffer_ptr, option->value); text_buffer_ptr += strlen(text_buffer_ptr) + 24; } - if (option->label && text_buffer) { + if (option->label && text_buffer) + { option->label = strcpy(text_buffer_ptr, option->label); text_buffer_ptr += strlen(text_buffer_ptr) + 24; } @@ -822,9 +824,9 @@ bool rg_gui_confirm(const char *title, const char *message, bool default_yes) { const rg_gui_option_t options[] = { {0, (char *)message, NULL, -1, NULL}, - {0, "", NULL, -1, NULL}, - {1, "Yes", NULL, 1, NULL}, - {0, "No ", NULL, 1, NULL}, + {0, "", NULL, -1, NULL}, + {1, "Yes", NULL, 1, NULL}, + {0, "No ", NULL, 1, NULL}, RG_DIALOG_CHOICE_LAST }; return rg_gui_dialog(title, message ? options : options + 1, default_yes ? -2 : -1) == 1; @@ -834,8 +836,8 @@ void rg_gui_alert(const char *title, const char *message) { const rg_gui_option_t options[] = { {0, (char *)message, NULL, -1, NULL}, - {0, "", NULL, -1, NULL}, - {1, "OK", NULL, 1, NULL}, + {0, "", NULL, -1, NULL}, + {1, "OK", NULL, 1, NULL}, RG_DIALOG_CHOICE_LAST }; rg_gui_dialog(title, message ? options : options + 1, -1); @@ -1016,7 +1018,8 @@ static rg_gui_event_t speedup_update_cb(rg_gui_option_t *option, rg_gui_event_t static rg_gui_event_t disk_activity_cb(rg_gui_option_t *option, rg_gui_event_t event) { - if (event == RG_DIALOG_PREV || event == RG_DIALOG_NEXT) { + if (event == RG_DIALOG_PREV || event == RG_DIALOG_NEXT) + { rg_storage_set_activity_led(!rg_storage_get_activity_led()); } strcpy(option->value, rg_storage_get_activity_led() ? "On " : "Off"); @@ -1027,10 +1030,12 @@ static rg_gui_event_t font_type_cb(rg_gui_option_t *option, rg_gui_event_t event { if (event == RG_DIALOG_PREV || event == RG_DIALOG_NEXT) { - if (event == RG_DIALOG_PREV && !rg_gui_set_font_type(gui.style.font_type - 1)) { + if (event == RG_DIALOG_PREV && !rg_gui_set_font_type(gui.style.font_type - 1)) + { rg_gui_set_font_type(0); } - if (event == RG_DIALOG_NEXT && !rg_gui_set_font_type(gui.style.font_type + 1)) { + if (event == RG_DIALOG_NEXT && !rg_gui_set_font_type(gui.style.font_type + 1)) + { rg_gui_set_font_type(0); } } @@ -1093,26 +1098,71 @@ void rg_gui_options_menu(void) rg_audio_set_mute(false); } -void rg_gui_about_menu(const rg_gui_option_t *extra_options) +void rg_gui_sysinfo_menu(void) { - char build_ver[32], build_date[32], build_user[32], network_str[64]; + char screen_str[32], network_str[64], memory_str[32]; + char storage_str[32], localtime_str[32], uptime[32]; const rg_gui_option_t options[] = { - {0, "Version", build_ver, 1, NULL}, - {0, "Date", build_date, 1, NULL}, - {0, "By", build_user, 1, NULL}, - #ifdef RG_ENABLE_NETWORKING + {0, "Console", RG_TARGET_NAME, 1, NULL}, + {0, "Screen", screen_str, 1, NULL}, + {0, "Memory", memory_str, 1, NULL}, {0, "Network", network_str, 1, NULL}, - #endif + // {0, "Storage", storage_str, 1, NULL}, + {0, "RTC", localtime_str, 1, NULL}, + {0, "Uptime", uptime, 1, NULL}, RG_DIALOG_SEPARATOR, - {1000, "Reboot to firmware", NULL, 1, NULL}, - {2000, "Reset settings", NULL, 1, NULL}, - {3000, "Clear cache", NULL, 1, NULL}, - {4000, "Debug", NULL, 1, NULL}, - {0000, "Close", NULL, 1, NULL}, + {0, "Close", NULL, 1, NULL}, RG_DIALOG_CHOICE_LAST }; + const rg_display_t *display = rg_display_get_info(); + rg_stats_t stats = rg_system_get_counters(); + time_t now = time(NULL); + + snprintf(screen_str, 32, "%dx%d (%d)", display->screen.width, display->screen.height, display->screen.format); + snprintf(memory_str, 32, "%dKB + %dKB", stats.totalMemoryInt / 1024, stats.totalMemoryExt / 1024); + snprintf(uptime, 32, "%ds", (int)(rg_system_timer() / 1000000)); + snprintf(storage_str, 32, "%s", "N/A"); + strftime(localtime_str, 32, "%F %T", localtime(&now)); + +#ifdef RG_ENABLE_NETWORKING + rg_network_t net = rg_network_get_info(); + if (net.state == RG_NETWORK_CONNECTED) + snprintf(network_str, 64, "%s\n%s", net.name, net.ip_addr); + else if (net.state == RG_NETWORK_CONNECTING) + snprintf(network_str, 64, "%s\n%s", net.name, "connecting..."); + else if (net.name[0]) + snprintf(network_str, 64, "%s\n%s", net.name, "disconnected"); + else + snprintf(network_str, 64, "%s", "disconnected"); +#else + strcpy(network_str, "No adapter"); +#endif + + rg_gui_dialog("System Information", options, -1); +} + +void rg_gui_about_menu(const rg_gui_option_t *extra_options) +{ + char build_ver[32], build_date[32], build_user[32]; + + size_t extra_options_count = get_dialog_items_count(extra_options); + + rg_gui_option_t options[16 + extra_options_count]; + rg_gui_option_t *opt = &options[0]; + + *opt++ = (rg_gui_option_t){0, "Version", build_ver, 1, NULL}; + *opt++ = (rg_gui_option_t){0, "Date", build_date, 1, NULL}; + *opt++ = (rg_gui_option_t){0, "By", build_user, 1, NULL}; + *opt++ = (rg_gui_option_t)RG_DIALOG_SEPARATOR; + *opt++ = (rg_gui_option_t){1000, "System information", NULL, 1, NULL}; + for (size_t i = 0; i < extra_options_count; i++) + *opt++ = extra_options[i]; + *opt++ = (rg_gui_option_t){2000, "Reset settings", NULL, 1, NULL}; + *opt++ = (rg_gui_option_t){3000, "Debug", NULL, 1, NULL}; + *opt++ = (rg_gui_option_t)RG_DIALOG_CHOICE_LAST; + const rg_app_t *app = rg_system_get_app(); snprintf(build_ver, 30, "%s", app->version); @@ -1129,39 +1179,28 @@ void rg_gui_about_menu(const rg_gui_option_t *extra_options) strcat(build_ver, ")"); } - rg_network_t net = rg_network_get_info(); - if (net.state == RG_NETWORK_CONNECTED) - snprintf(network_str, 64, "%s\n%s", net.name, net.ip_addr); - else if (net.state == RG_NETWORK_CONNECTING) - snprintf(network_str, 64, "%s\n%s", net.name, "connecting..."); - else if (net.name[0]) - snprintf(network_str, 64, "%s\n%s", net.name, "disconnected"); - else - snprintf(network_str, 64, "%s", "disconnected"); - - int sel = rg_gui_dialog("Retro-Go", options, -1); - - rg_settings_commit(); - rg_system_save_time(); - - switch (sel) + while (true) { - case 1000: - rg_system_switch_app(RG_APP_FACTORY, RG_APP_FACTORY, 0, 0); - break; - case 2000: - if (rg_gui_confirm("Reset all settings?", NULL, false)) { - rg_settings_reset(); - rg_system_restart(); - } - break; - case 3000: - rg_storage_delete(RG_BASE_PATH_CACHE); - rg_system_restart(); - break; - case 4000: - rg_gui_debug_menu(NULL); - break; + switch (rg_gui_dialog("Retro-Go", options, 4)) + { + case 1000: + rg_gui_sysinfo_menu(); + break; + case 2000: + if (rg_gui_confirm("Reset all settings?", NULL, false)) { + rg_storage_delete(RG_BASE_PATH_CACHE); + rg_settings_reset(); + rg_system_restart(); + return; + } + break; + case 3000: + rg_gui_debug_menu(NULL); + break; + default: + return; + } + rg_system_event(RG_EVENT_REDRAW, NULL); } } @@ -1182,10 +1221,12 @@ void rg_gui_debug_menu(const rg_gui_option_t *extra_options) {0, "Timezone ", timezone, 1, NULL}, {0, "Uptime ", uptime, 1, NULL}, RG_DIALOG_SEPARATOR, - {1000, "Save screenshot", NULL, 1, NULL}, - {2000, "Save trace", NULL, 1, NULL}, - {3000, "Cheats", NULL, 1, NULL}, - {4000, "Crash", NULL, 1, NULL}, + {1, "Reboot to firmware", NULL, 1, NULL}, + {2, "Clear cache", NULL, 1, NULL}, + {3, "Save screenshot", NULL, 1, NULL}, + {4, "Save trace", NULL, 1, NULL}, + {5, "Cheats", NULL, 1, NULL}, + {6, "Crash", NULL, 1, NULL}, RG_DIALOG_CHOICE_LAST }; @@ -1205,13 +1246,22 @@ void rg_gui_debug_menu(const rg_gui_option_t *extra_options) switch (rg_gui_dialog("Debugging", options, 0)) { - case 1000: + case 1: + rg_system_switch_app(RG_APP_FACTORY, RG_APP_FACTORY, 0, 0); + break; + case 2: + rg_storage_delete(RG_BASE_PATH_CACHE); + rg_system_restart(); + break; + case 3: rg_emu_screenshot(RG_STORAGE_ROOT "/screenshot.png", 0, 0); break; - case 2000: + case 4: rg_system_save_trace(RG_STORAGE_ROOT "/trace.txt", 0); break; - case 4000: + case 5: + break; + case 6: RG_PANIC("Crash test!"); break; } diff --git a/components/retro-go/rg_gui.h b/components/retro-go/rg_gui.h index fdd4938d9..18303260a 100644 --- a/components/retro-go/rg_gui.h +++ b/components/retro-go/rg_gui.h @@ -64,12 +64,13 @@ struct rg_gui_option_s rg_gui_callback_t update_cb; }; -#define RG_DIALOG_FLAG_DISABLED 0 // (1 << 0) -#define RG_DIALOG_FLAG_NORMAL 1 // (1 << 1) -#define RG_DIALOG_FLAG_SKIP -1 // (1 << 2) +#define RG_DIALOG_FLAG_DISABLED (0) // (1 << 0) +#define RG_DIALOG_FLAG_NORMAL (1) // (1 << 1) +#define RG_DIALOG_FLAG_SKIP (-1) // (1 << 2) #define RG_DIALOG_CHOICE_LAST {0, NULL, NULL, 0, NULL} #define RG_DIALOG_SEPARATOR {0, "----------", NULL, RG_DIALOG_FLAG_SKIP, NULL} +#define RG_DIALOG_END RG_DIALOG_CHOICE_LAST #define RG_DIALOG_CANCELLED -0x7654321 diff --git a/components/retro-go/rg_input.c b/components/retro-go/rg_input.c index e6cd8d6c0..e4a4e95a0 100644 --- a/components/retro-go/rg_input.c +++ b/components/retro-go/rg_input.c @@ -236,7 +236,7 @@ void rg_input_init(void) if (input_task_running) return; -#if RG_GAMEPAD_DRIVER == 1 // GPIO +#if RG_GAMEPAD_DRIVER == 1 // GPIO const char *driver = "GPIO"; @@ -257,7 +257,7 @@ void rg_input_init(void) gpio_set_direction(RG_GPIO_GAMEPAD_B, GPIO_MODE_INPUT); gpio_set_pull_mode(RG_GPIO_GAMEPAD_B, GPIO_PULLUP_ONLY); -#elif RG_GAMEPAD_DRIVER == 2 // Serial +#elif RG_GAMEPAD_DRIVER == 2 // Serial const char *driver = "SERIAL"; @@ -268,14 +268,14 @@ void rg_input_init(void) gpio_set_level(RG_GPIO_GAMEPAD_LATCH, 0); gpio_set_level(RG_GPIO_GAMEPAD_CLOCK, 1); -#elif RG_GAMEPAD_DRIVER == 3 // I2C +#elif RG_GAMEPAD_DRIVER == 3 // I2C const char *driver = "I2C"; rg_i2c_init(); gamepad_read(); // First read contains garbage -#elif RG_GAMEPAD_DRIVER == 4 // I2C w/AW9523 +#elif RG_GAMEPAD_DRIVER == 4 // I2C w/AW9523 const char *driver = "AW9523-I2C"; @@ -297,7 +297,7 @@ void rg_input_init(void) #elif RG_GAMEPAD_DRIVER == 6 // SDL2 - const char *driver = "SDL2"; + const char *driver = "SDL2"; #else @@ -364,3 +364,26 @@ bool rg_input_read_battery(float *percent, float *volts) return true; } + +const char *rg_input_get_key_name(rg_key_t key) +{ + switch (key) + { + case RG_KEY_UP: return "Up"; + case RG_KEY_RIGHT: return "Right"; + case RG_KEY_DOWN: return "Down"; + case RG_KEY_LEFT: return "Left"; + case RG_KEY_SELECT: return "Select"; + case RG_KEY_START: return "Start"; + case RG_KEY_MENU: return "Menu"; + case RG_KEY_OPTION: return "Option"; + case RG_KEY_A: return "A"; + case RG_KEY_B: return "B"; + case RG_KEY_X: return "X"; + case RG_KEY_Y: return "Y"; + case RG_KEY_L: return "Left Shoulder"; + case RG_KEY_R: return "Right Shoulder"; + case RG_KEY_NONE: return "None"; + default: return "Unknown"; + } +} \ No newline at end of file diff --git a/components/retro-go/rg_input.h b/components/retro-go/rg_input.h index fd3a9096a..4abb62e96 100644 --- a/components/retro-go/rg_input.h +++ b/components/retro-go/rg_input.h @@ -19,14 +19,16 @@ typedef enum RG_KEY_Y = (1 << 11), RG_KEY_L = (1 << 12), RG_KEY_R = (1 << 13), + RG_KEY_COUNT = 14, RG_KEY_ANY = 0xFFFF, RG_KEY_ALL = 0xFFFF, - RG_KEY_COUNT = 14, + RG_KEY_NONE = 0, } rg_key_t; void rg_input_init(void); void rg_input_deinit(void); bool rg_input_key_is_pressed(rg_key_t key); void rg_input_wait_for_key(rg_key_t key, bool pressed); +const char *rg_input_get_key_name(rg_key_t key); uint32_t rg_input_read_gamepad(void); bool rg_input_read_battery(float *percent, float *volts); diff --git a/components/retro-go/rg_network.c b/components/retro-go/rg_network.c index d53ad4787..4bbcae70f 100644 --- a/components/retro-go/rg_network.c +++ b/components/retro-go/rg_network.c @@ -24,6 +24,7 @@ static const char *SETTING_WIFI_SLOT = "slot"; #ifdef RG_ENABLE_NETWORKING +#include #include #include #include @@ -293,3 +294,82 @@ bool rg_network_init(void) #endif return false; } + +rg_http_req_t *rg_network_http_open(const char *url, const rg_http_cfg_t *cfg) +{ + RG_ASSERT(url, "bad param"); +#ifdef RG_ENABLE_NETWORKING + esp_http_client_config_t http_config = {.url = url, .buffer_size = 1024, .buffer_size_tx = 1024}; + esp_http_client_handle_t http_client = esp_http_client_init(&http_config); + rg_http_req_t *req = calloc(1, sizeof(rg_http_req_t)); + + if (!http_client || !req) + { + RG_LOGE("Error creating client"); + goto fail; + } + +try_again: + if (esp_http_client_open(http_client, 0) != ESP_OK) + { + RG_LOGE("Error opening connection"); + goto fail; + } + + if (esp_http_client_fetch_headers(http_client) < 0) + { + RG_LOGE("Error fetching headers"); + goto fail; + } + + req->status_code = esp_http_client_get_status_code(http_client); + req->content_length = esp_http_client_get_content_length(http_client); + req->client = (void *)http_client; + + if (req->status_code == 301 || req->status_code == 302) + { + if (req->redirections < 5) + { + esp_http_client_set_redirection(http_client); + esp_http_client_close(http_client); + req->redirections++; + goto try_again; + } + } + + return req; + +fail: + esp_http_client_cleanup(http_client); + free(req); +#endif + return NULL; +} + +int rg_network_http_read(rg_http_req_t *req, void *buffer, size_t buffer_len) +{ + RG_ASSERT(req && buffer, "bad param"); +#ifdef RG_ENABLE_NETWORKING + // if (req->content_length >= 0 && req->received_bytes >= req->content_length) + // return 0; + int len = esp_http_client_read_response(req->client, buffer, buffer_len); + if (len > 0) + req->received_bytes += len; + else + esp_http_client_close(req->client); + return len; +#else + return -1; +#endif +} + +void rg_network_http_close(rg_http_req_t *req) +{ +#ifdef RG_ENABLE_NETWORKING + if (req == NULL) + return; + esp_http_client_cleanup(req->client); + req->client = NULL; + free(req); +#endif +} diff --git a/components/retro-go/rg_network.h b/components/retro-go/rg_network.h index 594885c8c..f157754b9 100644 --- a/components/retro-go/rg_network.h +++ b/components/retro-go/rg_network.h @@ -37,3 +37,22 @@ bool rg_network_wifi_start(void); void rg_network_wifi_stop(void); bool rg_network_sync_time(const char *host, int *out_delta); rg_network_t rg_network_get_info(void); + +typedef struct +{ + +} rg_http_cfg_t; + +typedef struct +{ + rg_http_cfg_t config; + int status_code; + int content_length; + int received_bytes; + int redirections; + void *client; +} rg_http_req_t; + +rg_http_req_t *rg_network_http_open(const char *url, const rg_http_cfg_t *cfg); +int rg_network_http_read(rg_http_req_t *req, void *buffer, size_t buffer_len); +void rg_network_http_close(rg_http_req_t *req); diff --git a/components/retro-go/rg_settings.c b/components/retro-go/rg_settings.c index 232e12293..df0940b2a 100644 --- a/components/retro-go/rg_settings.c +++ b/components/retro-go/rg_settings.c @@ -77,7 +77,7 @@ static cJSON *json_root(const char *name, bool mode) if (mode) { - cJSON_SetNumberHelper(cJSON_GetObjectItem(branch, "changed"), 1); + cJSON_SetNumberHelper(cJSON_GetObjectItem(branch, "changed"), 1); } return root; diff --git a/components/retro-go/rg_storage.c b/components/retro-go/rg_storage.c index 6197f60c7..9914ea6a7 100644 --- a/components/retro-go/rg_storage.c +++ b/components/retro-go/rg_storage.c @@ -323,19 +323,19 @@ rg_scandir_t *rg_storage_scandir(const char *path, bool (*validator)(const char strncpy(result->name, basename, sizeof(result->name) - 1); result->is_valid = 1; - #if defined(DT_REG) && defined(DT_DIR) - result->is_file = ent->d_type == DT_REG; - result->is_dir = ent->d_type == DT_DIR; - #else - flags |= RG_SCANDIR_STAT; - #endif + #if defined(DT_REG) && defined(DT_DIR) + result->is_file = ent->d_type == DT_REG; + result->is_dir = ent->d_type == DT_DIR; + #else + flags |= RG_SCANDIR_STAT; + #endif if ((flags & RG_SCANDIR_STAT) && stat(fullpath, &statbuf) == 0) { result->is_file = S_ISREG(statbuf.st_mode); result->is_dir = S_ISDIR(statbuf.st_mode); result->size = statbuf.st_size; - result->mtime = statbuf.st_mtim.tv_sec; + result->mtime = statbuf.st_mtime; } } memset(&results[count], 0, sizeof(rg_scandir_t)); diff --git a/components/retro-go/rg_utils.c b/components/retro-go/rg_utils.c index 08e7d9e6f..e042a6559 100644 --- a/components/retro-go/rg_utils.c +++ b/components/retro-go/rg_utils.c @@ -88,7 +88,7 @@ uint32_t rg_crc32(uint32_t crc, const uint8_t *buf, uint32_t len) { #ifndef RG_TARGET_SDL2 // This is part of the ROM but finding the correct header is annoying as it differs per SOC... - extern uint32_t crc32_le(uint32_t crc, const uint8_t * buf, uint32_t len); + extern uint32_t crc32_le(uint32_t crc, const uint8_t *buf, uint32_t len); return crc32_le(crc, buf, len); #else // Derived from: http://www.hackersdelight.org/hdcodetxt/crc.c.txt @@ -96,13 +96,13 @@ uint32_t rg_crc32(uint32_t crc, const uint8_t *buf, uint32_t len) for (size_t i = 0; i < len; ++i) { crc = crc ^ buf[i]; - for (int j = 7; j >= 0; j--) // Do eight times. + for (int j = 7; j >= 0; j--) // Do eight times. { uint32_t mask = -(crc & 1); crc = (crc >> 1) ^ (0xEDB88320 & mask); } } - return ~crc; + return ~crc; #endif } @@ -121,7 +121,7 @@ const char *const_string(const char *str) str = strdup(str); - strings = realloc(strings, (strings_count + 1) * sizeof(char*)); + strings = realloc(strings, (strings_count + 1) * sizeof(char *)); RG_ASSERT(strings && str, "alloc failed"); strings[strings_count++] = str; @@ -138,10 +138,14 @@ void *rg_alloc(size_t size, uint32_t caps) size_t available = 0; void *ptr; - if (caps & MEM_SLOW) strcat(caps_list, "SPIRAM|"); - if (caps & MEM_FAST) strcat(caps_list, "INTERNAL|"); - if (caps & MEM_DMA) strcat(caps_list, "DMA|"); - if (caps & MEM_EXEC) strcat(caps_list, "IRAM|"); + if (caps & MEM_SLOW) + strcat(caps_list, "SPIRAM|"); + if (caps & MEM_FAST) + strcat(caps_list, "INTERNAL|"); + if (caps & MEM_DMA) + strcat(caps_list, "DMA|"); + if (caps & MEM_EXEC) + strcat(caps_list, "IRAM|"); strcat(caps_list, (caps & MEM_32BIT) ? "32BIT" : "8BIT"); #ifndef RG_TARGET_SDL2 @@ -157,8 +161,8 @@ void *rg_alloc(size_t size, uint32_t caps) // Loosen the caps and try again if ((ptr = heap_caps_calloc(1, size, esp_caps & ~(MALLOC_CAP_SPIRAM | MALLOC_CAP_INTERNAL)))) { - RG_LOGW("SIZE=%u, CAPS=%s, PTR=%p << CAPS not fully met! (available: %d)\n", - size, caps_list, ptr, available); + RG_LOGW("SIZE=%u, CAPS=%s, PTR=%p << CAPS not fully met! (available: %d)\n", size, caps_list, ptr, + available); return ptr; } } diff --git a/components/retro-go/rg_utils.h b/components/retro-go/rg_utils.h index 10e61bf6d..46a192b74 100644 --- a/components/retro-go/rg_utils.h +++ b/components/retro-go/rg_utils.h @@ -5,12 +5,23 @@ #include #define RG_TIMER_INIT() int64_t _rgts_ = rg_system_timer(), _rgtl_ = rg_system_timer(); -#define RG_TIMER_LAP(name) \ +#define RG_TIMER_LAP(name) \ RG_LOGX("Lap %s: %.2f Total: %.2f\n", #name, (rg_system_timer() - _rgtl_) / 1000.f, \ - (rg_system_timer() - _rgts_) / 1000.f); _rgtl_ = rg_system_timer(); + (rg_system_timer() - _rgts_) / 1000.f); \ + _rgtl_ = rg_system_timer(); -#define RG_MIN(a, b) ({__typeof__(a) _a = (a); __typeof__(b) _b = (b);_a < _b ? _a : _b; }) -#define RG_MAX(a, b) ({__typeof__(a) _a = (a); __typeof__(b) _b = (b);_a > _b ? _a : _b; }) +#define RG_MIN(a, b) \ + ({ \ + __typeof__(a) _a = (a); \ + __typeof__(b) _b = (b); \ + _a < _b ? _a : _b; \ + }) +#define RG_MAX(a, b) \ + ({ \ + __typeof__(a) _a = (a); \ + __typeof__(b) _b = (b); \ + _a > _b ? _a : _b; \ + }) #define RG_COUNT(array) (sizeof(array) / sizeof((array)[0])) char *rg_strtolower(char *str); @@ -21,7 +32,7 @@ const char *rg_basename(const char *path); const char *rg_extension(const char *path); const char *rg_relpath(const char *path); const char *const_string(const char *str); -uint32_t rg_crc32(uint32_t crc, const uint8_t* buf, uint32_t len); +uint32_t rg_crc32(uint32_t crc, const uint8_t *buf, uint32_t len); void *rg_alloc(size_t size, uint32_t caps); #define MEM_ANY (0) @@ -32,4 +43,4 @@ void *rg_alloc(size_t size, uint32_t caps); #define MEM_32BIT (16) #define MEM_EXEC (32) -#define PTR_IN_SPIRAM(ptr) ((void*)(ptr) >= (void*)0x3F800000 && (void*)(ptr) < (void*)0x3FC00000) +#define PTR_IN_SPIRAM(ptr) ((void *)(ptr) >= (void *)0x3F800000 && (void *)(ptr) < (void *)0x3FC00000) diff --git a/gwenesis/components/gwenesis/src/vdp/gwenesis_vdp_gfx.c b/gwenesis/components/gwenesis/src/vdp/gwenesis_vdp_gfx.c index cd2b7de29..5babcf7b1 100644 --- a/gwenesis/components/gwenesis/src/vdp/gwenesis_vdp_gfx.c +++ b/gwenesis/components/gwenesis/src/vdp/gwenesis_vdp_gfx.c @@ -93,8 +93,8 @@ static int Window_firstcol; static int Window_lastcol; // 16 bits access to VRAM +// #define FETCH16VRAM(A) ({size_t addr = (A); (VRAM[addr+1]) | (VRAM[addr] << 8);}) #define FETCH16VRAM(A) ( (VRAM[(A)+1]) | (VRAM[(A)] << 8) ) - #define VDP_GFX_DISABLE_LOGGING 1 #if !VDP_GFX_DISABLE_LOGGING diff --git a/gwenesis/main/main.c b/gwenesis/main/main.c index 91b055e48..471797e04 100644 --- a/gwenesis/main/main.c +++ b/gwenesis/main/main.c @@ -239,22 +239,21 @@ void app_main(void) RG_DIALOG_CHOICE_LAST }; - app = rg_system_init(AUDIO_SAMPLE_RATE, &handlers, options); + app = rg_system_init(AUDIO_SAMPLE_RATE / 2, &handlers, options); yfm_enabled = rg_settings_get_number(NS_APP, SETTING_YFM_EMULATION, 1); - sn76489_enabled = rg_settings_get_number(NS_APP, SETTING_SN76489_EMULATION, 1); + sn76489_enabled = rg_settings_get_number(NS_APP, SETTING_SN76489_EMULATION, 0); // yfm_resample = rg_settings_get_number(NS_APP, SETTING_YFM_RESAMPLE, 1); z80_enabled = rg_settings_get_number(NS_APP, SETTING_Z80_EMULATION, 1); frameskip = rg_settings_get_number(NS_APP, SETTING_FRAMESKIP, frameskip); - VRAM = rg_alloc(VRAM_MAX_SIZE, MEM_FAST); - updates[0].buffer = rg_alloc(320 * 240, MEM_FAST); - // updates[1].buffer = rg_alloc(320 * 240 * 2, MEM_FAST); + // updates[1].buffer = rg_alloc(320 * 240, MEM_FAST); + + VRAM = rg_alloc(VRAM_MAX_SIZE, MEM_FAST); // rg_task_create("gen_sound", &sound_task, NULL, 2048, 7, 1); // rg_audio_set_sample_rate(yfm_resample ? 26634 : 53267); - rg_audio_set_sample_rate(26634); RG_LOGI("Genesis start\n"); diff --git a/launcher/main/applications.c b/launcher/main/applications.c index ccc5d0d37..2abe5fb2b 100644 --- a/launcher/main/applications.c +++ b/launcher/main/applications.c @@ -546,7 +546,7 @@ static void show_file_info(retro_file_t *file) RG_DIALOG_SEPARATOR, {5, "Delete file", NULL, 1, NULL}, {1, "Close", NULL, 1, NULL}, - RG_DIALOG_CHOICE_LAST + RG_DIALOG_END, }; sprintf(filesize, "%ld KB", st.st_size / 1024); @@ -598,7 +598,7 @@ void application_show_file_menu(retro_file_t *file, bool advanced) {2, "Delete save", NULL, has_save || has_sram, NULL}, RG_DIALOG_SEPARATOR, {4, "Properties", NULL, 1, NULL}, - RG_DIALOG_CHOICE_LAST + RG_DIALOG_END, }; int sel = rg_gui_dialog(NULL, choices, has_save ? 0 : 1); diff --git a/launcher/main/main.c b/launcher/main/main.c index c494e23b3..2041ddac1 100644 --- a/launcher/main/main.c +++ b/launcher/main/main.c @@ -16,6 +16,7 @@ #include "gui.h" #include "webui.h" #include "timezones.h" +#include "updater.h" #define MAX_AP_LIST 5 @@ -39,10 +40,11 @@ static rg_gui_event_t toggle_tabs_cb(rg_gui_option_t *option, rg_gui_event_t eve if (event == RG_DIALOG_ENTER) { rg_gui_option_t options[gui.tabs_count + 1]; + rg_gui_option_t *opt = options; for (size_t i = 0; i < gui.tabs_count; ++i) - options[i] = (rg_gui_option_t){i, gui.tabs[i]->name, "...", 1, &toggle_tab_cb}; - options[gui.tabs_count] = (rg_gui_option_t)RG_DIALOG_CHOICE_LAST; + *opt++ = (rg_gui_option_t){i, gui.tabs[i]->name, "...", 1, &toggle_tab_cb}; + *opt++ = (rg_gui_option_t)RG_DIALOG_END; rg_gui_dialog("Tabs Visibility", options, 0); gui_redraw(); @@ -52,13 +54,14 @@ static rg_gui_event_t toggle_tabs_cb(rg_gui_option_t *option, rg_gui_event_t eve static rg_gui_event_t timezone_cb(rg_gui_option_t *option, rg_gui_event_t event) { - rg_gui_option_t options[timezones_count + 1]; - if (event == RG_DIALOG_ENTER) { + rg_gui_option_t options[timezones_count + 1]; + rg_gui_option_t *opt = options; + for (size_t i = 0; i < timezones_count; i++) - options[i] = (rg_gui_option_t){i, timezones[i].name, NULL, 1, NULL}; - options[timezones_count] = (rg_gui_option_t)RG_DIALOG_CHOICE_LAST; + *opt++ = (rg_gui_option_t){i, timezones[i].name, NULL, 1, NULL}; + *opt++ = (rg_gui_option_t)RG_DIALOG_END; int sel = rg_gui_dialog("Timezone", options, 0); if (sel != RG_DIALOG_CANCELLED) @@ -122,18 +125,18 @@ static rg_gui_event_t wifi_select_cb(rg_gui_option_t *option, rg_gui_event_t eve if (event == RG_DIALOG_ENTER) { rg_gui_option_t options[MAX_AP_LIST + 2]; - size_t index = 0; + rg_gui_option_t *opt = options; for (size_t i = 0; i < MAX_AP_LIST; i++) { char slot[6]; sprintf(slot, "ssid%d", i); char *ap_name = rg_settings_get_string(NS_WIFI, slot, NULL); - options[index++] = (rg_gui_option_t){i, ap_name ?: "(empty)", NULL, ap_name ? 1 : 0, NULL}; + *opt++ = (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){-1, ap_name ?: "(empty)", NULL, ap_name ? 1 : 0, NULL}; - options[index++] = (rg_gui_option_t)RG_DIALOG_CHOICE_LAST; + *opt++ = (rg_gui_option_t){-1, ap_name ?: "(empty)", NULL, ap_name ? 1 : 0, NULL}; + *opt++ = (rg_gui_option_t)RG_DIALOG_END; int sel = rg_gui_dialog("Select saved AP", options, rg_settings_get_number(NS_WIFI, SETTING_WIFI_SLOT, 0)); if (sel != RG_DIALOG_CANCELLED) @@ -184,7 +187,7 @@ static rg_gui_event_t wifi_options_cb(rg_gui_option_t *option, rg_gui_event_t ev RG_DIALOG_SEPARATOR, {0, "File server" , "...", 1, &webui_switch_cb}, {0, "Time sync" , "On", 0, NULL}, - RG_DIALOG_CHOICE_LAST, + RG_DIALOG_END, }; rg_gui_dialog("Wifi Options", options, 0); } @@ -220,10 +223,29 @@ static rg_gui_event_t startup_app_cb(rg_gui_option_t *option, rg_gui_event_t eve return RG_DIALOG_VOID; } +static rg_gui_event_t updater_cb(rg_gui_option_t *option, rg_gui_event_t event) +{ + if (event == RG_DIALOG_ENTER) + { + updater_show_dialog(); + gui_redraw(); + } + return RG_DIALOG_VOID; +} + +static void show_about_menu(void) +{ + const rg_gui_option_t options[] = { + {0, "Check for updates", NULL, 1, &updater_cb}, + RG_DIALOG_END, + }; + rg_gui_about_menu(options); +} + static rg_gui_event_t about_app_cb(rg_gui_option_t *option, rg_gui_event_t event) { if (event == RG_DIALOG_ENTER) - rg_gui_about_menu(NULL); + show_about_menu(); return RG_DIALOG_VOID; } @@ -324,7 +346,7 @@ static void retro_loop(void) { #if RG_GAMEPAD_HAS_OPTION_BTN if (joystick == RG_KEY_MENU) - rg_gui_about_menu(NULL); + show_about_menu(); else #endif rg_gui_options_menu(); @@ -460,7 +482,7 @@ void app_main(void) RG_DIALOG_SEPARATOR, {0, "About Retro-Go", NULL, 1, &about_app_cb}, #endif - RG_DIALOG_CHOICE_LAST + RG_DIALOG_END, }; app = rg_system_init(32000, &handlers, options); diff --git a/launcher/main/updater.c b/launcher/main/updater.c new file mode 100644 index 000000000..99d517d7f --- /dev/null +++ b/launcher/main/updater.c @@ -0,0 +1,192 @@ +#include "rg_system.h" +#include "gui.h" + +#include +#include + +#define GITHUB_RELEASES_URL "https://api.github.com/repos/ducalex/retro-go/releases" + +#ifdef RG_TARGET_ODROID_GO +#define DOWNLOAD_LOCATION RG_STORAGE_ROOT "/odroid/firmware" +#else +#define DOWNLOAD_LOCATION RG_STORAGE_ROOT "/espgbc/firmware" +#endif + +typedef struct +{ + char name[32]; + char url[256]; +} asset_t; + +typedef struct +{ + char name[32]; + char date[32]; + asset_t *assets; + size_t assets_count; +} release_t; + +static int download_file(const char *url, const char *filename) +{ + RG_ASSERT(url && filename, "bad param"); + + rg_http_req_t *req = NULL; + FILE *fp = NULL; + void *buffer = NULL; + int received = 0; + int len; + int ret = -1; + + RG_LOGI("Downloading: '%s' to '%s'", url, filename); + rg_gui_draw_dialog("Connecting...", NULL, 0); + + if (!(req = rg_network_http_open(url, NULL))) + goto cleanup; + + if (!(fp = fopen(filename, "wb"))) + goto cleanup; + + if (!(buffer = malloc(16 * 1024))) + goto cleanup; + + rg_gui_draw_dialog("Receiving...", NULL, 0); + + while ((len = rg_network_http_read(req, buffer, 16 * 1024)) > 0) + { + received += len; + fwrite(buffer, 1, len, fp); + sprintf(buffer, "Received %d / %d", received, req->content_length); + rg_gui_draw_dialog(buffer, NULL, 0); + rg_system_tick(0); + } + + if (req->content_length == received) + ret = 0; + else if (req->content_length == -1) + ret = 0; + +cleanup: + rg_network_http_close(req); + free(buffer); + fclose(fp); + + return ret; +} + +static cJSON *fetch_json(const char *url) +{ + RG_ASSERT(url, "bad param"); + + RG_LOGI("Fetching: '%s'", url); + rg_gui_draw_hourglass(); + + rg_http_req_t *req = NULL; + char *buffer = NULL; + cJSON *json = NULL; + + if (!(req = rg_network_http_open(url, NULL))) + goto cleanup; + + size_t buffer_length = RG_MAX(256 * 1024, req->content_length); + + if (!(buffer = calloc(1, buffer_length + 1))) + goto cleanup; + + if (rg_network_http_read(req, buffer, buffer_length) < 16) + goto cleanup; + + if (!(json = cJSON_Parse(buffer))) + goto cleanup; + +cleanup: + rg_network_http_close(req); + free(buffer); + return json; +} + +static rg_gui_event_t view_release_cb(rg_gui_option_t *option, rg_gui_event_t event) +{ + if (event == RG_DIALOG_ENTER) + { + release_t *release = (release_t *)option->arg; + + rg_gui_option_t options[release->assets_count + 4]; + rg_gui_option_t *opt = options; + + *opt++ = (rg_gui_option_t){0, "Date", release->date, -1, NULL}; + *opt++ = (rg_gui_option_t){0, "Files:", NULL, -1, NULL}; + + for (int i = 0; i < release->assets_count; i++) + *opt++ = (rg_gui_option_t){i, release->assets[i].name, NULL, 1, NULL}; + *opt++ = (rg_gui_option_t)RG_DIALOG_END; + + int sel = rg_gui_dialog(release->name, options, -1); + if (sel != RG_DIALOG_CANCELLED) + { + char dest_path[RG_PATH_MAX]; + snprintf(dest_path, RG_PATH_MAX, "%s/%s", DOWNLOAD_LOCATION, release->assets[sel].name); + + int ret = download_file(release->assets[sel].url, dest_path); + gui_redraw(); + + if (ret != 0) + rg_gui_alert("Download failed!", "..."); + else if (rg_gui_confirm("Download complete!", "Reboot to flash?", true)) + rg_system_switch_app(RG_APP_FACTORY, RG_APP_FACTORY, NULL, 0); + } + gui_redraw(); + } + + return RG_DIALOG_VOID; +} + +void updater_show_dialog(void) +{ + cJSON *releases_json = fetch_json(GITHUB_RELEASES_URL); + size_t releases_count = RG_MIN(cJSON_GetArraySize(releases_json), 20); + + release_t *releases = calloc(releases_count, sizeof(release_t)); + for (int i = 0; i < releases_count; ++i) + { + cJSON *release_json = cJSON_GetArrayItem(releases_json, i); + cJSON *assets_json = cJSON_GetObjectItem(release_json, "assets"); + size_t assets_count = cJSON_GetArraySize(assets_json); + + snprintf(releases[i].name, 32, "%s", cJSON_GetStringValue(cJSON_GetObjectItem(release_json, "name"))); + snprintf(releases[i].date, 32, "%s", cJSON_GetStringValue(cJSON_GetObjectItem(release_json, "published_at"))); + releases[i].assets = calloc(assets_count, sizeof(asset_t)); + releases[i].assets_count = assets_count; + + for (int j = 0; j < assets_count; ++j) + { + cJSON *asset_json = cJSON_GetArrayItem(assets_json, j); + asset_t *asset = &releases[i].assets[j]; + snprintf(asset->name, 32, "%s", cJSON_GetStringValue(cJSON_GetObjectItem(asset_json, "name"))); + snprintf(asset->url, 256, "%s", cJSON_GetStringValue(cJSON_GetObjectItem(asset_json, "browser_download_url"))); + } + } + + cJSON_Delete(releases_json); + + gui_redraw(); + + if (releases_count > 0) + { + rg_gui_option_t options[releases_count + 1]; + rg_gui_option_t *opt = options; + + for (int i = 0; i < releases_count; ++i) + *opt++ = (rg_gui_option_t){(intptr_t)&releases[i], releases[i].name, NULL, 1, &view_release_cb}; + *opt++ = (rg_gui_option_t)RG_DIALOG_END; + + rg_gui_dialog("Available Releases", options, 0); + } + else + { + rg_gui_alert("Available Releases", "Received empty list!"); + } + + for (int i = 0; i < releases_count; ++i) + free(releases[i].assets); + free(releases); +} diff --git a/launcher/main/updater.h b/launcher/main/updater.h new file mode 100644 index 000000000..979c4e8d9 --- /dev/null +++ b/launcher/main/updater.h @@ -0,0 +1 @@ +void updater_show_dialog(void); diff --git a/snes9x-go/main/keymap.h b/snes9x-go/main/keymap.h index 442f238eb..d4b120a5d 100644 --- a/snes9x-go/main/keymap.h +++ b/snes9x-go/main/keymap.h @@ -3,7 +3,6 @@ typedef struct { char name[16]; - size_t size; struct { uint16_t snes9x_mask; uint16_t local_mask; @@ -12,7 +11,7 @@ typedef struct } keymap_t; static const keymap_t KEYMAPS[] = { - {"Type A", 12, { + {"Type A", { {SNES_A_MASK, RG_KEY_A, 0}, {SNES_B_MASK, RG_KEY_B, 0}, {SNES_X_MASK, RG_KEY_START, 0}, @@ -26,7 +25,7 @@ static const keymap_t KEYMAPS[] = { {SNES_LEFT_MASK, RG_KEY_LEFT, 0}, {SNES_RIGHT_MASK, RG_KEY_RIGHT, 0}, }}, - {"Type B", 12, { + {"Type B", { {SNES_A_MASK, RG_KEY_START, 0}, {SNES_B_MASK, RG_KEY_A, 0}, {SNES_X_MASK, RG_KEY_SELECT, 0}, @@ -40,9 +39,13 @@ static const keymap_t KEYMAPS[] = { {SNES_LEFT_MASK, RG_KEY_LEFT, 0}, {SNES_RIGHT_MASK, RG_KEY_RIGHT, 0}, }}, - {"Type C", 8, { + {"Type C", { {SNES_A_MASK, RG_KEY_A, 0}, {SNES_B_MASK, RG_KEY_B, 0}, + {SNES_X_MASK, 0, 0}, + {SNES_Y_MASK, 0, 0}, + {SNES_TL_MASK, 0, 0}, + {SNES_TR_MASK, 0, 0}, {SNES_START_MASK, RG_KEY_START, 0}, {SNES_SELECT_MASK, RG_KEY_SELECT, 0}, {SNES_UP_MASK, RG_KEY_UP, 0}, @@ -54,10 +57,6 @@ static const keymap_t KEYMAPS[] = { static const size_t KEYMAPS_COUNT = (sizeof(KEYMAPS) / sizeof(keymap_t)); -static const char *CONSOLE_BUTTONS[] = { - "UP", "RIGHT", "DOWN", "LEFT", "SELECT", "START", "A", "B", "MENU", "OPTION", "NONE", "NONE" -}; - static const char *SNES_BUTTONS[] = { - "NONE", "NONE", "NONE", "NONE", "TR", "TL", "X", "A", "RIGHT", "LEFT", "DOWN", "UP", "START", "SELECT", "Y", "B" + "None", "None", "None", "None", "R", "L", "X", "A", "Right", "Left", "Down", "Up", "Start", "Select", "Y", "B" }; diff --git a/snes9x-go/main/main.c b/snes9x-go/main/main.c index 05faa89b7..71c6d1c27 100644 --- a/snes9x-go/main/main.c +++ b/snes9x-go/main/main.c @@ -132,9 +132,9 @@ static rg_gui_event_t menu_keymap_cb(rg_gui_option_t *option, rg_gui_event_t eve while (!dismissed) { - rg_gui_option_t options[keymap.size + 4]; + rg_gui_option_t options[20]; rg_gui_option_t *option = options; - char values[keymap.size][20]; + char values[16][20]; char profile[32]; option->label = "Profile"; @@ -155,21 +155,24 @@ static rg_gui_event_t menu_keymap_cb(rg_gui_option_t *option, rg_gui_event_t eve option->update_cb = &change_keymap_cb; option++; - for (int i = 0; i < keymap.size; i++) + for (int i = 0; i < RG_COUNT(keymap.keys); i++) { - // keys[i].key_id contains a bitmask, convert to bit number - int local_button = log2(keymap.keys[i].local_mask); - int mod_button = log2(keymap.keys[i].mod_mask); - int snes9x_button = log2(keymap.keys[i].snes9x_mask); + int local_button = keymap.keys[i].local_mask; + int mod_button = keymap.keys[i].mod_mask; + int snes9x_button = log2(keymap.keys[i].snes9x_mask); // convert bitmask to bit number + + // Empty mapping + if (snes9x_button < 4) + continue; // For now we don't display the D-PAD because it doesn't fit on large font - if (local_button < 4) + if (local_button & (RG_KEY_UP|RG_KEY_DOWN|RG_KEY_LEFT|RG_KEY_RIGHT)) continue; if (keymap.keys[i].mod_mask) - sprintf(values[i], "%s + %s", CONSOLE_BUTTONS[mod_button], CONSOLE_BUTTONS[local_button]); + sprintf(values[i], "%s + %s", rg_input_get_key_name(mod_button), rg_input_get_key_name(local_button)); else - sprintf(values[i], "%s", CONSOLE_BUTTONS[local_button]); + sprintf(values[i], "%s", rg_input_get_key_name(local_button)); option->label = SNES_BUTTONS[snes9x_button]; option->value = values[i]; @@ -214,7 +217,7 @@ uint32_t S9xReadJoypad(int32_t port) uint32_t joystick = rg_input_read_gamepad(); uint32_t joypad = 0; - for (int i = 0; i < keymap.size; ++i) + for (int i = 0; i < RG_COUNT(keymap.keys); ++i) { uint32_t bitmask = keymap.keys[i].local_mask | keymap.keys[i].mod_mask; if (bitmask && bitmask == (joystick & bitmask))