Path: blob/master/nyx/nyx_gui/frontend/gui_emummc_tools.c
1476 views
/*1* Copyright (c) 2019-2024 CTCaer2*3* This program is free software; you can redistribute it and/or modify it4* under the terms and conditions of the GNU General Public License,5* version 2, as published by the Free Software Foundation.6*7* This program is distributed in the hope it will be useful, but WITHOUT8* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or9* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for10* more details.11*12* You should have received a copy of the GNU General Public License13* along with this program. If not, see <http://www.gnu.org/licenses/>.14*/1516#include <stdlib.h>1718#include <bdk.h>1920#include "gui.h"21#include "fe_emummc_tools.h"22#include "gui_tools_partition_manager.h"23#include <libs/fatfs/ff.h>2425extern char *emmcsn_path_impl(char *path, char *sub_dir, char *filename, sdmmc_storage_t *storage);2627typedef struct _mbr_ctxt_t28{29u32 available;30u32 sector[3];31u32 resized_cnt[3];3233int part_idx;34u32 sector_start;35} mbr_ctxt_t;3637static bool emummc_backup;38static mbr_ctxt_t mbr_ctx;39static lv_obj_t *emummc_manage_window;40static lv_res_t (*emummc_tools)(lv_obj_t *btn);4142static lv_res_t _action_emummc_window_close(lv_obj_t *btn)43{44nyx_win_close_action_custom(btn);4546// Delete and relaunch main emuMMC window.47lv_obj_del(emummc_manage_window);48(*emummc_tools)(NULL);4950return LV_RES_INV;51}5253static void _create_window_emummc()54{55emmc_tool_gui_t emmc_tool_gui_ctxt;5657lv_obj_t *win;58if (!mbr_ctx.part_idx)59win = nyx_create_window_custom_close_btn(SYMBOL_DRIVE" Create SD File emuMMC", _action_emummc_window_close);60else61win = nyx_create_window_custom_close_btn(SYMBOL_DRIVE" Create SD Partition emuMMC", _action_emummc_window_close);6263//Disable buttons.64nyx_window_toggle_buttons(win, true);6566// Create important info container.67lv_obj_t *h1 = lv_cont_create(win, NULL);68lv_cont_set_fit(h1, false, true);69lv_obj_set_width(h1, (LV_HOR_RES / 9) * 5);70lv_obj_set_click(h1, false);71lv_cont_set_layout(h1, LV_LAYOUT_OFF);7273static lv_style_t h_style;74lv_style_copy(&h_style, lv_cont_get_style(h1));75h_style.body.main_color = LV_COLOR_HEX(0x1d1d1d);76h_style.body.grad_color = h_style.body.main_color;77h_style.body.opa = LV_OPA_COVER;7879// Chreate log container.80lv_obj_t *h2 = lv_cont_create(win, h1);81lv_cont_set_style(h2, &h_style);82lv_cont_set_fit(h2, false, false);83lv_obj_set_size(h2, (LV_HOR_RES / 11) * 4, LV_DPI * 5);84lv_cont_set_layout(h2, LV_LAYOUT_OFF);85lv_obj_align(h2, h1, LV_ALIGN_OUT_RIGHT_TOP, 0, LV_DPI / 5);8687lv_obj_t *label_log = lv_label_create(h2, NULL);88lv_label_set_recolor(label_log, true);89lv_obj_set_style(label_log, &monospace_text);90lv_label_set_long_mode(label_log, LV_LABEL_LONG_BREAK);91lv_label_set_static_text(label_log, "");92lv_obj_set_width(label_log, lv_obj_get_width(h2));93lv_obj_align(label_log, h2, LV_ALIGN_IN_TOP_LEFT, LV_DPI / 10, LV_DPI / 10);94emmc_tool_gui_ctxt.label_log = label_log;9596// Create elements for info container.97lv_obj_t *label_sep = lv_label_create(h1, NULL);98lv_label_set_static_text(label_sep, "");99100lv_obj_t *label_info = lv_label_create(h1, NULL);101lv_label_set_recolor(label_info, true);102lv_obj_set_width(label_info, lv_obj_get_width(h1));103lv_label_set_static_text(label_info, "\n\n\n\n\n\n\n\n\n");104lv_obj_set_style(label_info, lv_theme_get_current()->label.prim);105lv_obj_align(label_info, label_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, LV_DPI / 10);106emmc_tool_gui_ctxt.label_info = label_info;107108lv_obj_t *bar = lv_bar_create(h1, NULL);109lv_obj_set_size(bar, LV_DPI * 38 / 10, LV_DPI / 5);110lv_bar_set_range(bar, 0, 100);111lv_bar_set_value(bar, 0);112lv_obj_align(bar, label_info, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 8);113lv_obj_set_opa_scale(bar, LV_OPA_0);114lv_obj_set_opa_scale_enable(bar, true);115emmc_tool_gui_ctxt.bar = bar;116117lv_obj_t *label_pct= lv_label_create(h1, NULL);118lv_label_set_recolor(label_pct, true);119lv_label_set_static_text(label_pct, " "SYMBOL_DOT" 0%");120lv_obj_set_style(label_pct, lv_theme_get_current()->label.prim);121lv_obj_align(label_pct, bar, LV_ALIGN_OUT_RIGHT_MID, LV_DPI / 20, 0);122lv_obj_set_opa_scale(label_pct, LV_OPA_0);123lv_obj_set_opa_scale_enable(label_pct, true);124emmc_tool_gui_ctxt.label_pct = label_pct;125126lv_obj_t *label_finish = lv_label_create(h1, NULL);127lv_label_set_recolor(label_finish, true);128lv_label_set_static_text(label_finish, "");129lv_obj_set_style(label_finish, lv_theme_get_current()->label.prim);130lv_obj_align(label_finish, bar, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI * 9 / 20);131emmc_tool_gui_ctxt.label_finish = label_finish;132133if (!mbr_ctx.part_idx)134dump_emummc_file(&emmc_tool_gui_ctxt);135else136dump_emummc_raw(&emmc_tool_gui_ctxt, mbr_ctx.part_idx, mbr_ctx.sector_start, mbr_ctx.resized_cnt[mbr_ctx.part_idx - 1]);137138nyx_window_toggle_buttons(win, false);139}140141static lv_res_t _create_emummc_raw_format(lv_obj_t * btns, const char * txt)142{143int btn_idx = lv_btnm_get_pressed(btns);144145// Delete parent mbox.146mbox_action(btns, txt);147148// Create partition window.149if (!btn_idx)150create_window_partition_manager(btns);151152mbr_ctx.part_idx = 0;153mbr_ctx.sector_start = 0;154155return LV_RES_INV;156}157158static lv_res_t _create_emummc_raw_action(lv_obj_t * btns, const char * txt)159{160int btn_idx = lv_btnm_get_pressed(btns);161lv_obj_t *bg = lv_obj_get_parent(lv_obj_get_parent(btns));162163mbr_ctx.sector_start = 0x8000; // Protective offset.164165switch (btn_idx)166{167case 0:168mbr_ctx.part_idx = 1;169mbr_ctx.sector_start += mbr_ctx.sector[0];170break;171case 1:172mbr_ctx.part_idx = 2;173mbr_ctx.sector_start += mbr_ctx.sector[1];174break;175case 2:176mbr_ctx.part_idx = 3;177mbr_ctx.sector_start += mbr_ctx.sector[2];178break;179default:180break;181}182183if (btn_idx < 3)184{185lv_obj_set_style(bg, &lv_style_transp);186_create_window_emummc();187}188189mbr_ctx.part_idx = 0;190mbr_ctx.sector_start = 0;191192mbox_action(btns, txt);193194return LV_RES_INV;195}196197static void _create_mbox_emummc_raw()198{199lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);200lv_obj_set_style(dark_bg, &mbox_darken);201lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);202203static const char *mbox_btn_format[] = { "\222Continue", "\222Cancel", "" };204static char *mbox_btn_parts[] = { "\262Part 1", "\262Part 2", "\262Part 3", "\222Cancel", "" };205lv_obj_t * mbox = lv_mbox_create(dark_bg, NULL);206lv_mbox_set_recolor_text(mbox, true);207lv_obj_set_width(mbox, LV_HOR_RES / 9 * 6);208209char *txt_buf = (char *)malloc(SZ_16K);210mbr_t *mbr = (mbr_t *)malloc(sizeof(mbr_t));211212memset(&mbr_ctx, 0, sizeof(mbr_ctxt_t));213214sd_mount();215sdmmc_storage_read(&sd_storage, 0, 1, mbr);216sd_unmount();217218emmc_initialize(false);219220u32 emmc_size_safe = emmc_storage.sec_cnt + 0xC000; // eMMC GPP size + BOOT0/1.221222emmc_end();223224for (int i = 1; i < 4; i++)225{226u32 part_size = mbr->partitions[i].size_sct;227u32 part_start = mbr->partitions[i].start_sct;228u8 part_type = mbr->partitions[i].type;229230// Skip Linux, GPT (Android) and SFD partitions.231bool valid_part = (part_type != 0x83) && (part_type != 0xEE) && (part_type != 0xFF);232233// Check if at least 4GB and start above 16MB.234if ((part_size >= 0x80F000) && part_start > 0x8000 && valid_part)235{236mbr_ctx.available |= BIT(i - 1);237mbr_ctx.sector[i - 1] = part_start;238239// Only allow up to 16GB resized emuMMC.240if (part_size <= 0x2010000)241mbr_ctx.resized_cnt[i - 1] = part_size - 0xC000; // Save sectors count without protective size and BOOT0/1.242else if (part_size >= emmc_size_safe)243mbr_ctx.resized_cnt[i - 1] = 0;244else245{246mbr_ctx.available &= ~BIT(i - 1);247mbr_ctx.sector[i - 1] = 0;248}249}250}251252if (mbr_ctx.available)253{254s_printf(txt_buf,255"#C7EA46 Found applicable partition(s)!#\n"256"#FF8000 Choose a partition to continue:#\n\n");257}258else259s_printf(txt_buf, "#FFDD00 Failed to find applicable partition!#\n\n");260261s_printf(txt_buf + strlen(txt_buf),262"Partition table:\n"263"#C0C0C0 Part 0: Type: %02x, Start: %08x, Size: %08x#\n"264"#%s Part 1: Type: %02x, Start: %08x, Size: %08x#\n"265"#%s Part 2: Type: %02x, Start: %08x, Size: %08x#\n"266"#%s Part 3: Type: %02x, Start: %08x, Size: %08x#",267mbr->partitions[0].type, mbr->partitions[0].start_sct, mbr->partitions[0].size_sct,268(mbr_ctx.available & BIT(0)) ? (mbr_ctx.resized_cnt[0] ? "FFDD00" : "C7EA46") : "C0C0C0",269mbr->partitions[1].type, mbr->partitions[1].start_sct, mbr->partitions[1].size_sct,270(mbr_ctx.available & BIT(1)) ? (mbr_ctx.resized_cnt[1] ? "FFDD00" : "C7EA46") : "C0C0C0",271mbr->partitions[2].type, mbr->partitions[2].start_sct, mbr->partitions[2].size_sct,272(mbr_ctx.available & BIT(2)) ? (mbr_ctx.resized_cnt[2] ? "FFDD00" : "C7EA46") : "C0C0C0",273mbr->partitions[3].type, mbr->partitions[3].start_sct, mbr->partitions[3].size_sct);274275if (mbr_ctx.resized_cnt[0] || mbr_ctx.resized_cnt[1] || mbr_ctx.resized_cnt[2])276strcat(txt_buf, "\n\n#FFDD00 Note:# Yellow entries have USER partition resized.");277278if (!mbr_ctx.available)279strcat(txt_buf, "\n#FF8000 Do you want to partition the SD card?#\n"280"#FF8000 (You will be asked on how to proceed)#");281282lv_mbox_set_text(mbox, txt_buf);283free(txt_buf);284free(mbr);285286if (mbr_ctx.available)287{288// Check available partitions and enable the corresponding buttons.289if (mbr_ctx.available & 1)290mbox_btn_parts[0][0] = '\222';291else292mbox_btn_parts[0][0] = '\262';293if (mbr_ctx.available & 2)294mbox_btn_parts[1][0] = '\222';295else296mbox_btn_parts[1][0] = '\262';297if (mbr_ctx.available & 4)298mbox_btn_parts[2][0] = '\222';299else300mbox_btn_parts[2][0] = '\262';301302lv_mbox_add_btns(mbox, (const char **)mbox_btn_parts, _create_emummc_raw_action);303}304else305lv_mbox_add_btns(mbox, mbox_btn_format, _create_emummc_raw_format);306307lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);308lv_obj_set_top(mbox, true);309}310311static lv_res_t _create_emummc_action(lv_obj_t * btns, const char * txt)312{313int btn_idx = lv_btnm_get_pressed(btns);314lv_obj_t *bg = lv_obj_get_parent(lv_obj_get_parent(btns));315316mbr_ctx.part_idx = 0;317mbr_ctx.sector_start = 0;318319switch (btn_idx)320{321case 0:322lv_obj_set_style(bg, &lv_style_transp);323_create_window_emummc();324break;325case 1:326_create_mbox_emummc_raw();327break;328}329330mbox_action(btns, txt);331332return LV_RES_INV;333}334335static lv_res_t _create_mbox_emummc_create(lv_obj_t *btn)336{337if (!nyx_emmc_check_battery_enough())338return LV_RES_OK;339340lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);341lv_obj_set_style(dark_bg, &mbox_darken);342lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);343344static const char * mbox_btn_map[] = { "\222SD File", "\222SD Partition", "\222Cancel", "" };345lv_obj_t * mbox = lv_mbox_create(dark_bg, NULL);346lv_mbox_set_recolor_text(mbox, true);347lv_obj_set_width(mbox, LV_HOR_RES / 9 * 6);348349lv_mbox_set_text(mbox,350"Welcome to #C7EA46 emuMMC# creation tool!\n\n"351"Please choose what type of emuMMC you want to create.\n"352"#FF8000 SD File# is saved as files in the FAT partition.\n"353"#FF8000 SD Partition# is saved as raw image in an available partition.");354355lv_mbox_add_btns(mbox, mbox_btn_map, _create_emummc_action);356357lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);358lv_obj_set_top(mbox, true);359360return LV_RES_OK;361}362363static void _change_raw_emummc_part_type()364{365mbr_t *mbr = (mbr_t *)malloc(sizeof(mbr_t));366sdmmc_storage_read(&sd_storage, 0, 1, mbr);367mbr->partitions[mbr_ctx.part_idx].type = 0xE0;368sdmmc_storage_write(&sd_storage, 0, 1, mbr);369free(mbr);370}371372static lv_res_t _save_emummc_cfg_mig_mbox_action(lv_obj_t *btns, const char *txt)373{374// Delete main emuMMC and popup windows and relaunch main emuMMC window.375lv_obj_del(emummc_manage_window);376mbox_action(btns, txt);377378(*emummc_tools)(NULL);379380return LV_RES_INV;381}382383static void _create_emummc_migrated_mbox()384{385lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);386lv_obj_set_style(dark_bg, &mbox_darken);387lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);388389static const char *mbox_btn_map[] = { "\251", "OK", "\251", "" };390lv_obj_t * mbox = lv_mbox_create(dark_bg, NULL);391lv_mbox_set_recolor_text(mbox, true);392lv_obj_set_width(mbox, LV_HOR_RES / 9 * 4);393394lv_mbox_set_text(mbox,395"#FF8000 emuMMC Configuration#\n\n"396"#96FF00 The emuMMC configuration#\n#96FF00 was saved to sd card!#");397398lv_mbox_add_btns(mbox, mbox_btn_map, _save_emummc_cfg_mig_mbox_action);399400lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);401lv_obj_set_top(mbox, true);402}403404static void _migrate_sd_raw_based()405{406mbr_ctx.sector_start = 2;407408sd_mount();409f_mkdir("emuMMC");410f_mkdir("emuMMC/ER00");411412f_rename("Emutendo", "emuMMC/ER00/Nintendo");413FIL fp;414f_open(&fp, "emuMMC/ER00/raw_based", FA_CREATE_ALWAYS | FA_WRITE);415f_write(&fp, &mbr_ctx.sector_start, 4, NULL);416f_close(&fp);417418save_emummc_cfg(1, mbr_ctx.sector_start, "emuMMC/ER00");419_create_emummc_migrated_mbox();420sd_unmount();421}422423static void _migrate_sd_raw_emummc_based()424{425char *tmp = (char *)malloc(0x80);426s_printf(tmp, "emuMMC/RAW%d", mbr_ctx.part_idx);427428sd_mount();429f_mkdir("emuMMC");430f_mkdir(tmp);431strcat(tmp, "/raw_based");432433FIL fp;434if (!f_open(&fp, tmp, FA_CREATE_ALWAYS | FA_WRITE))435{436f_write(&fp, &mbr_ctx.sector_start, 4, NULL);437f_close(&fp);438}439440s_printf(tmp, "emuMMC/RAW%d", mbr_ctx.part_idx);441442_change_raw_emummc_part_type();443444save_emummc_cfg(mbr_ctx.part_idx, mbr_ctx.sector_start, tmp);445_create_emummc_migrated_mbox();446free(tmp);447448sd_unmount();449}450451static void _migrate_sd_file_based()452{453sd_mount();454f_mkdir("emuMMC");455f_mkdir("emuMMC/EF00");456457f_rename("Emutendo", "emuMMC/EF00/Nintendo");458FIL fp;459f_open(&fp, "emuMMC/EF00/file_based", FA_CREATE_ALWAYS | FA_WRITE);460f_close(&fp);461462char *path = (char *)malloc(128);463char *path2 = (char *)malloc(128);464s_printf(path, "%c%c%c%c%s", 's', 'x', 'o', 's', "/emunand");465f_rename(path, "emuMMC/EF00/eMMC");466467for (int i = 0; i < 2; i++)468{469s_printf(path, "emuMMC/EF00/eMMC/boot%d.bin", i);470s_printf(path2, "emuMMC/EF00/eMMC/BOOT%d", i);471f_rename(path, path2);472}473for (int i = 0; i < 8; i++)474{475s_printf(path, "emuMMC/EF00/eMMC/full.%02d.bin", i);476s_printf(path2, "emuMMC/EF00/eMMC/%02d", i);477f_rename(path, path2);478}479480free(path);481free(path2);482483save_emummc_cfg(0, 0, "emuMMC/EF00");484_create_emummc_migrated_mbox();485sd_unmount();486}487488static void _migrate_sd_backup_file_based()489{490char *emu_path = (char *)malloc(128);491char *parts_path = (char *)malloc(128);492char *backup_path = (char *)malloc(128);493char *backup_file_path = (char *)malloc(128);494495sd_mount();496f_mkdir("emuMMC");497498strcpy(emu_path, "emuMMC/BK");499u32 base_len = strlen(emu_path);500501for (int j = 0; j < 100; j++)502{503update_emummc_base_folder(emu_path, base_len, j);504if (f_stat(emu_path, NULL) == FR_NO_FILE)505break;506}507base_len = strlen(emu_path);508509f_mkdir(emu_path);510strcat(emu_path, "/eMMC");511f_mkdir(emu_path);512513FIL fp;514// Create file based flag.515strcpy(emu_path + base_len, "/file_based");516f_open(&fp, "emuMMC/BK00/file_based", FA_CREATE_ALWAYS | FA_WRITE);517f_close(&fp);518519if (!emummc_backup)520emmcsn_path_impl(backup_path, "", "", NULL);521else522emmcsn_path_impl(backup_path, "/emummc", "", NULL);523524// Move BOOT0.525s_printf(backup_file_path, "%s/BOOT0", backup_path);526strcpy(emu_path + base_len, "/eMMC/BOOT0");527f_rename(backup_file_path, emu_path);528529// Move BOOT1.530s_printf(backup_file_path, "%s/BOOT1", backup_path);531strcpy(emu_path + base_len, "/eMMC/BOOT1");532f_rename(backup_file_path, emu_path);533534// Move raw GPP.535bool multipart = false;536s_printf(backup_file_path, "%s/rawnand.bin", backup_path);537538if (f_stat(backup_file_path, NULL))539multipart = true;540541if (!multipart)542{543strcpy(emu_path + base_len, "/eMMC/00");544f_rename(backup_file_path, emu_path);545}546else547{548emu_path[base_len] = 0;549for (int i = 0; i < 32; i++)550{551s_printf(backup_file_path, "%s/rawnand.bin.%02d", backup_path, i);552s_printf(parts_path, "%s/eMMC/%02d", emu_path, i);553if (f_rename(backup_file_path, parts_path))554break;555}556}557558free(emu_path);559free(parts_path);560free(backup_path);561free(backup_file_path);562563save_emummc_cfg(0, 0, "emuMMC/BK00");564_create_emummc_migrated_mbox();565sd_unmount();566}567568static lv_res_t _create_emummc_mig1_action(lv_obj_t * btns, const char * txt)569{570switch (lv_btnm_get_pressed(btns))571{572case 0:573_migrate_sd_file_based();574break;575case 1:576_migrate_sd_raw_based();577break;578}579580mbr_ctx.part_idx = 0;581mbr_ctx.sector_start = 0;582583mbox_action(btns, txt);584585return LV_RES_INV;586}587588static lv_res_t _create_emummc_mig0_action(lv_obj_t * btns, const char * txt)589{590switch (lv_btnm_get_pressed(btns))591{592case 0:593_migrate_sd_file_based();594break;595}596597mbr_ctx.part_idx = 0;598mbr_ctx.sector_start = 0;599600mbox_action(btns, txt);601602return LV_RES_INV;603}604605static lv_res_t _create_emummc_mig2_action(lv_obj_t * btns, const char * txt)606{607switch (lv_btnm_get_pressed(btns))608{609case 0:610_migrate_sd_raw_based();611break;612}613614mbr_ctx.part_idx = 0;615mbr_ctx.sector_start = 0;616617mbox_action(btns, txt);618619return LV_RES_INV;620}621622static lv_res_t _create_emummc_mig3_action(lv_obj_t * btns, const char * txt)623{624switch (lv_btnm_get_pressed(btns))625{626case 0:627_migrate_sd_raw_emummc_based();628break;629}630631mbr_ctx.part_idx = 0;632mbr_ctx.sector_start = 0;633634mbox_action(btns, txt);635636return LV_RES_INV;637}638639static lv_res_t _create_emummc_mig4_action(lv_obj_t * btns, const char * txt)640{641switch (lv_btnm_get_pressed(btns))642{643case 0:644_migrate_sd_backup_file_based();645break;646}647648mbr_ctx.part_idx = 0;649mbr_ctx.sector_start = 0;650651mbox_action(btns, txt);652653return LV_RES_INV;654}655656bool em_raw;657bool em_file;658static lv_res_t _create_emummc_migrate_action(lv_obj_t * btns, const char * txt)659{660bool backup = false;661bool emummc = false;662663switch (lv_btnm_get_pressed(btns))664{665case 0:666backup = true;667break;668case 1:669emummc = true;670break;671case 2:672break;673case 3:674mbox_action(btns, txt);675return LV_RES_INV;676}677678lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);679lv_obj_set_style(dark_bg, &mbox_darken);680lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);681682static const char *mbox_btn_map[] = { "\222Continue", "\222Cancel", "" };683static const char *mbox_btn_map1[] = { "\222SD File", "\222SD Partition", "\222Cancel", "" };684static const char *mbox_btn_map3[] = { "\251", "OK", "\251", "" };685lv_obj_t * mbox = lv_mbox_create(dark_bg, NULL);686lv_mbox_set_recolor_text(mbox, true);687lv_obj_set_width(mbox, LV_HOR_RES / 9 * 6);688689char *txt_buf = (char *)malloc(SZ_16K);690691if (backup)692{693if (!emummc_backup)694s_printf(txt_buf,695"#C7EA46 Found suitable eMMC backup!#\n\n"696"#FF8000 Do you want to migrate it?#\n");697else698s_printf(txt_buf,699"#C7EA46 Found suitable emuMMC backup!#\n\n"700"#FF8000 Do you want to migrate it?#\n");701lv_mbox_add_btns(mbox, mbox_btn_map, _create_emummc_mig4_action);702}703else if (emummc)704{705s_printf(txt_buf,706"#C7EA46 Found SD Partition based emuMMC!#\n\n"707"#FF8000 Do you want to repair the config and partition type for it?#\n");708lv_mbox_add_btns(mbox, mbox_btn_map, _create_emummc_mig3_action);709}710else if (em_raw && em_file)711{712s_printf(txt_buf,713"#C7EA46 Found both foreign SD File and Partition emunand!#\n\n"714"#FF8000 Choose what to migrate:#\n");715lv_mbox_add_btns(mbox, mbox_btn_map1, _create_emummc_mig1_action);716}717else if (em_raw)718{719s_printf(txt_buf,720"#C7EA46 Found foreign SD Partition emunand!#\n\n"721"#FF8000 Do you want to migrate it?#\n");722lv_mbox_add_btns(mbox, mbox_btn_map, _create_emummc_mig2_action);723}724else if (em_file)725{726s_printf(txt_buf,727"#C7EA46 Found foreign SD File emunand!#\n\n"728"#FF8000 Do you want to migrate it?#\n");729lv_mbox_add_btns(mbox, mbox_btn_map, _create_emummc_mig0_action);730}731else732{733s_printf(txt_buf, "No emuMMC or foreign emunand found!\n");734lv_mbox_add_btns(mbox, mbox_btn_map3, mbox_action);735}736737lv_mbox_set_text(mbox, txt_buf);738free(txt_buf);739740lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);741lv_obj_set_top(mbox, true);742743mbox_action(btns, txt);744745return LV_RES_INV;746}747748typedef struct _emummc_images_t749{750dirlist_t *dirlist;751u32 part_sector[3];752u32 part_type[3];753u32 part_end[3];754char part_path[3 * 128];755lv_obj_t *win;756} emummc_images_t;757758static lv_res_t _create_mbox_emummc_migrate(lv_obj_t *btn)759{760lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);761lv_obj_set_style(dark_bg, &mbox_darken);762lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);763764static char *mbox_btn_map[] = { "\262Backup", "\262Fix RAW", "\262Emunand", "\222Cancel", "" };765lv_obj_t * mbox = lv_mbox_create(dark_bg, NULL);766lv_mbox_set_recolor_text(mbox, true);767lv_obj_set_width(mbox, LV_HOR_RES / 9 * 6);768769lv_mbox_set_text(mbox,770"Welcome to #C7EA46 emuMMC# migration tool!\n\n"771"Please choose what type of migration you want to do.\n"772"Anything that was not found will have the button disabled.");773774char *path_buf = (char *)malloc(0x512);775mbr_t *mbr = (mbr_t *)malloc(sizeof(mbr_t));776u8 *efi_part = (u8 *)malloc(0x200);777778sd_mount();779sdmmc_storage_read(&sd_storage, 0, 1, mbr);780781emmc_initialize(false);782783em_raw = false;784em_file = false;785bool backup = false;786bool emummc = false;787bool rawnand_backup = false;788789mbr_ctx.sector_start = 0;790mbr_ctx.part_idx = 0;791792// Try to find a partition based emuMMC.793for (int i = 1; i < 4; i++)794{795mbr_ctx.sector_start = mbr->partitions[i].start_sct;796797if (!mbr_ctx.sector_start)798continue;799800sdmmc_storage_read(&sd_storage, mbr_ctx.sector_start + 0xC001, 1, efi_part);801if (!memcmp(efi_part, "EFI PART", 8))802{803mbr_ctx.sector_start += 0x8000;804emummc = true;805mbr_ctx.part_idx = i;806break;807}808else809{810sdmmc_storage_read(&sd_storage, mbr_ctx.sector_start + 0x4001, 1, efi_part);811if (!memcmp(efi_part, "EFI PART", 8))812{813emummc = true;814mbr_ctx.part_idx = i;815break;816}817}818}819820if (!mbr_ctx.part_idx)821{822sdmmc_storage_read(&sd_storage, 0x4003, 1, efi_part);823if (!memcmp(efi_part, "EFI PART", 8))824em_raw = true;825}826827s_printf(path_buf, "%c%c%c%c%s", 's', 'x', 'o','s', "/emunand/boot0.bin");828829if (!f_stat(path_buf, NULL))830em_file = true;831832emummc_backup = false;833834emmcsn_path_impl(path_buf, "", "BOOT0", &emmc_storage);835if (!f_stat(path_buf, NULL))836backup = true;837838emmcsn_path_impl(path_buf, "", "rawnand.bin", &emmc_storage);839if (!f_stat(path_buf, NULL))840rawnand_backup = true;841842emmcsn_path_impl(path_buf, "", "rawnand.bin.00", &emmc_storage);843if (!f_stat(path_buf, NULL))844rawnand_backup = true;845846backup = backup && rawnand_backup;847848if (!backup)849{850rawnand_backup = false;851emummc_backup = true;852853emmcsn_path_impl(path_buf, "/emummc", "BOOT0", &emmc_storage);854if (!f_stat(path_buf, NULL))855backup = true;856857emmcsn_path_impl(path_buf, "/emummc", "rawnand.bin", &emmc_storage);858if (!f_stat(path_buf, NULL))859rawnand_backup = true;860861emmcsn_path_impl(path_buf, "/emummc", "rawnand.bin.00", &emmc_storage);862if (!f_stat(path_buf, NULL))863rawnand_backup = true;864865backup = backup && rawnand_backup;866}867868sd_unmount();869emmc_end();870871// Check available types and enable the corresponding buttons.872if (backup)873mbox_btn_map[0][0] = '\222';874else875mbox_btn_map[0][0] = '\262';876if (emummc)877mbox_btn_map[1][0] = '\222';878else879mbox_btn_map[1][0] = '\262';880if (em_raw || em_file)881mbox_btn_map[2][0] = '\222';882else883mbox_btn_map[2][0] = '\262';884885free(path_buf);886free(mbr);887free(efi_part);888889lv_mbox_add_btns(mbox, (const char **)mbox_btn_map, _create_emummc_migrate_action);890891lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);892lv_obj_set_top(mbox, true);893894return LV_RES_OK;895}896897static emummc_images_t *emummc_img;898899static lv_res_t _save_emummc_cfg_mbox_action(lv_obj_t *btns, const char *txt)900{901// Free components, delete main emuMMC and popup windows and relaunch main emuMMC window.902free(emummc_img->dirlist);903lv_obj_del(emummc_img->win);904lv_obj_del(emummc_manage_window);905free(emummc_img);906907mbox_action(btns, txt);908909(*emummc_tools)(NULL);910911return LV_RES_INV;912}913914static void _create_emummc_saved_mbox()915{916lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);917lv_obj_set_style(dark_bg, &mbox_darken);918lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);919920static const char *mbox_btn_map[] = { "\251", "OK", "\251", "" };921lv_obj_t * mbox = lv_mbox_create(dark_bg, NULL);922lv_mbox_set_recolor_text(mbox, true);923lv_obj_set_width(mbox, LV_HOR_RES / 9 * 4);924925lv_mbox_set_text(mbox,926"#FF8000 emuMMC Configuration#\n\n"927"#96FF00 The emuMMC configuration#\n#96FF00 was saved to sd card!#");928929lv_mbox_add_btns(mbox, mbox_btn_map, _save_emummc_cfg_mbox_action);930931lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);932lv_obj_set_top(mbox, true);933}934935static lv_res_t _save_raw_emummc_cfg_action(lv_obj_t * btn)936{937lv_btn_ext_t *ext = lv_obj_get_ext_attr(btn);938switch (ext->idx)939{940case 0:941save_emummc_cfg(1, emummc_img->part_sector[0], &emummc_img->part_path[0]);942break;943case 1:944save_emummc_cfg(2, emummc_img->part_sector[1], &emummc_img->part_path[128]);945break;946case 2:947save_emummc_cfg(3, emummc_img->part_sector[2], &emummc_img->part_path[256]);948break;949}950951_create_emummc_saved_mbox();952sd_unmount();953954return LV_RES_INV;955}956957static lv_res_t _save_disable_emummc_cfg_action(lv_obj_t * btn)958{959save_emummc_cfg(0, 0, NULL);960_create_emummc_saved_mbox();961sd_unmount();962963return LV_RES_INV;964}965966static lv_res_t _save_file_emummc_cfg_action(lv_obj_t *btn)967{968save_emummc_cfg(0, 0, lv_list_get_btn_text(btn));969_create_emummc_saved_mbox();970sd_unmount();971972return LV_RES_INV;973}974975static lv_res_t _create_change_emummc_window(lv_obj_t *btn_caller)976{977lv_obj_t *win = nyx_create_standard_window(SYMBOL_SETTINGS" Change emuMMC");978lv_win_add_btn(win, NULL, SYMBOL_POWER" Disable", _save_disable_emummc_cfg_action);979980sd_mount();981982emummc_img = malloc(sizeof(emummc_images_t));983emummc_img->win = win;984985mbr_t *mbr = (mbr_t *)malloc(sizeof(mbr_t));986char *path = malloc(512);987988sdmmc_storage_read(&sd_storage, 0, 1, mbr);989990memset(emummc_img->part_path, 0, 3 * 128);991992for (int i = 1; i < 4; i++)993{994emummc_img->part_sector[i - 1] = mbr->partitions[i].start_sct;995emummc_img->part_end[i - 1] = emummc_img->part_sector[i - 1] + mbr->partitions[i].size_sct - 1;996emummc_img->part_type[i - 1] = mbr->partitions[i].type;997}998free(mbr);9991000emummc_img->dirlist = dirlist("emuMMC", NULL, false, true);10011002if (!emummc_img->dirlist)1003goto out0;10041005u32 emummc_idx = 0;10061007FIL fp;10081009// Check for sd raw partitions, based on the folders in /emuMMC.1010while (emummc_img->dirlist->name[emummc_idx])1011{1012s_printf(path, "emuMMC/%s/raw_based", emummc_img->dirlist->name[emummc_idx]);10131014if (!f_stat(path, NULL))1015{1016f_open(&fp, path, FA_READ);1017u32 curr_list_sector = 0;1018f_read(&fp, &curr_list_sector, 4, NULL);1019f_close(&fp);10201021// Check if there's a HOS image there.1022if ((curr_list_sector == 2) || (emummc_img->part_sector[0] && curr_list_sector >= emummc_img->part_sector[0] &&1023curr_list_sector < emummc_img->part_end[0] && emummc_img->part_type[0] != 0x83))1024{1025s_printf(&emummc_img->part_path[0], "emuMMC/%s", emummc_img->dirlist->name[emummc_idx]);1026emummc_img->part_sector[0] = curr_list_sector;1027emummc_img->part_end[0] = 0;1028}1029else if (emummc_img->part_sector[1] && curr_list_sector >= emummc_img->part_sector[1] &&1030curr_list_sector < emummc_img->part_end[1] && emummc_img->part_type[1] != 0x83)1031{1032s_printf(&emummc_img->part_path[1 * 128], "emuMMC/%s", emummc_img->dirlist->name[emummc_idx]);1033emummc_img->part_sector[1] = curr_list_sector;1034emummc_img->part_end[1] = 0;1035}1036else if (emummc_img->part_sector[2] && curr_list_sector >= emummc_img->part_sector[2] &&1037curr_list_sector < emummc_img->part_end[2] && emummc_img->part_type[2] != 0x83)1038{1039s_printf(&emummc_img->part_path[2 * 128], "emuMMC/%s", emummc_img->dirlist->name[emummc_idx]);1040emummc_img->part_sector[2] = curr_list_sector;1041emummc_img->part_end[2] = 0;1042}1043}1044emummc_idx++;1045}10461047emummc_idx = 0;1048u32 file_based_idx = 0;10491050// Sanitize the directory list with sd file based ones.1051while (emummc_img->dirlist->name[emummc_idx])1052{1053s_printf(path, "emuMMC/%s/file_based", emummc_img->dirlist->name[emummc_idx]);10541055if (!f_stat(path, NULL))1056{1057char *tmp = emummc_img->dirlist->name[emummc_idx];1058memcpy(emummc_img->dirlist->name[file_based_idx], tmp, strlen(tmp) + 1);1059file_based_idx++;1060}1061emummc_idx++;1062}1063emummc_img->dirlist->name[file_based_idx] = NULL;10641065out0:;1066static lv_style_t h_style;1067lv_style_copy(&h_style, &lv_style_transp);1068h_style.body.padding.inner = 0;1069h_style.body.padding.hor = LV_DPI - (LV_DPI / 4);1070h_style.body.padding.ver = LV_DPI / 6;10711072// Create SD Raw Partitions container.1073lv_obj_t *h1 = lv_cont_create(win, NULL);1074lv_cont_set_style(h1, &h_style);1075lv_cont_set_fit(h1, false, true);1076lv_obj_set_width(h1, (LV_HOR_RES / 9) * 4);1077lv_obj_set_click(h1, false);1078lv_cont_set_layout(h1, LV_LAYOUT_OFF);10791080lv_obj_t *label_sep = lv_label_create(h1, NULL);1081lv_label_set_static_text(label_sep, "");10821083lv_obj_t *label_txt = lv_label_create(h1, NULL);1084lv_label_set_static_text(label_txt, "SD Raw Partitions");1085lv_obj_set_style(label_txt, lv_theme_get_current()->label.prim);1086lv_obj_align(label_txt, label_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, -(LV_DPI / 2));10871088lv_obj_t *line_sep = lv_line_create(h1, NULL);1089static const lv_point_t line_pp[] = { {0, 0}, { LV_HOR_RES - (LV_DPI - (LV_DPI / 4)) * 2, 0} };1090lv_line_set_points(line_sep, line_pp, 2);1091lv_line_set_style(line_sep, lv_theme_get_current()->line.decor);1092lv_obj_align(line_sep, label_txt, LV_ALIGN_OUT_BOTTOM_LEFT, -(LV_DPI / 4), LV_DPI / 8);10931094lv_obj_t *btn = NULL;1095lv_btn_ext_t *ext;1096lv_obj_t *btn_label = NULL;1097lv_obj_t *lv_desc = NULL;1098char *txt_buf = malloc(SZ_16K);10991100// Create RAW buttons.1101for (u32 raw_btn_idx = 0; raw_btn_idx < 3; raw_btn_idx++)1102{1103btn = lv_btn_create(h1, btn);1104ext = lv_obj_get_ext_attr(btn);1105ext->idx = raw_btn_idx;1106btn_label = lv_label_create(btn, btn_label);11071108lv_btn_set_state(btn, LV_BTN_STATE_REL);1109lv_obj_set_click(btn, true);11101111if (emummc_img->part_type[raw_btn_idx] != 0x83)1112{1113s_printf(txt_buf, "SD RAW %d", raw_btn_idx + 1);1114lv_label_set_text(btn_label, txt_buf);1115}11161117if (!emummc_img->part_sector[raw_btn_idx] || emummc_img->part_type[raw_btn_idx] == 0x83 || !emummc_img->part_path[raw_btn_idx * 128])1118{1119lv_btn_set_state(btn, LV_BTN_STATE_INA);1120lv_obj_set_click(btn, false);11211122if (emummc_img->part_type[raw_btn_idx] == 0x83)1123lv_label_set_static_text(btn_label, "Linux");1124}11251126if (!raw_btn_idx)1127{1128lv_btn_set_fit(btn, false, true);1129lv_obj_set_width(btn, LV_DPI * 3);1130lv_obj_align(btn, line_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 2, LV_DPI / 5);1131}1132else1133lv_obj_align(btn, lv_desc, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3);11341135lv_btn_set_action(btn, LV_BTN_ACTION_CLICK, _save_raw_emummc_cfg_action);11361137lv_desc = lv_label_create(h1, lv_desc);1138lv_label_set_recolor(lv_desc, true);1139lv_obj_set_style(lv_desc, &hint_small_style);11401141s_printf(txt_buf, "Sector start: 0x%08X\nFolder: %s", emummc_img->part_sector[raw_btn_idx], &emummc_img->part_path[raw_btn_idx * 128]);1142lv_label_set_text(lv_desc, txt_buf);1143lv_obj_align(lv_desc, btn, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 5);1144}1145free(txt_buf);11461147// Create SD File Based container.1148lv_obj_t *h2 = lv_cont_create(win, NULL);1149lv_cont_set_style(h2, &h_style);1150lv_cont_set_fit(h2, false, true);1151lv_obj_set_width(h2, (LV_HOR_RES / 9) * 4);1152lv_obj_set_click(h2, false);1153lv_cont_set_layout(h2, LV_LAYOUT_OFF);1154lv_obj_align(h2, h1, LV_ALIGN_OUT_RIGHT_TOP, LV_DPI * 17 / 29, 0);11551156label_sep = lv_label_create(h2, NULL);1157lv_label_set_static_text(label_sep, "");11581159lv_obj_t *label_txt3 = lv_label_create(h2, NULL);1160lv_label_set_static_text(label_txt3, "SD File Based");1161lv_obj_set_style(label_txt3, lv_theme_get_current()->label.prim);1162lv_obj_align(label_txt3, label_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, -LV_DPI / 7);11631164line_sep = lv_line_create(h2, line_sep);1165lv_obj_align(line_sep, label_txt3, LV_ALIGN_OUT_BOTTOM_LEFT, -(LV_DPI / 2), LV_DPI / 8);1166lv_line_set_style(line_sep, lv_theme_get_current()->line.decor);11671168lv_obj_t *list_sd_based = lv_list_create(h2, NULL);1169lv_obj_align(list_sd_based, line_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 2, LV_DPI / 4);11701171lv_obj_set_size(list_sd_based, LV_HOR_RES * 4 / 10, LV_VER_RES * 6 / 10);1172lv_list_set_single_mode(list_sd_based, true);11731174if (!emummc_img->dirlist)1175goto out1;11761177emummc_idx = 0;11781179// Add file based to the list.1180while (emummc_img->dirlist->name[emummc_idx])1181{1182s_printf(path, "emuMMC/%s", emummc_img->dirlist->name[emummc_idx]);11831184lv_list_add(list_sd_based, NULL, path, _save_file_emummc_cfg_action);11851186emummc_idx++;1187}11881189out1:1190free(path);1191sd_unmount();11921193return LV_RES_OK;1194}11951196lv_res_t create_win_emummc_tools(lv_obj_t *btn)1197{1198lv_obj_t *win = nyx_create_standard_window(SYMBOL_EDIT" emuMMC Manage");11991200// Set resources to be managed by other windows.1201emummc_manage_window = win;1202emummc_tools = (void *)create_win_emummc_tools;12031204sd_mount();12051206emummc_cfg_t emu_info;1207load_emummc_cfg(&emu_info);12081209sd_unmount();12101211static lv_style_t h_style;1212lv_style_copy(&h_style, &lv_style_transp);1213h_style.body.padding.inner = 0;1214h_style.body.padding.hor = LV_DPI - (LV_DPI / 4);1215h_style.body.padding.ver = LV_DPI / 9;12161217// Create emuMMC Info & Selection container.1218lv_obj_t *h1 = lv_cont_create(win, NULL);1219lv_cont_set_style(h1, &h_style);1220lv_cont_set_fit(h1, false, true);1221lv_obj_set_width(h1, (LV_HOR_RES / 9) * 4);1222lv_obj_set_click(h1, false);1223lv_cont_set_layout(h1, LV_LAYOUT_OFF);12241225lv_obj_t *label_sep = lv_label_create(h1, NULL);1226lv_label_set_static_text(label_sep, "");12271228lv_obj_t *label_txt = lv_label_create(h1, NULL);1229lv_label_set_static_text(label_txt, "emuMMC Info & Selection");1230lv_obj_set_style(label_txt, lv_theme_get_current()->label.prim);1231lv_obj_align(label_txt, label_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, -LV_DPI / 9);12321233lv_obj_t *line_sep = lv_line_create(h1, NULL);1234static const lv_point_t line_pp[] = { {0, 0}, { LV_HOR_RES - (LV_DPI - (LV_DPI / 4)) * 2, 0} };1235lv_line_set_points(line_sep, line_pp, 2);1236lv_line_set_style(line_sep, lv_theme_get_current()->line.decor);1237lv_obj_align(line_sep, label_txt, LV_ALIGN_OUT_BOTTOM_LEFT, -(LV_DPI / 4), LV_DPI / 8);12381239// Create emuMMC info labels.1240lv_obj_t *label_btn = lv_label_create(h1, NULL);1241lv_label_set_recolor(label_btn, true);1242lv_label_set_static_text(label_btn, emu_info.enabled ? "#96FF00 "SYMBOL_OK" Enabled!#" : "#FF8000 "SYMBOL_CLOSE" Disabled!#");1243lv_obj_align(label_btn, line_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, LV_DPI / 4);12441245lv_obj_t *label_txt2 = lv_label_create(h1, NULL);1246lv_label_set_recolor(label_txt2, true);1247char *txt_buf = (char *)malloc(SZ_16K);12481249if (emu_info.enabled)1250{1251if (emu_info.sector)1252s_printf(txt_buf, "#00DDFF Type:# SD Raw Partition\n#00DDFF Sector:# 0x%08X\n#00DDFF Nintendo folder:# %s",1253emu_info.sector, emu_info.nintendo_path ? emu_info.nintendo_path : "");1254else1255s_printf(txt_buf, "#00DDFF Type:# SD File\n#00DDFF Base folder:# %s\n#00DDFF Nintendo folder:# %s",1256emu_info.path ? emu_info.path : "", emu_info.nintendo_path ? emu_info.nintendo_path : "");12571258lv_label_set_text(label_txt2, txt_buf);1259}1260else1261{1262lv_label_set_static_text(label_txt2, "emuMMC is disabled and eMMC will be used for boot.\n\n");1263}12641265if (emu_info.path)1266free(emu_info.path);1267if (emu_info.nintendo_path)1268free(emu_info.nintendo_path);1269free(txt_buf);12701271lv_obj_set_style(label_txt2, &hint_small_style);1272lv_obj_align(label_txt2, label_btn, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3);12731274// Create Change emuMMC button.1275lv_obj_t *btn2 = lv_btn_create(h1, NULL);1276lv_btn_set_fit(btn2, true, true);1277label_btn = lv_label_create(btn2, NULL);1278lv_label_set_static_text(label_btn, SYMBOL_SETTINGS" Change emuMMC");1279lv_obj_align(btn2, label_txt2, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI * 6 / 10);1280lv_btn_set_action(btn2, LV_BTN_ACTION_CLICK, _create_change_emummc_window);12811282label_txt2 = lv_label_create(h1, NULL);1283lv_label_set_recolor(label_txt2, true);1284lv_label_set_static_text(label_txt2,1285"Choose between images created in the emuMMC folder\n"1286"or in SD card partitions. You can have at most 3 partition\n"1287"based and countless file based.");12881289lv_obj_set_style(label_txt2, &hint_small_style);1290lv_obj_align(label_txt2, btn2, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3);12911292// Create emuMMC Tools container.1293lv_obj_t *h2 = lv_cont_create(win, NULL);1294lv_cont_set_style(h2, &h_style);1295lv_cont_set_fit(h2, false, true);1296lv_obj_set_width(h2, (LV_HOR_RES / 9) * 4);1297lv_obj_set_click(h2, false);1298lv_cont_set_layout(h2, LV_LAYOUT_OFF);1299lv_obj_align(h2, h1, LV_ALIGN_OUT_RIGHT_TOP, LV_DPI * 17 / 29, 0);13001301label_sep = lv_label_create(h2, NULL);1302lv_label_set_static_text(label_sep, "");13031304lv_obj_t *label_txt3 = lv_label_create(h2, NULL);1305lv_label_set_static_text(label_txt3, "emuMMC Tools");1306lv_obj_set_style(label_txt3, lv_theme_get_current()->label.prim);1307lv_obj_align(label_txt3, label_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, 0);13081309line_sep = lv_line_create(h2, line_sep);1310lv_obj_align(line_sep, label_txt3, LV_ALIGN_OUT_BOTTOM_LEFT, -(LV_DPI / 4), LV_DPI / 8);13111312// Create Create emuMMC button.1313lv_obj_t *btn3 = lv_btn_create(h2, btn2);1314label_btn = lv_label_create(btn3, NULL);1315lv_btn_set_fit(btn3, true, true);1316lv_label_set_static_text(label_btn, SYMBOL_DRIVE" Create emuMMC");1317lv_obj_align(btn3, line_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, LV_DPI / 4);1318lv_btn_set_action(btn3, LV_BTN_ACTION_CLICK, _create_mbox_emummc_create);13191320lv_obj_t *label_txt4 = lv_label_create(h2, NULL);1321lv_label_set_recolor(label_txt4, true);1322lv_label_set_static_text(label_txt4,1323"Allows you to create a new #C7EA46 SD File# or #C7EA46 SD Raw Partition#\n"1324"emuMMC. You can create it from eMMC or a eMMC Backup.");13251326lv_obj_set_style(label_txt4, &hint_small_style);1327lv_obj_align(label_txt4, btn3, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3);13281329// Create Migrate emuMMC button.1330lv_obj_t *btn4 = lv_btn_create(h2, btn2);1331label_btn = lv_label_create(btn4, NULL);1332lv_label_set_static_text(label_btn, SYMBOL_SHUFFLE" Migrate emuMMC");1333lv_obj_align(btn4, label_txt4, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 2);1334lv_btn_set_action(btn4, LV_BTN_ACTION_CLICK, NULL);1335lv_btn_set_action(btn4, LV_BTN_ACTION_CLICK, _create_mbox_emummc_migrate);13361337label_txt4 = lv_label_create(h2, NULL);1338lv_label_set_recolor(label_txt4, true);1339lv_label_set_static_text(label_txt4,1340"Migrate a backup to a #C7EA46 SD File# or repair existing #C7EA46 SD Raw Partition#.\n"1341"Additionally it allows you to migrate from other emunand\nsolutions.");1342lv_obj_set_style(label_txt4, &hint_small_style);1343lv_obj_align(label_txt4, btn4, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3);13441345return LV_RES_OK;1346}134713481349