diff --git a/Font5x7.c b/Font5x7.c index 2eab2eb..9ab283f 100644 --- a/Font5x7.c +++ b/Font5x7.c @@ -958,8 +958,8 @@ const uint8_t x5x7_bits[] = +--------+ */ 0b01100000|CHAR5x7_WIDTH_5px, 0b10010000, - 0b10110000, - 0b11010000, + 0b10010000, + 0b10010000, 0b10010000, 0b10010000, 0b01100000, diff --git a/Font7x13b.c b/Font7x13b.c index 6b72062..dc882ac 100644 --- a/Font7x13b.c +++ b/Font7x13b.c @@ -1345,8 +1345,8 @@ const uint8_t x7x11b_bits[] = 0b01111000, 0b11001100, 0b11001100, - 0b11011100, - 0b11101100, + 0b11001100, + 0b11001100, 0b11001100, 0b11001100, 0b11001100, diff --git a/main.c b/main.c index 7c543a2..20f9a77 100644 --- a/main.c +++ b/main.c @@ -122,7 +122,8 @@ const char *info_about[]={ "Platform: " PLATFORM_NAME, 0 // sentinel }; -extern int dirty; + +uint16_t dirty = true; bool completed = false; @@ -201,6 +202,10 @@ static THD_FUNCTION(Thread1, arg) } +#pragma GCC push_options +#pragma GCC optimize ("Os") + + int is_paused(void) { @@ -2528,10 +2533,12 @@ static void shell_init_connection(void){ // Only USB console, shell_stream always on USB #define PREPARE_STREAM +#if 0 // Not used // Check connection as Active, if no suspend input static bool shell_check_connect(void){ return SDU1.config->usbp->state == USB_ACTIVE; } +#endif // Init shell I/O connection over USB static void shell_init_connection(void){ @@ -2698,6 +2705,7 @@ static DACConfig dac1cfg1 = { datamode: DAC_DHRM_12BIT_RIGHT }; +#pragma GCC pop_options static const GPTConfig gpt4cfg = { 1000000, // 1 MHz timer clock. diff --git a/nanovna.h b/nanovna.h index 48648ac..912a97c 100644 --- a/nanovna.h +++ b/nanovna.h @@ -211,7 +211,8 @@ extern const char *info_about[]; extern const char * const unit_string[]; extern uint8_t signal_is_AM; extern const int reffer_freq[]; - +extern uint32_t minFreq; +extern uint32_t maxFreq; int level_is_calibrated(void); void reset_settings(int); void update_min_max_freq(void); @@ -419,7 +420,7 @@ extern const uint8_t numfont16x22[]; #define bFONT_GET_DATA(ch) ( &x7x11b_bits[(ch-bFONT_START_CHAR)*bFONT_GET_HEIGHT]) #define bFONT_GET_WIDTH(ch) (8-(x7x11b_bits[(ch-bFONT_START_CHAR)*bFONT_GET_HEIGHT]&7)) -#if 1 // Set to 0 to save 3kByte +#if 1 // Set to 0 to save 3kByte and loose nice font #define wFONT_START_CHAR 0x17 #define wFONT_MAX_WIDTH 12 #define wFONT_GET_HEIGHT 14 @@ -759,7 +760,7 @@ typedef struct setting // uint32_t _frequency1; int mode; uint16_t _sweep_points; - float attenuate; + int16_t attenuate_x2; int auto_attenuation; int atten_step; uint32_t rbw_x10; @@ -820,9 +821,11 @@ typedef struct setting float normalize_level; // Level to set normalize to, zero if not doing anything int modulation_frequency; int trigger_mode; - uint32_t checksum; + int slider_position; + int32_t slider_span; int extra_lna; int ultra; + uint32_t checksum; // must be last }setting_t; extern setting_t setting; @@ -1024,6 +1027,15 @@ typedef struct ui_button { char text[32]; } ui_button_t; +typedef struct ui_slider { + uint8_t keypad; + uint8_t has_steps; + uint16_t slider_position; + uint16_t slider_step; + float min_value; + float max_value; +} ui_slider_t; + extern uistat_t uistat; void ui_init(void); void ui_show(void); diff --git a/plot.c b/plot.c index 1c649cf..0a449e4 100644 --- a/plot.c +++ b/plot.c @@ -25,7 +25,7 @@ #pragma GCC push_options -// #pragma GCC optimize ("O2") // Makes the code just a bit faster, disable during debugging. +#pragma GCC optimize ("Os") // Makes the code just a bit faster, disable during debugging. #ifdef __SCROLL__ @@ -517,6 +517,9 @@ draw_on_strut(int v0, int d, int color) #define LOG_10_SQRT_50 ((float)0.84948500216800) #define POW_30_20 ((float) 0.215443469) #define POW_SQRT ((float)1.5234153789) +#define LOG_10_SQRT_50_x20_plus30 ((float)46.98970004336) +#define LOG_10_SQRT_50_x20_plus90 ((float)106.98970004336) + /* * calculate log10f(abs(gamma)) */ @@ -535,11 +538,11 @@ value(const float v) { case U_DBMV: // return v + 30.0 + 20.0*log10f(sqrt(50)); - return v + 30.0 + 20.0*LOG_10_SQRT_50; //TODO convert constants to single float number as GCC compiler does runtime calculation + return v + LOG_10_SQRT_50_x20_plus30; // + 30.0 + 20.0*LOG_10_SQRT_50; //TODO convert constants to single float number as GCC compiler does runtime calculation break; case U_DBUV: // return v + 90.0 + 20.0*log10f(sqrt(50.0)); //TODO convert constants to single float number as GCC compiler does runtime calculation - return v + 90.0 + 20.0*LOG_10_SQRT_50; + return v + LOG_10_SQRT_50_x20_plus90; // 90.0 + 20.0*LOG_10_SQRT_50; break; case U_VOLT: // return pow(10, (v-30.0)/20.0) * sqrt((float)50.0); @@ -562,11 +565,11 @@ to_dBm(const float v) { case U_DBMV: // return v - 30.0 - 20.0*log10f(sqrt(50)); - return v - 30.0 - 20.0*LOG_10_SQRT_50; + return v - LOG_10_SQRT_50_x20_plus30; // (30.0 + 20.0*LOG_10_SQRT_50); break; case U_DBUV: // return v - 90.0 - 20.0*log10f(sqrt(50.0)); //TODO convert constants to single float number as GCC compiler does runtime calculation - return v - 90.0 - 20.0*LOG_10_SQRT_50; + return v - LOG_10_SQRT_50_x20_plus90; // (90.0 + 20.0*LOG_10_SQRT_50); break; case U_VOLT: // return log10f( v / (sqrt(50.0))) * 20.0 + 30.0 ; diff --git a/sa_cmd.c b/sa_cmd.c index ce76bf1..93cc561 100644 --- a/sa_cmd.c +++ b/sa_cmd.c @@ -383,7 +383,7 @@ VNA_SHELL_FUNCTION(cmd_y) shell_printf("\r\n"); #endif } - +#if 0 // not used VNA_SHELL_FUNCTION(cmd_z) { static const char cmd_z_list[] = "t|r|i"; @@ -409,7 +409,7 @@ VNA_SHELL_FUNCTION(cmd_z) #endif } } - +#endif VNA_SHELL_FUNCTION(cmd_selftest) { diff --git a/sa_core.c b/sa_core.c index 00bc6ba..aefa955 100644 --- a/sa_core.c +++ b/sa_core.c @@ -21,7 +21,7 @@ #include "stdlib.h" #pragma GCC push_options -#pragma GCC optimize ("Os") // "Os" causes problem in selftest!!!!!!!! +#pragma GCC optimize ("Os") //#define __DEBUG_AGC__ If set the AGC value will be shown in the stored trace and FAST_SWEEP rmmode will be disabled @@ -30,14 +30,14 @@ #undef __FAST_SWEEP__ #endif #endif -int dirty = true; +// uint8_t dirty = true; int scandirty = true; setting_t setting; uint32_t frequencies[POINTS_COUNT]; uint16_t actual_rbw_x10 = 0; -int vbwSteps = 1; +uint16_t vbwSteps = 1; uint32_t minFreq = 0; uint32_t maxFreq = 520000000; @@ -93,7 +93,7 @@ void reset_settings(int m) setting.unit = U_DBM; set_scale(10); set_reflevel(-10); - setting.attenuate = 0; + setting.attenuate_x2 = 0; setting.rbw_x10 = 0; setting.average = 0; setting.harmonic = 0; @@ -144,6 +144,9 @@ void reset_settings(int m) setting.spur_removal = S_OFF; #endif setting.mirror_masking = 0; + setting.slider_position = 0; + setting.slider_span = 100000; + #endif switch(m) { case M_LOW: @@ -153,8 +156,8 @@ void reset_settings(int m) set_sweep_frequency(ST_STOP, 2900000000); // TODO <----------------- temp ---------------------- else set_sweep_frequency(ST_STOP, 800000000); // TODO <----------------- temp ---------------------- - setting.attenuate = 0.0; // <---------------- WARNING ----------------- - setting.auto_attenuation = false; // <---------------- WARNING ----------------- + setting.attenuate_x2 = 0; // TODO <----------------- temp --------------- + setting.auto_attenuation = true; setting.sweep_time_us = 0; setting.lo_drive=1; break; @@ -162,7 +165,7 @@ void reset_settings(int m) case M_ULTRA: set_sweep_frequency(ST_START, minFreq); set_sweep_frequency(ST_STOP, maxFreq); - setting.attenuate = 0; + setting.attenuate_x2 = 0; setting.sweep_time_us = 0; break; #endif @@ -185,7 +188,7 @@ void reset_settings(int m) setting.sweep_time_us = 10*ONE_SECOND_TIME; break; } - for (int i = 0; i< MARKERS_MAX; i++) { + for (uint8_t i = 0; i< MARKERS_MAX; i++) { markers[i].enabled = M_DISABLED; markers[i].mtype = M_NORMAL; } @@ -293,7 +296,7 @@ void set_measurement(int m) for (int j = 0; j < setting._sweep_points; j++) stored_t[j] = -150; setting.linearity_step = 0; - setting.attenuate = 29.0; + setting.attenuate_x2 = 29*2; setting.auto_attenuation = false; } #endif @@ -466,9 +469,9 @@ void set_auto_attenuation(void) { setting.auto_attenuation = true; if (setting.mode == M_LOW) { - setting.attenuate = 30.0; + setting.attenuate_x2 = 60; } else { - setting.attenuate = 0; + setting.attenuate_x2 = 0; } setting.atten_step = false; dirty = true; @@ -481,18 +484,19 @@ void set_auto_reflevel(int v) float get_attenuation(void) { + float actual_attenuation = setting.attenuate_x2 / 2.0; if (setting.mode == M_GENLOW) { if (setting.atten_step) - return ( -(POWER_OFFSET + setting.attenuate - (setting.atten_step-1)*POWER_STEP + SWITCH_ATTENUATION)); + return ( -(POWER_OFFSET + actual_attenuation - (setting.atten_step-1)*POWER_STEP + SWITCH_ATTENUATION)); else - return ( -POWER_OFFSET - setting.attenuate + (setting.rx_drive & 7) * 3); + return ( -POWER_OFFSET - actual_attenuation + (setting.rx_drive & 7) * 3); } else if (setting.atten_step) { if (setting.mode == M_LOW) - return setting.attenuate + RECEIVE_SWITCH_ATTENUATION; + return actual_attenuation + RECEIVE_SWITCH_ATTENUATION; else - return setting.attenuate + SWITCH_ATTENUATION; + return actual_attenuation + SWITCH_ATTENUATION; } - return(setting.attenuate); + return(actual_attenuation); } static pureRSSI_t get_signal_path_loss(void){ @@ -507,7 +511,7 @@ static pureRSSI_t get_signal_path_loss(void){ static const int drive_dBm [16] = {-38,-35,-33,-30,-27,-24,-21,-19,-7,-4,-2, 1, 4, 7, 10, 13}; -void set_level(float v) // Set the drive level of the LO +void set_level(float v) // Set the output level in dB in high/low output { if (setting.mode == M_GENHIGH) { int d = 0; @@ -523,7 +527,7 @@ void set_level(float v) // Set the drive level of the LO dirty = true; } -void set_attenuation(float a) // Is used both in output mode and input mode +void set_attenuation(float a) // Is used both in low output mode and high/low input mode { if (setting.mode == M_GENLOW) { a = a + POWER_OFFSET; @@ -565,9 +569,9 @@ void set_attenuation(float a) // Is used both in output mode and input mod a=31.0; if (setting.mode == M_HIGH) // No attenuator in high mode a = 0; - if (setting.attenuate == a) + if (setting.attenuate_x2 == a*2) return; - setting.attenuate = a; + setting.attenuate_x2 = a*2; dirty = true; } @@ -964,10 +968,12 @@ void set_scale(float t) { round_reflevel_to_scale(); } +extern char low_level_help_text[12]; void set_offset(float offset) { setting.offset = offset; + plot_printf(low_level_help_text, sizeof low_level_help_text, "%+d..%+d", -76 + (int)offset, -6 + (int)offset); force_set_markmap(); dirty = true; // No HW update required, only status panel refresh but need to ensure the cached value is updated in the calculation of the RSSI } @@ -1085,7 +1091,7 @@ void apply_settings(void) // Ensure all settings in the setting structure if (setting.mode == M_HIGH) PE4302_Write_Byte(40); // Ensure defined input impedance of low port when using high input mode (power calibration) else - PE4302_Write_Byte((int)(setting.attenuate * 2)); + PE4302_Write_Byte((int)(setting.attenuate_x2)); #endif if (setting.mode == M_LOW) { @@ -1373,7 +1379,7 @@ case M_ULTRA: else set_switch_off(); // SI4432_Receive(); For noise testing only - SI4432_Transmit(setting.drive); + SI4432_Transmit(setting.lo_drive); // set_calibration_freq(setting.refer); #endif enable_rx_output(false); @@ -1421,7 +1427,7 @@ case M_GENLOW: // Mixed output from 0 } else { set_switch_transmit(); } - SI4432_Transmit(setting.drive); + SI4432_Transmit(setting.rx_drive); SI4432_Sel = SI4432_LO ; if (setting.modulation == MO_EXTERNAL) { @@ -1459,12 +1465,12 @@ case M_GENHIGH: // Direct output from 1 set_switch_receive(); SI4432_Sel = SI4432_LO ; - if (setting.drive < 8) { + if (setting.lo_drive < 8) { set_switch_off(); // use switch as attenuator } else { set_switch_transmit(); } - SI4432_Transmit(setting.drive); + SI4432_Transmit(setting.lo_drive); #endif #ifdef __SI4468__ SI4463_init_tx(); @@ -1906,7 +1912,7 @@ modulation_again: // ----------------------------------------------------- modulation for output modes --------------------------------------- if (MODE_OUTPUT(setting.mode)){ if (setting.modulation == MO_AM) { // AM modulation - int p = setting.attenuate * 2 + am_modulation[modulation_counter]; + int p = setting.attenuate_x2 + am_modulation[modulation_counter]; if (p>63) p = 63; else if (p< 0) p = 0; #ifdef __PE4302__ @@ -1973,8 +1979,13 @@ modulation_again: local_IF = DEFAULT_IF; if (setting.mode == M_LOW) { if (tracking) { // VERY SPECIAL CASE!!!!! Measure BPF +#if 0 // Isolation test + local_IF = lf; + lf = 0; +#else local_IF += lf - reffer_freq[setting.refer]; // Offset so fundamental of reffer is visible lf = reffer_freq[setting.refer]; +#endif } else { if(!in_selftest && avoid_spur(lf)) { // check if alternate IF is needed to avoid spur. local_IF = spur_alternate_IF; @@ -2052,7 +2063,7 @@ modulation_again: #endif { // Else set LO ('s) uint32_t target_f; - if (setting.mode == M_LOW && !setting.tracking && S_STATE(setting.below_IF)) // if in low input mode and below IF + if (setting.mode == M_LOW && !setting.tracking && S_STATE(setting.below_IF)) // if in low input mode and below IF target_f = local_IF-lf; // set LO SI4432 to below IF frequency else target_f = local_IF+lf; // otherwise to above IF, local_IF == 0 in high mode @@ -2620,17 +2631,17 @@ sweep_again: // stay in sweep loop when output mo int changed = false; int delta = 0; int actual_max_level = (max_index[0] == 0 ? -100 :(int) (actual_t[max_index[0]] - get_attenuation()) ); // If no max found reduce attenuation - if (actual_max_level < AUTO_TARGET_LEVEL && setting.attenuate > 0) { + if (actual_max_level < AUTO_TARGET_LEVEL && setting.attenuate_x2 > 0) { delta = - (AUTO_TARGET_LEVEL - actual_max_level); - } else if (actual_max_level > AUTO_TARGET_LEVEL && setting.attenuate < 30) { + } else if (actual_max_level > AUTO_TARGET_LEVEL && setting.attenuate_x2 < 60) { delta = actual_max_level - AUTO_TARGET_LEVEL; } if ((chVTGetSystemTimeX() - sweep_elapsed > 10000 && delta != 0) || delta > 5 ) { - setting.attenuate += delta; - if (setting.attenuate < 0) - setting.attenuate= 0; - if (setting.attenuate > 30) - setting.attenuate = 30; + setting.attenuate_x2 += delta + delta; + if (setting.attenuate_x2 < 0) + setting.attenuate_x2= 0; + if (setting.attenuate_x2 > 60) + setting.attenuate_x2 = 60; changed = true; sweep_elapsed = chVTGetSystemTimeX(); } @@ -2905,7 +2916,7 @@ sweep_again: // stay in sweep loop when output mo #ifdef __LINEARITY__ //---------------- in Linearity measurement the attenuation has to be adapted ------------------ if (setting.measurement == M_LINEARITY && setting.linearity_step < sweep_points) { - setting.attenuate = 29.0 - setting.linearity_step * 30.0 / (sweep_points); + setting.attenuate_x2 = (29.0 - setting.linearity_step * 30.0 / (sweep_points))*2.0; dirty = true; stored_t[setting.linearity_step] = peakLevel; setting.linearity_step++; @@ -3071,11 +3082,11 @@ enum { TP_SILENT, TPH_SILENT, TP_10MHZ, TP_10MHZEXTRA, TP_10MHZ_SWITCH, TP_30MHZ, TPH_30MHZ, TPH_30MHZ_SWITCH }; -#define TEST_COUNT 21 +#define TEST_COUNT (sizeof test_case / sizeof test_case[0]) #define W2P(w) (sweep_points * w / 100) // convert width in % to actual sweep points -static const struct { +typedef struct test_case { int kind; int setup; float center; // In MHz @@ -3083,7 +3094,9 @@ static const struct { float pass; int width; float stop; -} test_case [TEST_COUNT] = +} test_case_t; + +const test_case_t test_case [] = {// Condition Preparation Center Span Pass Width(%)Stop {TC_BELOW, TP_SILENT, 0.005, 0.01, 0, 0, 0}, // 1 Zero Hz leakage {TC_BELOW, TP_SILENT, 0.015, 0.01, -30, 0, 0}, // 2 Phase noise of zero Hz @@ -3092,7 +3105,7 @@ static const struct { #define TEST_SILENCE 4 {TC_BELOW, TP_SILENT, 200, 100, -75, 0, 0}, // 5 Wide band noise floor low mode {TC_BELOW, TPH_SILENT, 600, 720, -75, 0, 0}, // 6 Wide band noise floor high mode - {TC_SIGNAL, TP_10MHZEXTRA, 10, 8, -20, 27, -80 }, // 7 BPF loss and stop band + {TC_SIGNAL, TP_10MHZEXTRA, 10, 7, -20, 27, -80 }, // 7 BPF loss and stop band {TC_FLAT, TP_10MHZEXTRA, 10, 4, -18, 9, -60}, // 8 BPF pass band flatness {TC_BELOW, TP_30MHZ, 400, 60, -75, 0, -75}, // 9 LPF cutoff {TC_SIGNAL, TP_10MHZ_SWITCH,20, 7, -39, 10, -60 }, // 10 Switch isolation using high attenuation @@ -3122,8 +3135,8 @@ static const char *(test_text [4]) = { "Waiting", "Pass", "Fail", "Critical" }; -static const char *(test_fail_cause [TEST_COUNT]); +static const char *(test_fail_cause [TEST_COUNT]); static int test_status[TEST_COUNT]; static int show_test_info = FALSE; static volatile int test_wait = false; @@ -3375,7 +3388,7 @@ common_silent: set_mode(M_LOW); setting.tracking = true; //Sweep BPF setting.auto_IF = false; - setting.frequency_IF = DEFAULT_IF; // Center on SAW filters + setting.frequency_IF = DEFAULT_IF+200000; // Center on SAW filters set_refer_output(2); goto common; case TP_10MHZ: // 10MHz input @@ -3470,7 +3483,7 @@ void self_test(int test) reset_settings(M_LOW); // Make sure we are in a defined state in_selftest = true; menu_autosettings_cb(0); - for (int i=0; i < TEST_COUNT; i++) { // All test cases waiting + for (uint16_t i=0; i < TEST_COUNT; i++) { // All test cases waiting if (test_case[i].kind == TC_END) break; test_status[i] = TS_WAITING; @@ -3489,7 +3502,7 @@ void self_test(int test) test_step = TEST_END; ili9341_set_foreground(LCD_BRIGHT_COLOR_RED); ili9341_drawstring_7x13("Signal level too low", 30, 140); - ili9341_drawstring_7x13("Check cable between High and Low connectors", 30, 160); + ili9341_drawstring_7x13("Did you connect high and low ports with cable?", 0, 210); goto resume2; } diff --git a/ui.c b/ui.c index 125ed1f..4213efe 100644 --- a/ui.c +++ b/ui.c @@ -88,6 +88,16 @@ static char *kp_help_text = NULL; static uint8_t menu_current_level = 0; static int selection = 0; +static const uint8_t slider_bitmap[]= +{ + _BMP8(0b11111110), + _BMP8(0b11111110), + _BMP8(0b11111110), + _BMP8(0b01111100), + _BMP8(0b00111000), + _BMP8(0b00010000) +}; + // Button definition (used in MT_ADV_CALLBACK for custom) #define BUTTON_ICON_NONE -1 #define BUTTON_ICON_NOCHECK 0 @@ -215,7 +225,7 @@ static int btn_wait_release(void) } // ADC read count for measure X and Y (2^N count) -#define TOUCH_X_N 3 +#define TOUCH_X_N 4 #define TOUCH_Y_N 3 static int touch_measure_y(void) @@ -289,8 +299,13 @@ touch_check(void) { int stat = touch_status(); if (stat) { + static int prev_x=0; int y = touch_measure_y(); int x = touch_measure_x(); +#define X_NOISE 5 + if (x > prev_x - X_NOISE && x < prev_x + X_NOISE) // avoid noise + x = prev_x; + prev_x = x; touch_prepare_sense(); if (touch_status()) { @@ -1843,6 +1858,21 @@ draw_menu_buttons(const menuitem_t *menu) blit8BitWidthBitmap(button_start+MENU_FORM_WIDTH- FORM_ICON_WIDTH-8,y+(button_height-FORM_ICON_HEIGHT)/2,FORM_ICON_WIDTH,FORM_ICON_HEIGHT,&right_icons[((menu[i].data >>0)&0xf)*2*FORM_ICON_HEIGHT]); } #endif + int local_slider_positions = 0; + if (MT_MASK(menu[i].type) == MT_KEYPAD) { + if (menu[i].data == KM_CENTER) { + local_slider_positions = LCD_WIDTH/2+setting.slider_position; + goto draw_slider; + } else if (menu[i].data == KM_LOWOUTLEVEL) { + local_slider_positions = (get_attenuation() + 76 ) * MENU_FORM_WIDTH / 70 + OFFSETX; + goto draw_slider; + } + } + if (MT_MASK(menu[i].type) == MT_ADV_CALLBACK && menu[i].reference == menu_sdrive_acb) { + local_slider_positions = (menu_drive_value[setting.lo_drive] + 38 ) * MENU_FORM_WIDTH / 51 + OFFSETX; + draw_slider: + blit8BitWidthBitmap(local_slider_positions - 4, y, 7, 6, slider_bitmap); + } } else { int button_width = MENU_BUTTON_WIDTH; int button_start = LCD_WIDTH - MENU_BUTTON_WIDTH; @@ -1874,6 +1904,28 @@ draw_menu_buttons(const menuitem_t *menu) static systime_t prev_touch_time = 0; static int prev_touch_button = -1; +enum { SL_UNKNOWN, SL_SPAN, SL_MOVE}; + +void set_keypad_value(int v) +{ + keypad_mode = v; + set_numeric_value(); +} + +void check_frequency_slider(uint32_t slider_freq) +{ + + if ( (maxFreq - minFreq) < (uint32_t)setting.slider_span ) { + setting.slider_span = maxFreq - minFreq; // absolute mode with max step size + } + uint32_t half_span = setting.slider_span >> 1; + if (minFreq + (uint32_t)half_span > slider_freq) { + setting.slider_position -= (minFreq + half_span - slider_freq) / (setting.slider_span /MENU_FORM_WIDTH); // reposition if needed + } + if (maxFreq < slider_freq + (uint32_t)half_span) { + setting.slider_position += (slider_freq + half_span - maxFreq) / (setting.slider_span /MENU_FORM_WIDTH); // reposition if needed + } +} static void menu_select_touch(int i) @@ -1882,49 +1934,115 @@ menu_select_touch(int i) draw_menu(); #if 1 // drag values const menuitem_t *menu = menu_stack[menu_current_level]; + int keypad = menu[i].data; + prev_touch_time = chVTGetSystemTimeX(); - if (menu_is_form(menu) && MT_MASK(menu[i].type) == MT_KEYPAD){ - int touch_x, touch_y; - touch_position(&touch_x, &touch_y); + int touch_x, touch_y, prev_touch_x = 0; +// touch_position(&touch_x, &touch_y); systime_t dt = 0; - while (touch_check() != EVT_TOUCH_RELEASED) { + int mode = SL_UNKNOWN; + while (touch_check() != EVT_TOUCH_NONE) { + systime_t ticks = chVTGetSystemTimeX(); - if (prev_touch_button != i) { // new button, initialize - prev_touch_time = ticks; - prev_touch_button = i; - } dt = ticks - prev_touch_time; if (dt > BUTTON_DOWN_LONG_TICKS) { - int v = menu[i].data; + touch_position(&touch_x, &touch_y); + if (touch_x != prev_touch_x /* - 1 || prev_touch_x + 1 < touch_x */ ) { int old_keypad_mode = keypad_mode; - keypad_mode = v; + keypad_mode = keypad; fetch_numeric_target(); - float m = 1.0; -#define TOUCH_DEAD_ZONE 5 - if (touch_x < LCD_WIDTH/2 - TOUCH_DEAD_ZONE) { - m = 1 / (1 + pow(10, -6 + ((LCD_WIDTH/2 - TOUCH_DEAD_ZONE) - touch_x)/20.0)); - } else if (touch_x > LCD_WIDTH/2 + 10) { - m = 1 + pow(10, -6 + (touch_x - (LCD_WIDTH/2 + TOUCH_DEAD_ZONE))/20.0); + int new_slider = touch_x - LCD_WIDTH/2; + if (new_slider < -MENU_FORM_WIDTH/2) + new_slider = -MENU_FORM_WIDTH/2; + if (new_slider > MENU_FORM_WIDTH/2) + new_slider = MENU_FORM_WIDTH/2; + if (menu_is_form(menu) && MT_MASK(menu[i].type) == MT_KEYPAD && keypad == KM_CENTER){ +#define TOUCH_DEAD_ZONE 40 + if (mode == SL_UNKNOWN ) { + if (setting.slider_position - TOUCH_DEAD_ZONE < new_slider && new_slider < setting.slider_position + TOUCH_DEAD_ZONE) { // Pick up slider + mode = SL_MOVE; + } else { + mode = SL_SPAN; + goto first_span; + } + } + if (mode == SL_MOVE ) { + uistat.value = uistat.value - setting.slider_position * (setting.slider_span/MENU_FORM_WIDTH) + new_slider * (setting.slider_span/MENU_FORM_WIDTH); + if (uistat.value < minFreq) + uistat.value = minFreq; + if (uistat.value > maxFreq) + uistat.value = maxFreq; + setting.slider_position = new_slider; + set_keypad_value(keypad); + perform(false, 0, (uint32_t)uistat.value, false); + draw_menu(); + } else if (mode == SL_SPAN ){ + uint32_t slider_freq; + first_span: + slider_freq = (uint32_t) uistat.value; + int pw=new_slider + LCD_WIDTH/2; + setting.slider_position = pw - LCD_WIDTH/2; // Show delta on slider + setting.slider_span = 10; + while (pw>0) { + setting.slider_span += setting.slider_span; + pw -= 12; + if (pw <=0) + break; + setting.slider_span += setting.slider_span + (setting.slider_span >>1); + pw -= 12; + if (pw<=0) + break; + setting.slider_span *= 2; + pw -= 12; + } + if ((uint32_t)setting.slider_span > (maxFreq - minFreq)) + setting.slider_span = (maxFreq - minFreq); + uint32_t old_minFreq = minFreq; // Save when in high mode + minFreq = 0; // And set minFreq to 0 for span display + uistat.value = setting.slider_span; + set_keypad_value(keypad); + center_text[0] = 'S'; + center_text[1] = 'P'; + center_text[2] = 'A'; + center_text[3] = 'N'; + draw_menu(); // Show slider span + minFreq = old_minFreq; // and restore minFreq + uistat.value = (float) slider_freq; // and restore current slider freq + set_keypad_value(keypad); + center_text[0] = 'F'; + center_text[1] = 'R'; + center_text[2] = 'E'; + center_text[3] = 'Q'; + setting.slider_position = 0; // reset slider after span change + check_frequency_slider(slider_freq); + } + } else if (menu_is_form(menu) && MT_MASK(menu[i].type) == MT_KEYPAD && keypad == KM_LOWOUTLEVEL) { + uistat.value = setting.offset + (touch_x - OFFSETX) *( -6 - -76) / MENU_FORM_WIDTH + -76; + set_keypad_value(keypad); + apply: + perform(false, 0, get_sweep_frequency(ST_CENTER), false); + draw_menu(); +// } + } else if (MT_MASK(menu[i].type) == MT_ADV_CALLBACK && menu[i].reference == menu_sdrive_acb) { + set_level( (touch_x - OFFSETX) *( 13 - -38) / MENU_FORM_WIDTH + -38 ); + goto apply; } - uistat.value *= m; - set_numeric_value(); -// selection = -1; - draw_menu(); keypad_mode = old_keypad_mode; - return; } + } + prev_touch_x = touch_x; } if (dt > BUTTON_DOWN_LONG_TICKS) { selection = -1; draw_menu(); return; } + setting.slider_position = 0; // Reset slider when entering frequency prev_touch_button = -1; - } else #endif - touch_wait_release(); +// touch_wait_release(); selection = -1; menu_invoke(i); } diff --git a/ui_sa.c b/ui_sa.c index e0f8ca6..b8cc625 100644 --- a/ui_sa.c +++ b/ui_sa.c @@ -402,11 +402,17 @@ static const keypads_t keypads_time[] = { }; enum { - KM_START, KM_STOP, KM_CENTER, KM_SPAN, KM_CW, KM_REFLEVEL, KM_SCALE, KM_ATTENUATION, + KM_START, KM_STOP, KM_CENTER, KM_SPAN, KM_CW, // These must be first to share common help text + 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_GRIDLINES, KM_MARKER, KM_MODULATION,KM_COR_AM,KM_COR_WFM, KM_COR_NFM, KM_IF2, - KM_R,KM_MOD,KM_CP,KM_ATTACK, + KM_FAST_SPEEDUP, KM_GRIDLINES, KM_MARKER, KM_MODULATION, + KM_R,KM_MOD,KM_CP, +#if 0 + KM_COR_AM,KM_COR_WFM, KM_COR_NFM, +#endif + KM_ATTACK, + KM_IF2, KM_NONE // always at enum end }; @@ -440,9 +446,11 @@ static const struct { {keypads_positive , "MINIMUM\nGRIDLINES"}, // KM_GRIDLINES {keypads_freq , "MARKER\nFREQ"}, // KM_MARKER {keypads_freq , "MODULATION\nFREQ"}, // KM_MODULATION +#if 0 {keypads_plusmin , "COR\nAM"}, // KM_COR_AM {keypads_plusmin , "COR\nWFM"}, // KM_COR_WFM {keypads_plusmin , "COR\nNFM"}, // KM_COR_NFM +#endif {keypads_freq , "IF2"}, // KM_IF2 {keypads_positive , "R"}, // KM_R {keypads_positive , "MODULO"}, // KM_MOD @@ -450,6 +458,14 @@ static const struct { {keypads_positive , "ATTACK"}, // KM_ATTACK }; +#if 0 // Not used +ui_slider_t ui_sliders [] = +{ + { KM_CENTER, true, 0, 1000000, 0, 350000000, M_GENLOW}, + { KM_CENTER, true, 0, 1000000, 240000000, 960000000, M_GENHIGH}, + { KM_LOWOUTLEVEL, false,0, 1, -76, -6, M_GENLOW}, +}; +#endif // ===[MENU CALLBACKS]========================================================= @@ -472,6 +488,7 @@ static const menuitem_t menu_topultra[]; static UI_FUNCTION_ADV_CALLBACK(menu_sweep_acb) { (void)data; + (void)item; if (b){ if (setting.level_sweep != 0 || get_sweep_frequency(ST_SPAN) != 0) { plot_printf(uistat.text, sizeof uistat.text, "SW:%3.2fMHz %+ddB %.3Fs", @@ -723,12 +740,12 @@ static UI_FUNCTION_ADV_CALLBACK(menu_sreffer_acb){ } const int8_t menu_drive_value[]={-38,-35,-33,-30,-27,-24,-21,-19, -7,-4,-2,1,4,7,10,13}; -static UI_FUNCTION_ADV_CALLBACK(menu_drive_acb) +static UI_FUNCTION_ADV_CALLBACK(menu_lo_drive_acb) { (void)item; if(b){ b->param_1.i = menu_drive_value[data] + (setting.mode==M_GENHIGH ? setting.offset : 0); - b->icon = data == setting.drive ? BUTTON_ICON_GROUP_CHECKED : BUTTON_ICON_GROUP; + b->icon = data == setting.lo_drive ? BUTTON_ICON_GROUP_CHECKED : BUTTON_ICON_GROUP; return; } //Serial.println(item); @@ -742,7 +759,7 @@ static UI_FUNCTION_ADV_CALLBACK(menu_sdrive_acb){ (void)item; (void)data; if(b){ - b->param_1.i = menu_drive_value[setting.drive] + (setting.mode==M_GENHIGH ? setting.offset : 0); + b->param_1.i = menu_drive_value[setting.lo_drive] + (setting.mode==M_GENHIGH ? setting.offset : 0); return; } menu_push_submenu(menu_drive_wide); @@ -1459,33 +1476,33 @@ static const menuitem_t menu_lo_drive[] = { }; static const menuitem_t menu_drive_wide3[] = { - { MT_FORM | MT_ADV_CALLBACK, 5, "%+ddBm", menu_drive_acb}, - { MT_FORM | MT_ADV_CALLBACK, 4, "%+ddBm", menu_drive_acb}, - { MT_FORM | MT_ADV_CALLBACK, 3, "%+ddBm", menu_drive_acb}, - { MT_FORM | MT_ADV_CALLBACK, 2, "%+ddBm", menu_drive_acb}, - { MT_FORM | MT_ADV_CALLBACK, 1, "%+ddBm", menu_drive_acb}, - { MT_FORM | MT_ADV_CALLBACK, 0, "%+ddBm", menu_drive_acb}, + { MT_FORM | MT_ADV_CALLBACK, 5, "%+ddBm", menu_lo_drive_acb}, + { MT_FORM | MT_ADV_CALLBACK, 4, "%+ddBm", menu_lo_drive_acb}, + { MT_FORM | MT_ADV_CALLBACK, 3, "%+ddBm", menu_lo_drive_acb}, + { MT_FORM | MT_ADV_CALLBACK, 2, "%+ddBm", menu_lo_drive_acb}, + { MT_FORM | MT_ADV_CALLBACK, 1, "%+ddBm", menu_lo_drive_acb}, + { MT_FORM | MT_ADV_CALLBACK, 0, "%+ddBm", menu_lo_drive_acb}, { MT_FORM | MT_CANCEL, 255, S_LARROW" BACK", NULL }, { MT_FORM | MT_NONE, 0, NULL, NULL } // sentinel }; static const menuitem_t menu_drive_wide2[] = { - { MT_FORM | MT_ADV_CALLBACK, 10, "%+ddBm", menu_drive_acb}, - { MT_FORM | MT_ADV_CALLBACK, 9, "%+ddBm", menu_drive_acb}, - { MT_FORM | MT_ADV_CALLBACK, 8, "%+ddBm", menu_drive_acb}, - { MT_FORM | MT_ADV_CALLBACK, 7, "%+ddBm", menu_drive_acb}, - { MT_FORM | MT_ADV_CALLBACK, 6, "%+ddBm", menu_drive_acb}, + { MT_FORM | MT_ADV_CALLBACK, 10, "%+ddBm", menu_lo_drive_acb}, + { MT_FORM | MT_ADV_CALLBACK, 9, "%+ddBm", menu_lo_drive_acb}, + { MT_FORM | MT_ADV_CALLBACK, 8, "%+ddBm", menu_lo_drive_acb}, + { MT_FORM | MT_ADV_CALLBACK, 7, "%+ddBm", menu_lo_drive_acb}, + { MT_FORM | MT_ADV_CALLBACK, 6, "%+ddBm", menu_lo_drive_acb}, { MT_FORM | MT_SUBMENU, 255, S_RARROW" MORE", menu_drive_wide3}, { MT_FORM | MT_CANCEL, 255, S_LARROW" BACK", NULL }, { MT_FORM | MT_NONE, 0, NULL, NULL } // sentinel }; static const menuitem_t menu_drive_wide[] = { - { MT_FORM | MT_ADV_CALLBACK, 15, "%+ddBm", menu_drive_acb}, - { MT_FORM | MT_ADV_CALLBACK, 14, "%+ddBm", menu_drive_acb}, - { MT_FORM | MT_ADV_CALLBACK, 13, "%+ddBm", menu_drive_acb}, - { MT_FORM | MT_ADV_CALLBACK, 12, "%+ddBm", menu_drive_acb}, - { MT_FORM | MT_ADV_CALLBACK, 11, "%+ddBm", menu_drive_acb}, + { MT_FORM | MT_ADV_CALLBACK, 15, "%+ddBm", menu_lo_drive_acb}, + { MT_FORM | MT_ADV_CALLBACK, 14, "%+ddBm", menu_lo_drive_acb}, + { MT_FORM | MT_ADV_CALLBACK, 13, "%+ddBm", menu_lo_drive_acb}, + { MT_FORM | MT_ADV_CALLBACK, 12, "%+ddBm", menu_lo_drive_acb}, + { MT_FORM | MT_ADV_CALLBACK, 11, "%+ddBm", menu_lo_drive_acb}, { MT_FORM | MT_SUBMENU, 255, S_RARROW" MORE", menu_drive_wide2}, { MT_FORM | MT_CANCEL, 255, S_LARROW" BACK", NULL }, { MT_FORM | MT_NONE, 0, NULL, NULL } // sentinel @@ -1511,31 +1528,33 @@ static const menuitem_t menu_sweep[] = { { MT_FORM | MT_NONE, 0, NULL, NULL } // sentinel }; +char low_level_help_text[12] = "-76..-6"; +char center_text[10] = "FREQ: %s"; static const menuitem_t menu_lowoutputmode[] = { { MT_FORM | MT_ADV_CALLBACK, 0, "LOW OUTPUT %s", menu_outputmode_acb}, - { MT_FORM | MT_KEYPAD, KM_CENTER, "FREQ: %s", "10kHz..350MHz"}, - { MT_FORM | MT_KEYPAD, KM_LOWOUTLEVEL, "LEVEL: %s", "-76..-6"}, // { MT_FORM | MT_ADV_CALLBACK, 0, "MOD: %s", menu_smodulation_acb}, { MT_FORM | MT_SUBMENU, 255, S_RARROW" Settings", menu_settings3}, + { MT_FORM | MT_KEYPAD, KM_CENTER, center_text, "10kHz..350MHz"}, + { MT_FORM | MT_KEYPAD, KM_LOWOUTLEVEL, "LEVEL: %s", low_level_help_text /* "-76..-6" */}, { MT_FORM | MT_ADV_CALLBACK, 0, "MOD: %s", menu_smodulation_acb}, { MT_FORM | MT_ADV_CALLBACK, 0, "%s", menu_sweep_acb}, // { MT_FORM | MT_KEYPAD, KM_SPAN, "SPAN: %s", "0..350MHz"}, // { MT_FORM | MT_KEYPAD | MT_LOW, KM_LEVELSWEEP,"LEVEL CHANGE: %s", "-70..70"}, // { MT_FORM | MT_KEYPAD, KM_SWEEP_TIME, "SWEEP TIME: %s", "0..600 seconds"}, - { MT_FORM | MT_KEYPAD, KM_OFFSET, "AMP: %s", "-100..+100"}, + { MT_FORM | MT_KEYPAD, KM_OFFSET, "EXTERNAL AMP: %s", "-100..+100"}, { MT_FORM | MT_CANCEL, 0, "MODE", NULL }, { MT_FORM | MT_NONE, 0, NULL, NULL } // sentinel }; static const menuitem_t menu_highoutputmode[] = { { MT_FORM | MT_ADV_CALLBACK, 0, "HIGH OUTPUT %s", menu_outputmode_acb}, - { MT_FORM | MT_KEYPAD, KM_CENTER, "FREQ: %s", "240MHz..960MHz"}, + { MT_FORM | MT_KEYPAD, KM_CENTER, center_text, "240MHz..960MHz"}, { MT_FORM | MT_ADV_CALLBACK, 0, "LEVEL: %+ddBm", menu_sdrive_acb}, { MT_FORM | MT_ADV_CALLBACK, 0, "MOD: %s", menu_smodulation_acb}, { MT_FORM | MT_KEYPAD, KM_SPAN, "SPAN: %s", NULL}, { MT_FORM | MT_KEYPAD, KM_SWEEP_TIME,"SWEEP TIME: %s", "0..600 seconds"}, - { MT_FORM | MT_KEYPAD, KM_OFFSET, "AMP: %s", "-100..+100"}, + { MT_FORM | MT_KEYPAD, KM_OFFSET, "EXTERNAL AMP: %s", "-100..+100"}, { MT_FORM | MT_CANCEL, 0, "MODE", NULL }, { MT_FORM | MT_NONE, 0, NULL, NULL } // sentinel }; @@ -1756,9 +1775,11 @@ static const menuitem_t menu_settings3[] = { { MT_KEYPAD, KM_10MHZ, "CORRECT\nFREQUENCY", "Enter actual lMHz frequency"}, { MT_KEYPAD, KM_GRIDLINES, "MINIMUM\nGRIDLINES", "Enter minimum horizontal grid divisions"}, -// { MT_KEYPAD, KM_COR_AM, "COR\nAM", "Enter AM modulation correction"}, +#if 0 // only used during development + { MT_KEYPAD, KM_COR_AM, "COR\nAM", "Enter AM modulation correction"}, { MT_KEYPAD, KM_COR_WFM, "COR\nWFM", "Enter WFM modulation correction"}, -// { MT_KEYPAD, KM_COR_NFM, "COR\nNFM", "Enter NFM modulation correction"}, + { MT_KEYPAD, KM_COR_NFM, "COR\nNFM", "Enter NFM modulation correction"}, +#endif // { MT_KEYPAD | MT_LOW, KM_IF2, "IF2 FREQ", "Set to zero for no IF2"}, { MT_KEYPAD, KM_R, "R", "Set R"}, { MT_KEYPAD, KM_MOD, "MODULO", "Set MODULO"}, @@ -2070,7 +2091,7 @@ static void fetch_numeric_target(void) break; case KM_CENTER: uistat.value = get_sweep_frequency(ST_CENTER); - plot_printf(uistat.text, sizeof uistat.text, "%3.3fMHz", uistat.value / 1000000.0); + plot_printf(uistat.text, sizeof uistat.text, "%3.4fMHz", uistat.value / 1000000.0); break; case KM_SPAN: uistat.value = get_sweep_frequency(ST_SPAN); @@ -2168,7 +2189,7 @@ static void fetch_numeric_target(void) // 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 = setting.sweep_time_us; uistat.value /= (float)ONE_SECOND_TIME; plot_printf(uistat.text, sizeof uistat.text, "%.3Fs", uistat.value); break; @@ -2313,6 +2334,7 @@ set_numeric_value(void) case KM_MODULATION: set_modulation_frequency((int)uistat.value); break; +#if 0 case KM_COR_AM: config.cor_am =(int)uistat.value; config_save(); @@ -2325,7 +2347,7 @@ set_numeric_value(void) config.cor_nfm =(int)uistat.value; config_save(); break; - +#endif } }