// // Copyright (C) 2015-2023 Markus Hiienkari // // This file is part of Open Source Scan Converter project. // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . // #include #include #include #include "system.h" #include "alt_types.h" #include "controls.h" #include "menu.h" #include "av_controller.h" #include "video_modes.h" #include "userdata.h" #include "firmware.h" #include "lcd.h" #include "altera_avalon_pio_regs.h" static const char *rc_keydesc[REMOTE_MAX_KEYS] = { "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", \ "MENU", "OK", "BACK", "UP", "DOWN", "LEFT", "RIGHT", "INFO", "LCD_BACKLIGHT", "SCANLINE_MODE", \ "SCANLINE_TYPE", "SCANLINE_INT+", "SCANLINE_INT-", "SHMASK_MODE+", "SHMASK_MODE-", "SHMASK_INT+", "SHMASK_INT-", "LINEMULT_MODE", "PHASE+", "PHASE-", "PROFILE_HOTKEY"}; const alt_u16 rc_keymap_default[REMOTE_MAX_KEYS] = {0x3E29, 0x3EA9, 0x3E69, 0x3EE9, 0x3E19, 0x3E99, 0x3E59, 0x3ED9, 0x3E39, 0x3EC9, \ 0x3E4D, 0x3E1D, 0x3EED, 0x3E2D, 0x3ECD, 0x3EAD, 0x3E6D, 0x3E65, 0x3E01, 0x1C48, \ 0x1C18, 0x1C50, 0x1CD0, 0x3E5D, 0x3E9D, 0x1C70, 0x1CF0, 0x1CC8, 0x5E58, 0x5ED8, 0x3EB9}; alt_u16 rc_keymap[REMOTE_MAX_KEYS]; extern char menu_row1[LCD_ROW_LEN+1], menu_row2[LCD_ROW_LEN+1]; extern mode_data_t video_modes_plm[]; extern avmode_t cm; extern avconfig_t tc; extern settings_t ts; extern avinput_t target_input; extern alt_u8 menu_active; extern alt_u32 sys_ctrl; extern alt_u16 tc_sampler_phase; extern alt_u8 profile_sel, profile_sel_menu; extern alt_u8 vm_edit; extern volatile osd_regs *osd; extern menu_t menu_scanlines, menu_advtiming, menu_postproc; alt_u32 remote_code; alt_u8 remote_rpt, remote_rpt_prev; alt_u32 btn_code, btn_code_prev; void setup_rc() { int i, confirm; alt_u32 remote_code_prev = 0; for (i=0; iosd_config.menu_active = 1; ui_disp_menu(1); confirm = 0; while (1) { remote_code = IORD_ALTERA_AVALON_PIO_DATA(PIO_1_BASE) & RC_MASK; btn_code = ~IORD_ALTERA_AVALON_PIO_DATA(PIO_1_BASE) & PB_MASK; if (remote_code && (remote_code != remote_code_prev)) { if (confirm == 0) { rc_keymap[i] = remote_code; strncpy(menu_row1, "Confirm", LCD_ROW_LEN+1); ui_disp_menu(1); confirm = 1; } else { if (remote_code == rc_keymap[i]) { confirm = 2; } else { strncpy(menu_row1, "Mismatch, retry", LCD_ROW_LEN+1); ui_disp_menu(1); confirm = 0; } } } if ((btn_code_prev == 0) && (btn_code == PB0_BIT)) { if (i == 0) { set_default_keymap(); i=REMOTE_MAX_KEYS; } else { i-=2; } confirm = 2; } remote_code_prev = remote_code; btn_code_prev = btn_code; if (confirm == 2) break; usleep(WAITLOOP_SLEEP_US); } } write_userdata(INIT_CONFIG_SLOT); osd->osd_config.menu_active = 0; } void set_default_keymap() { memcpy(rc_keymap, rc_keymap_default, sizeof(rc_keymap)); } int parse_control() { int i, prof_x10=0, ret=0, retval; alt_u32 btn_vec, btn_vec_prev=1; alt_u8 pt_only = 0; avinput_t man_target_input = AV_LAST; // one for each video_group alt_u8* pmcfg_ptr[] = { &pt_only, &tc.pm_240p, &tc.pm_240p, &tc.pm_384p, &tc.pm_480i, &tc.pm_480i, &tc.pm_480p, &tc.pm_480p, &pt_only, &tc.pm_1080i, &pt_only }; alt_u8 valid_pm[] = { 0x1, 0x3f, 0x3f, 0x7, 0xf, 0xf, 0x7, 0x7, 0x1, 0x3, 0x1 }; avinput_t next_input = (cm.avinput == AV3_YPBPR) ? AV1_RGBs : (cm.avinput+1); if (remote_code) printf("RCODE: 0x%.4lx, %d\n", remote_code, remote_rpt); if (btn_code) printf("BCODE: 0x%.2lx\n", btn_code>>16); for (i = RC_BTN1; i < REMOTE_MAX_KEYS; i++) { if (remote_code == rc_keymap[i]) break; if (i == REMOTE_MAX_KEYS - 1) goto Button_Check; } switch (i) { case RC_BTN1: man_target_input = AV1_RGBs; break; case RC_BTN4: man_target_input = AV1_RGsB; break; case RC_BTN7: man_target_input = AV1_YPBPR; break; case RC_BTN2: man_target_input = AV2_YPBPR; break; case RC_BTN5: man_target_input = AV2_RGsB; break; case RC_BTN3: man_target_input = AV3_RGBHV; break; case RC_BTN6: man_target_input = AV3_RGBs; break; case RC_BTN9: man_target_input = AV3_RGsB; break; case RC_BTN0: man_target_input = AV3_YPBPR; break; case RC_MENU: menu_active = !menu_active; osd->osd_config.menu_active = menu_active; profile_sel_menu = profile_sel; if (menu_active) { render_osd_page(); display_menu(1); } else { ui_disp_status(0); } break; case RC_INFO: print_vm_stats(); break; case RC_LCDBL: sys_ctrl ^= LCD_BL; break; case RC_SL_MODE: tc.sl_mode = (tc.sl_mode < SL_MODE_MAX) ? (tc.sl_mode + 1) : 0; if (!menu_active) { strncpy((char*)osd->osd_array.data[0][0], menu_scanlines.items[0].name, OSD_CHAR_COLS); strncpy((char*)osd->osd_array.data[1][0], menu_scanlines.items[0].sel.setting_str[tc.sl_mode], OSD_CHAR_COLS); osd->osd_config.status_refresh = 1; osd->osd_row_color.mask = 0; osd->osd_sec_enable[0].mask = 3; osd->osd_sec_enable[1].mask = 0; } else if (get_current_menunavi()->m == &menu_scanlines) { render_osd_page(); } break; case RC_SL_TYPE: tc.sl_type = (tc.sl_type < SL_TYPE_MAX) ? (tc.sl_type + 1) : 0; if (!menu_active) { strncpy((char*)osd->osd_array.data[0][0], menu_scanlines.items[6].name, OSD_CHAR_COLS); strncpy((char*)osd->osd_array.data[1][0], menu_scanlines.items[6].sel.setting_str[tc.sl_type], OSD_CHAR_COLS); osd->osd_config.status_refresh = 1; osd->osd_row_color.mask = 0; osd->osd_sec_enable[0].mask = 3; osd->osd_sec_enable[1].mask = 0; } else if (get_current_menunavi()->m == &menu_scanlines) { render_osd_page(); } break; case RC_SL_MINUS: case RC_SL_PLUS: if (i == RC_SL_MINUS) tc.sl_str = tc.sl_str ? (tc.sl_str - 1) : 0; else tc.sl_str = (tc.sl_str < SCANLINESTR_MAX) ? (tc.sl_str + 1) : SCANLINESTR_MAX; if (!menu_active) { strncpy((char*)osd->osd_array.data[0][0], menu_scanlines.items[1].name, OSD_CHAR_COLS); menu_scanlines.items[1].num.df(tc.sl_str); strncpy((char*)osd->osd_array.data[1][0], menu_row2, OSD_CHAR_COLS); osd->osd_config.status_refresh = 1; osd->osd_row_color.mask = 0; osd->osd_sec_enable[0].mask = 3; osd->osd_sec_enable[1].mask = 0; } else if (get_current_menunavi()->m == &menu_scanlines) { render_osd_page(); } break; case RC_SHMMODE_MINUS: case RC_SHMMODE_PLUS: if (i == RC_SHMMODE_MINUS) tc.shmask_mode = tc.shmask_mode ? (tc.shmask_mode - 1) : menu_postproc.items[0].sel.max; else tc.shmask_mode = (tc.shmask_mode < menu_postproc.items[0].sel.max) ? (tc.shmask_mode + 1) : 0; if (!menu_active) { strncpy((char*)osd->osd_array.data[0][0], menu_postproc.items[0].name, OSD_CHAR_COLS); strncpy((char*)osd->osd_array.data[1][0], menu_postproc.items[0].sel.setting_str[tc.shmask_mode], OSD_CHAR_COLS); osd->osd_config.status_refresh = 1; osd->osd_row_color.mask = 0; osd->osd_sec_enable[0].mask = 3; osd->osd_sec_enable[1].mask = 0; } else if (get_current_menunavi()->m == &menu_postproc) { render_osd_page(); } break; case RC_SHMINT_MINUS: case RC_SHMINT_PLUS: if (i == RC_SHMINT_MINUS) tc.shmask_str = tc.shmask_str ? (tc.shmask_str - 1) : 0; else tc.shmask_str = (tc.shmask_str < SCANLINESTR_MAX) ? (tc.shmask_str + 1) : SCANLINESTR_MAX; if (!menu_active) { strncpy((char*)osd->osd_array.data[0][0], menu_postproc.items[2].name, OSD_CHAR_COLS); menu_postproc.items[2].num.df(tc.shmask_str); strncpy((char*)osd->osd_array.data[1][0], menu_row2, OSD_CHAR_COLS); osd->osd_config.status_refresh = 1; osd->osd_row_color.mask = 0; osd->osd_sec_enable[0].mask = 3; osd->osd_sec_enable[1].mask = 0; } else if (get_current_menunavi()->m == &menu_postproc) { render_osd_page(); } break; case RC_LM_MODE: strncpy(menu_row1, "Linemult mode:", LCD_ROW_LEN+1); strncpy(menu_row2, "press 1-6", LCD_ROW_LEN+1); osd->osd_config.menu_active = 1; ui_disp_menu(1); while (1) { btn_vec = IORD_ALTERA_AVALON_PIO_DATA(PIO_1_BASE) & RC_MASK; for (i = RC_BTN1; i < REMOTE_MAX_KEYS; i++) { if (btn_vec == rc_keymap[i]) break; } if (video_modes_plm[cm.id].group > GROUP_1080P) { printf("WARNING: Corrupted mode (id %d)\n", cm.id); break; } if (i <= RC_BTN6) { if ((1<osd_config.menu_active = 0; ui_disp_status(0); break; case RC_PHASE_MINUS: case RC_PHASE_PLUS: if (ts.phase_hotkey_enable) { if (i == RC_PHASE_MINUS) video_modes_plm[cm.id].sampler_phase = video_modes_plm[cm.id].sampler_phase ? (video_modes_plm[cm.id].sampler_phase - 1) : SAMPLER_PHASE_MAX; else video_modes_plm[cm.id].sampler_phase = (video_modes_plm[cm.id].sampler_phase < SAMPLER_PHASE_MAX) ? (video_modes_plm[cm.id].sampler_phase + 1) : 0; if (cm.id == vm_edit) tc_sampler_phase = video_modes_plm[cm.id].sampler_phase; set_sampler_phase(video_modes_plm[cm.id].sampler_phase, 1); if (!menu_active) { strncpy((char*)osd->osd_array.data[0][0], menu_advtiming.items[10].name, OSD_CHAR_COLS); sampler_phase_disp(video_modes_plm[cm.id].sampler_phase); strncpy((char*)osd->osd_array.data[1][0], menu_row2, OSD_CHAR_COLS); osd->osd_config.status_refresh = 1; osd->osd_row_color.mask = 0; osd->osd_sec_enable[0].mask = 3; osd->osd_sec_enable[1].mask = 0; } else if (get_current_menunavi()->m == &menu_advtiming) { render_osd_page(); } } break; case RC_PROF_HOTKEY: Prof_Hotkey_Prompt: strncpy(menu_row1, "Profile load:", LCD_ROW_LEN+1); sniprintf(menu_row2, LCD_ROW_LEN+1, "press %u-%u", prof_x10*10, ((prof_x10*10+9) > MAX_PROFILE) ? MAX_PROFILE : (prof_x10*10+9)); osd->osd_config.menu_active = 1; ui_disp_menu(1); while (1) { btn_vec = IORD_ALTERA_AVALON_PIO_DATA(PIO_1_BASE) & RC_MASK; if ((btn_vec_prev == 0) && (btn_vec != 0)) { for (i = RC_BTN1; i < REMOTE_MAX_KEYS; i++) { if (btn_vec == rc_keymap[i]) break; } if ((i == RC_BTN0) || (i < (RC_BTN1 + (prof_x10 == (MAX_PROFILE/10)) ? (MAX_PROFILE%10) : 9))) { profile_sel_menu = prof_x10*10 + ((i+1)%10); retval = load_profile(); sniprintf(menu_row2, LCD_ROW_LEN+1, "%s", (retval==0) ? "Done" : "Failed"); ui_disp_menu(1); usleep(500000); break; } else if (i == RC_PROF_HOTKEY) { prof_x10 = (prof_x10+1) % ((MAX_PROFILE/10)+1); btn_vec_prev = btn_vec; goto Prof_Hotkey_Prompt; } else if (i == RC_BACK) { break; } } btn_vec_prev = btn_vec; usleep(WAITLOOP_SLEEP_US); } menu_active = 0; osd->osd_config.menu_active = 0; ui_disp_status(0); break; case RC_RIGHT: if (!menu_active) man_target_input = next_input; break; default: break; } sys_ctrl ^= REMOTE_EVENT; Button_Check: if (btn_code & PB0_BIT) man_target_input = next_input; if (btn_code & PB1_BIT) tc.sl_mode = tc.sl_mode < SL_MODE_MAX ? tc.sl_mode + 1 : 0; if (man_target_input != AV_LAST) { target_input = man_target_input; ret = 1; } sys_ctrl &= ~(3<