From 32af38e252b39f7d9c70b2943002c8a016df52ae Mon Sep 17 00:00:00 2001 From: marqs Date: Mon, 27 Oct 2025 00:25:11 +0200 Subject: [PATCH] code cleanup --- software/sys_controller/inc/firmware.h | 2 +- software/sys_controller/inc/menu.h | 34 ++- software/sys_controller/src/file.c | 5 + software/sys_controller/src/firmware.c | 26 +- software/sys_controller/src/menu.c | 352 ++++++++++++++++++++++++- 5 files changed, 386 insertions(+), 33 deletions(-) diff --git a/software/sys_controller/inc/firmware.h b/software/sys_controller/inc/firmware.h index b36b979..1048b03 100644 --- a/software/sys_controller/inc/firmware.h +++ b/software/sys_controller/inc/firmware.h @@ -62,6 +62,6 @@ typedef struct { int fw_init_secondary(); int fw_update(); -void fw_update_commit(uint32_t* cluster_idx, uint8_t* databuf, uint32_t bytes_to_copy, uint16_t fs_csize, uint16_t fs_startsec, uint32_t flash_addr); +void fw_update_commit(uint32_t* cluster_idx, uint32_t bytes_to_copy, uint16_t fs_csize, uint16_t fs_startsec, uint32_t flash_addr); #endif diff --git a/software/sys_controller/inc/menu.h b/software/sys_controller/inc/menu.h index 7c32086..be8e851 100644 --- a/software/sys_controller/inc/menu.h +++ b/software/sys_controller/inc/menu.h @@ -31,11 +31,22 @@ #define LNG(e, j) e #endif +typedef enum { + NO_ACTION = 0, + OPT_SELECT = RC_OK, + PREV_MENU = RC_BACK, + PREV_PAGE = RC_UP, + NEXT_PAGE = RC_DOWN, + VAL_MINUS = RC_LEFT, + VAL_PLUS = RC_RIGHT, +} menucode_id; // order must be consequential with rc_code_t + typedef enum { OPT_AVCONFIG_SELECTION, OPT_AVCONFIG_NUMVALUE, OPT_AVCONFIG_NUMVAL_U16, OPT_SUBMENU, + OPT_CUSTOMMENU, OPT_FUNC_CALL, } menuitem_type; @@ -43,6 +54,7 @@ typedef int (*func_call)(void); typedef void (*arg_func)(void); typedef void (*disp_func)(alt_u8); typedef void (*disp_func_u16)(alt_u16*); +typedef void (*cstm_disp_func)(menucode_id, int); typedef struct { alt_u8 *data; @@ -86,6 +98,10 @@ typedef struct { arg_func arg_f; } opt_submenu; +typedef struct { + cstm_disp_func cstm_f; +} opt_custommenu; + typedef struct { const char *name; menuitem_type type; @@ -94,6 +110,7 @@ typedef struct { opt_avconfig_numvalue num; opt_avconfig_numvalue_u16 num_u16; opt_submenu sub; + opt_custommenu cstm; opt_func_call fun; }; } menuitem_t; @@ -107,28 +124,25 @@ struct menustruct { #define MENU(X, Y) const menuitem_t X##_items[] = Y; const menu_t X = { sizeof(X##_items)/sizeof(menuitem_t), X##_items }; #define P99_PROTECT(...) __VA_ARGS__ -typedef enum { - NO_ACTION = 0, - OPT_SELECT = RC_OK, - PREV_MENU = RC_BACK, - PREV_PAGE = RC_UP, - NEXT_PAGE = RC_DOWN, - VAL_MINUS = RC_LEFT, - VAL_PLUS = RC_RIGHT, -} menucode_id; // order must be consequential with rc_code_t - typedef struct { const menu_t *m; alt_u8 mp; } menunavi; +typedef int (*load_func)(char*, char*); + menunavi* get_current_menunavi(); void init_menu(); void render_osd_page(); void display_menu(alt_u8 forcedisp); void sampler_phase_disp(alt_u8 v); +void set_func_ret_msg(char *msg); void update_osd_size(mode_data_t *vm_out); void refresh_osd(); +void cstm_shmask_load(menucode_id code, int setup_disp); +void cstm_lc_palette_set_load(menucode_id code, int setup_disp); +void cstm_fw_update(menucode_id code, int setup_disp); +void enter_cstm(const menuitem_t *item, int detached_mode); static void vm_select(); static void vm_tweak(alt_u16 *v); diff --git a/software/sys_controller/src/file.c b/software/sys_controller/src/file.c index 1d0bf37..d0418f5 100644 --- a/software/sys_controller/src/file.c +++ b/software/sys_controller/src/file.c @@ -9,6 +9,11 @@ FRESULT file_mount() return f_mount(&fs, "", 1); } +FRESULT file_unmount() +{ + return f_unmount(""); +} + FRESULT file_open(FIL* fil, char* path) { return f_open(fil, path, FA_READ); diff --git a/software/sys_controller/src/firmware.c b/software/sys_controller/src/firmware.c index d1871e0..afd7aca 100644 --- a/software/sys_controller/src/firmware.c +++ b/software/sys_controller/src/firmware.c @@ -40,6 +40,7 @@ extern char menu_row1[LCD_ROW_LEN+1], menu_row2[LCD_ROW_LEN+1]; extern alt_u16 rc_keymap[REMOTE_MAX_KEYS]; +extern char tmpbuf[SD_BLK_SIZE]; extern SD_DEV sdcard_dev; extern alt_u32 sys_ctrl; extern flash_ctrl_dev flashctrl_dev; @@ -62,8 +63,7 @@ int fw_init_secondary() { return 0; } -//int fw_update(char *dirname, char *filename) { -int fw_update() { +int fw_update(char *dirname, char *filename) { FIL fw_file; SDRESULTS res; char dirname_root[10]; @@ -72,7 +72,6 @@ int fw_update() { unsigned bytes_read, bytes_to_copy; uint32_t crcval, hdr_len, btn_vec; uint32_t cluster_idx[100]; // enough for >=4kB cluster size - uint8_t databuf[SD_BLK_SIZE]; // temp buffer for data uint16_t fs_csize, fs_startsec, cl_iter, cl_soffs; uint32_t flash_addr; @@ -84,11 +83,10 @@ int fw_update() { } } - //sniprintf(dirname_root, sizeof(dirname_root), "/%s", dirname); - sniprintf(dirname_root, sizeof(dirname_root), "/"); + sniprintf(dirname_root, sizeof(dirname_root), "/%s", dirname); f_chdir(dirname_root); - if (!file_open(&fw_file, "ossc.bin")) { + if (!file_open(&fw_file, filename)) { strlcpy(menu_row1, "Checking FW", LCD_ROW_LEN+1); strlcpy(menu_row2, "Please wait...", LCD_ROW_LEN+1); ui_disp_menu(1); @@ -140,7 +138,7 @@ int fw_update() { if (btn_vec == rc_keymap[RC_BTN1]) { break; } else if (btn_vec == rc_keymap[RC_BTN2]) { - //set_func_ret_msg("Cancelled"); + set_func_ret_msg("Cancelled"); retval = 1; goto close_file; } @@ -175,14 +173,14 @@ int fw_update() { printf("Checking copied data...\n"); while (bytes_to_copy > 0) { bytes_read = (bytes_to_copy > SD_BLK_SIZE) ? SD_BLK_SIZE : bytes_to_copy; - res = SD_Read(&sdcard_dev, databuf, ((cluster_idx[cl_iter]-2)*fs_csize+fs_startsec+cl_soffs), 0, bytes_read); + res = SD_Read(&sdcard_dev, tmpbuf, ((cluster_idx[cl_iter]-2)*fs_csize+fs_startsec+cl_soffs), 0, bytes_read); if (res != SD_OK) { printf("FW data read error\n"); retval = -8; goto close_file; } - crcval = crc32((unsigned char *)&databuf, bytes_read, (bytes_to_copy==hdr.data_len)); + crcval = crc32((unsigned char *)&tmpbuf, bytes_read, (bytes_to_copy==hdr.data_len)); bytes_to_copy -= bytes_read; cl_soffs += 1; @@ -209,7 +207,7 @@ int fw_update() { usleep(10000); // No return from here - fw_update_commit(cluster_idx, databuf, hdr.data_len, fs_csize, fs_startsec, flash_addr); + fw_update_commit(cluster_idx, hdr.data_len, fs_csize, fs_startsec, flash_addr); return 0; } else { printf("FW file not found\n"); @@ -224,7 +222,7 @@ close_file: } // commit FW update. Do not call functions located in flash during update -void __attribute__((noinline, flatten, noreturn, __section__(".text_bram"))) fw_update_commit(uint32_t* cluster_idx, uint8_t* databuf, uint32_t bytes_to_copy, uint16_t fs_csize, uint16_t fs_startsec, uint32_t flash_addr) { +void __attribute__((noinline, flatten, noreturn, __section__(".text_bram"))) fw_update_commit(uint32_t* cluster_idx, uint32_t bytes_to_copy, uint16_t fs_csize, uint16_t fs_startsec, uint32_t flash_addr) { int i, sectors; SDRESULTS res; uint16_t cl_iter, cl_soffs; @@ -254,14 +252,14 @@ void __attribute__((noinline, flatten, noreturn, __section__(".text_bram"))) fw_ // Write data while (bytes_to_copy > 0) { bytes_read = (bytes_to_copy > SD_BLK_SIZE) ? SD_BLK_SIZE : bytes_to_copy; - res = SD_Read(&sdcard_dev, databuf, ((cluster_idx[cl_iter]-2)*fs_csize+fs_startsec+cl_soffs), 0, bytes_read); + res = SD_Read(&sdcard_dev, tmpbuf, ((cluster_idx[cl_iter]-2)*fs_csize+fs_startsec+cl_soffs), 0, bytes_read); //TODO: retry if read fails bytes_to_copy -= bytes_read; for (i=0; i", OPT_CUSTOMMENU, { .cstm = { &cstm_lc_palette_set_load } } }, })) MENU(menu_sampling, P99_PROTECT({ \ @@ -218,7 +227,7 @@ MENU(menu_scanlines, P99_PROTECT({ \ MENU(menu_postproc, P99_PROTECT({ \ { "Shadow mask", OPT_AVCONFIG_SELECTION, { .sel = { &tc.shmask_mode, OPT_WRAP, SETTING_ITEM(shmask_mode_desc) } } }, - //{ "Custom shadow mask", OPT_CUSTOMMENU, { .cstm = { &cstm_shmask_load } } }, + { "", OPT_CUSTOMMENU, { .cstm = { &cstm_shmask_load } } }, { "Sh. mask strength", OPT_AVCONFIG_NUMVALUE, { .num = { &tc.shmask_str, OPT_NOWRAP, 0, SCANLINESTR_MAX, sl_str_disp } } }, { "Border color", OPT_AVCONFIG_SELECTION, { .sel = { &tc.mask_color, OPT_NOWRAP, SETTING_ITEM(mask_color_desc) } } }, { LNG("Border brightn.","マスクアカルサ"), OPT_AVCONFIG_NUMVALUE, { .num = { &tc.mask_br, OPT_NOWRAP, 0, HV_MASK_MAX_BR, value_disp } } }, @@ -231,6 +240,7 @@ MENU(menu_compatibility, P99_PROTECT({ \ { "AV3 use alt. RGB", OPT_AVCONFIG_SELECTION, { .sel = { &tc.av3_alt_rgb, OPT_WRAP, SETTING_ITEM(av3_alt_rgb_desc) } } }, { "Full VSYNC bypas", OPT_AVCONFIG_SELECTION, { .sel = { &tc.full_vs_bypass, OPT_WRAP, SETTING_ITEM(off_on_desc) } } }, { "Default HDMI VIC", OPT_AVCONFIG_NUMVALUE, { .num = { &tc.default_vic, OPT_NOWRAP, 0, HDMI_1080p50, value_disp } } }, + { "Panasonic hack", OPT_AVCONFIG_SELECTION, { .sel = { &tc.panasonic_hack, OPT_WRAP, SETTING_ITEM(off_on_desc) } } }, })) MENU(menu_audio, P99_PROTECT({ \ @@ -261,7 +271,7 @@ MENU(menu_settings, P99_PROTECT({ \ { LNG("","<セッテイヲショキカ >"), OPT_FUNC_CALL, { .fun = { reset_profile, NULL } } }, //{ LNG("","<セッテイヨミコミ >"), OPT_FUNC_CALL, { .fun = { import_userdata, NULL } } }, //{ LNG("","<セッテイカキコミ >"), OPT_FUNC_CALL, { .fun = { export_userdata, NULL } } }, - { LNG("","<ファームウェアアップデート>"), OPT_FUNC_CALL, { .fun = { fw_update, NULL } } }, + { LNG("","<ファームウェアアップデート>"), OPT_CUSTOMMENU, { .cstm = { &cstm_fw_update } } }, { "", OPT_FUNC_CALL, { .fun = { fw_init_secondary, NULL } } }, })) @@ -282,6 +292,11 @@ MENU(menu_main, P99_PROTECT({ \ menunavi navi[] = {{&menu_main, 0}, {NULL, 0}, {NULL, 0}}; alt_u8 navlvl = 0; +static int osd_list_iter; +char tmpbuf[SD_BLK_SIZE]; // 512 byte temp buffer for data + +// Pointer to custom menu display function +void (*cstm_f)(menucode_id, int); menunavi* get_current_menunavi() { return &navi[navlvl]; @@ -320,12 +335,17 @@ void write_option_value(const menuitem_t *item, int func_called, int retval) else menu_row2[0] = 0; break; + case OPT_CUSTOMMENU: + menu_row2[0] = 0; + break; case OPT_FUNC_CALL: if (func_called) { if (retval == 0) strncpy(menu_row2, "Done", LCD_ROW_LEN+1); else if (retval < 0) sniprintf(menu_row2, LCD_ROW_LEN+1, "Failed (%d)", retval); + else + strlcpy(menu_row2, func_ret_status, LCD_ROW_LEN+1); } else if (item->fun.arg_info) { item->fun.arg_info->df(*item->fun.arg_info->data); } else { @@ -350,7 +370,7 @@ void render_osd_page() { strncpy((char*)osd->osd_array.data[i][0], item->name, OSD_CHAR_COLS); row_mask[0] |= (1<type != OPT_SUBMENU) && (item->type != OPT_FUNC_CALL)) { + if ((item->type != OPT_SUBMENU) && (item->type != OPT_CUSTOMMENU) && (item->type != OPT_FUNC_CALL)) { write_option_value(item, 0, 0); strncpy((char*)osd->osd_array.data[i][1], menu_row2, OSD_CHAR_COLS); row_mask[1] |= (1<items[navi[navlvl].mp]; // Parse menu control switch (code) { case PREV_PAGE: case NEXT_PAGE: - if ((item->type == OPT_FUNC_CALL) || (item->type == OPT_SUBMENU)) + if ((item->type == OPT_FUNC_CALL) || (item->type == OPT_SUBMENU) || (item->type == OPT_CUSTOMMENU)) osd->osd_sec_enable[1].mask &= ~(1< 0) { - navlvl--; + if (cstm_f != NULL) + cstm_f = NULL; + else + navlvl--; render_osd_page(); } else { menu_active = 0; osd->osd_config.menu_active = 0; + cstm_f = NULL; ui_disp_status(0); return; } @@ -416,6 +447,10 @@ void display_menu(alt_u8 forcedisp) navlvl++; render_osd_page(); + break; + case OPT_CUSTOMMENU: + enter_cstm(item, 0); + return; break; case OPT_FUNC_CALL: retval = item->fun.f(); @@ -492,6 +527,10 @@ void display_menu(alt_u8 forcedisp) ui_disp_menu(0); } +void set_func_ret_msg(char *msg) { + strlcpy(func_ret_status, msg, LCD_ROW_LEN+1); +} + void update_osd_size(mode_data_t *vm_out) { uint8_t osd_size = vm_out->timings.v_active / 700; uint8_t par_x4 = (((400*vm_out->timings.h_active*vm_out->ar.v)/((vm_out->timings.v_active<timings.interlaced)*vm_out->ar.h))+50)/100; @@ -507,13 +546,310 @@ void update_osd_size(mode_data_t *vm_out) { } void refresh_osd() { - if (menu_active) { + if (menu_active && (cstm_f == NULL)) { remote_code = 0; render_osd_page(); display_menu(1); } } +void osd_array_fname_fill(FILINFO *fno) { + // Buffer has space for up to 21 strings + if (osd_list_iter < (sizeof(tmpbuf)/24) ) { + sniprintf(&tmpbuf[osd_list_iter*24], 24, "%s", fno->fname); + strncpy((char*)osd->osd_array.data[osd_list_iter+2][0], &tmpbuf[osd_list_iter*24], OSD_CHAR_COLS); + } + + osd_list_iter++; +} + +int load_shmask(char *dirname, char *filename) { + FIL f_shmask; + char dirname_root[10]; + int arr_size_loaded=0; + int v0=0,v1=0; + int p; + + if (!sdcard_dev.mount) { + if (file_mount() != 0) { + printf("SD card not detected\n"); + return -1; + } + } + + sniprintf(dirname_root, sizeof(dirname_root), "/%s", dirname); + f_chdir(dirname_root); + + if (!file_open(&f_shmask, filename)) { + while (file_get_string(&f_shmask, tmpbuf, sizeof(tmpbuf))) { + // strip CR / CRLF + tmpbuf[strcspn(tmpbuf, "\r\n")] = 0; + + // Skip empty / comment lines + if ((tmpbuf[0] == 0) || (tmpbuf[0] == '#')) + continue; + + if (!arr_size_loaded && (sscanf(tmpbuf, "%d,%d", &v0, &v1) == 2)) { + c_shmask.arr.iv_x = v0-1; + c_shmask.arr.iv_y = v1-1; + arr_size_loaded = 1; + } else if (arr_size_loaded && (v1 > 0)) { + p = c_shmask.arr.iv_y+1-v1; + if (sscanf(tmpbuf, "%hx,%hx,%hx,%hx,%hx,%hx,%hx,%hx,%hx,%hx,%hx,%hx,%hx,%hx,%hx,%hx", &c_shmask.arr.v[p][0], + &c_shmask.arr.v[p][1], + &c_shmask.arr.v[p][2], + &c_shmask.arr.v[p][3], + &c_shmask.arr.v[p][4], + &c_shmask.arr.v[p][5], + &c_shmask.arr.v[p][6], + &c_shmask.arr.v[p][7], + &c_shmask.arr.v[p][8], + &c_shmask.arr.v[p][9], + &c_shmask.arr.v[p][10], + &c_shmask.arr.v[p][11], + &c_shmask.arr.v[p][12], + &c_shmask.arr.v[p][13], + &c_shmask.arr.v[p][14], + &c_shmask.arr.v[p][15]) == v0) + v1--; + } + } + + file_close(&f_shmask); + } + + f_chdir("/"); + + sniprintf(c_shmask.name, sizeof(c_shmask.name), "C: %s", filename); + shmask_loaded_array = -1; + update_sc_config(); + return 0; +} + +int load_lc_palette_set(char *dirname, char *filename) { + FIL f_lc_palset; + char dirname_root[10]; + int entries_remaining=0; + int offset; + + if (!sdcard_dev.mount) { + if (file_mount() != 0) { + printf("SD card not detected\n"); + return -1; + } + } + + sniprintf(dirname_root, sizeof(dirname_root), "/%s", dirname); + f_chdir(dirname_root); + + if (!file_open(&f_lc_palset, filename)) { + while (file_get_string(&f_lc_palset, tmpbuf, sizeof(tmpbuf))) { + // strip CR / CRLF + tmpbuf[strcspn(tmpbuf, "\r\n")] = 0; + + // Skip empty / comment lines + if ((tmpbuf[0] == 0) || (tmpbuf[0] == '#')) + continue; + + if (!entries_remaining) { + if (strncmp(tmpbuf, "c64_pal", 10) == 0) { + offset = offsetof(lc_palette_set, c64_pal)/4; + entries_remaining = 16; + } else if (strncmp(tmpbuf, "zx_pal", 10) == 0) { + offset = offsetof(lc_palette_set, zx_pal)/4; + entries_remaining = 16; + } else if (strncmp(tmpbuf, "msx_pal", 10) == 0) { + offset = offsetof(lc_palette_set, msx_pal)/4; + entries_remaining = 16; + } else if (strncmp(tmpbuf, "intv_pal", 10) == 0) { + offset = offsetof(lc_palette_set, intv_pal)/4; + entries_remaining = 16; + } else if (strncmp(tmpbuf, "nes_pal", 10) == 0) { + offset = offsetof(lc_palette_set, nes_pal)/4; + entries_remaining = 64; + } else if (strncmp(tmpbuf, "tia_pal", 10) == 0) { + offset = offsetof(lc_palette_set, tia_pal)/4; + entries_remaining = 128; + } else if (strncmp(tmpbuf, "gtia_pal", 10) == 0) { + offset = offsetof(lc_palette_set, gtia_pal)/4; + entries_remaining = 128; + } + } else if (sscanf(tmpbuf, "%lx,%lx,%lx,%lx,%lx,%lx,%lx,%lx,%lx,%lx,%lx,%lx,%lx,%lx,%lx,%lx", &c_lc_palette_set.pal.data[offset], + &c_lc_palette_set.pal.data[offset+1], + &c_lc_palette_set.pal.data[offset+2], + &c_lc_palette_set.pal.data[offset+3], + &c_lc_palette_set.pal.data[offset+4], + &c_lc_palette_set.pal.data[offset+5], + &c_lc_palette_set.pal.data[offset+6], + &c_lc_palette_set.pal.data[offset+7], + &c_lc_palette_set.pal.data[offset+8], + &c_lc_palette_set.pal.data[offset+9], + &c_lc_palette_set.pal.data[offset+10], + &c_lc_palette_set.pal.data[offset+11], + &c_lc_palette_set.pal.data[offset+12], + &c_lc_palette_set.pal.data[offset+13], + &c_lc_palette_set.pal.data[offset+14], + &c_lc_palette_set.pal.data[offset+15]) == 16) { + + + offset += 16; + entries_remaining -= 16; + } + } + + file_close(&f_lc_palset); + } + + f_chdir("/"); + + sniprintf(c_lc_palette_set.name, sizeof(c_lc_palette_set.name), "C: %s", filename); + loaded_lc_palette = -1; + update_sc_config(); + return 0; +} + +void cstm_file_load(menucode_id code, int setup_disp, char *dir, char *pattern, load_func load_f) { + uint32_t row_mask[2] = {0x03, 0x00}; + int i, retval, items_curpage; + static int file_load_nav = 0; + static int file_load_page = 0; + static int files_found; + + FILINFO fno; + + if (!sdcard_dev.mount) { + if (file_mount() != 0) { + sniprintf(menu_row1, LCD_ROW_LEN+1, "No SD card"); + sniprintf(menu_row2, LCD_ROW_LEN+1, "detected"); + ui_disp_menu(1); + + return; + } + } + + if (setup_disp) { + files_found = find_files_exec(dir, pattern, &fno, 0, 99, NULL); + printf("%d %s files found\n", files_found, dir); + + if (file_load_page*20+file_load_nav > files_found) { + file_load_page = 0; + file_load_nav = 0; + } + } + + if (files_found == 0) { + sniprintf(menu_row1, LCD_ROW_LEN+1, "No %s/%s", dir, pattern); + sniprintf(menu_row2, LCD_ROW_LEN+1, "files found"); + ui_disp_menu(1); + + return; + } + + // Parse menu control + switch (code) { + case PREV_PAGE: + file_load_nav--; + break; + case NEXT_PAGE: + file_load_nav++; + break; + case VAL_MINUS: + file_load_page = (file_load_page == 0) ? ((files_found-1)/20) : (file_load_page - 1); + setup_disp = 1; + break; + case VAL_PLUS: + file_load_page = (file_load_page + 1) % (((files_found-1)/20)+1); + setup_disp = 1; + break; + case OPT_SELECT: + find_files_exec(dir, pattern, &fno, 0, file_load_page*20+file_load_nav, NULL); + retval = load_f(dir, fno.fname); + setup_disp = 1; + break; + default: + break; + } + + if (file_load_page > (files_found/20)) + file_load_page = 0; + items_curpage = files_found-file_load_page*20; + if (items_curpage > 20) + items_curpage = 20; + + if (file_load_nav < 0) + file_load_nav = items_curpage-1; + else if (file_load_nav >= items_curpage) + file_load_nav = 0; + + if (setup_disp) { + memset((void*)osd->osd_array.data, 0, sizeof(osd_char_array)); + + sniprintf(menu_row1, LCD_ROW_LEN+1, "%s p. %d/%d", dir, file_load_page+1, ((files_found-1)/20)+1); + strncpy((char*)osd->osd_array.data[0][0], menu_row1, OSD_CHAR_COLS); + for (i=0; iosd_array.data[1][0][i] = '-'; + + osd_list_iter = 0; + find_files_exec(dir, pattern, &fno, file_load_page*20, file_load_page*20+items_curpage-1, osd_array_fname_fill); + + for (i=0; iosd_array.data[items_curpage+3][0], OSD_CHAR_COLS, "< Prev Next >"); + row_mask[0] |= (3<<(items_curpage+2)); + + if (code == OPT_SELECT) { + if (retval == 0) + strlcpy(menu_row2, "Done", LCD_ROW_LEN+1); + else if (retval < 0) + sniprintf(menu_row2, LCD_ROW_LEN+1, "Failed (%d)", retval); + else + strlcpy(menu_row2, func_ret_status, LCD_ROW_LEN+1); + + strncpy((char*)osd->osd_array.data[file_load_nav+2][1], menu_row2, OSD_CHAR_COLS); + + row_mask[1] = (1<<(file_load_nav+2)); + } + + osd->osd_sec_enable[0].mask = row_mask[0]; + osd->osd_sec_enable[1].mask = row_mask[1]; + } + + osd->osd_row_color.mask = (1<<(file_load_nav+2)); + + if (code != OPT_SELECT) + sniprintf(menu_row2, LCD_ROW_LEN+1, "%s", &tmpbuf[file_load_nav*24]); + + ui_disp_menu(0); +} + +void cstm_shmask_load(menucode_id code, int setup_disp) { + cstm_file_load(code, setup_disp, "shmask", "*.txt", load_shmask); +} + +void cstm_lc_palette_set_load(menucode_id code, int setup_disp) { + cstm_file_load(code, setup_disp, "lumacode", "*.txt", load_lc_palette_set); +} + +void cstm_fw_update(menucode_id code, int setup_disp) { + cstm_file_load(code, setup_disp, "fw", "*.bin", fw_update); +} + +void enter_cstm(const menuitem_t *item, int detached_mode) { + if (detached_mode) { + navlvl = 0; + menu_active = 1; + osd->osd_config.menu_active = menu_active; + } + /*if (item->type == OPT_AVCONFIG_SELECTION) { + lw_item = item; + cstm_f = cstm_listview; + } else {*/ + cstm_f = item->cstm.cstm_f; + //} + cstm_f(NO_ACTION, 1); +} + static void vm_select() { vm_edit = vm_sel; tc_h_samplerate = video_modes_plm[vm_edit].timings.h_total;