Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
CTCaer
GitHub Repository: CTCaer/hekate
Path: blob/master/nyx/nyx_gui/frontend/gui_emummc_tools.c
3711 views
1
/*
2
* Copyright (c) 2019-2026 CTCaer
3
*
4
* This program is free software; you can redistribute it and/or modify it
5
* under the terms and conditions of the GNU General Public License,
6
* version 2, as published by the Free Software Foundation.
7
*
8
* This program is distributed in the hope it will be useful, but WITHOUT
9
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11
* more details.
12
*
13
* You should have received a copy of the GNU General Public License
14
* along with this program. If not, see <http://www.gnu.org/licenses/>.
15
*/
16
17
#include <stdlib.h>
18
19
#include <bdk.h>
20
21
#include "gui.h"
22
#include "fe_emummc_tools.h"
23
#include "gui_tools_partition_manager.h"
24
#include <libs/fatfs/ff.h>
25
26
extern char *emmcsn_path_impl(char *path, char *sub_dir, char *filename, sdmmc_storage_t *storage);
27
28
typedef struct _mbr_ctxt_t
29
{
30
u32 available;
31
u32 sector[3];
32
u32 resized_cnt[3];
33
34
int part_idx;
35
u32 sector_start;
36
} mbr_ctxt_t;
37
38
static bool emummc_backup;
39
static mbr_ctxt_t mbr_ctx;
40
static lv_obj_t *emummc_manage_window;
41
static lv_res_t (*emummc_tools)(lv_obj_t *btn);
42
43
static lv_res_t _action_emummc_window_close(lv_obj_t *btn)
44
{
45
nyx_win_close_action(btn);
46
47
// Delete and relaunch main emuMMC window.
48
lv_obj_del(emummc_manage_window);
49
(*emummc_tools)(NULL);
50
51
return LV_RES_INV;
52
}
53
54
static void _create_window_emummc()
55
{
56
emmc_tool_gui_t emmc_tool_gui_ctxt;
57
58
lv_obj_t *win;
59
if (!mbr_ctx.part_idx)
60
win = nyx_create_standard_window(SYMBOL_DRIVE" Create SD File emuMMC", _action_emummc_window_close);
61
else
62
win = nyx_create_standard_window(SYMBOL_DRIVE" Create SD Partition emuMMC", _action_emummc_window_close);
63
64
//Disable buttons.
65
nyx_window_toggle_buttons(win, true);
66
67
// Create important info container.
68
lv_obj_t *h1 = lv_cont_create(win, NULL);
69
lv_cont_set_fit(h1, false, true);
70
lv_obj_set_width(h1, (LV_HOR_RES / 9) * 5);
71
lv_obj_set_click(h1, false);
72
lv_cont_set_layout(h1, LV_LAYOUT_OFF);
73
74
static lv_style_t h_style;
75
lv_style_copy(&h_style, lv_cont_get_style(h1));
76
h_style.body.main_color = LV_COLOR_HEX(0x1d1d1d);
77
h_style.body.grad_color = h_style.body.main_color;
78
h_style.body.opa = LV_OPA_COVER;
79
80
// Chreate log container.
81
lv_obj_t *h2 = lv_cont_create(win, h1);
82
lv_cont_set_style(h2, &h_style);
83
lv_cont_set_fit(h2, false, false);
84
lv_obj_set_size(h2, (LV_HOR_RES / 11) * 4, LV_DPI * 5);
85
lv_cont_set_layout(h2, LV_LAYOUT_OFF);
86
lv_obj_align(h2, h1, LV_ALIGN_OUT_RIGHT_TOP, 0, LV_DPI / 5);
87
88
lv_obj_t *label_log = lv_label_create(h2, NULL);
89
lv_label_set_recolor(label_log, true);
90
lv_obj_set_style(label_log, &monospace_text);
91
lv_label_set_long_mode(label_log, LV_LABEL_LONG_BREAK);
92
lv_label_set_static_text(label_log, "");
93
lv_obj_set_width(label_log, lv_obj_get_width(h2));
94
lv_obj_align(label_log, h2, LV_ALIGN_IN_TOP_LEFT, LV_DPI / 10, LV_DPI / 10);
95
emmc_tool_gui_ctxt.label_log = label_log;
96
97
// Create elements for info container.
98
lv_obj_t *label_sep = lv_label_create(h1, NULL);
99
lv_label_set_static_text(label_sep, "");
100
101
lv_obj_t *label_info = lv_label_create(h1, NULL);
102
lv_label_set_recolor(label_info, true);
103
lv_obj_set_width(label_info, lv_obj_get_width(h1));
104
lv_label_set_static_text(label_info, "\n\n\n\n\n\n\n\n\n");
105
lv_obj_set_style(label_info, lv_theme_get_current()->label.prim);
106
lv_obj_align(label_info, label_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, LV_DPI / 10);
107
emmc_tool_gui_ctxt.label_info = label_info;
108
109
lv_obj_t *bar = lv_bar_create(h1, NULL);
110
lv_obj_set_size(bar, LV_DPI * 38 / 10, LV_DPI / 5);
111
lv_bar_set_range(bar, 0, 100);
112
lv_bar_set_value(bar, 0);
113
lv_obj_align(bar, label_info, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 8);
114
lv_obj_set_opa_scale(bar, LV_OPA_0);
115
lv_obj_set_opa_scale_enable(bar, true);
116
emmc_tool_gui_ctxt.bar = bar;
117
118
lv_obj_t *label_pct= lv_label_create(h1, NULL);
119
lv_label_set_recolor(label_pct, true);
120
lv_label_set_static_text(label_pct, " "SYMBOL_DOT" 0%");
121
lv_obj_set_style(label_pct, lv_theme_get_current()->label.prim);
122
lv_obj_align(label_pct, bar, LV_ALIGN_OUT_RIGHT_MID, LV_DPI / 20, 0);
123
lv_obj_set_opa_scale(label_pct, LV_OPA_0);
124
lv_obj_set_opa_scale_enable(label_pct, true);
125
emmc_tool_gui_ctxt.label_pct = label_pct;
126
127
lv_obj_t *label_finish = lv_label_create(h1, NULL);
128
lv_label_set_recolor(label_finish, true);
129
lv_label_set_static_text(label_finish, "");
130
lv_obj_set_style(label_finish, lv_theme_get_current()->label.prim);
131
lv_obj_align(label_finish, bar, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI * 9 / 20);
132
emmc_tool_gui_ctxt.label_finish = label_finish;
133
134
if (!mbr_ctx.part_idx)
135
dump_emummc_file(&emmc_tool_gui_ctxt);
136
else
137
dump_emummc_raw(&emmc_tool_gui_ctxt, mbr_ctx.part_idx, mbr_ctx.sector_start, mbr_ctx.resized_cnt[mbr_ctx.part_idx - 1]);
138
139
nyx_window_toggle_buttons(win, false);
140
}
141
142
static lv_res_t _create_emummc_raw_format(lv_obj_t * btns, const char * txt)
143
{
144
int btn_idx = lv_btnm_get_pressed(btns);
145
146
// Delete parent mbox.
147
nyx_mbox_action(btns, txt);
148
149
// Create partition window.
150
if (!btn_idx)
151
create_window_sd_partition_manager(btns);
152
153
mbr_ctx.part_idx = 0;
154
mbr_ctx.sector_start = 0;
155
156
return LV_RES_INV;
157
}
158
159
static lv_res_t _create_emummc_raw_action(lv_obj_t * btns, const char * txt)
160
{
161
int btn_idx = lv_btnm_get_pressed(btns);
162
lv_obj_t *bg = lv_obj_get_parent(lv_obj_get_parent(btns));
163
164
mbr_ctx.sector_start = 0x8000; // Protective offset.
165
166
switch (btn_idx)
167
{
168
case 0:
169
mbr_ctx.part_idx = 1;
170
mbr_ctx.sector_start += mbr_ctx.sector[0];
171
break;
172
case 1:
173
mbr_ctx.part_idx = 2;
174
mbr_ctx.sector_start += mbr_ctx.sector[1];
175
break;
176
case 2:
177
mbr_ctx.part_idx = 3;
178
mbr_ctx.sector_start += mbr_ctx.sector[2];
179
break;
180
default:
181
break;
182
}
183
184
if (btn_idx < 3)
185
{
186
lv_obj_set_style(bg, &lv_style_transp);
187
_create_window_emummc();
188
}
189
190
mbr_ctx.part_idx = 0;
191
mbr_ctx.sector_start = 0;
192
193
nyx_mbox_action(btns, txt);
194
195
return LV_RES_INV;
196
}
197
198
static void _create_mbox_emummc_raw()
199
{
200
lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);
201
lv_obj_set_style(dark_bg, &mbox_darken);
202
lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);
203
204
static const char *mbox_btn_format[] = { "\222Continue", "\222Cancel", "" };
205
static char *mbox_btn_parts[] = { "\262Part 1", "\262Part 2", "\262Part 3", "\222Cancel", "" };
206
lv_obj_t * mbox = lv_mbox_create(dark_bg, NULL);
207
lv_mbox_set_recolor_text(mbox, true);
208
lv_obj_set_width(mbox, LV_HOR_RES / 9 * 6);
209
210
char *txt_buf = (char *)malloc(SZ_16K);
211
mbr_t *mbr = (mbr_t *)malloc(sizeof(mbr_t));
212
213
memset(&mbr_ctx, 0, sizeof(mbr_ctxt_t));
214
215
sd_mount();
216
sdmmc_storage_read(&sd_storage, 0, 1, mbr);
217
sd_unmount();
218
219
emmc_initialize(false);
220
221
u32 emmc_size_safe = emmc_storage.sec_cnt + 0xC000; // eMMC GPP size + BOOT0/1.
222
223
emmc_end();
224
225
for (int i = 1; i < 4; i++)
226
{
227
u32 part_size = mbr->partitions[i].size_sct;
228
u32 part_start = mbr->partitions[i].start_sct;
229
u8 part_type = mbr->partitions[i].type;
230
231
// Skip Linux, GPT (Android) and SFD partitions.
232
bool valid_part = (part_type != 0x83) && (part_type != 0xEE) && (part_type != 0xFF);
233
234
// Check if at least 4GB and start above 16MB.
235
if ((part_size >= 0x80F000) && part_start > 0x8000 && valid_part)
236
{
237
mbr_ctx.available |= BIT(i - 1);
238
mbr_ctx.sector[i - 1] = part_start;
239
240
// Only allow up to 28GB resized emuMMC.
241
if (part_size <= 0x3810000)
242
mbr_ctx.resized_cnt[i - 1] = part_size - 0xC000; // Save sectors count without protective size and BOOT0/1.
243
else if (part_size >= emmc_size_safe)
244
mbr_ctx.resized_cnt[i - 1] = 0;
245
else
246
{
247
mbr_ctx.available &= ~BIT(i - 1);
248
mbr_ctx.sector[i - 1] = 0;
249
}
250
}
251
}
252
253
if (mbr_ctx.available)
254
{
255
s_printf(txt_buf,
256
"#C7EA46 Found applicable partition(s)!#\n"
257
"#FF8000 Choose a partition to continue:#\n\n");
258
}
259
else
260
s_printf(txt_buf, "#FFDD00 Failed to find applicable partition!#\n\n");
261
262
s_printf(txt_buf + strlen(txt_buf),
263
"Partition table:\n"
264
"#C0C0C0 Part 0: Type: %02x, Start: %08x, Size: %08x#\n"
265
"#%s Part 1: Type: %02x, Start: %08x, Size: %08x#\n"
266
"#%s Part 2: Type: %02x, Start: %08x, Size: %08x#\n"
267
"#%s Part 3: Type: %02x, Start: %08x, Size: %08x#",
268
mbr->partitions[0].type, mbr->partitions[0].start_sct, mbr->partitions[0].size_sct,
269
(mbr_ctx.available & BIT(0)) ? (mbr_ctx.resized_cnt[0] ? "FFDD00" : "C7EA46") : "C0C0C0",
270
mbr->partitions[1].type, mbr->partitions[1].start_sct, mbr->partitions[1].size_sct,
271
(mbr_ctx.available & BIT(1)) ? (mbr_ctx.resized_cnt[1] ? "FFDD00" : "C7EA46") : "C0C0C0",
272
mbr->partitions[2].type, mbr->partitions[2].start_sct, mbr->partitions[2].size_sct,
273
(mbr_ctx.available & BIT(2)) ? (mbr_ctx.resized_cnt[2] ? "FFDD00" : "C7EA46") : "C0C0C0",
274
mbr->partitions[3].type, mbr->partitions[3].start_sct, mbr->partitions[3].size_sct);
275
276
if (mbr_ctx.resized_cnt[0] || mbr_ctx.resized_cnt[1] || mbr_ctx.resized_cnt[2])
277
strcat(txt_buf, "\n\n#FFDD00 Note:# Yellow entries have USER partition resized.");
278
279
if (!mbr_ctx.available)
280
strcat(txt_buf, "\n#FF8000 Do you want to partition the SD card?#\n"
281
"#FF8000 (You will be asked on how to proceed)#");
282
283
lv_mbox_set_text(mbox, txt_buf);
284
free(txt_buf);
285
free(mbr);
286
287
if (mbr_ctx.available)
288
{
289
// Check available partitions and enable the corresponding buttons.
290
if (mbr_ctx.available & 1)
291
mbox_btn_parts[0][0] = '\222';
292
else
293
mbox_btn_parts[0][0] = '\262';
294
if (mbr_ctx.available & 2)
295
mbox_btn_parts[1][0] = '\222';
296
else
297
mbox_btn_parts[1][0] = '\262';
298
if (mbr_ctx.available & 4)
299
mbox_btn_parts[2][0] = '\222';
300
else
301
mbox_btn_parts[2][0] = '\262';
302
303
lv_mbox_add_btns(mbox, (const char **)mbox_btn_parts, _create_emummc_raw_action);
304
}
305
else
306
lv_mbox_add_btns(mbox, mbox_btn_format, _create_emummc_raw_format);
307
308
lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);
309
lv_obj_set_top(mbox, true);
310
}
311
312
static lv_res_t _create_emummc_action(lv_obj_t * btns, const char * txt)
313
{
314
int btn_idx = lv_btnm_get_pressed(btns);
315
lv_obj_t *bg = lv_obj_get_parent(lv_obj_get_parent(btns));
316
317
mbr_ctx.part_idx = 0;
318
mbr_ctx.sector_start = 0;
319
320
switch (btn_idx)
321
{
322
case 0:
323
lv_obj_set_style(bg, &lv_style_transp);
324
_create_window_emummc();
325
break;
326
case 1:
327
_create_mbox_emummc_raw();
328
break;
329
}
330
331
nyx_mbox_action(btns, txt);
332
333
return LV_RES_INV;
334
}
335
336
static lv_res_t _create_mbox_emummc_create(lv_obj_t *btn)
337
{
338
if (!nyx_emmc_check_battery_enough())
339
return LV_RES_OK;
340
341
lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);
342
lv_obj_set_style(dark_bg, &mbox_darken);
343
lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);
344
345
static const char * mbox_btn_map[] = { "\222SD File", "\222SD Partition", "\222Cancel", "" };
346
lv_obj_t * mbox = lv_mbox_create(dark_bg, NULL);
347
lv_mbox_set_recolor_text(mbox, true);
348
lv_obj_set_width(mbox, LV_HOR_RES / 9 * 6);
349
350
lv_mbox_set_text(mbox,
351
"Welcome to #C7EA46 emuMMC# creation tool!\n\n"
352
"Please choose what type of emuMMC you want to create.\n"
353
"#FF8000 SD File# is saved as files in the FAT partition.\n"
354
"#FF8000 SD Partition# is saved as raw image in an available partition.");
355
356
lv_mbox_add_btns(mbox, mbox_btn_map, _create_emummc_action);
357
358
lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);
359
lv_obj_set_top(mbox, true);
360
361
return LV_RES_OK;
362
}
363
364
static void _change_raw_emummc_part_type()
365
{
366
mbr_t *mbr = (mbr_t *)malloc(sizeof(mbr_t));
367
sdmmc_storage_read(&sd_storage, 0, 1, mbr);
368
mbr->partitions[mbr_ctx.part_idx].type = 0xE0;
369
sdmmc_storage_write(&sd_storage, 0, 1, mbr);
370
free(mbr);
371
}
372
373
static lv_res_t _save_emummc_cfg_mig_mbox_action(lv_obj_t *btns, const char *txt)
374
{
375
// Delete main emuMMC and popup windows and relaunch main emuMMC window.
376
lv_obj_del(emummc_manage_window);
377
nyx_mbox_action(btns, txt);
378
379
(*emummc_tools)(NULL);
380
381
return LV_RES_INV;
382
}
383
384
static void _create_emummc_migrated_mbox()
385
{
386
lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);
387
lv_obj_set_style(dark_bg, &mbox_darken);
388
lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);
389
390
static const char *mbox_btn_map[] = { "\251", "OK", "\251", "" };
391
lv_obj_t * mbox = lv_mbox_create(dark_bg, NULL);
392
lv_mbox_set_recolor_text(mbox, true);
393
lv_obj_set_width(mbox, LV_HOR_RES / 9 * 4);
394
395
lv_mbox_set_text(mbox,
396
"#FF8000 emuMMC Configuration#\n\n"
397
"#96FF00 The emuMMC configuration#\n#96FF00 was saved to sd card!#");
398
399
lv_mbox_add_btns(mbox, mbox_btn_map, _save_emummc_cfg_mig_mbox_action);
400
401
lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);
402
lv_obj_set_top(mbox, true);
403
}
404
405
static void _migrate_sd_raw_emummc_based()
406
{
407
char *tmp = (char *)malloc(0x80);
408
s_printf(tmp, "emuMMC/RAW%d", mbr_ctx.part_idx);
409
410
sd_mount();
411
f_mkdir("emuMMC");
412
f_mkdir(tmp);
413
strcat(tmp, "/raw_based");
414
415
FIL fp;
416
if (!f_open(&fp, tmp, FA_CREATE_ALWAYS | FA_WRITE))
417
{
418
f_write(&fp, &mbr_ctx.sector_start, 4, NULL);
419
f_close(&fp);
420
}
421
422
s_printf(tmp, "emuMMC/RAW%d", mbr_ctx.part_idx);
423
424
_change_raw_emummc_part_type();
425
426
save_emummc_cfg(mbr_ctx.part_idx, mbr_ctx.sector_start, tmp);
427
_create_emummc_migrated_mbox();
428
free(tmp);
429
430
sd_unmount();
431
}
432
433
static void _migrate_sd_backup_file_based()
434
{
435
char *emu_path = (char *)malloc(128);
436
char *parts_path = (char *)malloc(128);
437
char *backup_path = (char *)malloc(128);
438
char *backup_file_path = (char *)malloc(128);
439
440
sd_mount();
441
f_mkdir("emuMMC");
442
443
strcpy(emu_path, "emuMMC/BK");
444
u32 base_len = strlen(emu_path);
445
446
for (int j = 0; j < 100; j++)
447
{
448
update_emummc_base_folder(emu_path, base_len, j);
449
if (f_stat(emu_path, NULL) == FR_NO_FILE)
450
break;
451
}
452
base_len = strlen(emu_path);
453
454
f_mkdir(emu_path);
455
strcat(emu_path, "/eMMC");
456
f_mkdir(emu_path);
457
458
FIL fp;
459
// Create file based flag.
460
strcpy(emu_path + base_len, "/file_based");
461
f_open(&fp, "emuMMC/BK00/file_based", FA_CREATE_ALWAYS | FA_WRITE);
462
f_close(&fp);
463
464
if (!emummc_backup)
465
emmcsn_path_impl(backup_path, "", "", NULL);
466
else
467
emmcsn_path_impl(backup_path, "/emummc", "", NULL);
468
469
// Move BOOT0.
470
s_printf(backup_file_path, "%s/BOOT0", backup_path);
471
strcpy(emu_path + base_len, "/eMMC/BOOT0");
472
f_rename(backup_file_path, emu_path);
473
474
// Move BOOT1.
475
s_printf(backup_file_path, "%s/BOOT1", backup_path);
476
strcpy(emu_path + base_len, "/eMMC/BOOT1");
477
f_rename(backup_file_path, emu_path);
478
479
// Move raw GPP.
480
bool multipart = false;
481
s_printf(backup_file_path, "%s/rawnand.bin", backup_path);
482
483
if (f_stat(backup_file_path, NULL))
484
multipart = true;
485
486
if (!multipart)
487
{
488
strcpy(emu_path + base_len, "/eMMC/00");
489
f_rename(backup_file_path, emu_path);
490
}
491
else
492
{
493
emu_path[base_len] = 0;
494
for (int i = 0; i < 32; i++)
495
{
496
s_printf(backup_file_path, "%s/rawnand.bin.%02d", backup_path, i);
497
s_printf(parts_path, "%s/eMMC/%02d", emu_path, i);
498
if (f_rename(backup_file_path, parts_path))
499
break;
500
}
501
}
502
503
free(emu_path);
504
free(parts_path);
505
free(backup_path);
506
free(backup_file_path);
507
508
save_emummc_cfg(0, 0, "emuMMC/BK00");
509
_create_emummc_migrated_mbox();
510
sd_unmount();
511
}
512
513
static lv_res_t _create_emummc_mig0_action(lv_obj_t * btns, const char * txt)
514
{
515
switch (lv_btnm_get_pressed(btns))
516
{
517
case 0:
518
_migrate_sd_raw_emummc_based();
519
break;
520
}
521
522
mbr_ctx.part_idx = 0;
523
mbr_ctx.sector_start = 0;
524
525
nyx_mbox_action(btns, txt);
526
527
return LV_RES_INV;
528
}
529
530
static lv_res_t _create_emummc_mig1_action(lv_obj_t * btns, const char * txt)
531
{
532
switch (lv_btnm_get_pressed(btns))
533
{
534
case 0:
535
_migrate_sd_backup_file_based();
536
break;
537
}
538
539
mbr_ctx.part_idx = 0;
540
mbr_ctx.sector_start = 0;
541
542
nyx_mbox_action(btns, txt);
543
544
return LV_RES_INV;
545
}
546
547
static lv_res_t _create_emummc_migrate_action(lv_obj_t * btns, const char * txt)
548
{
549
bool backup = false;
550
bool emummc = false;
551
552
switch (lv_btnm_get_pressed(btns))
553
{
554
case 0:
555
backup = true;
556
break;
557
case 1:
558
emummc = true;
559
break;
560
case 2:
561
nyx_mbox_action(btns, txt);
562
return LV_RES_INV;
563
}
564
565
lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);
566
lv_obj_set_style(dark_bg, &mbox_darken);
567
lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);
568
569
static const char *mbox_btn_map[] = { "\222Continue", "\222Cancel", "" };
570
static const char *mbox_btn_map1[] = { "\251", "OK", "\251", "" };
571
lv_obj_t * mbox = lv_mbox_create(dark_bg, NULL);
572
lv_mbox_set_recolor_text(mbox, true);
573
lv_obj_set_width(mbox, LV_HOR_RES / 9 * 6);
574
575
char *txt_buf = (char *)malloc(SZ_16K);
576
577
if (backup)
578
{
579
if (!emummc_backup)
580
s_printf(txt_buf,
581
"#C7EA46 Found suitable eMMC backup!#\n\n"
582
"#FF8000 Do you want to migrate it?#\n");
583
else
584
s_printf(txt_buf,
585
"#C7EA46 Found suitable emuMMC backup!#\n\n"
586
"#FF8000 Do you want to migrate it?#\n");
587
lv_mbox_add_btns(mbox, mbox_btn_map, _create_emummc_mig1_action);
588
}
589
else if (emummc)
590
{
591
s_printf(txt_buf,
592
"#C7EA46 Found SD Partition based emuMMC!#\n\n"
593
"#FF8000 Do you want to repair the config and partition type for it?#\n");
594
lv_mbox_add_btns(mbox, mbox_btn_map, _create_emummc_mig0_action);
595
}
596
else
597
{
598
s_printf(txt_buf, "No emuMMC found!\n");
599
lv_mbox_add_btns(mbox, mbox_btn_map1, nyx_mbox_action);
600
}
601
602
lv_mbox_set_text(mbox, txt_buf);
603
free(txt_buf);
604
605
lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);
606
lv_obj_set_top(mbox, true);
607
608
nyx_mbox_action(btns, txt);
609
610
return LV_RES_INV;
611
}
612
613
typedef struct _emummc_images_t
614
{
615
dirlist_t *dirlist;
616
u32 part_sector[3];
617
u32 part_type[3];
618
u32 part_end[3];
619
char part_path[3 * 128];
620
lv_obj_t *win;
621
} emummc_images_t;
622
623
static lv_res_t _create_mbox_emummc_migrate(lv_obj_t *btn)
624
{
625
lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);
626
lv_obj_set_style(dark_bg, &mbox_darken);
627
lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);
628
629
static char *mbox_btn_map[] = { "\262Backup", "\262Fix RAW", "\222Cancel", "" };
630
lv_obj_t * mbox = lv_mbox_create(dark_bg, NULL);
631
lv_mbox_set_recolor_text(mbox, true);
632
lv_obj_set_width(mbox, LV_HOR_RES / 9 * 6);
633
634
lv_mbox_set_text(mbox,
635
"Welcome to #C7EA46 emuMMC# migration tool!\n\n"
636
"Please choose what type of migration you want to do.\n"
637
"Anything that was not found will have the button disabled.");
638
639
char *path_buf = (char *)malloc(0x512);
640
mbr_t *mbr = (mbr_t *)malloc(sizeof(mbr_t));
641
u8 *efi_part = (u8 *)malloc(0x200);
642
643
sd_mount();
644
sdmmc_storage_read(&sd_storage, 0, 1, mbr);
645
646
emmc_initialize(false);
647
648
bool backup = false;
649
bool emummc = false;
650
bool rawnand_backup = false;
651
652
mbr_ctx.sector_start = 0;
653
mbr_ctx.part_idx = 0;
654
655
// Try to find a partition based emuMMC.
656
for (int i = 1; i < 4; i++)
657
{
658
mbr_ctx.sector_start = mbr->partitions[i].start_sct;
659
660
if (!mbr_ctx.sector_start)
661
continue;
662
663
sdmmc_storage_read(&sd_storage, mbr_ctx.sector_start + 0xC001, 1, efi_part);
664
if (!memcmp(efi_part, "EFI PART", 8))
665
{
666
mbr_ctx.sector_start += 0x8000;
667
emummc = true;
668
mbr_ctx.part_idx = i;
669
break;
670
}
671
else
672
{
673
sdmmc_storage_read(&sd_storage, mbr_ctx.sector_start + 0x4001, 1, efi_part);
674
if (!memcmp(efi_part, "EFI PART", 8))
675
{
676
emummc = true;
677
mbr_ctx.part_idx = i;
678
break;
679
}
680
}
681
}
682
683
emummc_backup = false;
684
685
emmcsn_path_impl(path_buf, "", "BOOT0", &emmc_storage);
686
if (!f_stat(path_buf, NULL))
687
backup = true;
688
689
emmcsn_path_impl(path_buf, "", "rawnand.bin", &emmc_storage);
690
if (!f_stat(path_buf, NULL))
691
rawnand_backup = true;
692
693
emmcsn_path_impl(path_buf, "", "rawnand.bin.00", &emmc_storage);
694
if (!f_stat(path_buf, NULL))
695
rawnand_backup = true;
696
697
backup = backup && rawnand_backup;
698
699
if (!backup)
700
{
701
rawnand_backup = false;
702
emummc_backup = true;
703
704
emmcsn_path_impl(path_buf, "/emummc", "BOOT0", &emmc_storage);
705
if (!f_stat(path_buf, NULL))
706
backup = true;
707
708
emmcsn_path_impl(path_buf, "/emummc", "rawnand.bin", &emmc_storage);
709
if (!f_stat(path_buf, NULL))
710
rawnand_backup = true;
711
712
emmcsn_path_impl(path_buf, "/emummc", "rawnand.bin.00", &emmc_storage);
713
if (!f_stat(path_buf, NULL))
714
rawnand_backup = true;
715
716
backup = backup && rawnand_backup;
717
}
718
719
sd_unmount();
720
emmc_end();
721
722
// Check available types and enable the corresponding buttons.
723
if (backup)
724
mbox_btn_map[0][0] = '\222';
725
else
726
mbox_btn_map[0][0] = '\262';
727
if (emummc)
728
mbox_btn_map[1][0] = '\222';
729
else
730
mbox_btn_map[1][0] = '\262';
731
732
free(path_buf);
733
free(mbr);
734
free(efi_part);
735
736
lv_mbox_add_btns(mbox, (const char **)mbox_btn_map, _create_emummc_migrate_action);
737
738
lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);
739
lv_obj_set_top(mbox, true);
740
741
return LV_RES_OK;
742
}
743
744
static emummc_images_t *emummc_img;
745
746
static lv_res_t _save_emummc_cfg_mbox_action(lv_obj_t *btns, const char *txt)
747
{
748
// Free components, delete main emuMMC and popup windows and relaunch main emuMMC window.
749
lv_obj_del(emummc_img->win);
750
lv_obj_del(emummc_manage_window);
751
free(emummc_img->dirlist);
752
free(emummc_img);
753
754
nyx_mbox_action(btns, txt);
755
756
(*emummc_tools)(NULL);
757
758
return LV_RES_INV;
759
}
760
761
static void _create_emummc_saved_mbox()
762
{
763
lv_obj_t *dark_bg = lv_obj_create(lv_scr_act(), NULL);
764
lv_obj_set_style(dark_bg, &mbox_darken);
765
lv_obj_set_size(dark_bg, LV_HOR_RES, LV_VER_RES);
766
767
static const char *mbox_btn_map[] = { "\251", "OK", "\251", "" };
768
lv_obj_t * mbox = lv_mbox_create(dark_bg, NULL);
769
lv_mbox_set_recolor_text(mbox, true);
770
lv_obj_set_width(mbox, LV_HOR_RES / 9 * 4);
771
772
lv_mbox_set_text(mbox,
773
"#FF8000 emuMMC Configuration#\n\n"
774
"#96FF00 The emuMMC configuration#\n#96FF00 was saved to sd card!#");
775
776
lv_mbox_add_btns(mbox, mbox_btn_map, _save_emummc_cfg_mbox_action);
777
778
lv_obj_align(mbox, NULL, LV_ALIGN_CENTER, 0, 0);
779
lv_obj_set_top(mbox, true);
780
}
781
782
static lv_res_t _save_raw_emummc_cfg_action(lv_obj_t * btn)
783
{
784
lv_btn_ext_t *ext = lv_obj_get_ext_attr(btn);
785
switch (ext->idx)
786
{
787
case 0:
788
save_emummc_cfg(1, emummc_img->part_sector[0], &emummc_img->part_path[0]);
789
break;
790
case 1:
791
save_emummc_cfg(2, emummc_img->part_sector[1], &emummc_img->part_path[128]);
792
break;
793
case 2:
794
save_emummc_cfg(3, emummc_img->part_sector[2], &emummc_img->part_path[256]);
795
break;
796
}
797
798
_create_emummc_saved_mbox();
799
sd_unmount();
800
801
return LV_RES_INV;
802
}
803
804
static lv_res_t _save_disable_emummc_cfg_action(lv_obj_t * btn)
805
{
806
save_emummc_cfg(0, 0, NULL);
807
_create_emummc_saved_mbox();
808
sd_unmount();
809
810
return LV_RES_INV;
811
}
812
813
static lv_res_t _save_file_emummc_cfg_action(lv_obj_t *btn)
814
{
815
save_emummc_cfg(0, 0, lv_list_get_btn_text(btn));
816
_create_emummc_saved_mbox();
817
sd_unmount();
818
819
return LV_RES_INV;
820
}
821
822
static lv_res_t _action_win_change_emummc_close(lv_obj_t *btn)
823
{
824
free(emummc_img->dirlist);
825
free(emummc_img);
826
827
return nyx_win_close_action(btn);
828
}
829
830
static lv_res_t _create_change_emummc_window(lv_obj_t *btn_caller)
831
{
832
lv_obj_t *win = nyx_create_standard_window(SYMBOL_SETTINGS" Change emuMMC", _action_win_change_emummc_close);
833
lv_win_add_btn(win, NULL, SYMBOL_POWER" Disable", _save_disable_emummc_cfg_action);
834
835
sd_mount();
836
837
emummc_img = malloc(sizeof(emummc_images_t));
838
emummc_img->win = win;
839
840
mbr_t *mbr = (mbr_t *)malloc(sizeof(mbr_t));
841
char *path = malloc(512);
842
843
sdmmc_storage_read(&sd_storage, 0, 1, mbr);
844
845
memset(emummc_img->part_path, 0, 3 * 128);
846
847
for (int i = 1; i < 4; i++)
848
{
849
emummc_img->part_sector[i - 1] = mbr->partitions[i].start_sct;
850
emummc_img->part_end[i - 1] = emummc_img->part_sector[i - 1] + mbr->partitions[i].size_sct - 1;
851
emummc_img->part_type[i - 1] = mbr->partitions[i].type;
852
}
853
free(mbr);
854
855
emummc_img->dirlist = dirlist("emuMMC", NULL, DIR_SHOW_DIRS);
856
857
if (!emummc_img->dirlist)
858
goto out0;
859
860
u32 emummc_idx = 0;
861
862
FIL fp;
863
864
// Check for sd raw partitions, based on the folders in /emuMMC.
865
while (emummc_img->dirlist->name[emummc_idx])
866
{
867
s_printf(path, "emuMMC/%s/raw_based", emummc_img->dirlist->name[emummc_idx]);
868
869
if (!f_stat(path, NULL))
870
{
871
f_open(&fp, path, FA_READ);
872
u32 curr_list_sector = 0;
873
f_read(&fp, &curr_list_sector, 4, NULL);
874
f_close(&fp);
875
876
// Check if there's a HOS image there.
877
if ((curr_list_sector == 2) || (emummc_img->part_sector[0] && curr_list_sector >= emummc_img->part_sector[0] &&
878
curr_list_sector < emummc_img->part_end[0] && emummc_img->part_type[0] != 0x83))
879
{
880
s_printf(&emummc_img->part_path[0], "emuMMC/%s", emummc_img->dirlist->name[emummc_idx]);
881
emummc_img->part_sector[0] = curr_list_sector;
882
emummc_img->part_end[0] = 0;
883
}
884
else if (emummc_img->part_sector[1] && curr_list_sector >= emummc_img->part_sector[1] &&
885
curr_list_sector < emummc_img->part_end[1] && emummc_img->part_type[1] != 0x83)
886
{
887
s_printf(&emummc_img->part_path[1 * 128], "emuMMC/%s", emummc_img->dirlist->name[emummc_idx]);
888
emummc_img->part_sector[1] = curr_list_sector;
889
emummc_img->part_end[1] = 0;
890
}
891
else if (emummc_img->part_sector[2] && curr_list_sector >= emummc_img->part_sector[2] &&
892
curr_list_sector < emummc_img->part_end[2] && emummc_img->part_type[2] != 0x83)
893
{
894
s_printf(&emummc_img->part_path[2 * 128], "emuMMC/%s", emummc_img->dirlist->name[emummc_idx]);
895
emummc_img->part_sector[2] = curr_list_sector;
896
emummc_img->part_end[2] = 0;
897
}
898
}
899
emummc_idx++;
900
}
901
902
emummc_idx = 0;
903
u32 file_based_idx = 0;
904
905
// Sanitize the directory list with sd file based ones.
906
while (emummc_img->dirlist->name[emummc_idx])
907
{
908
s_printf(path, "emuMMC/%s/file_based", emummc_img->dirlist->name[emummc_idx]);
909
910
if (!f_stat(path, NULL))
911
{
912
char *tmp = emummc_img->dirlist->name[emummc_idx];
913
memcpy(emummc_img->dirlist->name[file_based_idx], tmp, strlen(tmp) + 1);
914
file_based_idx++;
915
}
916
emummc_idx++;
917
}
918
emummc_img->dirlist->name[file_based_idx] = NULL;
919
920
out0:;
921
static lv_style_t h_style;
922
lv_style_copy(&h_style, &lv_style_transp);
923
h_style.body.padding.inner = 0;
924
h_style.body.padding.hor = LV_DPI - (LV_DPI / 4);
925
h_style.body.padding.ver = LV_DPI / 6;
926
927
// Create SD Raw Partitions container.
928
lv_obj_t *h1 = lv_cont_create(win, NULL);
929
lv_cont_set_style(h1, &h_style);
930
lv_cont_set_fit(h1, false, true);
931
lv_obj_set_width(h1, (LV_HOR_RES / 9) * 4);
932
lv_obj_set_click(h1, false);
933
lv_cont_set_layout(h1, LV_LAYOUT_OFF);
934
935
lv_obj_t *label_sep = lv_label_create(h1, NULL);
936
lv_label_set_static_text(label_sep, "");
937
938
lv_obj_t *label_txt = lv_label_create(h1, NULL);
939
lv_label_set_static_text(label_txt, "SD Raw Partitions");
940
lv_obj_set_style(label_txt, lv_theme_get_current()->label.prim);
941
lv_obj_align(label_txt, label_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, -(LV_DPI / 2));
942
943
lv_obj_t *line_sep = lv_line_create(h1, NULL);
944
static const lv_point_t line_pp[] = { {0, 0}, { LV_HOR_RES - (LV_DPI - (LV_DPI / 4)) * 2, 0} };
945
lv_line_set_points(line_sep, line_pp, 2);
946
lv_line_set_style(line_sep, lv_theme_get_current()->line.decor);
947
lv_obj_align(line_sep, label_txt, LV_ALIGN_OUT_BOTTOM_LEFT, -(LV_DPI / 4), LV_DPI / 8);
948
949
lv_obj_t *btn = NULL;
950
lv_btn_ext_t *ext;
951
lv_obj_t *btn_label = NULL;
952
lv_obj_t *lv_desc = NULL;
953
char *txt_buf = malloc(SZ_16K);
954
955
// Create RAW buttons.
956
for (u32 raw_btn_idx = 0; raw_btn_idx < 3; raw_btn_idx++)
957
{
958
btn = lv_btn_create(h1, btn);
959
ext = lv_obj_get_ext_attr(btn);
960
ext->idx = raw_btn_idx;
961
btn_label = lv_label_create(btn, btn_label);
962
963
lv_btn_set_state(btn, LV_BTN_STATE_REL);
964
lv_obj_set_click(btn, true);
965
966
if (emummc_img->part_type[raw_btn_idx] != 0x83)
967
{
968
s_printf(txt_buf, "SD RAW %d", raw_btn_idx + 1);
969
lv_label_set_text(btn_label, txt_buf);
970
}
971
972
if (!emummc_img->part_sector[raw_btn_idx] || emummc_img->part_type[raw_btn_idx] == 0x83 || !emummc_img->part_path[raw_btn_idx * 128])
973
{
974
lv_btn_set_state(btn, LV_BTN_STATE_INA);
975
lv_obj_set_click(btn, false);
976
977
if (emummc_img->part_type[raw_btn_idx] == 0x83)
978
lv_label_set_static_text(btn_label, "Linux");
979
}
980
981
if (!raw_btn_idx)
982
{
983
lv_btn_set_fit(btn, false, true);
984
lv_obj_set_width(btn, LV_DPI * 3);
985
lv_obj_align(btn, line_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 2, LV_DPI / 5);
986
}
987
else
988
lv_obj_align(btn, lv_desc, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3);
989
990
lv_btn_set_action(btn, LV_BTN_ACTION_CLICK, _save_raw_emummc_cfg_action);
991
992
lv_desc = lv_label_create(h1, lv_desc);
993
lv_label_set_recolor(lv_desc, true);
994
lv_obj_set_style(lv_desc, &hint_small_style);
995
996
s_printf(txt_buf, "Sector start: 0x%08X\nFolder: %s", emummc_img->part_sector[raw_btn_idx], &emummc_img->part_path[raw_btn_idx * 128]);
997
lv_label_set_text(lv_desc, txt_buf);
998
lv_obj_align(lv_desc, btn, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 5);
999
}
1000
free(txt_buf);
1001
1002
// Create SD File Based container.
1003
lv_obj_t *h2 = lv_cont_create(win, NULL);
1004
lv_cont_set_style(h2, &h_style);
1005
lv_cont_set_fit(h2, false, true);
1006
lv_obj_set_width(h2, (LV_HOR_RES / 9) * 4);
1007
lv_obj_set_click(h2, false);
1008
lv_cont_set_layout(h2, LV_LAYOUT_OFF);
1009
lv_obj_align(h2, h1, LV_ALIGN_OUT_RIGHT_TOP, LV_DPI * 17 / 29, 0);
1010
1011
label_sep = lv_label_create(h2, NULL);
1012
lv_label_set_static_text(label_sep, "");
1013
1014
lv_obj_t *label_txt3 = lv_label_create(h2, NULL);
1015
lv_label_set_static_text(label_txt3, "SD File Based");
1016
lv_obj_set_style(label_txt3, lv_theme_get_current()->label.prim);
1017
lv_obj_align(label_txt3, label_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, -LV_DPI / 7);
1018
1019
line_sep = lv_line_create(h2, line_sep);
1020
lv_obj_align(line_sep, label_txt3, LV_ALIGN_OUT_BOTTOM_LEFT, -(LV_DPI / 2), LV_DPI / 8);
1021
lv_line_set_style(line_sep, lv_theme_get_current()->line.decor);
1022
1023
lv_obj_t *list_sd_based = lv_list_create(h2, NULL);
1024
lv_obj_align(list_sd_based, line_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 2, LV_DPI / 4);
1025
1026
lv_obj_set_size(list_sd_based, LV_HOR_RES * 4 / 10, LV_VER_RES * 6 / 10);
1027
lv_list_set_single_mode(list_sd_based, true);
1028
1029
if (!emummc_img->dirlist)
1030
goto out1;
1031
1032
emummc_idx = 0;
1033
1034
// Add file based to the list.
1035
while (emummc_img->dirlist->name[emummc_idx])
1036
{
1037
s_printf(path, "emuMMC/%s", emummc_img->dirlist->name[emummc_idx]);
1038
1039
lv_list_add(list_sd_based, NULL, path, _save_file_emummc_cfg_action);
1040
1041
emummc_idx++;
1042
}
1043
1044
out1:
1045
free(path);
1046
sd_unmount();
1047
1048
return LV_RES_OK;
1049
}
1050
1051
lv_res_t create_win_emummc_tools(lv_obj_t *btn)
1052
{
1053
lv_obj_t *win = nyx_create_standard_window(SYMBOL_EDIT" emuMMC Manage", NULL);
1054
1055
// Set resources to be managed by other windows.
1056
emummc_manage_window = win;
1057
emummc_tools = (void *)create_win_emummc_tools;
1058
1059
sd_mount();
1060
1061
emummc_cfg_t emu_info;
1062
load_emummc_cfg(&emu_info);
1063
1064
sd_unmount();
1065
1066
static lv_style_t h_style;
1067
lv_style_copy(&h_style, &lv_style_transp);
1068
h_style.body.padding.inner = 0;
1069
h_style.body.padding.hor = LV_DPI - (LV_DPI / 4);
1070
h_style.body.padding.ver = LV_DPI / 9;
1071
1072
// Create emuMMC Info & Selection container.
1073
lv_obj_t *h1 = lv_cont_create(win, NULL);
1074
lv_cont_set_style(h1, &h_style);
1075
lv_cont_set_fit(h1, false, true);
1076
lv_obj_set_width(h1, (LV_HOR_RES / 9) * 4);
1077
lv_obj_set_click(h1, false);
1078
lv_cont_set_layout(h1, LV_LAYOUT_OFF);
1079
1080
lv_obj_t *label_sep = lv_label_create(h1, NULL);
1081
lv_label_set_static_text(label_sep, "");
1082
1083
lv_obj_t *label_txt = lv_label_create(h1, NULL);
1084
lv_label_set_static_text(label_txt, "emuMMC Info & Selection");
1085
lv_obj_set_style(label_txt, lv_theme_get_current()->label.prim);
1086
lv_obj_align(label_txt, label_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, LV_DPI / 11);
1087
1088
lv_obj_t *line_sep = lv_line_create(h1, NULL);
1089
static const lv_point_t line_pp[] = { {0, 0}, { LV_HOR_RES - (LV_DPI - (LV_DPI / 4)) * 2, 0} };
1090
lv_line_set_points(line_sep, line_pp, 2);
1091
lv_line_set_style(line_sep, lv_theme_get_current()->line.decor);
1092
lv_obj_align(line_sep, label_txt, LV_ALIGN_OUT_BOTTOM_LEFT, -(LV_DPI / 4), LV_DPI / 8);
1093
1094
// Create emuMMC info labels.
1095
lv_obj_t *label_btn = lv_label_create(h1, NULL);
1096
lv_label_set_recolor(label_btn, true);
1097
lv_label_set_static_text(label_btn, emu_info.enabled ? "#96FF00 "SYMBOL_OK" Enabled!#" : "#FF8000 "SYMBOL_CLOSE" Disabled!#");
1098
lv_obj_align(label_btn, line_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, LV_DPI / 4);
1099
1100
lv_obj_t *label_txt2 = lv_label_create(h1, NULL);
1101
lv_label_set_recolor(label_txt2, true);
1102
char *txt_buf = (char *)malloc(SZ_16K);
1103
1104
if (emu_info.enabled)
1105
{
1106
if (emu_info.sector)
1107
s_printf(txt_buf, "#00DDFF Type:# SD Raw Partition\n#00DDFF Sector:# 0x%08X\n#00DDFF Nintendo folder:# %s\n",
1108
emu_info.sector, emu_info.nintendo_path ? emu_info.nintendo_path : "");
1109
else
1110
s_printf(txt_buf, "#00DDFF Type:# SD File\n#00DDFF Base folder:# %s\n#00DDFF Nintendo folder:# %s\n",
1111
emu_info.path ? emu_info.path : "", emu_info.nintendo_path ? emu_info.nintendo_path : "");
1112
1113
lv_label_set_text(label_txt2, txt_buf);
1114
}
1115
else
1116
{
1117
lv_label_set_static_text(label_txt2, "emuMMC is disabled and eMMC will be used for boot.\n\n\n");
1118
}
1119
1120
if (emu_info.path)
1121
free(emu_info.path);
1122
if (emu_info.nintendo_path)
1123
free(emu_info.nintendo_path);
1124
free(txt_buf);
1125
1126
lv_obj_set_style(label_txt2, &hint_small_style);
1127
lv_obj_align(label_txt2, label_btn, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3);
1128
1129
// Create Change emuMMC button.
1130
lv_obj_t *btn2 = lv_btn_create(h1, NULL);
1131
lv_btn_set_fit(btn2, true, true);
1132
label_btn = lv_label_create(btn2, NULL);
1133
lv_label_set_static_text(label_btn, SYMBOL_SETTINGS" Change emuMMC");
1134
lv_obj_align(btn2, label_txt2, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI * 6 / 10);
1135
lv_btn_set_action(btn2, LV_BTN_ACTION_CLICK, _create_change_emummc_window);
1136
1137
label_txt2 = lv_label_create(h1, NULL);
1138
lv_label_set_recolor(label_txt2, true);
1139
lv_label_set_static_text(label_txt2,
1140
"Choose between images created in the emuMMC folder\n"
1141
"or in SD card partitions. You can have at most 3 partition\n"
1142
"based and countless file based.");
1143
1144
lv_obj_set_style(label_txt2, &hint_small_style);
1145
lv_obj_align(label_txt2, btn2, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3);
1146
1147
// Create emuMMC Tools container.
1148
lv_obj_t *h2 = lv_cont_create(win, NULL);
1149
lv_cont_set_style(h2, &h_style);
1150
lv_cont_set_fit(h2, false, true);
1151
lv_obj_set_width(h2, (LV_HOR_RES / 9) * 4);
1152
lv_obj_set_click(h2, false);
1153
lv_cont_set_layout(h2, LV_LAYOUT_OFF);
1154
lv_obj_align(h2, h1, LV_ALIGN_OUT_RIGHT_TOP, LV_DPI * 17 / 29, 0);
1155
1156
label_sep = lv_label_create(h2, NULL);
1157
lv_label_set_static_text(label_sep, "");
1158
1159
lv_obj_t *label_txt3 = lv_label_create(h2, NULL);
1160
lv_label_set_static_text(label_txt3, "emuMMC Tools");
1161
lv_obj_set_style(label_txt3, lv_theme_get_current()->label.prim);
1162
lv_obj_align(label_txt3, label_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, LV_DPI / 5);
1163
1164
line_sep = lv_line_create(h2, line_sep);
1165
lv_obj_align(line_sep, label_txt3, LV_ALIGN_OUT_BOTTOM_LEFT, -(LV_DPI / 4), LV_DPI / 8);
1166
1167
// Create Create emuMMC button.
1168
lv_obj_t *btn3 = lv_btn_create(h2, btn2);
1169
label_btn = lv_label_create(btn3, NULL);
1170
lv_btn_set_fit(btn3, true, true);
1171
lv_label_set_static_text(label_btn, SYMBOL_DRIVE" Create emuMMC");
1172
lv_obj_align(btn3, line_sep, LV_ALIGN_OUT_BOTTOM_LEFT, LV_DPI / 4, LV_DPI / 4);
1173
lv_btn_set_action(btn3, LV_BTN_ACTION_CLICK, _create_mbox_emummc_create);
1174
1175
lv_obj_t *label_txt4 = lv_label_create(h2, NULL);
1176
lv_label_set_recolor(label_txt4, true);
1177
lv_label_set_static_text(label_txt4,
1178
"Allows you to create a new #C7EA46 SD File# or #C7EA46 SD Raw Partition#\n"
1179
"emuMMC. You can create it from eMMC or a eMMC Backup.\n");
1180
1181
lv_obj_set_style(label_txt4, &hint_small_style);
1182
lv_obj_align(label_txt4, btn3, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3);
1183
1184
// Create Migrate emuMMC button.
1185
lv_obj_t *btn4 = lv_btn_create(h2, btn2);
1186
label_btn = lv_label_create(btn4, NULL);
1187
lv_label_set_static_text(label_btn, SYMBOL_SHUFFLE" Migrate emuMMC");
1188
lv_obj_align(btn4, label_txt4, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 2);
1189
lv_btn_set_action(btn4, LV_BTN_ACTION_CLICK, NULL);
1190
lv_btn_set_action(btn4, LV_BTN_ACTION_CLICK, _create_mbox_emummc_migrate);
1191
1192
label_txt4 = lv_label_create(h2, NULL);
1193
lv_label_set_recolor(label_txt4, true);
1194
lv_label_set_static_text(label_txt4,
1195
"Migrate a backup to a #C7EA46 SD File emuMMC# or repair an existing\n#C7EA46 SD Raw Partition emuMMC#.\n");
1196
lv_obj_set_style(label_txt4, &hint_small_style);
1197
lv_obj_align(label_txt4, btn4, LV_ALIGN_OUT_BOTTOM_LEFT, 0, LV_DPI / 3);
1198
1199
return LV_RES_OK;
1200
}
1201
1202