/* Copyright (c) 2020, Erik Kaashoek erik@kaashoek.com * All rights reserved. * * This 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, or (at your option) * any later version. * * The software 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 GNU Radio; see the file COPYING. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, * Boston, MA 02110-1301, USA. */ const uint16_t left_icons [] = { #define I_EMPTY 0*16 0x0000, 0x0000, 0x0000, 0x0001, 0x0001, 0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0001, 0x0001, 0x0000, 0x0000, 0x0000, #define I_HIGH_INPUT 1*16 /* +-----------------+ | | | ** | | *** | | ************ | | *** | | ** | | | | | | | | | | | | | | | | | | | | | +-----------------+ */ 0x0000, 0x0000, 0x0060, 0x0039, 0x0fff, 0x0039, 0x0060, 0x0000, 0x0000, 0x0000, 0x0001, 0x0001, 0x0001, 0x0000, 0x0000, 0x0000, #define I_LOW_INPUT 2*16 /* +-----------------+ | | | | | | | | | | | | | | | | | | | | | ** | | **** | | ************ | | **** | | ** | | | +-----------------+ */ 0x0000, 0x0000, 0x0000, 0x0001, 0x0001, 0x0001, 0x0000, 0x0000, 0x0000, 0x0060, 0x0039, 0x0fff, 0x0039, 0x0060, 0x0000, 0x0000, #define I_LOW_OUTPUT 3*16 0b0000000000000000, 0b0000000000000000, 0b0000000000000000, 0b0000000000000001, 0b0000000000000001, 0b0000000000000001, 0b0000000000000000, 0b0000000000000000, 0b0000000000000000, 0b0000000110000000, 0b0000011100000001, 0b0000111111111111, 0b0000011100000001, 0b0000000110000000, 0b0000000000000000, 0b0000000000000000, #define I_HIGH_OUTPUT 4*16 0b0000000000000000, 0b0000000000000000, 0b0000000110000000, 0b0000011100000001, 0b0000111111111111, 0b0000011100000001, 0b0000000110000000, 0b0000000000000000, 0b0000000000000000, 0b0000000000000000, 0b0000000000000001, 0b0000000000000001, 0b0000000000000001, 0b0000000000000000, 0b0000000000000000, 0b0000000000000000, #define I_CONNECT 5*16 0b0000000000000000, 0b0000000000000000, 0b0000000000110000, 0b0000000000111101, 0b0000001111111111, 0b0000010000111101, 0b0000100000110000, 0b0001000000000000, 0b0001000000000000, 0b0000100000110000, 0b0000010000111101, 0b0000001111111111, 0b0000000000111101, 0b0000000000110000, 0b0000000000000000, 0b0000000000000000, }; const uint16_t right_icons [] = { #define I_SA 0 /* Character 0 (0x00): width 16 +-----------------+ | | | *************** | | * * | |** * | | * * * | | * * * | | * * * * | | * * * * | | * * * * * | | * * * * * * | | * * * * * * * | | * * * * * * * | |** *********** * | | * * | | *************** | | | +-----------------+ */ 0x0000, 0x7fff, 0x4001, 0xc001, 0xc001, 0xc001, 0x4801, 0x4801, 0x4a89, 0x4aa9, 0xcaa9, 0xdffd, 0xc001, 0x4001, 0x7fff, 0x0000, #define I_GEN 1 /* Character 0 (0x00): width 16 +-----------------+ | | | *************** | | * * | |** * | | * ***** ** * | | * * * * * | | * * * * * | | * * * * * | | * * * * * | | * * * * * | | * * * * * | | * ** ***** * | |** * | | * * | | *************** | | | +-----------------+ */ 0x0000, 0x7fff, 0x4001, 0xc001, 0xcf8d, 0xc889, 0x4889, 0x4889, 0x4889, 0x4889, 0xc889, 0xd8f9, 0xc001, 0x4001, 0x7fff, 0x0000, #define I_CONFIG 2 0b0000000000000000, 0b0111111111111111, 0b0100000000000001, 0b1100000010000001, 0b1100001111000001, 0b1100011110001001, 0b0100011100011101, 0b0100011110111001, 0b0100001111111001, 0b0100011111110001, 0b1100111110000001, 0b1101111100000001, 0b1100111000000001, 0b0100000000000001, 0b0111111111111111, 0b0000000000000000, #define I_SINUS 3 0b0000000000000000, 0b0111111111111111, // 1 0b0100000000000001, // 2 0b1100000000000001, // 3 0b1100000000110001, // 4 0b1100000001001001, // 5 0b0100000010000101, // 6 0b0101000010000101, // 7 0b0101000010000101, // 8 0b0101000010000001, // 9 0b1100100100000001, //10 0b1100011000000001, //11 0b1100000000000001, //12 0b0100000000000001, //13 0b0111111111111111, //14 0b0000000000000000, }; enum { KM_START, KM_STOP, KM_CENTER, KM_SPAN, KM_CW, KM_REFLEVEL, KM_SCALE, KM_ATTENUATION, KM_ACTUALPOWER, KM_IF, KM_SAMPLETIME, KM_DRIVE, KM_LOWOUTLEVEL, KM_DECAY, KM_NOISE, KM_10MHZ, KM_REPEAT, KM_OFFSET, KM_TRIGGER, KM_LEVELSWEEP, KM_SWEEP_TIME, KM_OFFSET_DELAY, KM_FAST_SPEEDUP, KM_NONE // always at enum end }; #define KP_X(x) (48*(x) + 2 + (LCD_WIDTH-BUTTON_WIDTH-192)) #define KP_Y(y) (48*(y) + 2) #define KP_PERIOD 10 #define KP_MINUS 11 #define KP_X1 12 #define KP_K 13 #define KP_M 14 #define KP_G 15 #define KP_BS 16 #define KP_INF 17 #define KP_DB 18 #define KP_PLUSMINUS 19 #define KP_KEYPAD 20 #define KP_m 21 #define KP_u 22 #define KP_n 23 #define KP_p 24 #define KP_1 32 #define KP_2 33 #define KP_5 34 #define KP_10 35 #define KP_20 36 #define KP_50 37 #define KP_100 38 #define KP_200 39 #define KP_500 40 typedef struct { uint8_t x:4; uint8_t y:4; int8_t c; } keypads_t; static const keypads_t *keypads; static uint8_t keypads_last_index; // 7 8 9 G // 4 5 6 M // 1 2 3 k // 0 . < x static const keypads_t keypads_freq[] = { { 1, 3, KP_PERIOD }, { 0, 3, 0 }, { 0, 2, 1 }, { 1, 2, 2 }, { 2, 2, 3 }, { 0, 1, 4 }, { 1, 1, 5 }, { 2, 1, 6 }, { 0, 0, 7 }, { 1, 0, 8 }, { 2, 0, 9 }, { 3, 0, KP_G }, { 3, 1, KP_M }, { 3, 2, KP_K }, { 3, 3, KP_X1 }, { 2, 3, KP_BS }, { 0, 0, -1 } }; // 7 8 9 // 4 5 6 // 1 2 3 // 0 . < x static const keypads_t keypads_positive[] = { { 1, 3, KP_PERIOD }, { 0, 3, 0 }, { 0, 2, 1 }, { 1, 2, 2 }, { 2, 2, 3 }, { 0, 1, 4 }, { 1, 1, 5 }, { 2, 1, 6 }, { 0, 0, 7 }, { 1, 0, 8 }, { 2, 0, 9 }, { 3, 3, KP_X1 }, { 2, 3, KP_BS }, { 0, 0, -1 } }; // 100 200 500 n // 10 20 50 u // 1 2 5 m // 0 . < x static const keypads_t keypads_pos_unit[] = { { 1, 3, KP_PERIOD }, { 0, 3, 0 }, { 0, 2, KP_1 }, { 1, 2, KP_2 }, { 2, 2, KP_5 }, { 0, 1, KP_10 }, { 1, 1, KP_20 }, { 2, 1, KP_50 }, { 0, 0, KP_100 }, { 1, 0, KP_200 }, { 2, 0, KP_500 }, { 3, 0, KP_n }, { 3, 1, KP_u }, { 3, 2, KP_m }, { 3, 3, KP_X1 }, { 2, 3, KP_BS }, { 0, 0, -1 } }; // 7 8 9 m // 4 5 6 u // 1 2 3 - // 0 . < x static const keypads_t keypads_plusmin_unit[] = { { 1, 3, KP_PERIOD }, { 0, 3, 0 }, { 0, 2, 1 }, { 1, 2, 2 }, { 2, 2, 3 }, { 0, 1, 4 }, { 1, 1, 5 }, { 2, 1, 6 }, { 0, 0, 7 }, { 1, 0, 8 }, { 2, 0, 9 }, { 3, 0, KP_u}, { 3, 1, KP_m}, { 3, 2, KP_MINUS }, { 3, 3, KP_X1 }, { 2, 3, KP_BS }, { 0, 0, -1 } }; // 7 8 9 // 4 5 6 // 1 2 3 - // 0 . < x static const keypads_t keypads_plusmin[] = { { 1, 3, KP_PERIOD }, { 0, 3, 0 }, { 0, 2, 1 }, { 1, 2, 2 }, { 2, 2, 3 }, { 0, 1, 4 }, { 1, 1, 5 }, { 2, 1, 6 }, { 0, 0, 7 }, { 1, 0, 8 }, { 2, 0, 9 }, { 3, 0, KP_u}, { 3, 1, KP_m}, { 3, 2, KP_MINUS }, { 3, 3, KP_X1 }, { 2, 3, KP_BS }, { 0, 0, -1 } }; // 7 8 9 // 4 5 6 // 1 2 3 m // 0 . < x static const keypads_t keypads_time[] = { { 1, 3, KP_PERIOD }, { 0, 3, 0 }, { 0, 2, 1 }, { 1, 2, 2 }, { 2, 2, 3 }, { 0, 1, 4 }, { 1, 1, 5 }, { 2, 1, 6 }, { 0, 0, 7 }, { 1, 0, 8 }, { 2, 0, 9 }, // { 3, 0, KP_n}, // { 3, 1, KP_u}, { 3, 2, KP_m }, { 3, 3, KP_X1 }, { 2, 3, KP_BS }, { 0, 0, -1 } }; static const struct { const keypads_t *keypad_type; char * name; } keypads_mode_tbl[KM_NONE] = { {keypads_freq , "START"}, // start {keypads_freq , "STOP"}, // stop {keypads_freq , "CENTER"}, // center {keypads_freq , "SPAN"}, // span {keypads_freq , "FREQ"}, // cw freq {keypads_plusmin_unit, "REF\nLEVEL"}, // reflevel {keypads_pos_unit , "SCALE"}, // scale {keypads_positive , "ATTENUATE"}, // attenuation {keypads_plusmin_unit, "ACTUAL\nPOWER"}, // actual power {keypads_freq , "IF"}, // IF {keypads_positive , "SAMPLE\nDELAY"}, // sample delay {keypads_positive , "DRIVE"}, // drive {keypads_plusmin , "LEVEL"}, // KM_LOWOUTLEVEL {keypads_positive , "SCANS"}, // KM_DECAY {keypads_positive , "LEVEL"}, // KM_NOISE {keypads_freq , "FREQ"}, // KM_10MHz {keypads_positive , "SAMPLE\nREPEAT"}, // KM_REPEA {keypads_plusmin , "OFFSET"}, // KM_OFFSET {keypads_plusmin_unit, "TRIGGER\nLEVEL"}, // KM_TRIGGER {keypads_plusmin , "LEVEL\nSWEEP"}, // KM_LEVELSWEEP {keypads_time , "SWEEP\nSECONDS"}, // KM_SWEEP_TIME {keypads_positive , "OFFSET\nDELAY"}, // KM_OFFSET_DELAY {keypads_positive , "FAST\nSPEEDUP"}, // KM_FAST_SPEEDUP }; // ===[MENU CALLBACKS]========================================================= int generator_enabled = false; extern const menuitem_t menu_lowoutputmode[]; extern const menuitem_t menu_highoutputmode[]; extern const menuitem_t menu_modulation[]; extern const menuitem_t menu_top[]; extern const menuitem_t menu_tophigh[]; extern const menuitem_t menu_topultra[]; static UI_FUNCTION_CALLBACK(menu_mode_cb) { (void)data; set_mode(item); // draw_cal_status(); switch (item) { case 0: // if (setting.mode != M_LOW) // set_mode(M_LOW); menu_move_back_and_leave_ui(); break; case 1: // if (setting.mode != M_HIGH) // set_mode(M_HIGH); menu_move_back_and_leave_ui(); break; case 2: menu_push_submenu(menu_lowoutputmode); break; case 3: menu_push_submenu(menu_highoutputmode); break; #ifdef __ULTRA__ case 7: menu_push_submenu(menu_topultra); break; #endif } redraw_request |= REDRAW_CAL_STATUS; } static UI_FUNCTION_CALLBACK(menu_load_preset_cb) { (void)item; if (caldata_recall(data) == -1) { if (data == 0) reset_settings(setting.mode); // Restore all defaults else { draw_menu(); return; } } menu_move_back_and_leave_ui(); } static UI_FUNCTION_CALLBACK(menu_store_preset_cb) { (void)item; if (data == 100) { reset_settings(M_LOW); // Restore all defaults in Low mode set_refer_output(-1); // setting.mode = -1; data = 0; } caldata_save(data); menu_move_back_and_leave_ui(); } extern int dirty; UI_FUNCTION_CALLBACK(menu_autosettings_cb) { (void)item; (void)data; reset_settings(setting.mode); active_marker = 0; for (int i = 1; i= 0 && item < MARKERS_MAX) { markers[item].enabled = true; active_marker_select(item); menu_push_submenu(menu_marker_modify); redraw_marker(active_marker); draw_menu(); } } static UI_FUNCTION_CALLBACK(menu_marker_modify_cb) { (void)item; if (markers[active_marker].enabled == M_ENABLED) { if (data == M_DELETE) { markers[active_marker].enabled = false; menu_move_back(); // ui_mode_normal(); // return; } else if (data == M_NORMAL) { markers[active_marker].mtype = M_NORMAL; } else if (data == M_REFERENCE) { for (int i = 0; i 0) mark = true; if (item == 5 && setting.offset_delay > 0) mark = true; } else if (menu == menu_sweep_speed) { if (item == setting.step_delay_mode && item < SD_MANUAL){ mark = true; } else if (item == 3 && setting.sweep_time_us != 0){ mark = true; } else if (item == 5 && setting.fast_speedup != 0){ mark = true; } } else if (menu == menu_sweep_points) { if (points_setting[data] == sweep_points){ mark = true; } #ifdef __ULTRA__ } else if (MT_MASK(menu[item].type) == MT_CALLBACK && menu == menu_harmonic) { if (data == setting.harmonic) mark = true; #endif } else if (MT_MASK(menu[item].type) == MT_CALLBACK && menu == menu_settings2) { int v=0; switch(data) { case 1: v = setting.agc; break; case 2: v = setting.lna; break; case 3: v = setting.tracking; break; case 4: v = setting.below_IF; break; } if (S_IS_AUTO(v)) m_auto = true; else if (v == S_ON) mark = true; } else if (menu == menu_marker_modify && active_marker >= 0 && markers[active_marker].enabled == M_ENABLED) { if (data & markers[active_marker].mtype) mark = true; else if (item < 5 && data==markers[active_marker].mtype) // This catches the M_NORMAL case mark = true; } else if (menu == menu_marker_search) { if (item == 4 && markers[active_marker].mtype & M_TRACKING) mark = true; } else if (/* menu == menu_marker_sel || */ menu == menu_marker_select) { param_1.i = data; if (item < 4 && markers[item].enabled) mark = true; #if 0 else if (item == 4 && uistat.marker_delta) mark = true; else if (item == 5 && uistat.marker_noise) mark = true; else if (item == 6 && uistat.marker_tracking) mark = true; #endif } else if (menu == menu_reflevel) { if ((item == 0 && setting.auto_reflevel) || (item == 1 && !setting.auto_reflevel)) mark = true; } else if (menu == menu_atten) { if ((item == 0 && setting.auto_attenuation )) mark = true; if (!setting.auto_attenuation) { if (item == 1) mark = true; if (item == 2 && !setting.atten_step) mark = true; if (item == 3 && setting.atten_step) mark = true; } } // Only keypad retrieves value if (menu[item].type & MT_FORM && MT_MASK(menu[item].type) == MT_KEYPAD) { keypad_mode = menu[item].data; fetch_numeric_target(); param_1.text = uistat.text; } // Prepare button label plot_printf(button->text, sizeof button->text, menu[item].label, param_1.u, param_2.u); if (m_auto) { button->bg = LIGHT_GREY; button->fg = config.menu_normal_color; } else if (mark) { button->bg = DEFAULT_MENU_TEXT_COLOR; button->fg = config.menu_normal_color; } if (ui_mode == UI_MENU && menu_is_form(menu)) { // if (item == 0) // redraw_frame(); if (item <= 1) { area_width = 0; } }else{ area_width = AREA_WIDTH_NORMAL - MENU_BUTTON_WIDTH; } } static void fetch_numeric_target(void) { switch (keypad_mode) { case KM_START: uistat.value = get_sweep_frequency(ST_START); plot_printf(uistat.text, sizeof uistat.text, "%3.3fMHz", uistat.value / 1000000.0); break; case KM_STOP: uistat.value = get_sweep_frequency(ST_STOP); plot_printf(uistat.text, sizeof uistat.text, "%3.3fMHz", uistat.value / 1000000.0); break; case KM_CENTER: uistat.value = get_sweep_frequency(ST_CENTER); plot_printf(uistat.text, sizeof uistat.text, "%3.3fMHz", uistat.value / 1000000.0); break; case KM_SPAN: uistat.value = get_sweep_frequency(ST_SPAN); plot_printf(uistat.text, sizeof uistat.text, "%3.3fMHz", uistat.value / 1000000.0); break; case KM_CW: uistat.value = get_sweep_frequency(ST_CW); plot_printf(uistat.text, sizeof uistat.text, "%3.3fMHz", uistat.value / 1000000.0); break; case KM_SCALE: uistat.value = setting.scale; plot_printf(uistat.text, sizeof uistat.text, "%f/", uistat.value); break; case KM_REFLEVEL: uistat.value = setting.reflevel; plot_printf(uistat.text, sizeof uistat.text, "%f", uistat.value); break; case KM_ATTENUATION: uistat.value = get_attenuation(); plot_printf(uistat.text, sizeof uistat.text, "%ddB", ((int32_t)uistat.value)); break; case KM_ACTUALPOWER: uistat.value = get_level_offset(); plot_printf(uistat.text, sizeof uistat.text, "%ddB", ((int32_t)uistat.value)); break; case KM_IF: uistat.value = setting.frequency_IF; plot_printf(uistat.text, sizeof uistat.text, "%3.3fMHz", uistat.value / 1000000.0); break; case KM_SAMPLETIME: uistat.value = setting.step_delay; plot_printf(uistat.text, sizeof uistat.text, "%3dus", ((int32_t)uistat.value)); break; case KM_REPEAT: uistat.value = setting.repeat; plot_printf(uistat.text, sizeof uistat.text, "%2d", ((int32_t)uistat.value)); break; case KM_DRIVE: uistat.value = setting.drive; plot_printf(uistat.text, sizeof uistat.text, "%3ddB", ((int32_t)uistat.value)); break; case KM_LOWOUTLEVEL: uistat.value = get_attenuation(); // compensation for dB offset during low output mode int end_level = ((int32_t)uistat.value)+setting.level_sweep; if (end_level < -76) end_level = -76; if (end_level > -6) end_level = -6; if (setting.level_sweep != 0) plot_printf(uistat.text, sizeof uistat.text, "%ddBm to %ddBm", ((int32_t)uistat.value), end_level); else plot_printf(uistat.text, sizeof uistat.text, "%ddBm", ((int32_t)uistat.value)); break; case KM_DECAY: uistat.value = setting.decay; plot_printf(uistat.text, sizeof uistat.text, "%3d", ((int32_t)uistat.value)); break; case KM_NOISE: uistat.value = setting.noise; plot_printf(uistat.text, sizeof uistat.text, "%3d", ((int32_t)uistat.value)); break; case KM_10MHZ: uistat.value = setting_frequency_10mhz; plot_printf(uistat.text, sizeof uistat.text, "%3.6fMHz", uistat.value / 1000000.0); break; case KM_OFFSET: uistat.value = setting.offset; plot_printf(uistat.text, sizeof uistat.text, "%.1fdB", uistat.value); break; case KM_LEVELSWEEP: uistat.value = setting.level_sweep; plot_printf(uistat.text, sizeof uistat.text, "%.1fdB", uistat.value); break; case KM_SWEEP_TIME: // if (setting.sweep_time_us < calc_min_sweep_time_us()) // uistat.value = calc_min_sweep_time_us(); // else uistat.value = setting.actual_sweep_time_us; uistat.value /= (float)ONE_SECOND_TIME; plot_printf(uistat.text, sizeof uistat.text, "%.3Fs", uistat.value); break; case KM_TRIGGER: uistat.value = setting.trigger_level; plot_printf(uistat.text, sizeof uistat.text, "%.1fdB", uistat.value); break; } { uint32_t x = uistat.value; int n = 0; for (; x >= 10 && n < 9; n++) x /= 10; uistat.digit = n; } // uistat.previous_value = uistat.value; } static void set_numeric_value(void) { switch (keypad_mode) { case KM_START: set_sweep_frequency(ST_START, (uint32_t)uistat.value); break; case KM_STOP: set_sweep_frequency(ST_STOP, (uint32_t)uistat.value); break; case KM_CENTER: set_sweep_frequency(ST_CENTER, (uint32_t)uistat.value); break; case KM_SPAN: setting.modulation = MO_NONE; set_sweep_frequency(ST_SPAN, (uint32_t)uistat.value); break; case KM_CW: set_sweep_frequency(ST_CW, (uint32_t)uistat.value); break; case KM_SCALE: user_set_scale(uistat.value); break; case KM_REFLEVEL: user_set_reflevel(uistat.value); break; case KM_ATTENUATION: setting.auto_attenuation = false; set_attenuation(uistat.value); break; case KM_ACTUALPOWER: set_actual_power(uistat.value); config_save(); break; case KM_IF: setting.auto_IF = false; set_IF(uistat.value); // config_save(); break; case KM_SAMPLETIME: set_step_delay(uistat.value); break; case KM_OFFSET_DELAY: set_offset_delay(uistat.value); break; case KM_FAST_SPEEDUP: set_fast_speedup(uistat.value); break; case KM_REPEAT: set_repeat(uistat.value); break; case KM_DRIVE: set_drive(uistat.value); break; case KM_LOWOUTLEVEL: set_level(uistat.value); break; case KM_DECAY: set_decay(uistat.value); break; case KM_NOISE: set_noise(uistat.value); break; case KM_10MHZ: set_10mhz(uistat.value); dirty = true; break; case KM_OFFSET: set_offset(uistat.value); break; case KM_LEVELSWEEP: setting.modulation = MO_NONE; set_level_sweep(uistat.value); break; case KM_SWEEP_TIME: set_sweep_time_us(uistat.value*ONE_SECOND_TIME); update_grid(); break; case KM_TRIGGER: if (setting.trigger == T_AUTO ) set_trigger(T_NORMAL); set_trigger_level(to_dBm(uistat.value)); completed = true; break; } } void menu_move_top(void) { while (menu_current_level > 0) menu_move_back(); }