diff --git a/software/ossc_sw.project b/software/ossc_sw.project
index 5e35c03..49fd560 100644
--- a/software/ossc_sw.project
+++ b/software/ossc_sw.project
@@ -59,14 +59,17 @@
-
-
+
+
+
+
+
diff --git a/software/sys_controller/Makefile b/software/sys_controller/Makefile
index c5136c6..e745cc0 100644
--- a/software/sys_controller/Makefile
+++ b/software/sys_controller/Makefile
@@ -155,6 +155,7 @@ C_SRCS += ths7353/ths7353.c
C_SRCS += spi_charlcd/lcd.c
C_SRCS += memory/flash.c
C_SRCS += memory/sdcard.c
+C_SRCS += ossc/menu.c
CXX_SRCS :=
ASM_SRCS :=
diff --git a/software/sys_controller/av_controller.c b/software/sys_controller/av_controller.c
index 8b6f7dd..ff361dd 100644
--- a/software/sys_controller/av_controller.c
+++ b/software/sys_controller/av_controller.c
@@ -29,6 +29,7 @@
#include "lcd.h"
#include "flash.h"
#include "sdcard.h"
+#include "menu.h"
#include "sysconfig.h"
#include "it6613.h"
#include "it6613_sys.h"
@@ -49,24 +50,10 @@ alt_u8 fw_ver_minor = 70;
#define MAINLOOP_SLEEP_US 10000
-#define SCANLINESTR_MAX 15
-#define HV_MASK_MAX 63
-#define L3_MODE_MAX 3
-#define S480P_MODE_MAX 2
-#define SL_MODE_MAX 2
-#define SYNC_LPF_MAX 3
-#define VIDEO_LPF_MAX 5
-#define SAMPLER_PHASE_MIN -16
-#define SAMPLER_PHASE_MAX 15
-#define SYNC_VTH_MIN -11
-#define SYNC_VTH_MAX 20
-#define VSYNC_THOLD_MIN 10
-#define VSYNC_THOLD_MAX 200
-#define PLL_COAST_MIN 0
-#define PLL_COAST_MAX 5
-
#define DEFAULT_PRE_COAST 1
#define DEFAULT_POST_COAST 0
+#define DEFAULT_SAMPLER_PHASE 16
+#define DEFAULT_SYNC_VTH 11
#define RC_MASK 0x0000ffff
#define PB_MASK 0x00030000
@@ -78,40 +65,10 @@ static const char *rc_keydesc[] = { "1", "2", "3", "4", "5", "6", "7", "8", "9",
#define REMOTE_MAX_KEYS (sizeof(rc_keydesc)/sizeof(char*))
alt_u16 rc_keymap[REMOTE_MAX_KEYS] = {0x3E29, 0x3EA9, 0x3E69, 0x3EE9, 0x3E19, 0x3E99, 0x3E59, 0x3ED9, 0x3E39, 0x3EC9, 0x3E4D, 0x3E1D, 0x3EED, 0x3E2D, 0x3ECD, 0x3EAD, 0x3E6D, 0x3E65, 0x3E01, 0x1C48, 0x1C50, 0x1CD0};
-typedef enum {
- RC_BTN1 = 0,
- RC_BTN2,
- RC_BTN3,
- RC_BTN4,
- RC_BTN5,
- RC_BTN6,
- RC_BTN7,
- RC_BTN8,
- RC_BTN9,
- RC_BTN0,
- RC_MENU,
- RC_OK,
- RC_BACK,
- RC_UP,
- RC_DOWN,
- RC_LEFT,
- RC_RIGHT,
- RC_INFO,
- RC_LCDBL,
- RC_SL_TGL,
- RC_SL_PLUS,
- RC_SL_MINUS,
-} rc_code_t;
-
#define lcd_write_menu() lcd_write((char*)&menu_row1, (char*)&menu_row2)
#define lcd_write_status() lcd_write((char*)&row1, (char*)&row2)
static const char *avinput_str[] = { "-", "AV1: RGBS", "AV1: RGsB", "AV1: YPbPr", "AV2: YPbPr", "AV2: RGsB", "AV3: RGBHV", "AV3: RGBS", "AV3: RGsB", "AV3: YPbPr" };
-static const char *l3_mode_desc[] = { "Generic 16:9", "Generic 4:3", "320x240 optim.", "256x240 optim." };
-static const char *s480p_desc[] = { "Auto", "DTV 480p", "VGA 640x480" };
-static const char *sl_mode_desc[] = { "Off", "Horizontal", "Vertical" };
-static const char *sync_lpf_desc[] = { "Off", "33MHz (min)", "10MHz (med)", "2.5MHz (max)" };
-static const char *video_lpf_desc[] = { "Auto", "Off", "95MHz (HDTV II)", "35MHz (HDTV I)", "16MHz (EDTV)", "9MHz (SDTV)" };
typedef enum {
AV_KEEP = 0,
@@ -135,66 +92,12 @@ typedef enum {
ACTIVITY_CHANGE = 4
} status_t;
-typedef enum {
- SCANLINE_MODE,
- SCANLINE_STRENGTH,
- SCANLINE_ID,
- H_MASK,
- V_MASK,
- SAMPLER_480P,
- SAMPLER_PHASE,
- YPBPR_COLORSPACE,
- SYNC_VTH,
- VSYNC_THOLD,
- PRE_COAST,
- POST_COAST,
- SYNC_LPF,
- VIDEO_LPF,
- LINETRIPLE_ENABLE,
- LINETRIPLE_MODE,
- EN_ALC,
- TX_MODE,
-#ifndef DEBUG
- FW_UPDATE,
-#endif
- RESET_CONFIG,
- SAVE_CONFIG
-} menuitem_id;
-
-typedef enum {
- NO_ACTION = 0,
- NEXT_PAGE = 1,
- PREV_PAGE = 2,
- VAL_PLUS = 3,
- VAL_MINUS = 4,
- OPT_SELECT = 5,
-} menucode_id;
-
typedef enum {
TX_HDMI = 0,
TX_DVI = 1
} tx_mode_t;
-typedef struct {
- alt_u8 sl_mode;
- alt_u8 sl_str;
- alt_u8 sl_id;
- alt_u8 linemult_target;
- alt_u8 l3_mode;
- alt_u8 h_mask;
- alt_u8 v_mask;
- alt_u8 tx_mode;
- alt_u8 s480p_mode;
- alt_8 sampler_phase;
- alt_u8 ypbpr_cs;
- alt_8 sync_vth;
- alt_8 vsync_thold;
- alt_u8 sync_lpf;
- alt_u8 video_lpf;
- alt_u8 en_alc;
- alt_u8 pre_coast;
- alt_u8 post_coast;
-} avconfig_t;
+
// Target configuration
avconfig_t tc;
@@ -216,39 +119,6 @@ typedef struct {
// Current mode
avmode_t cm;
-typedef struct {
- const menuitem_id id;
- const char *desc;
-} menuitem_t;
-
-const menuitem_t menu[] = {
- { SCANLINE_MODE, "Scanlines" },
- { SCANLINE_STRENGTH, "Scanline str." },
- { SCANLINE_ID, "Scanline id" },
- { H_MASK, "Horizontal mask" },
- { V_MASK, "Vertical mask" },
- { SAMPLER_480P, "480p in sampler" },
- { SAMPLER_PHASE, "Sampling phase" },
- { YPBPR_COLORSPACE, "YPbPr in ColSpa" },
- { SYNC_VTH, "Analog sync Vth" },
- { VSYNC_THOLD, "Vsync threshold" },
- { PRE_COAST, "H-PLL Pre-Coast" },
- { POST_COAST, "H-PLL Post-Coast" },
- { SYNC_LPF, "Analog sync LPF" },
- { VIDEO_LPF, "Video LPF" },
- { LINETRIPLE_ENABLE, "240p/288p lineX3" },
- { LINETRIPLE_MODE, "Linetriple mode" },
- { EN_ALC, "Auto Lev. Contr." },
- { TX_MODE, "TX mode" },
-#ifndef DEBUG
- { FW_UPDATE, "" },
-#endif
- { RESET_CONFIG, "" },
- { SAVE_CONFIG, "" },
-};
-
-#define MENUITEMS (sizeof(menu)/sizeof(menuitem_t))
-
typedef struct {
char fw_key[4];
alt_u8 version_major;
@@ -288,7 +158,7 @@ alt_u8 stable_frames;
char row1[LCD_ROW_LEN+1], row2[LCD_ROW_LEN+1], menu_row1[LCD_ROW_LEN+1], menu_row2[LCD_ROW_LEN+1];
-alt_u8 menu_active, menu_page;
+alt_u8 menu_active;
alt_u32 remote_code;
alt_u8 remote_rpt, remote_rpt_prev;
alt_u32 btn_code, btn_code_prev;
@@ -360,6 +230,15 @@ int check_fw_image(alt_u32 offset, alt_u32 size, alt_u32 golden_crc, alt_u8 *tmp
return 0;
}
+#ifdef DEBUG
+int fw_update()
+{
+ sniprintf(menu_row2, LCD_ROW_LEN+1, "Not implemented");
+ lcd_write_menu();
+ usleep(1000000);
+ return -1;
+}
+#else
int fw_update()
{
int retval, i;
@@ -451,6 +330,7 @@ failure:
return -1;
}
+#endif
int write_userdata()
{
@@ -491,13 +371,17 @@ int write_userdata()
}
-void set_default_avconfig()
+int set_default_avconfig()
{
memset(&tc, 0, sizeof(avconfig_t));
tc.pre_coast = DEFAULT_PRE_COAST;
tc.post_coast = DEFAULT_POST_COAST;
+ tc.sampler_phase = DEFAULT_SAMPLER_PHASE;
+ tc.sync_vth = DEFAULT_SYNC_VTH;
tc.vsync_thold = DEFAULT_VSYNC_THOLD;
tc.en_alc = 1;
+
+ return 0;
}
int read_userdata()
@@ -623,199 +507,6 @@ inline void TX_enable(tx_mode_t mode)
SetAVMute(FALSE);
}
-void display_menu(alt_u8 forcedisp)
-{
- menucode_id code;
- int retval;
-
- if (remote_code == rc_keymap[RC_UP])
- code = PREV_PAGE;
- else if (remote_code == rc_keymap[RC_DOWN])
- code = NEXT_PAGE;
- else if (remote_code == rc_keymap[RC_RIGHT])
- code = VAL_PLUS;
- else if (remote_code == rc_keymap[RC_LEFT])
- code = VAL_MINUS;
- else if (remote_code == rc_keymap[RC_OK])
- code = OPT_SELECT;
- else
- code = NO_ACTION;
-
- if (!forcedisp && (code == NO_ACTION))
- return;
-
- if (code == PREV_PAGE)
- menu_page = (menu_page+MENUITEMS-1) % MENUITEMS;
- else if (code == NEXT_PAGE)
- menu_page = (menu_page+1) % MENUITEMS;
-
- strncpy(menu_row1, menu[menu_page].desc, LCD_ROW_LEN+1);
-
- switch (menu[menu_page].id) {
- case SCANLINE_MODE:
- if ((code == VAL_MINUS) && (tc.sl_mode > 0))
- tc.sl_mode--;
- else if ((code == VAL_PLUS) && (tc.sl_mode < SL_MODE_MAX))
- tc.sl_mode++;
- strncpy(menu_row2, sl_mode_desc[tc.sl_mode], LCD_ROW_LEN+1);
- break;
- case SCANLINE_STRENGTH:
- if ((code == VAL_MINUS) && (tc.sl_str > 0))
- tc.sl_str--;
- else if ((code == VAL_PLUS) && (tc.sl_str < SCANLINESTR_MAX))
- tc.sl_str++;
- sniprintf(menu_row2, LCD_ROW_LEN+1, "%u%%", ((tc.sl_str+1)*625)/100);
- break;
- case SCANLINE_ID:
- if ((code == VAL_MINUS) || (code == VAL_PLUS))
- tc.sl_id = !tc.sl_id;
- sniprintf(menu_row2, LCD_ROW_LEN+1, tc.sl_id ? "Odd" : "Even");
- break;
- case H_MASK:
- if ((code == VAL_MINUS) && (tc.h_mask > 0))
- tc.h_mask--;
- else if ((code == VAL_PLUS) && (tc.h_mask < HV_MASK_MAX))
- tc.h_mask++;
- sniprintf(menu_row2, LCD_ROW_LEN+1, "%u pixels", tc.h_mask);
- break;
- case V_MASK:
- if ((code == VAL_MINUS) && (tc.v_mask > 0))
- tc.v_mask--;
- else if ((code == VAL_PLUS) && (tc.v_mask < HV_MASK_MAX))
- tc.v_mask++;
- sniprintf(menu_row2, LCD_ROW_LEN+1, "%u pixels", tc.v_mask);
- break;
- case SAMPLER_480P:
- if ((code == VAL_MINUS) && (tc.s480p_mode > 0))
- tc.s480p_mode--;
- else if ((code == VAL_PLUS) && (tc.s480p_mode < S480P_MODE_MAX))
- tc.s480p_mode++;
- strncpy(menu_row2, s480p_desc[tc.s480p_mode], LCD_ROW_LEN+1);
- break;
- case SAMPLER_PHASE:
- if ((code == VAL_MINUS) && (tc.sampler_phase > SAMPLER_PHASE_MIN))
- tc.sampler_phase--;
- else if ((code == VAL_PLUS) && (tc.sampler_phase < SAMPLER_PHASE_MAX))
- tc.sampler_phase++;
- sniprintf(menu_row2, LCD_ROW_LEN+1, "%d deg", ((tc.sampler_phase-SAMPLER_PHASE_MIN)*1125)/100);
- break;
- case YPBPR_COLORSPACE:
- if ((code == VAL_MINUS) || (code == VAL_PLUS))
- tc.ypbpr_cs = !tc.ypbpr_cs;
- strncpy(menu_row2, csc_coeffs[tc.ypbpr_cs].name, LCD_ROW_LEN+1);
- break;
- case SYNC_VTH:
- if ((code == VAL_MINUS) && (tc.sync_vth > SYNC_VTH_MIN))
- tc.sync_vth--;
- else if ((code == VAL_PLUS) && (tc.sync_vth < SYNC_VTH_MAX))
- tc.sync_vth++;
- sniprintf(menu_row2, LCD_ROW_LEN+1, "%d mV", ((tc.sync_vth-SYNC_VTH_MIN)*1127)/100);
- break;
- case VSYNC_THOLD:
- if ((code == VAL_MINUS) && (tc.vsync_thold > VSYNC_THOLD_MIN))
- tc.vsync_thold--;
- else if ((code == VAL_PLUS) && (tc.vsync_thold < VSYNC_THOLD_MAX))
- tc.vsync_thold++;
- sniprintf(menu_row2, LCD_ROW_LEN+1, "%u ns", (1000000UL*tc.vsync_thold)/(clkrate[REFCLK_INTCLK]/1000));
- break;
- case PRE_COAST:
- if ((code == VAL_MINUS) && (tc.pre_coast > PLL_COAST_MIN))
- tc.pre_coast--;
- else if ((code == VAL_PLUS) && (tc.pre_coast < PLL_COAST_MAX))
- tc.pre_coast++;
- sniprintf(menu_row2, LCD_ROW_LEN+1, "%u lines", tc.pre_coast);
- break;
- case POST_COAST:
- if ((code == VAL_MINUS) && (tc.post_coast > PLL_COAST_MIN))
- tc.post_coast--;
- else if ((code == VAL_PLUS) && (tc.post_coast < PLL_COAST_MAX))
- tc.post_coast++;
- sniprintf(menu_row2, LCD_ROW_LEN+1, "%u lines", tc.post_coast);
- break;
- case SYNC_LPF:
- if ((code == VAL_MINUS) && (tc.sync_lpf > 0))
- tc.sync_lpf--;
- else if ((code == VAL_PLUS) && (tc.sync_lpf < SYNC_LPF_MAX))
- tc.sync_lpf++;
- strncpy(menu_row2, sync_lpf_desc[tc.sync_lpf], LCD_ROW_LEN+1);
- break;
- case VIDEO_LPF:
- if ((code == VAL_MINUS) && (tc.video_lpf > 0))
- tc.video_lpf--;
- else if ((code == VAL_PLUS) && (tc.video_lpf < VIDEO_LPF_MAX))
- tc.video_lpf++;
- strncpy(menu_row2, video_lpf_desc[tc.video_lpf], LCD_ROW_LEN+1);
- break;
- case LINETRIPLE_ENABLE:
- if ((code == VAL_MINUS) || (code == VAL_PLUS))
- tc.linemult_target = !tc.linemult_target;
- sniprintf(menu_row2, LCD_ROW_LEN+1, tc.linemult_target ? "On" : "Off");
- break;
- case LINETRIPLE_MODE:
- if ((code == VAL_MINUS) && (tc.l3_mode > 0))
- tc.l3_mode--;
- else if ((code == VAL_PLUS) && (tc.l3_mode < L3_MODE_MAX))
- tc.l3_mode++;
- strncpy(menu_row2, l3_mode_desc[tc.l3_mode], LCD_ROW_LEN+1);
- break;
- case EN_ALC:
- if ((code == VAL_MINUS) || (code == VAL_PLUS))
- tc.en_alc = !tc.en_alc;
- sniprintf(menu_row2, LCD_ROW_LEN+1, tc.en_alc ? "Enabled" : "Disabled");
- break;
- case TX_MODE:
- if (!(IORD_ALTERA_AVALON_PIO_DATA(PIO_1_BASE) & HDMITX_MODE_MASK) && ((code == VAL_MINUS) || (code == VAL_PLUS))) {
- tc.tx_mode = !tc.tx_mode;
- TX_enable(tc.tx_mode);
- }
- sniprintf(menu_row2, LCD_ROW_LEN+1, tc.tx_mode ? "DVI" : "HDMI");
- break;
-#ifndef DEBUG
- case FW_UPDATE:
- if (code == OPT_SELECT) {
- retval = fw_update();
- if (retval == 0) {
- sniprintf(menu_row1, LCD_ROW_LEN+1, "Fw update OK");
- sniprintf(menu_row2, LCD_ROW_LEN+1, "Please restart");
- } else {
- sniprintf(menu_row1, LCD_ROW_LEN+1, "FW not");
- sniprintf(menu_row2, LCD_ROW_LEN+1, "updated");
- }
- } else {
- sniprintf(menu_row2, LCD_ROW_LEN+1, "");
- }
- break;
-#endif
- case RESET_CONFIG:
- if (code == OPT_SELECT) {
- set_default_avconfig();
- sniprintf(menu_row2, LCD_ROW_LEN+1, "Done");
- } else {
- sniprintf(menu_row2, LCD_ROW_LEN+1, "");
- }
- break;
- case SAVE_CONFIG:
- if (code == OPT_SELECT) {
- retval = write_userdata();
- if (retval == 0) {
- sniprintf(menu_row2, LCD_ROW_LEN+1, "Done");
- } else {
- sniprintf(menu_row2, LCD_ROW_LEN+1, "error");
- }
- } else {
- sniprintf(menu_row2, LCD_ROW_LEN+1, "");
- }
- break;
- default:
- sniprintf(menu_row2, LCD_ROW_LEN+1, "MISSING ITEM");
- break;
- }
-
- lcd_write_menu();
-
- return;
-}
-
void parse_control()
{
if (remote_code)
@@ -850,9 +541,9 @@ void parse_control()
} else {
lcd_write_status();
}
- } else if (remote_code == rc_keymap[RC_BACK]) {
+ /*} else if (remote_code == rc_keymap[RC_BACK]) {
menu_active = 0;
- lcd_write_status();
+ lcd_write_status();*/
} else if (remote_code == rc_keymap[RC_INFO]) {
sniprintf(menu_row1, LCD_ROW_LEN+1, "VMod: %s", video_modes[cm.id].name);
//sniprintf(menu_row1, LCD_ROW_LEN+1, "0x%x 0x%x 0x%x", ths_readreg(THS_CH1), ths_readreg(THS_CH2), ths_readreg(THS_CH3));
@@ -1020,13 +711,10 @@ status_t get_status(tvp_input_t input, video_format format)
status = (status < INFO_CHANGE) ? INFO_CHANGE : status;
if (tc.sampler_phase != cm.cc.sampler_phase)
- tvp_set_hpll_phase(tc.sampler_phase-SAMPLER_PHASE_MIN);
+ tvp_set_hpll_phase(tc.sampler_phase);
if (tc.sync_vth != cm.cc.sync_vth)
- tvp_set_sog_thold(tc.sync_vth-SYNC_VTH_MIN);
-
- if (tc.vsync_thold != cm.cc.vsync_thold)
- tvp_set_ssthold(tc.vsync_thold);
+ tvp_set_sog_thold(tc.sync_vth);
if (tc.vsync_thold != cm.cc.vsync_thold)
tvp_set_ssthold(tc.vsync_thold);
@@ -1046,7 +734,6 @@ status_t get_status(tvp_input_t input, video_format format)
if (tc.en_alc != cm.cc.en_alc)
tvp_set_alc(tc.en_alc, target_type);
- // use memcpy instead?
cm.cc = tc;
return status;
@@ -1340,6 +1027,12 @@ int main()
lcd_write_status();
}
+ // Check here to enable regardless of av_init
+ if (tc.tx_mode != cm.cc.tx_mode) {
+ TX_enable(tc.tx_mode);
+ cm.cc.tx_mode = tc.tx_mode;
+ }
+
if (av_init) {
status = get_status(target_input, target_format);
diff --git a/software/sys_controller/ossc/menu.c b/software/sys_controller/ossc/menu.c
new file mode 100644
index 0000000..766a2af
--- /dev/null
+++ b/software/sys_controller/ossc/menu.c
@@ -0,0 +1,218 @@
+//
+// Copyright (C) 2015-2016 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 "menu.h"
+#include "lcd.h"
+#include "tvp7002.h"
+
+extern char row1[LCD_ROW_LEN+1], row2[LCD_ROW_LEN+1], menu_row1[LCD_ROW_LEN+1], menu_row2[LCD_ROW_LEN+1];
+extern avconfig_t tc;
+extern alt_u32 remote_code;
+extern alt_u8 menu_active;
+
+//TODO: move to separate source file(s)
+extern alt_u16 rc_keymap[22];
+#define lcd_write_menu() lcd_write((char*)&menu_row1, (char*)&menu_row2)
+#define lcd_write_status() lcd_write((char*)&row1, (char*)&row2)
+
+static const char *off_on_desc[] = { "Off", "On" };
+static const char *video_lpf_desc[] = { "Auto", "Off", "95MHz (HDTV II)", "35MHz (HDTV I)", "16MHz (EDTV)", "9MHz (SDTV)" };
+static const char *ypbpr_cs_desc[] = { "Rec. 601", "Rec. 709" };
+static const char *s480p_mode_desc[] = { "Auto", "DTV 480p", "VGA 640x480" };
+static const char *sync_lpf_desc[] = { "Off", "33MHz (min)", "10MHz (med)", "2.5MHz (max)" };
+static const char *l3_mode_desc[] = { "Generic 16:9", "Generic 4:3", "320x240 optim.", "256x240 optim." };
+static const char *tx_mode_desc[] = { "HDMI", "DVI" };
+static const char *sl_mode_desc[] = { "Off", "Horizontal", "Vertical" };
+static const char *sl_id_desc[] = { "Even", "Odd" };
+
+static void sampler_phase_disp(alt_u8 v) { sniprintf(menu_row2, LCD_ROW_LEN+1, "%d deg", (v*1125)/100); }
+static void sync_vth_disp(alt_u8 v) { sniprintf(menu_row2, LCD_ROW_LEN+1, "%d mV", (v*1127)/100); }
+static void vsync_thold_disp(alt_u8 v) { sniprintf(menu_row2, LCD_ROW_LEN+1, "%u.%u us", (unsigned)(((1000000U*v)/(clkrate[REFCLK_INTCLK]/1000))/1000), (unsigned)((((1000000U*v)/(clkrate[REFCLK_INTCLK]/1000))%1000)/100)); }
+static void sl_str_disp(alt_u8 v) { sniprintf(menu_row2, LCD_ROW_LEN+1, "%u%%", ((v+1)*625)/100); }
+static void lines_disp(alt_u8 v) { sniprintf(menu_row2, LCD_ROW_LEN+1, "%u lines", v); }
+static void pixels_disp(alt_u8 v) { sniprintf(menu_row2, LCD_ROW_LEN+1, "%u pixels", v); }
+
+MENU(menu_vinputproc, P99_PROTECT({ \
+ { "Video LPF", OPT_AVCONFIG_SELECTION, { .sel = { &tc.video_lpf, SETTING_ITEM(video_lpf_desc) } } },
+ { "YPbPr in ColSpa", OPT_AVCONFIG_SELECTION, { .sel = { &tc.ypbpr_cs, SETTING_ITEM(ypbpr_cs_desc) } } },
+ { "Auto lev. ctrl", OPT_AVCONFIG_SELECTION, { .sel = { &tc.en_alc, SETTING_ITEM(off_on_desc) } } },
+}))
+
+MENU(menu_sampling, P99_PROTECT({ \
+ { "Sampling phase", OPT_AVCONFIG_NUMVALUE, { .num = { &tc.sampler_phase, 0, 31, sampler_phase_disp } } },
+ { "480p in sampler", OPT_AVCONFIG_SELECTION, { .sel = { &tc.s480p_mode, SETTING_ITEM(s480p_mode_desc) } } },
+ //{ "Modeparam editor", OPT_SUBMENU, { .sub = NULL } },
+}))
+
+MENU(menu_sync, P99_PROTECT({ \
+ { "Analog sync LPF", OPT_AVCONFIG_SELECTION, { .sel = { &tc.sync_lpf, SETTING_ITEM(sync_lpf_desc) } } },
+ { "Analog sync Vth", OPT_AVCONFIG_NUMVALUE, { .num = { &tc.sync_vth, 0, 31, sync_vth_disp } } },
+ { "Vsync threshold", OPT_AVCONFIG_NUMVALUE, { .num = { &tc.vsync_thold, 10, 200, vsync_thold_disp } } },
+ { "H-PLL Pre-Coast", OPT_AVCONFIG_NUMVALUE, { .num = { &tc.pre_coast, 0, 5, lines_disp } } },
+ { "H-PLL Post-Coast", OPT_AVCONFIG_NUMVALUE, { .num = { &tc.post_coast, 0, 5, lines_disp } } },
+}))
+
+MENU(menu_output, P99_PROTECT({ \
+ { "240p/288p lineX3", OPT_AVCONFIG_SELECTION, { .sel = { &tc.linemult_target, SETTING_ITEM(off_on_desc) } } },
+ { "Linetriple mode", OPT_AVCONFIG_SELECTION, { .sel = { &tc.l3_mode, SETTING_ITEM(l3_mode_desc) } } },
+ //{ "Interlace passt.", OPT_AVCONFIG_SELECTION, { .sel = { &tc.s480p_mode, SETTING_ITEM(s480p_desc) } } },
+ { "TX mode", OPT_AVCONFIG_SELECTION, { .sel = { &tc.tx_mode, SETTING_ITEM(tx_mode_desc) } } },
+}))
+
+MENU(menu_postproc, P99_PROTECT({ \
+ { "Scanlines", OPT_AVCONFIG_SELECTION, { .sel = { &tc.sl_mode, SETTING_ITEM(sl_mode_desc) } } },
+ { "Scanline str.", OPT_AVCONFIG_NUMVALUE, { .num = { &tc.sl_str, 0, 15, sl_str_disp } } },
+ { "Scanline id.", OPT_AVCONFIG_SELECTION, { .sel = { &tc.sl_id, SETTING_ITEM(sl_id_desc) } } },
+ { "Horizontal mask", OPT_AVCONFIG_NUMVALUE, { .num = { &tc.h_mask, 0, 63, pixels_disp } } },
+ { "Vertical mask", OPT_AVCONFIG_NUMVALUE, { .num = { &tc.v_mask, 0, 63, pixels_disp } } },
+}))
+
+MENU(menu_main, P99_PROTECT({ \
+ { "Video in proc", OPT_SUBMENU, { .sub = &menu_vinputproc } }, \
+ { "Sampling opt.", OPT_SUBMENU, { .sub = &menu_sampling } }, \
+ { "Sync opt.", OPT_SUBMENU, { .sub = &menu_sync } }, \
+ { "Output opt.", OPT_SUBMENU, { .sub = &menu_output } }, \
+ { "Post-proc.", OPT_SUBMENU, { .sub = &menu_postproc } }, \
+ { "Fw. update", OPT_FUNC_CALL, { .fun = { fw_update, "OK - pls restart" } } }, \
+ { "Reset settings", OPT_FUNC_CALL, { .fun = { set_default_avconfig, "Reset done" } } }, \
+ { "Save settings", OPT_FUNC_CALL, { .fun = { write_userdata, "Saved" } } }, \
+}))
+
+// Max 2 levels currently
+menunavi navi[] = {{&menu_main, 0}, {NULL, 0}};
+alt_u8 navlvl = 0;
+
+
+void display_menu(alt_u8 forcedisp)
+{
+ menucode_id code;
+ int retval = 0;
+
+ if (remote_code == rc_keymap[RC_UP])
+ code = PREV_PAGE;
+ else if (remote_code == rc_keymap[RC_DOWN])
+ code = NEXT_PAGE;
+ else if (remote_code == rc_keymap[RC_RIGHT])
+ code = VAL_PLUS;
+ else if (remote_code == rc_keymap[RC_LEFT])
+ code = VAL_MINUS;
+ else if (remote_code == rc_keymap[RC_OK])
+ code = OPT_SELECT;
+ else if (remote_code == rc_keymap[RC_BACK])
+ code = PREV_MENU;
+ else
+ code = NO_ACTION;
+
+ if (!forcedisp && (code == NO_ACTION))
+ return;
+
+ // Parse menu control
+ switch (code) {
+ case PREV_PAGE:
+ navi[navlvl].mp = (navi[navlvl].mp == 0) ? navi[navlvl].m->num_items-1 : (navi[navlvl].mp-1);
+ break;
+ case NEXT_PAGE:
+ navi[navlvl].mp = (navi[navlvl].mp+1) % navi[navlvl].m->num_items;
+ break;
+ case PREV_MENU:
+ if (navlvl > 0) {
+ navlvl--;
+ } else {
+ menu_active = 0;
+ lcd_write_status();
+ return;
+ }
+ break;
+ case OPT_SELECT:
+ switch (navi[navlvl].m->items[navi[navlvl].mp].type) {
+ case OPT_SUBMENU:
+ if (navi[navlvl+1].m != navi[navlvl].m->items[navi[navlvl].mp].sub)
+ navi[navlvl+1].mp = 0;
+ navi[navlvl+1].m = navi[navlvl].m->items[navi[navlvl].mp].sub;
+ navlvl++;
+ break;
+ case OPT_FUNC_CALL:
+ retval = navi[navlvl].m->items[navi[navlvl].mp].fun.f();
+ break;
+ default:
+ break;
+ }
+ break;
+ case VAL_MINUS:
+ switch (navi[navlvl].m->items[navi[navlvl].mp].type) {
+ case OPT_AVCONFIG_SELECTION:
+ if (*(navi[navlvl].m->items[navi[navlvl].mp].sel.data) > 0)
+ *(navi[navlvl].m->items[navi[navlvl].mp].sel.data) = *(navi[navlvl].m->items[navi[navlvl].mp].sel.data) - 1;
+ break;
+ case OPT_AVCONFIG_NUMVALUE:
+ if (*(navi[navlvl].m->items[navi[navlvl].mp].num.data) > navi[navlvl].m->items[navi[navlvl].mp].num.min)
+ *(navi[navlvl].m->items[navi[navlvl].mp].num.data) = *(navi[navlvl].m->items[navi[navlvl].mp].num.data) - 1;
+ break;
+ default:
+ break;
+ }
+ break;
+ case VAL_PLUS:
+ switch (navi[navlvl].m->items[navi[navlvl].mp].type) {
+ case OPT_AVCONFIG_SELECTION:
+ if (*(navi[navlvl].m->items[navi[navlvl].mp].sel.data) < navi[navlvl].m->items[navi[navlvl].mp].sel.num_settings-1)
+ *(navi[navlvl].m->items[navi[navlvl].mp].sel.data) = *(navi[navlvl].m->items[navi[navlvl].mp].sel.data) + 1;
+ break;
+ case OPT_AVCONFIG_NUMVALUE:
+ if (*(navi[navlvl].m->items[navi[navlvl].mp].num.data) < navi[navlvl].m->items[navi[navlvl].mp].num.max)
+ *(navi[navlvl].m->items[navi[navlvl].mp].num.data) = *(navi[navlvl].m->items[navi[navlvl].mp].num.data) + 1;
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+
+ // Generate menu text
+ switch (navi[navlvl].m->items[navi[navlvl].mp].type) {
+ case OPT_AVCONFIG_SELECTION:
+ strncpy(menu_row1, navi[navlvl].m->items[navi[navlvl].mp].name, LCD_ROW_LEN+1);
+ strncpy(menu_row2, navi[navlvl].m->items[navi[navlvl].mp].sel.setting_str[*(navi[navlvl].m->items[navi[navlvl].mp].sel.data)], LCD_ROW_LEN+1);
+ break;
+ case OPT_AVCONFIG_NUMVALUE:
+ strncpy(menu_row1, navi[navlvl].m->items[navi[navlvl].mp].name, LCD_ROW_LEN+1);
+ navi[navlvl].m->items[navi[navlvl].mp].num.f(*(navi[navlvl].m->items[navi[navlvl].mp].num.data));
+ break;
+ case OPT_SUBMENU:
+ sniprintf(menu_row1, LCD_ROW_LEN+1, "%s >", navi[navlvl].m->items[navi[navlvl].mp].name);
+ menu_row2[0] = 0;
+ break;
+ case OPT_FUNC_CALL:
+ sniprintf(menu_row1, LCD_ROW_LEN+1, "<%s>", navi[navlvl].m->items[navi[navlvl].mp].name);
+ if (code == OPT_SELECT)
+ sniprintf(menu_row2, LCD_ROW_LEN+1, "%s", (retval==0) ? navi[navlvl].m->items[navi[navlvl].mp].fun.text_success : "Error");
+ else
+ menu_row2[0] = 0;
+ break;
+ default:
+ break;
+ }
+
+ lcd_write_menu();
+
+ return;
+}
diff --git a/software/sys_controller/ossc/menu.h b/software/sys_controller/ossc/menu.h
new file mode 100644
index 0000000..7080e80
--- /dev/null
+++ b/software/sys_controller/ossc/menu.h
@@ -0,0 +1,153 @@
+//
+// Copyright (C) 2015-2016 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 "alt_types.h"
+
+#ifndef MENU_H_
+#define MENU_H_
+
+typedef enum {
+ OPT_AVCONFIG_SELECTION,
+ OPT_AVCONFIG_NUMVALUE,
+ OPT_SUBMENU,
+ OPT_FUNC_CALL,
+} menuitem_type;
+
+typedef int (*func_call)(void);
+typedef void (*disp_func)(alt_u8);
+
+
+typedef struct {
+ alt_u8 *data;
+ alt_u8 num_settings;
+ const char **setting_str;
+} opt_avconfig_selection;
+
+typedef struct {
+ alt_u8 *data;
+ alt_u8 min;
+ alt_u8 max;
+ disp_func f;
+} opt_avconfig_numvalue;
+
+typedef struct {
+ func_call f;
+ char *text_success;
+} opt_func_call;
+
+typedef struct menustruct menu_t;
+
+typedef struct {
+ char *name;
+ menuitem_type type;
+ union {
+ opt_avconfig_selection sel;
+ opt_avconfig_numvalue num;
+ const menu_t *sub;
+ opt_func_call fun;
+ };
+} menuitem_t;
+
+struct menustruct {
+ alt_u8 num_items;
+ menuitem_t *items;
+};
+
+typedef struct {
+ menu_t *menu;
+} opt_submenu;
+
+#define SETTING_ITEM(x) sizeof(x)/sizeof(char*), x
+#define MENU(X, Y) menuitem_t X##_items[] = Y; const menu_t X = { sizeof(X##_items)/sizeof(menuitem_t), X##_items };
+#define P99_PROTECT(...) __VA_ARGS__
+
+#define MAX_MENU_LEVELS 4
+
+typedef enum {
+ NO_ACTION = 0,
+ NEXT_PAGE = 1,
+ PREV_PAGE = 2,
+ VAL_PLUS = 3,
+ VAL_MINUS = 4,
+ OPT_SELECT = 5,
+ PREV_MENU = 6,
+} menucode_id;
+
+typedef struct {
+ const menu_t *m;
+ alt_u8 mp;
+} menunavi;
+
+//TODO: move all below to separate header(s)
+
+#define SCANLINESTR_MAX 15
+#define VIDEO_LPF_MAX 5
+
+typedef struct {
+ alt_u8 sl_mode;
+ alt_u8 sl_str;
+ alt_u8 sl_id;
+ alt_u8 linemult_target;
+ alt_u8 l3_mode;
+ alt_u8 h_mask;
+ alt_u8 v_mask;
+ alt_u8 tx_mode;
+ alt_u8 s480p_mode;
+ alt_u8 sampler_phase;
+ alt_u8 ypbpr_cs;
+ alt_u8 sync_vth;
+ alt_u8 vsync_thold;
+ alt_u8 sync_lpf;
+ alt_u8 video_lpf;
+ alt_u8 en_alc;
+ alt_u8 pre_coast;
+ alt_u8 post_coast;
+} avconfig_t;
+
+typedef enum {
+ RC_BTN1 = 0,
+ RC_BTN2,
+ RC_BTN3,
+ RC_BTN4,
+ RC_BTN5,
+ RC_BTN6,
+ RC_BTN7,
+ RC_BTN8,
+ RC_BTN9,
+ RC_BTN0,
+ RC_MENU,
+ RC_OK,
+ RC_BACK,
+ RC_UP,
+ RC_DOWN,
+ RC_LEFT,
+ RC_RIGHT,
+ RC_INFO,
+ RC_LCDBL,
+ RC_SL_TGL,
+ RC_SL_PLUS,
+ RC_SL_MINUS,
+} rc_code_t;
+
+int write_userdata();
+int fw_update();
+int set_default_avconfig();
+
+
+#endif