diff --git a/NANOVNA_STM32_F072/board.h b/NANOVNA_STM32_F072/board.h index b0a3c1a..b1fa657 100644 --- a/NANOVNA_STM32_F072/board.h +++ b/NANOVNA_STM32_F072/board.h @@ -56,8 +56,8 @@ #define GPIOA_XP 6 #define GPIOA_YP 7 #define GPIOA_MCO 8 -#define GPIOA_TX 9 -#define GPIOA_USB_DISC 10 +#define GPIOA_USART1_TX 9 +#define GPIOA_USART1_RX 10 #define GPIOA_USB_DM 11 #define GPIOA_USB_DP 12 #define GPIOA_JTMS 13 @@ -117,6 +117,8 @@ * GPIOA setup: * * PA8 - MCO (alternate 0). + * PA9 - USART1_TX (alternate 1). + * PA10 - USART1_RX (alternate 1). * PA11 - USB_DM (alternate 14). * PA12 - USB_DP (alternate 14). * PA13 - SWDIO (alternate 0). @@ -131,8 +133,8 @@ PIN_MODE_ANALOG(GPIOA_XP) | \ PIN_MODE_ANALOG(GPIOA_YP) | \ PIN_MODE_ALTERNATE(GPIOA_MCO) | \ - PIN_MODE_ANALOG(9U) | \ - PIN_MODE_ANALOG(GPIOA_USB_DISC) | \ + PIN_MODE_ALTERNATE(GPIOA_USART1_TX) | \ + PIN_MODE_ALTERNATE(GPIOA_USART1_RX) | \ PIN_MODE_INPUT(GPIOA_USB_DM) | \ PIN_MODE_INPUT(GPIOA_USB_DP) | \ PIN_MODE_ALTERNATE(GPIOA_JTMS) | \ @@ -147,8 +149,8 @@ PIN_OTYPE_PUSHPULL(6U) | \ PIN_OTYPE_PUSHPULL(7U) | \ PIN_OTYPE_PUSHPULL(GPIOA_MCO) | \ - PIN_OTYPE_PUSHPULL(9U) | \ - PIN_OTYPE_PUSHPULL(GPIOA_USB_DISC) | \ + PIN_OTYPE_PUSHPULL(GPIOA_USART1_TX) | \ + PIN_OTYPE_PUSHPULL(GPIOA_USART1_RX) | \ PIN_OTYPE_PUSHPULL(GPIOA_USB_DM) | \ PIN_OTYPE_PUSHPULL(GPIOA_USB_DP) | \ PIN_OTYPE_PUSHPULL(GPIOA_JTMS) | \ @@ -163,8 +165,8 @@ PIN_OSPEED_2M(6) | \ PIN_OSPEED_2M(7) | \ PIN_OSPEED_100M(GPIOA_MCO) | \ - PIN_OSPEED_2M(9) | \ - PIN_OSPEED_2M(10) | \ + PIN_OSPEED_100M(GPIOA_USART1_TX) | \ + PIN_OSPEED_100M(GPIOA_USART1_RX) | \ PIN_OSPEED_100M(GPIOA_USB_DM) | \ PIN_OSPEED_100M(GPIOA_USB_DP) | \ PIN_OSPEED_100M(GPIOA_JTMS) | \ @@ -179,8 +181,8 @@ PIN_PUPDR_FLOATING(6) | \ PIN_PUPDR_FLOATING(7) | \ PIN_PUPDR_PULLUP(GPIOA_MCO) | \ - PIN_PUPDR_FLOATING(9) | \ - PIN_PUPDR_FLOATING(GPIOA_USB_DISC) | \ + PIN_PUPDR_FLOATING(GPIOA_USART1_TX) | \ + PIN_PUPDR_FLOATING(GPIOA_USART1_RX) | \ PIN_PUPDR_FLOATING(GPIOA_USB_DM) | \ PIN_PUPDR_FLOATING(GPIOA_USB_DP) | \ PIN_PUPDR_PULLDOWN(GPIOA_JTMS) | \ @@ -195,8 +197,8 @@ PIN_ODR_HIGH(6) | \ PIN_ODR_HIGH(7) | \ PIN_ODR_HIGH(GPIOA_MCO) | \ - PIN_ODR_HIGH(9) | \ - PIN_ODR_HIGH(GPIOA_USB_DISC) | \ + PIN_ODR_LOW(GPIOA_USART1_TX) | \ + PIN_ODR_LOW(GPIOA_USART1_RX) | \ PIN_ODR_HIGH(GPIOA_USB_DM) | \ PIN_ODR_HIGH(GPIOA_USB_DP) | \ PIN_ODR_HIGH(GPIOA_JTMS) | \ @@ -211,8 +213,8 @@ PIN_AFIO_AF(6, 0) | \ PIN_AFIO_AF(7, 0)) #define VAL_GPIOA_AFRH (PIN_AFIO_AF(GPIOA_MCO, 0) | \ - PIN_AFIO_AF(9, 0) | \ - PIN_AFIO_AF(GPIOA_USB_DISC, 0) | \ + PIN_AFIO_AF(GPIOA_USART1_TX, 1) | \ + PIN_AFIO_AF(GPIOA_USART1_RX, 1) | \ PIN_AFIO_AF(GPIOA_USB_DM, 0) | \ PIN_AFIO_AF(GPIOA_USB_DP, 0) | \ PIN_AFIO_AF(GPIOA_JTMS, 0) | \ diff --git a/flash.c b/flash.c index d7454a0..b204a95 100644 --- a/flash.c +++ b/flash.c @@ -188,7 +188,7 @@ caldata_recall(uint16_t id) memcpy(dst, src, sizeof(setting_t)); // Restore stored trace memcpy(stored_t, &src[1], sizeof(stored_t)); - + update_min_max_freq(); update_frequencies(); set_scale(setting.scale); set_reflevel(setting.reflevel); diff --git a/halconf.h b/halconf.h index 15f6596..1b1dd37 100644 --- a/halconf.h +++ b/halconf.h @@ -136,7 +136,7 @@ * @brief Enables the SERIAL subsystem. */ #if !defined(HAL_USE_SERIAL) || defined(__DOXYGEN__) -#define HAL_USE_SERIAL FALSE +#define HAL_USE_SERIAL TRUE #endif /** @@ -302,7 +302,7 @@ * buffers. */ #if !defined(SERIAL_BUFFERS_SIZE) || defined(__DOXYGEN__) -#define SERIAL_BUFFERS_SIZE 16 +#define SERIAL_BUFFERS_SIZE 64 #endif /*===========================================================================*/ @@ -325,7 +325,7 @@ * @note The default is 2 buffers. */ #if !defined(SERIAL_USB_BUFFERS_NUMBER) || defined(__DOXYGEN__) -#define SERIAL_USB_BUFFERS_NUMBER 1 +#define SERIAL_USB_BUFFERS_NUMBER 2 #endif /*===========================================================================*/ diff --git a/main.c b/main.c index defdd7d..5fe277b 100644 --- a/main.c +++ b/main.c @@ -47,7 +47,7 @@ int32_t frequencyExtra; // enable this need reduce spi_buffer size, by default shell run in main thread // #define VNA_SHELL_THREAD -static BaseSequentialStream *shell_stream = (BaseSequentialStream *)&SDU1; +static BaseSequentialStream *shell_stream; // Shell new line #define VNA_SHELL_NEWLINE_STR "\r\n" @@ -80,6 +80,7 @@ static volatile vna_shellcmd_t shell_function = 0; #define ENABLE_INFO_COMMAND // Enable color command, allow change config color for traces, grid, menu #define ENABLE_COLOR_COMMAND +#define ENABLE_USART_COMMAND #ifdef __VNA__ static void apply_error_term_at(int i); static void apply_edelay_at(int i); @@ -182,6 +183,8 @@ static THD_FUNCTION(Thread1, arg) int i = marker_search(); if (i != -1 && active_marker != -1) { markers[active_marker].index = i; + markers[active_marker].frequency = frequencies[i]; + redraw_request |= REDRAW_MARKER; } } @@ -327,6 +330,18 @@ int shell_printf(const char *fmt, ...) return formatted_bytes; } +#ifdef __USE_SERIAL_CONSOLE__ +// Serial Shell commands output +int shell_serial_printf(const char *fmt, ...) +{ + va_list ap; + int formatted_bytes; + va_start(ap, fmt); + formatted_bytes = chvprintf(&SD1, fmt, ap); + va_end(ap); + return formatted_bytes; +} +#endif VNA_SHELL_FUNCTION(cmd_pause) { (void)argc; @@ -471,7 +486,7 @@ calculate: return value; } -double +float my_atof(const char *p) { int neg = FALSE; @@ -479,11 +494,11 @@ my_atof(const char *p) neg = TRUE; if (*p == '-' || *p == '+') p++; - double x = my_atoi(p); + float x = my_atoi(p); while (_isdigit((int)*p)) p++; if (*p == '.') { - double d = 1.0f; + float d = 1.0f; p++; while (_isdigit((int)*p)) { d /= 10; @@ -846,13 +861,14 @@ config_t config = { .magic = CONFIG_MAGIC, .dac_value = 1922, .grid_color = DEFAULT_GRID_COLOR, + .ham_color = DEFAULT_HAM_COLOR, .menu_normal_color = DEFAULT_MENU_COLOR, .menu_active_color = DEFAULT_MENU_ACTIVE_COLOR, .trace_color = { DEFAULT_TRACE_1_COLOR, DEFAULT_TRACE_2_COLOR, DEFAULT_TRACE_3_COLOR}, // .touch_cal = { 693, 605, 124, 171 }, // 2.4 inch LCD panel -// .touch_cal = { 347, 495, 160, 205 }, // 2.8 inch LCD panel - .touch_cal = { 272, 521, 114, 153 }, //4.0" LCD - .freq_mode = FREQ_MODE_START_STOP, + .touch_cal = { 347, 495, 160, 205 }, // 2.8 inch LCD panel + ._mode = _MODE_USB, + ._serial_speed = USART_SPEED_SETTING(SERIAL_DEFAULT_BITRATE), #ifdef __VNA__ .harmonic_freq_threshold = 300000000, #endif @@ -861,6 +877,9 @@ config_t config = { .high_level_offset = 100, // Uncalibrated .correction_frequency = { 10000, 100000, 200000, 500000, 50000000, 140000000, 200000000, 300000000, 330000000, 350000000 }, .correction_value = { +6.0, +2.8, +1.6, -0.4, 0.0, -0.4, +0.4, +3.0, +4.0, +8.1 }, + .cor_am = -14, + .cor_wfm = -17, + .cor_nfm = -17, }; //properties_t current_props; @@ -1023,9 +1042,9 @@ VNA_SHELL_FUNCTION(cmd_scan) if (mask) { for (i = 0; i < points; i++) { if (mask & 1) shell_printf("%u ", frequencies[i]); - if (mask & 2) shell_printf("%f ", value(measured[0][i])); - if (mask & 4) shell_printf("%f ", value(measured[1][i])); - if (mask & 8) shell_printf("%f ", value(measured[2][i])); + if (mask & 2) shell_printf("%f %f ", value(measured[2][i]), 0.0); + if (mask & 4) shell_printf("%f %f ", value(measured[1][i]), 0.0); + if (mask & 8) shell_printf("%f %f ", value(measured[0][i]), 0.0); shell_printf("\r\n"); } } @@ -1053,6 +1072,7 @@ update_marker_index(void) for (i = 0; i < sweep_points-1; i++) { if (frequencies[i] <= f && f < frequencies[i+1]) { markers[m].index = f < (frequencies[i] / 2 + frequencies[i + 1] / 2) ? i : i + 1; + markers[m].frequency = frequencies[markers[m].index ]; break; } } @@ -1060,6 +1080,23 @@ update_marker_index(void) } } +void set_marker_frequency(int m, uint32_t f) +{ + if (m < 0 || !markers[m].enabled) + return; + int i = 1; + markers[m].mtype &= ~M_TRACKING; + uint32_t s = (frequencies[1] - frequencies[0])/2; + while (i< sweep_points - 1){ + if (frequencies[i]-s <= f && f < frequencies[i]+s) { + markers[m].index = i; + markers[m].frequency = f; + return; + } + i++; + } +} + static void set_frequencies(uint32_t start, uint32_t stop, uint16_t points) { @@ -1886,27 +1923,39 @@ VNA_SHELL_FUNCTION(cmd_marker) if (t < 0 || t >= MARKERS_MAX) goto usage; if (argc == 1) { + display_marker: shell_printf("%d %d %d %.2f\r\n", t+1, markers[t].index, markers[t].frequency, value(actual_t[markers[t].index])); active_marker = t; // select active marker markers[t].enabled = TRUE; return; } - static const char cmd_marker_list[] = "on|off"; + static const char cmd_marker_list[] = "on|off|peak"; switch (get_str_index(argv[1], cmd_marker_list)) { case 0: markers[t].enabled = TRUE; active_marker = t; return; case 1: markers[t].enabled =FALSE; if (active_marker == t) active_marker = -1; return; + case 2: markers[t].enabled = TRUE; active_marker = t; + int i = marker_search_max(); + if (i == -1) i = 0; + markers[active_marker].index = i; + markers[active_marker].frequency = frequencies[i]; + goto display_marker; default: - // select active marker and move to index + // select active marker and move to index or frequency markers[t].enabled = TRUE; - int index = my_atoi(argv[1]); - markers[t].index = index; - markers[t].frequency = frequencies[index]; + uint32_t value = my_atoui(argv[1]); + markers[t].mtype &= ~M_TRACKING; active_marker = t; + if (value > sweep_points) + set_marker_frequency(active_marker, value); + else { + markers[t].index = value; + markers[t].frequency = frequencies[value]; + } return; } usage: - shell_printf("marker [n] [%s|{index}]\r\n", cmd_marker_list); + shell_printf("marker [n] [%s|{freq}|{index}]\r\n", cmd_marker_list); } VNA_SHELL_FUNCTION(cmd_touchcal) @@ -2255,6 +2304,20 @@ VNA_SHELL_FUNCTION(cmd_threads) } #endif +#ifdef ENABLE_USART_COMMAND +VNA_SHELL_FUNCTION(cmd_usart) +{ + uint32_t time = 2000; // 200ms wait answer by default + if (argc == 0 || argc > 2 || (config._mode & _MODE_SERIAL)) return; + if (argc == 2) time = my_atoui(argv[1])*10; + sdWriteTimeout(&SD1, (uint8_t *)argv[0], strlen(argv[0]), time); + sdWriteTimeout(&SD1, (uint8_t *)VNA_SHELL_NEWLINE_STR, sizeof(VNA_SHELL_NEWLINE_STR)-1, time); + uint32_t size; + uint8_t buffer[64]; + while ((size = sdReadTimeout(&SD1, buffer, sizeof(buffer), time))) + streamWrite(&SDU1, buffer, size); +} +#endif #include "sa_cmd.c" //============================================================================= @@ -2305,6 +2368,7 @@ static const VNAShellCommand commands[] = {"touchtest" , cmd_touchtest , CMD_WAIT_MUTEX}, {"pause" , cmd_pause , 0}, {"resume" , cmd_resume , 0}, + {"caloutput" , cmd_caloutput , 0}, #ifdef __VNA__ {"cal" , cmd_cal , CMD_WAIT_MUTEX}, #endif @@ -2313,6 +2377,9 @@ static const VNAShellCommand commands[] = {"trace" , cmd_trace , CMD_WAIT_MUTEX}, {"trigger" , cmd_trigger , 0}, {"marker" , cmd_marker , 0}, +#ifdef ENABLE_USART_COMMAND + {"usart" , cmd_usart , CMD_WAIT_MUTEX}, +#endif #ifdef __VNA__ {"edelay" , cmd_edelay , 0}, #endif @@ -2389,6 +2456,110 @@ VNA_SHELL_FUNCTION(cmd_help) /* * VNA shell functions */ +// Check Serial connection requirements +#ifdef __USE_SERIAL_CONSOLE__ +#if HAL_USE_SERIAL == FALSE +#error "For serial console need HAL_USE_SERIAL as TRUE in halconf.h" +#endif + +// Before start process command from shell, need select input stream +#define PREPARE_STREAM shell_stream = (config._mode&_MODE_SERIAL) ? (BaseSequentialStream *)&SD1 : (BaseSequentialStream *)&SDU1; + +// Update Serial connection speed and settings +void shell_update_speed(void){ + // Update Serial speed settings + SerialConfig s_config = {USART_GET_SPEED(config._serial_speed), 0, USART_CR2_STOP1_BITS, 0 }; + sdStop(&SD1); + sdStart(&SD1, &s_config); // USART config +} + +// Check USB connection status +static bool usb_IsActive(void){ + return usbGetDriverStateI(&USBD1) == USB_ACTIVE; +} +void shell_reset_console(void){ + // Reset I/O queue over USB (for USB need also connect/disconnect) + if (usb_IsActive()){ + if (config._mode & _MODE_SERIAL) + sduDisconnectI(&SDU1); + else + sduConfigureHookI(&SDU1); + } + // Reset I/O queue over Serial + oqResetI(&SD1.oqueue); + iqResetI(&SD1.iqueue); +} + +// Check active connection for Shell +static bool shell_check_connect(void){ + // Serial connection always active + if (config._mode & _MODE_SERIAL) + return true; + // USB connection can be USB_SUSPENDED + return usb_IsActive(); +} + +static void shell_init_connection(void){ +/* + * Initializes and start serial-over-USB CDC driver SDU1, connected to USBD1 + */ + sduObjectInit(&SDU1); + sduStart(&SDU1, &serusbcfg); + +/* + * Set Serial speed settings for SD1 + */ + shell_update_speed(); + +/* + * Activates the USB driver and then the USB bus pull-up on D+. + * Note, a delay is inserted in order to not have to disconnect the cable + * after a reset. + */ + usbDisconnectBus(&USBD1); + chThdSleepMilliseconds(100); + usbStart(&USBD1, &usbcfg); + usbConnectBus(&USBD1); + +/* + * Set I/O stream (SDU1 or SD1) for shell + */ + PREPARE_STREAM; +} + +#else +// Only USB console, shell_stream always on USB +#define PREPARE_STREAM + +// Check connection as Active, if no suspend input +static bool shell_check_connect(void){ + return SDU1.config->usbp->state == USB_ACTIVE; +} + +// Init shell I/O connection over USB +static void shell_init_connection(void){ +/* + * Initializes and start serial-over-USB CDC driver SDU1, connected to USBD1 + */ + sduObjectInit(&SDU1); + sduStart(&SDU1, &serusbcfg); + +/* + * Activates the USB driver and then the USB bus pull-up on D+. + * Note, a delay is inserted in order to not have to disconnect the cable + * after a reset. + */ + usbDisconnectBus(&USBD1); + chThdSleepMilliseconds(100); + usbStart(&USBD1, &usbcfg); + usbConnectBus(&USBD1); + +/* + * Set I/O stream SDU1 for shell + */ + shell_stream = (BaseSequentialStream *)&SDU1; +} +#endif // // Read command line from shell_stream @@ -2398,6 +2569,8 @@ static int VNAShell_readLine(char *line, int max_size) // Read line from input stream uint8_t c; char *ptr = line; + // Prepare I/O for shell_stream + PREPARE_STREAM; while (1) { // Return 0 only if stream not active if (streamRead(shell_stream, &c, 1) == 0) @@ -2608,23 +2781,6 @@ int main(void) i2cStart(&I2CD1, &i2ccfg); si5351_init(); - // MCO on PA8 - //palSetPadMode(GPIOA, 8, PAL_MODE_ALTERNATE(0)); -/* - * Initializes a serial-over-USB CDC driver. - */ - sduObjectInit(&SDU1); - sduStart(&SDU1, &serusbcfg); -/* - * Activates the USB driver and then the USB bus pull-up on D+. - * Note, a delay is inserted in order to not have to disconnect the cable - * after a reset. - */ - usbDisconnectBus(serusbcfg.usbp); - chThdSleepMilliseconds(100); - usbStart(serusbcfg.usbp, &usbcfg); - usbConnectBus(serusbcfg.usbp); - #ifdef __SI4432__ /* * Powercycle the RF part to reset SI4432 @@ -2664,44 +2820,6 @@ int main(void) } #endif - -#if 0 - /* - * UART initialize - */ - uartStart(&UARTD1, &uart_cfg_1); -again: - uartStartSend(&UARTD1, 1, "H"); - uint8_t buf[10]; - uartStartReceive(&UARTD1, 1, buf); -goto again; -#endif - -#if 0 - again: - - palSetPadMode(GPIOA, 9, PAL_MODE_ALTERNATE(1)); // USART1 TX. - palSetPadMode(GPIOA,10, PAL_MODE_ALTERNATE(1)); // USART1 RX. - - - uint8_t buf[10]; - sdStart(&SD1,&default_config); - osalThreadSleepMilliseconds(10); - mySerialWrite("Hallo!?\n"); - - osalThreadSleepMilliseconds(10); - - mySerialReadline(buf, 10); - - sdReadTimeout(&SD1,buf,10, 10); - - sdWrite(&SD1,(const uint8_t *)"Test123",7); - osalThreadSleepMicroseconds(10); - sdReadTimeout(&SD1,buf,10,TIME_IMMEDIATE); - sdReadTimeout(&SD1,buf,10, 10); - int i = sdReadTimeout(&SD1,buf,10,TIME_IMMEDIATE); -goto again; -#endif #ifdef __ULTRA_SA__ ADF4351_Setup(); #endif @@ -2721,6 +2839,12 @@ goto again; if (caldata_recall(0) == -1) { load_default_properties(); } + +/* + * Init Shell console connection data (after load config for settings) + */ + shell_init_connection(); + /* restore frequencies and calibration 0 slot properties from flash memory */ dac1cfg1.init = config.dac_value; @@ -2755,7 +2879,7 @@ goto again; // menu_mode_cb(setting.mode,0); // } redraw_frame(); -#if 0 +#if 1 set_mode(M_HIGH); set_sweep_frequency(ST_STOP, (uint32_t) 30000000); sweep(false); @@ -2764,9 +2888,12 @@ goto again; set_mode(M_LOW); set_sweep_frequency(ST_STOP, (uint32_t) 4000000); sweep(false); - set_sweep_frequency(ST_STOP, (uint32_t) 350000000); #endif + if (caldata_recall(0) == -1) { + load_default_properties(); + } + set_refer_output(-1); // ui_mode_menu(); // Show menu when autostarting mode ui_mode_normal(); diff --git a/mcuconf.h b/mcuconf.h index 39f8156..9520c1c 100644 --- a/mcuconf.h +++ b/mcuconf.h @@ -193,7 +193,7 @@ /* * SERIAL driver system settings. */ -#define STM32_SERIAL_USE_USART1 FALSE +#define STM32_SERIAL_USE_USART1 TRUE #define STM32_SERIAL_USE_USART2 FALSE #define STM32_SERIAL_USART1_PRIORITY 3 #define STM32_SERIAL_USART2_PRIORITY 3 diff --git a/nanovna.h b/nanovna.h index acc9a4c..92423f5 100644 --- a/nanovna.h +++ b/nanovna.h @@ -38,11 +38,12 @@ #define __CALIBRATE__ #define __FAST_SWEEP__ // Pre-fill SI4432 RSSI buffer to get fastest sweep in zero span mode #define __AUDIO__ +#define __HAM_BAND__ //#define __ULTRA__ // Add harmonics mode on low input. //#define __ULTRA_SA__ // Adds ADF4351 control for extra high 1st IF stage #define __SPUR__ // Does spur reduction by shifting IF +#define __USE_SERIAL_CONSOLE__ // Enable serial I/O connection (need enable HAL_USE_SERIAL as TRUE in halconf.h) #define __SI4463__ - /* * main.c */ @@ -133,9 +134,10 @@ void update_frequencies(void); void set_sweep_frequency(int type, uint32_t frequency); uint32_t get_sweep_frequency(int type); void my_microsecond_delay(int t); -double my_atof(const char *p); +float my_atof(const char *p); int shell_printf(const char *fmt, ...); +void set_marker_frequency(int m, uint32_t f); void toggle_sweep(void); void toggle_mute(void); void load_default_properties(void); @@ -148,7 +150,7 @@ enum { }; enum { - MO_NONE, MO_AM_1kHz, MO_AM_10Hz, MO_NFM, MO_WFM, MO_EXTERNAL, + MO_NONE, MO_AM, MO_NFM, MO_WFM, MO_EXTERNAL, }; #define MODE_OUTPUT(x) ((x) == M_GENLOW || (x) == M_GENHIGH ) @@ -175,6 +177,7 @@ extern const char *info_about[]; // ------------------------------- sa_core.c ---------------------------------- void reset_settings(int); +void update_min_max_freq(void); //void ui_process_touch(void); void SetPowerGrid(int); void SetRefLevel(float); @@ -235,6 +238,7 @@ void toggle_tracking_output(void); extern int32_t frequencyExtra; void set_10mhz(uint32_t); void set_modulation(int); +void set_modulation_frequency(int); //extern int setting.modulation; void set_measurement(int); // extern int settingSpeed; @@ -288,10 +292,13 @@ extern void tlv320aic3204_select(int channel); #ifdef __SCROLL__ extern uint16_t _grid_y; #define GRIDY _grid_y -#define HEIGHT_SCROLL 250 -#define HEIGHT_NOSCROLL 310 +extern uint16_t graph_bottom; +#define BIG_WATERFALL 90 +#define SMALL_WATERFALL 180 +#define NO_WATERFALL CHART_BOTTOM +#define CHART_BOTTOM 310 #define SCROLL_GRIDY (HEIGHT_SCROLL / NGRIDY) -#define NOSCROLL_GRIDY (HEIGHT_NOSCROLL / NGRIDY) +#define NOSCROLL_GRIDY (CHART_BOTTOM / NGRIDY) #else #define GRIDY (310 / NGRIDY) #endif @@ -436,6 +443,11 @@ typedef struct trace { #define FREQ_MODE_CENTER_SPAN 0x1 #define FREQ_MODE_DOTTED_GRID 0x2 +// Connection flag +#define _MODE_CONNECTION_MASK 0x04 +#define _MODE_SERIAL 0x04 +#define _MODE_USB 0x00 + typedef struct config { int32_t magic; uint16_t dac_value; @@ -444,7 +456,8 @@ typedef struct config { uint16_t menu_active_color; uint16_t trace_color[TRACES_MAX]; int16_t touch_cal[4]; - int8_t freq_mode; + int8_t _mode; + uint32_t _serial_speed; #ifdef __VNA__ uint32_t harmonic_freq_threshold; #endif @@ -454,6 +467,13 @@ typedef struct config { uint32_t correction_frequency[CORRECTION_POINTS]; float correction_value[CORRECTION_POINTS]; uint32_t deviceid; + uint16_t ham_color; + uint16_t gridlines; + uint16_t hambands; + int8_t cor_am; + int8_t cor_wfm; + int8_t cor_nfm; + int8_t dummy; // uint8_t _reserved[22]; uint32_t checksum; } config_t; @@ -471,6 +491,20 @@ float get_trace_refpos(int t); const char *get_trace_typename(int t); extern int in_selftest; +// +// Shell config functions and macros +// Serial connect definitions not used if Serial mode disabled +// Minimum speed - USART_SPEED_MULTIPLIER +// Maximum speed - USART_SPEED_MULTIPLIER * 256 +// Can be: 19200, 38400, 57600, 76800, 115200, 230400, 460800, 921600, 1843200, 3686400 +#define USART_SPEED_MULTIPLIER 19200 +#define USART_SPEED_SETTING(speed) ((speed)/USART_SPEED_MULTIPLIER - 1) +#define USART_GET_SPEED(idx) (((idx) + 1) * USART_SPEED_MULTIPLIER) +void shell_update_speed(void); +void shell_reset_console(void); +int shell_serial_printf(const char *fmt, ...); + + #ifdef __VNA void set_electrical_delay(float picoseconds); float get_electrical_delay(void); @@ -559,6 +593,7 @@ extern volatile uint8_t redraw_request; #define DARK_GREY RGB565(140,140,140) #define LIGHT_GREY RGB565(220,220,220) #define DEFAULT_GRID_COLOR RGB565(128,128,128) +#define DEFAULT_HAM_COLOR RGB565(80,80,80) #define DEFAULT_GRID_VALUE_COLOR RGB565(196,196,196) #define DEFAULT_MENU_COLOR RGB565(255,255,255) #define DEFAULT_MENU_TEXT_COLOR RGB565( 0, 0, 0) @@ -683,6 +718,7 @@ typedef struct setting int offset_delay; int fast_speedup; float normalize_level; // Level to set normalize to, zero if not doing anything + int modulation_frequency; uint32_t checksum; }setting_t; @@ -714,7 +750,7 @@ extern uint32_t frequencies[POINTS_COUNT]; extern const float unit_scale_value[]; extern const char * const unit_scale_text[]; -#if 1 +#if 1 // Still sufficient flash // Flash save area - flash7 : org = 0x0801B000, len = 20k in *.ld file // 2k - for config save // 9 * 2k for setting_t + stored trace @@ -744,6 +780,7 @@ extern const char * const unit_scale_text[]; #define SAVE_PROP_CONFIG_3_ADDR 0x0801E000 #define SAVE_PROP_CONFIG_4_ADDR 0x0801e800 #endif + #if 0 typedef struct properties { uint32_t magic; @@ -945,11 +982,13 @@ extern uint16_t actual_rbw_x10; int get_waterfall(void); void toggle_tracking(void); +void toggle_hambands(void); void reset_calibration(void); void set_reflevel(float); void set_offset(float); void set_unit(int); void set_switches(int); +void set_gridlines(int); void set_trigger_level(float); void set_trigger(int); void update_rbw(void); @@ -964,7 +1003,7 @@ uint32_t calc_min_sweep_time_us(void); pureRSSI_t perform(bool b, int i, uint32_t f, int e); enum { - M_OFF, M_IMD, M_OIP3, M_PHASE_NOISE, M_STOP_BAND, M_PASS_BAND, M_LINEARITY + M_OFF, M_IMD, M_OIP3, M_PHASE_NOISE, M_STOP_BAND, M_PASS_BAND, M_LINEARITY, M_AM, M_FM }; enum { diff --git a/plot.c b/plot.c index 04ce9ec..40487ae 100644 --- a/plot.c +++ b/plot.c @@ -29,7 +29,8 @@ #ifdef __SCROLL__ -uint16_t _grid_y = NOSCROLL_GRIDY; +uint16_t _grid_y = (CHART_BOTTOM / NGRIDY); +uint16_t graph_bottom = CHART_BOTTOM; static int waterfall = false; #endif static void cell_draw_marker_info(int x0, int y0); @@ -41,6 +42,7 @@ void cell_draw_test_info(int x0, int y0); static int16_t grid_offset; static int16_t grid_width; +static int32_t grid_span; int16_t area_width = AREA_WIDTH_NORMAL; int16_t area_height; // initialized in main() = AREA_HEIGHT_NORMAL; @@ -126,24 +128,29 @@ void update_grid(void) fspan = setting.actual_sweep_time_us; // Time in uS fstart = 0; } + if (config.gridlines < 3) + config.gridlines = 6; while (gdigit > 100) { grid = 5 * gdigit; - if (fspan / grid >= 4) + if (fspan / grid >= config.gridlines) break; grid = 2 * gdigit; - if (fspan / grid >= 4) + if (fspan / grid >= config.gridlines) break; grid = gdigit; - if (fspan / grid >= 4) + if (fspan / grid >= config.gridlines) break; gdigit /= 10; } + grid_span = grid; grid_offset = (WIDTH) * ((fstart % grid) / 100) / (fspan / 100); grid_width = (WIDTH) * (grid / 100) / (fspan / 1000); force_set_markmap(); + if (get_waterfall()) + ili9341_fill(OFFSETX, graph_bottom, LCD_WIDTH - OFFSETX, CHART_BOTTOM - graph_bottom, 0); redraw_request |= REDRAW_FREQUENCY; } @@ -401,6 +408,51 @@ rectangular_grid(int x, int y) } #endif +#ifdef __HAM_BAND__ +typedef const struct { + uint32_t start; + uint32_t stop; +} ham_bands_t; + +const ham_bands_t ham_bands[] = +{ + {135700, 137800}, + {472000, 479000}, + {1800000, 2000000}, + {3500000, 3800000}, + {5250000, 5450000}, + {7000000, 7200000}, + {10100000, 10150000}, + {14000000, 14350000}, + {18068000, 18168000}, + {21000000, 21450000}, + {24890000, 24990000}, + {28000000, 29700000}, + {50000000, 52000000}, + {70000000, 70500000}, + {144000000, 146000000} +}; + +int ham_band(int x) // Search which index in the frequency tabled matches with frequency f using actual_rbw +{ + if (!config.hambands) + return false; + uint32_t f = frequencies[x]; + int L = 0; + int R = (sizeof ham_bands)/sizeof(uint32_t) - 1; + while (L <= R) { + int m = (L + R) / 2; + if (ham_bands[m].stop < f) + L = m + 1; + else if (ham_bands[m].start > f) + R = m - 1; + else + return true; // index is m + } + return false; +} +#endif + static int rectangular_grid_x(int x) { @@ -462,30 +514,31 @@ draw_on_strut(int v0, int d, int color) #define SQRT_50 ((float)7.0710678118654) #define LOG_10_SQRT_50 ((float)0.84948500216800) #define POW_30_20 ((float) 0.215443469) -#define POW_SQRT 1.5234153789 +#define POW_SQRT ((float)1.5234153789) /* - * calculate log10(abs(gamma)) + * calculate log10f(abs(gamma)) */ + float value(const float v) { switch(setting.unit) { case U_DBMV: -// return v + 30.0 + 20.0*log10(sqrt(50)); +// 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 break; case U_DBUV: -// return v + 90.0 + 20.0*log10(sqrt(50.0)); //TODO convert constants to single float number as GCC compiler does runtime calculation +// 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; break; case U_VOLT: -// return pow(10, (v-30.0)/20.0) * sqrt(50.0); - return pow(10, (v-30.0)/20.0)*SQRT_50; +// return pow(10, (v-30.0)/20.0) * sqrt((float)50.0); + return pow((float)10.0, (v-(float)30.0)/(float)20.0)*SQRT_50; // Do NOT change pow to powf as this will increase the size // return pow(10, v/20.0) * POW_SQRT; //TODO there is an error in this calculation as the outcome is different from the not optimized version break; case U_WATT: - return pow(10, v/10.0)/1000.0; + return pow((float)10.0, v/10.0)/1000.0; // Do NOT change pow to powf as this will increase the size break; } // case U_DBM: @@ -499,19 +552,19 @@ to_dBm(const float v) switch(setting.unit) { case U_DBMV: -// return v - 30.0 - 20.0*log10(sqrt(50)); +// return v - 30.0 - 20.0*log10f(sqrt(50)); return v - 30.0 - 20.0*LOG_10_SQRT_50; break; case U_DBUV: -// return v - 90.0 - 20.0*log10(sqrt(50.0)); //TODO convert constants to single float number as GCC compiler does runtime calculation +// 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; break; case U_VOLT: -// return log10( v / (sqrt(50.0))) * 20.0 + 30.0 ; - return log10( v / (SQRT_50)) * 20.0 + 30.0 ; +// return log10f( v / (sqrt(50.0))) * 20.0 + 30.0 ; + return log10f( v / (SQRT_50)) * 20.0 + 30.0 ; break; case U_WATT: - return log10(v*1000.0)*10.0; + return log10f(v*1000.0)*10.0; break; } // case U_DBM: @@ -842,7 +895,7 @@ trace_get_value_string_delta(int t, char *buf, int len, float array[POINTS_COUNT extern const char *unit_string[]; -static void trace_get_value_string( +inline void trace_get_value_string( // Only used at one place int t, char *buf, int len, int i, float coeff[POINTS_COUNT], int ri, int mtype, @@ -912,7 +965,7 @@ static void trace_get_value_string( #endif v = value(coeff[i]); if (mtype & M_NOISE) - v = v - 10*log10(actual_rbw_x10*100.0); + v = v - 10*log10f(actual_rbw_x10*100.0); if (v == -INFINITY) plot_printf(buf, len, "-INF"); else { @@ -1510,6 +1563,11 @@ draw_cell(int m, int n) // Draw rectangular plot (40 system ticks for all screen calls) if (trace_type & RECTANGULAR_GRID_MASK) { for (x = 0; x < w; x++) { +#ifdef __HAM_BAND__ + if (ham_band(x+x0)) { + for (y = 0; y < h; y++) cell_buffer[y * CELLWIDTH + x] = config.ham_color; + } +#endif if (rectangular_grid_x(x + x0)) { for (y = 0; y < h; y++) cell_buffer[y * CELLWIDTH + x] = c; } @@ -2140,11 +2198,11 @@ draw_frequencies(void) plot_printf(buf2, sizeof(buf2), " TIME %.3Fs", (float)t/ONE_SECOND_TIME); } else if (FREQ_IS_STARTSTOP()) { - plot_printf(buf1, sizeof(buf1), " START %qHz", get_sweep_frequency(ST_START)); - plot_printf(buf2, sizeof(buf2), " STOP %qHz", get_sweep_frequency(ST_STOP)); + plot_printf(buf1, sizeof(buf1), " START %.3qHz %5.1qHz/", get_sweep_frequency(ST_START), grid_span); + plot_printf(buf2, sizeof(buf2), " STOP %.3qHz", get_sweep_frequency(ST_STOP)); } else if (FREQ_IS_CENTERSPAN()) { - plot_printf(buf1, sizeof(buf1), " CENTER %qHz", get_sweep_frequency(ST_CENTER)); - plot_printf(buf2, sizeof(buf2), " SPAN %qHz", get_sweep_frequency(ST_SPAN)); + plot_printf(buf1, sizeof(buf1), " CENTER %.3qHz %5.1qHz/", get_sweep_frequency(ST_CENTER), grid_span); + plot_printf(buf2, sizeof(buf2), " SPAN %.3qHz", get_sweep_frequency(ST_SPAN)); } #ifdef __VNA__ } else { @@ -2159,12 +2217,12 @@ draw_frequencies(void) buf1[0] = S_SARROW[0]; if (uistat.lever_mode == LM_SPAN) buf2[0] = S_SARROW[0]; - int p2 = FREQUENCIES_XPOS2; - if (FREQ_IS_CW()) { - p2 = LCD_WIDTH - FONT_MAX_WIDTH*strlen(buf2); - } - ili9341_drawstring(buf1, FREQUENCIES_XPOS1, FREQUENCIES_YPOS); +// int p2 = FREQUENCIES_XPOS2; +// if (FREQ_IS_CW()) { + int p2 = LCD_WIDTH - FONT_MAX_WIDTH*strlen(buf2); +// } ili9341_drawstring(buf2, p2, FREQUENCIES_YPOS); + ili9341_drawstring(buf1, FREQUENCIES_XPOS1, FREQUENCIES_YPOS); } #ifdef __VNA__ void @@ -2259,22 +2317,23 @@ static void update_waterfall(void){ int i; int w_width = area_width < POINTS_COUNT ? area_width : POINTS_COUNT; // Waterfall only in 290 or 145 points - if (!(sweep_points == 290 || sweep_points == 145)) - return; - for (i = HEIGHT_NOSCROLL-1; i >=HEIGHT_SCROLL+2; i--) { // Scroll down +// if (!(sweep_points == 290 || sweep_points == 145)) +// return; + for (i = CHART_BOTTOM-1; i >=graph_bottom+1; i--) { // Scroll down ili9341_read_memory(OFFSETX, i , w_width, 1, w_width*1, spi_buffer); ili9341_bulk(OFFSETX, i+1, w_width, 1); } index_t *index = trace_index[TRACE_ACTUAL]; - for (i=0; i< w_width; i++) { // Add new topline + int j = 0; + for (i=0; i< sweep_points; i++) { // Add new topline uint16_t color; #ifdef _USE_WATERFALL_PALETTE - uint16_t y = _PALETTE_ALIGN(CELL_Y(index[i])); // should be always in range 0 - HEIGHT_SCROLL + uint16_t y = _PALETTE_ALIGN(CELL_Y(index[i])); // should be always in range 0 - graph_bottom // y = (uint8_t)i; // for test color = waterfall_palette[y]; #elif 0 - uint16_t y = CELL_Y(index[i]); // should be always in range 0 - HEIGHT_SCROLL - uint16_t ratio = (HEIGHT_SCROLL - y)*2; + uint16_t y = CELL_Y(index[i]); // should be always in range 0 - graph_bottom + uint16_t ratio = (graph_bottom - y)*2; // ratio = (i*2); // Uncomment for testing the waterfall colors int16_t b = 255 - ratio; if (b > 255) b = 255; @@ -2289,7 +2348,7 @@ static void update_waterfall(void){ gamma_correct(b); color = RGB565(r, g, b); #else - uint16_t y = CELL_Y(index[i]); // should be always in range 0 - HEIGHT_SCROLL + uint16_t y = CELL_Y(index[i])* (graph_bottom == BIG_WATERFALL ? 2 : 1); // should be always in range 0 - graph_bottom *2 depends on height of scroll // Calculate gradient palette for range 0 .. 192 // idx r g b // 0 - 127 0 0 @@ -2309,37 +2368,38 @@ static void update_waterfall(void){ else color = RGB565( 0, 124-((y-160)*4), 252-((y-160)*4)); #endif - if (sweep_points == 290) - spi_buffer[i] = color; - else { - spi_buffer[2*i ] = color; - spi_buffer[2*i+1] = color; + while (j * sweep_points < (i+1) * 290) { // Scale waterfall to 290 points + spi_buffer[j++] = color; } } - ili9341_bulk(OFFSETX, HEIGHT_SCROLL+2, w_width, 1); + ili9341_bulk(OFFSETX, graph_bottom+1, w_width, 1); } int get_waterfall(void) { return(waterfall); } +enum {W_OFF, W_SMALL, W_BIG}; void toggle_waterfall(void) { - if (!waterfall) { - _grid_y = SCROLL_GRIDY; - ili9341_fill(OFFSETX, HEIGHT_SCROLL, LCD_WIDTH - OFFSETX, HEIGHT_NOSCROLL - HEIGHT_SCROLL, 0); - waterfall = true; + if (waterfall == W_OFF) { w_min = (int)min_level; w_max = (int)peakLevel; if (w_max < w_min + 20) w_max = w_min + 20; - + graph_bottom = SMALL_WATERFALL; + waterfall = W_SMALL; + } else if (waterfall == W_SMALL) { + graph_bottom = BIG_WATERFALL; + waterfall = W_BIG; } else { - _grid_y = NOSCROLL_GRIDY; - waterfall = false; + graph_bottom = NO_WATERFALL; + waterfall = W_OFF; } + _grid_y = graph_bottom / NGRIDY; + ili9341_fill(OFFSETX, graph_bottom, LCD_WIDTH - OFFSETX, CHART_BOTTOM - graph_bottom, 0); request_to_redraw_grid(); } void diff --git a/sa_cmd.c b/sa_cmd.c index 9d32281..fda57b9 100644 --- a/sa_cmd.c +++ b/sa_cmd.c @@ -14,6 +14,8 @@ * the Free Software Foundation, Inc., 51 Franklin Street, * Boston, MA 02110-1301, USA. */ +#pragma GCC push_options +#pragma GCC optimize ("Os") static int VFO = 0; @@ -62,7 +64,7 @@ VNA_SHELL_FUNCTION(cmd_modulation ) shell_printf("usage: modulation %s\r\n", cmd_mod); return; } - static const int cmd_mod_val[] = { MO_NONE, MO_AM_1kHz, MO_AM_10Hz, MO_NFM, MO_WFM, MO_EXTERNAL}; + static const int cmd_mod_val[] = { MO_NONE, MO_AM, MO_NFM, MO_WFM, MO_EXTERNAL}; int m = get_str_index(argv[1], cmd_mod); if (m<0) goto usage; @@ -633,4 +635,20 @@ VNA_SHELL_FUNCTION(cmd_scanraw) redraw_request = 0; // disable screen update in this mode } +VNA_SHELL_FUNCTION(cmd_caloutput) +{ + static const char cmd[] = "off|30|15|10|4|3|2|1"; + if (argc != 1) { + usage: + shell_printf("usage: caloutput %s\r\n", cmd); + return; + } + int m = get_str_index(argv[0], cmd); + if (m != -1) + set_refer_output(m - 1); +} + + +#pragma GCC pop_options + diff --git a/sa_core.c b/sa_core.c index 4a0af21..9243f8f 100644 --- a/sa_core.c +++ b/sa_core.c @@ -16,9 +16,9 @@ * Boston, MA 02110-1301, USA. */ -//#ifdef __SI4432__ -#include "SI4432.h" // comment out for simulation -//#endif +#ifdef __SI4432__ +#include "si4432.h" // comment out for simulation +#endif #include "stdlib.h" #pragma GCC push_options @@ -62,10 +62,44 @@ this is a very long string only used to fill memory so I know when the memory is ; #endif +void update_min_max_freq(void) +{ + switch(setting.mode) { + case M_LOW: + minFreq = 0; + maxFreq = 350000000; + break; +#ifdef __ULTRA__ + case M_ULTRA: + minFreq = 674000000; + maxFreq = 4300000000; + break; +#endif + case M_GENLOW: + minFreq = 0; + maxFreq = 350000000; + break; + case M_HIGH: +#ifdef __ULTRA_SA__ + minFreq = 00000000; + maxFreq = 2000000000; +#else + minFreq = 24*setting_frequency_10mhz; + maxFreq = 96*setting_frequency_10mhz; +#endif + break; + case M_GENHIGH: + minFreq = 240000000; + maxFreq = 960000000; + break; + } +} + void reset_settings(int m) { // strcpy((char *)spi_buffer, dummy); setting.mode = m; + update_min_max_freq(); sweep_mode |= SWEEP_ENABLE; setting.unit_scale_index = 0; setting.unit_scale = 1; @@ -86,6 +120,7 @@ void reset_settings(int m) setting.lna = S_AUTO_OFF; setting.tracking = false; setting.modulation = MO_NONE; + setting.modulation_frequency = 1000; setting.step_delay = 0; setting.offset_delay = 0; setting.step_delay_mode = SD_NORMAL; @@ -127,18 +162,14 @@ void reset_settings(int m) break; #ifdef __ULTRA__ case M_ULTRA: - minFreq = 674000000; - maxFreq = 4300000000; - set_sweep_frequency(ST_START, (uint32_t) minFreq); - set_sweep_frequency(ST_STOP, (uint32_t) maxFreq); + set_sweep_frequency(ST_START, minFreq); + set_sweep_frequency(ST_STOP, maxFreq); setting.attenuate = 0; setting.sweep_time_us = 0; break; #endif case M_GENLOW: setting.drive=8; - minFreq = 0; - maxFreq = 350000000; set_sweep_frequency(ST_CENTER, 10000000); set_sweep_frequency(ST_SPAN, 0); setting.sweep_time_us = 10*ONE_SECOND_TIME; @@ -157,8 +188,6 @@ void reset_settings(int m) break; case M_GENHIGH: setting.drive=8; - minFreq = 240000000; - maxFreq = 960000000; set_sweep_frequency(ST_CENTER, 300000000); set_sweep_frequency(ST_SPAN, 0); setting.sweep_time_us = 10*ONE_SECOND_TIME; @@ -203,7 +232,10 @@ uint32_t calc_min_sweep_time_us(void) // Estimate minimum sweep time in void set_refer_output(int v) { setting.refer = v; - dirty = true; +#ifdef __SI4432__ + SI4432_SetReference(setting.refer); +#endif +// dirty = true; } void set_decay(int d) @@ -222,6 +254,16 @@ void set_noise(int d) dirty = true; } +void set_gridlines(int d) +{ + if (d < 3 || d > 20) + return; + config.gridlines = d; + config_save(); + dirty = true; + update_grid(); +} + void set_measurement(int m) { setting.measurement = m; @@ -292,6 +334,12 @@ void toggle_mute(void) dirty = true; } +void toggle_hambands(void) +{ + config.hambands = !config.hambands; + dirty = true; +} + void toggle_below_IF(void) { if (S_IS_AUTO(setting.below_IF )) @@ -309,6 +357,14 @@ void set_modulation(int m) dirty = true; } +void set_modulation_frequency(int f) +{ + if (100 <= f && f <= 6000) { + setting.modulation_frequency = f; + dirty = true; + } +} + void set_repeat(int r) { if (r > 0 && r <= 100) { @@ -1373,6 +1429,7 @@ search_maximum(int m, int center, int span) } } markers[m].index = max_index[0]; + markers[m].frequency = frequencies[markers[m].index]; return found; } @@ -1479,9 +1536,25 @@ int avoid_spur(int f) // find if this frequency should be avoi static int modulation_counter = 0; -static const int am_modulation[5] = { 4,0,1,5,7 }; // 5 step AM modulation -static const int nfm_modulation[5] = { 0, 2, 1, -1, -2}; // 5 step narrow FM modulation -static const int wfm_modulation[5] = { 0, 190, 118, -118, -190 }; // 5 step wide FM modulation +#define MODULATION_STEPS 8 +static const int am_modulation[MODULATION_STEPS] = { 5, 1, 0, 1, 5, 9, 11, 9 }; // AM modulation +// +// Offset is 156.25Hz when below 600MHz and 312.5 when above. +// +#define LND 16 // Total NFM deviation is LND * 4 * 156.25 = 5kHz when below 600MHz or 600MHz - 434MHz +#define HND 8 +#define LWD 96 // Total WFM deviation is LWD * 4 * 156.25 = 30kHz when below 600MHz +#define HWD 48 +static const int fm_modulation[4][MODULATION_STEPS] = // Avoid sign changes in NFM +{ + { 2*LND,(int)( 3.5*LND ), 4*LND, (int)(3.5*LND), 2*LND, (int)(0.5*LND), 0, (int)(0.5*LND)}, + { 0*LWD,(int)( 1.5*LWD ), 2*LWD, (int)(1.5*LWD), 0*LWD, (int)(-1.5*LWD), (int)-2*LWD, (int)(-1.5*LWD)}, + { 2*HND,(int)( 3.5*HND ), 4*HND, (int)(3.5*HND), 2*HND, (int)(0.5*HND), 0, (int)(0.5*HND)}, + { 0*HWD,(int)( 1.5*HWD ), 2*HWD, (int)(1.5*HWD), 0*HWD, (int)(-1.5*HWD), (int)-2*HWD, (int)(-1.5*HWD)}, +}; // narrow FM modulation avoid sign changes + +static const int fm_modulation_offset[4] = { LND*625/2, 0, LND*625/2, 0}; + deviceRSSI_t age[POINTS_COUNT]; // Array used for 1: calculating the age of any max and 2: buffer for fast sweep RSSI values; @@ -1493,6 +1566,8 @@ static systime_t sweep_elapsed = 0; // Time since fi pureRSSI_t perform(bool break_on_operation, int i, uint32_t f, int tracking) // Measure the RSSI for one frequency, used from sweep and other measurement routines. Must do all HW setup { + int modulation_delay = 0; + int modulation_index = 0; if (i == 0 && dirty ) { // if first point in scan and dirty calculate_correction(); // pre-calculate correction factor dividers to avoid float division apply_settings(); // Initialize HW @@ -1532,7 +1607,6 @@ pureRSSI_t perform(bool break_on_operation, int i, uint32_t f, int tracking) + get_attenuation() - setting.offset); } - // if (MODE_OUTPUT(setting.mode) && setting.additional_step_delay_us < 500) // Minimum wait time to prevent LO from lockup during output frequency sweep // setting.additional_step_delay_us = 500; // Update grid and status after @@ -1595,39 +1669,59 @@ pureRSSI_t perform(bool break_on_operation, int i, uint32_t f, int tracking) else auto_set_AGC_LNA(true, 0); } + // Calculate the RSSI correction for later use + if (MODE_INPUT(setting.mode)){ // only cases where the value can change on 0 point of sweep + if (i == 0 || setting.frequency_step != 0) + correct_RSSI_freq = get_frequency_correction(f); + } + int *current_fm_modulation; + if (MODE_OUTPUT(setting.mode)) { + if (setting.modulation != MO_NONE && setting.modulation != MO_EXTERNAL && setting.modulation_frequency != 0) { + modulation_delay = (1000000/ MODULATION_STEPS ) / setting.modulation_frequency; // 5 steps so 1MHz/5 + modulation_counter = 0; + if (setting.modulation == MO_AM) // -14 default + modulation_delay += config.cor_am; + else { // must be FM + if (setting.modulation == MO_WFM) { // -17 default + modulation_delay += config.cor_wfm; + modulation_index = 1; + } else { // must be NFM + modulation_delay += config.cor_nfm; // -17 default + // modulation_index = 0; // default value + } + if ((setting.mode == M_GENLOW && f > 480000000 - 433000000) || + (setting.mode == M_GENHIGH && f > 480000000) ) + modulation_index += 2; + current_fm_modulation = (int *)fm_modulation[modulation_index]; + f -= fm_modulation_offset[modulation_index]; // Shift output frequency + } + } + } modulation_again: // ----------------------------------------------------- modulation for output modes --------------------------------------- if (MODE_OUTPUT(setting.mode)){ - if (setting.modulation == MO_AM_1kHz || setting.modulation == MO_AM_10Hz) { // AM modulation - int p = setting.attenuate * 2 + am_modulation[modulation_counter++]; + if (setting.modulation == MO_AM) { // AM modulation + int p = setting.attenuate * 2 + am_modulation[modulation_counter]; if (p>63) p = 63; else if (p< 0) p = 0; #ifdef __PE4302__ PE4302_Write_Byte(p); #endif - if (modulation_counter == 5) // 3dB modulation depth - modulation_counter = 0; - my_microsecond_delay(setting.modulation == MO_AM_10Hz ? 20000 : 180); } else if (setting.modulation == MO_NFM || setting.modulation == MO_WFM ) { //FM modulation #ifdef __SI4432__ SI4432_Sel = SI4432_LO ; - int offset = setting.modulation == MO_NFM ? nfm_modulation[modulation_counter] : wfm_modulation[modulation_counter] ; - SI4432_Write_Byte(SI4432_FREQ_OFFSET1, (offset & 0xff )); // Use frequency hopping channel for FM modulation - SI4432_Write_Byte(SI4432_FREQ_OFFSET2, ((offset >> 8) & 0x03 )); // Use frequency hopping channel for FM modulation + int offset = current_fm_modulation[modulation_counter]; + SI4432_Write_2_Byte(SI4432_FREQ_OFFSET1, (offset & 0xff ), ((offset >> 8) & 0x03 )); // Use frequency hopping channel for FM modulation +// SI4432_Write_Byte(SI4432_FREQ_OFFSET2, ); // Use frequency hopping channel for FM modulation #endif - modulation_counter++; - if (modulation_counter == 5) // 3dB modulation depth - modulation_counter = 0; - my_microsecond_delay(200); - // chThdSleepMicroseconds(200); } - } - - // Calculate the RSSI correction for later use - if (MODE_INPUT(setting.mode)){ // only cases where the value can change on 0 point of sweep - if (i == 0 || setting.frequency_step != 0) - correct_RSSI_freq = get_frequency_correction(f); + modulation_counter++; + if (modulation_counter == MODULATION_STEPS) // 3dB modulation depth + modulation_counter = 0; + if (setting.modulation != MO_NONE && setting.modulation != MO_EXTERNAL) { + my_microsecond_delay(modulation_delay); + } } // -------------------------------- Acquisition loop for one requested frequency covering spur avoidance and vbwsteps ------------------------ @@ -1794,9 +1888,10 @@ modulation_again: if (MODE_OUTPUT(setting.mode)) { // No substepping and no RSSI in output mode if (break_on_operation && operation_requested) // break subscanning if requested return(0); // abort - if (MODE_OUTPUT(setting.mode) && setting.modulation != MO_NONE && setting.modulation != MO_EXTERNAL) // if in output mode with modulation + if (MODE_OUTPUT(setting.mode) && setting.modulation != MO_NONE && setting.modulation != MO_EXTERNAL) { // if in output mode with modulation + i = 1; // Everything set so skip LO setting goto modulation_again; // Keep repeating sweep loop till user aborts by input - + } return(0); } // ---------------- Prepare RSSI ---------------------- @@ -1959,7 +2054,7 @@ sweep_again: // stay in sweep loop when output mo scandirty = false; if (break_on_operation && operation_requested) { // break loop if needed if (setting.actual_sweep_time_us > ONE_SECOND_TIME && MODE_INPUT(setting.mode)) { - ili9341_fill(OFFSETX, HEIGHT_NOSCROLL+1, WIDTH, 1, 0); // Erase progress bar + ili9341_fill(OFFSETX, CHART_BOTTOM+1, WIDTH, 1, 0); // Erase progress bar } return false; } @@ -1999,8 +2094,8 @@ sweep_again: // stay in sweep loop when output mo if (setting.actual_sweep_time_us > ONE_SECOND_TIME && (i & 0x07) == 0) { // if required int pos = i * (WIDTH+1) / sweep_points; - ili9341_fill(OFFSETX, HEIGHT_NOSCROLL+1, pos, 1, BRIGHT_COLOR_GREEN); // update sweep progress bar - ili9341_fill(OFFSETX+pos, HEIGHT_NOSCROLL+1, WIDTH-pos, 1, 0); + ili9341_fill(OFFSETX, CHART_BOTTOM+1, pos, 1, BRIGHT_COLOR_GREEN); // update sweep progress bar + ili9341_fill(OFFSETX+pos, CHART_BOTTOM+1, WIDTH-pos, 1, 0); } // ------------------------ do all RSSI calculations from CALC menu ------------------- @@ -2198,7 +2293,7 @@ sweep_again: // stay in sweep loop when output mo setting.atten_step = false; // No step attenuate in low mode auto attenuate int changed = false; int delta = 0; - int actual_max_level = (int) (actual_t[max_index[0]] - get_attenuation()); + 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) { delta = - (AUTO_TARGET_LEVEL - actual_max_level); } else if (actual_max_level > AUTO_TARGET_LEVEL && setting.attenuate < 30) { @@ -2354,27 +2449,51 @@ sweep_again: // stay in sweep loop when output mo } uint32_t lf = frequencies[l]; uint32_t rf = frequencies[r]; + markers[0].frequency = lf; + markers[1].frequency = rf; + markers[2].enabled = search_maximum(2, lf - (rf - lf), 12); markers[3].enabled = search_maximum(3, rf + (rf - lf), 12); } else if (setting.measurement == M_PHASE_NOISE && markers[0].index > 10) { // ------------Phase noise measurement markers[1].index = markers[0].index + (setting.mode == M_LOW ? 290/4 : -290/4); // Position phase noise marker at requested offset + markers[1].frequency = frequencies[markers[1].index]; } else if (setting.measurement == M_STOP_BAND && markers[0].index > 10) { // -------------Stop band measurement markers[1].index = marker_search_left_min(markers[0].index); if (markers[1].index < 0) markers[1].index = 0; + markers[1].frequency = frequencies[markers[1].index]; markers[2].index = marker_search_right_min(markers[0].index); if (markers[2].index < 0) markers[1].index = setting._sweep_points - 1; + markers[2].frequency = frequencies[markers[2].index]; } else if (setting.measurement == M_PASS_BAND && markers[0].index > 10) { // ----------------Pass band measurement int t = markers[0].index; float v = actual_t[t]; - while (t > 0 && actual_t[t] > v - 3.0) // Find left -3dB point + while (t > 0 && actual_t[t] > v - 6.0) // Find left -3dB point t --; - if (t > 0) + if (t > 0) { markers[1].index = t; + markers[1].frequency = frequencies[t]; + } t = markers[0].index; - while (t < setting._sweep_points - 1 && actual_t[t] > v - 3.0) // find right -3dB point + while (t < setting._sweep_points - 1 && actual_t[t] > v - 6.0) // find right -3dB point t ++; - if (t < setting._sweep_points - 1 ) + if (t < setting._sweep_points - 1 ) { markers[2].index = t; + markers[2].frequency = frequencies[t]; + } + } else if (setting.measurement == M_AM) { // ----------------AM measurement + if (S_IS_AUTO(setting.agc )) { + if (actual_t[max_index[0]] - get_attenuation() > -20 ) { + setting.agc = S_AUTO_OFF; + setting.lna = S_AUTO_OFF; + } else if (actual_t[max_index[0]] - get_attenuation() < -45 ) { + setting.agc = S_AUTO_ON; + setting.lna = S_AUTO_ON; + } else { + setting.agc = S_AUTO_OFF; + setting.lna = S_AUTO_ON; + } + set_AGC_LNA(); + } } #endif @@ -2437,7 +2556,7 @@ sweep_again: // stay in sweep loop when output mo // redraw_marker(peak_marker, FALSE); // STOP_PROFILE; - ili9341_fill(OFFSETX, HEIGHT_NOSCROLL+1, WIDTH, 1, 0); + ili9341_fill(OFFSETX, CHART_BOTTOM+1, WIDTH, 1, 0); palSetPad(GPIOC, GPIOC_LED); return true; @@ -2632,7 +2751,7 @@ void draw_cal_status(void) rounding = true; const char * const unit = unit_string[setting.unit]; - ili9341_fill(0, 0, OFFSETX, HEIGHT_NOSCROLL, 0x0000); + ili9341_fill(0, 0, OFFSETX, CHART_BOTTOM, 0x0000); if (MODE_OUTPUT(setting.mode)) { // No cal status during output return; } @@ -2925,24 +3044,24 @@ void draw_cal_status(void) ili9341_drawstring(buf, x, y); // ili9341_set_background(DEFAULT_BG_COLOR); - - // Bottom level - y = area_height - 8 + OFFSETY; - if (rounding) - plot_printf(buf, BLEN, "%4d", (int)(yMax - setting.scale * NGRIDY)); - else - plot_printf(buf, BLEN, "%+4.3F", ((yMax - setting.scale * NGRIDY)/setting.unit_scale)); -// buf[5]=0; - if (level_is_calibrated()) - if (setting.auto_reflevel) - color = DEFAULT_FG_COLOR; + if (!get_waterfall()) { // Do not draw bottom level if in waterfall mode + // Bottom level + y = area_height - 8 + OFFSETY; + if (rounding) + plot_printf(buf, BLEN, "%4d", (int)(yMax - setting.scale * NGRIDY)); else - color = BRIGHT_COLOR_GREEN; - else - color = BRIGHT_COLOR_RED; - ili9341_set_foreground(color); - ili9341_drawstring(buf, x, y); - + plot_printf(buf, BLEN, "%+4.3F", ((yMax - setting.scale * NGRIDY)/setting.unit_scale)); + // buf[5]=0; + if (level_is_calibrated()) + if (setting.auto_reflevel) + color = DEFAULT_FG_COLOR; + else + color = BRIGHT_COLOR_GREEN; + else + color = BRIGHT_COLOR_RED; + ili9341_set_foreground(color); + ili9341_drawstring(buf, x, y); + } } // -------------------- Self testing ------------------------------------------------- @@ -2952,10 +3071,10 @@ enum { }; enum { - TP_SILENT, TPH_SILENT, TP_10MHZ, TP_10MHZEXTRA, TP_10MHZ_SWITCH, TP_30MHZ, TPH_30MHZ + TP_SILENT, TPH_SILENT, TP_10MHZ, TP_10MHZEXTRA, TP_10MHZ_SWITCH, TP_30MHZ, TPH_30MHZ, TPH_30MHZ_SWITCH }; -#define TEST_COUNT 17 +#define TEST_COUNT 19 #define W2P(w) (sweep_points * w / 100) // convert width in % to actual sweep points @@ -2973,6 +3092,7 @@ static const struct { {TC_BELOW, TP_SILENT, 0.015, 0.01, -30, 0, 0}, // 2 Phase noise of zero Hz {TC_SIGNAL, TP_10MHZ, 20, 7, -39, 10, -90 }, // 3 {TC_SIGNAL, TP_10MHZ, 30, 7, -34, 10, -90 }, // 4 +#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 @@ -2980,14 +3100,20 @@ static const struct { {TC_BELOW, TP_30MHZ, 430, 60, -75, 0, -75}, // 9 LPF cutoff {TC_SIGNAL, TP_10MHZ_SWITCH,20, 7, -39, 10, -60 }, // 10 Switch isolation using high attenuation {TC_END, 0, 0, 0, 0, 0, 0}, +#define TEST_POWER 11 {TC_MEASURE, TP_30MHZ, 30, 7, -25, 10, -55 }, // 12 Measure power level and noise {TC_MEASURE, TP_30MHZ, 270, 4, -50, 10, -75 }, // 13 Measure powerlevel and noise {TC_MEASURE, TPH_30MHZ, 270, 4, -40, 10, -65 }, // 14 Calibrate power high mode {TC_END, 0, 0, 0, 0, 0, 0}, +#define TEST_RBW 15 {TC_MEASURE, TP_30MHZ, 30, 1, -20, 10, -60 }, // 16 Measure RBW step time {TC_END, 0, 0, 0, 0, 0, 0}, + {TC_MEASURE, TPH_30MHZ, 300, 4, -48, 10, -65 }, // 14 Calibrate power high mode + {TC_MEASURE, TPH_30MHZ_SWITCH,300, 4, -40, 10, -65 }, // 14 Calibrate power high mode }; + + enum { TS_WAITING, TS_PASS, TS_FAIL, TS_CRITICAL }; @@ -3232,11 +3358,14 @@ common_silent: set_mode(M_LOW); maxFreq = 520000000; // needed to measure the LPF rejection set_refer_output(0); + dirty = true; // set_step_delay(1); // Do not set !!!!! #ifdef __SPUR__ setting.spur_removal = 1; #endif + goto common; + case TPH_30MHZ_SWITCH: case TPH_30MHZ: set_mode(M_HIGH); set_refer_output(0); @@ -3246,6 +3375,10 @@ common_silent: case TP_10MHZ_SWITCH: set_attenuation(32); // This forces the switch to transmit so isolation can be tested break; + case TPH_30MHZ_SWITCH: + set_attenuation(0); + setting.atten_step = true; // test high switch isolation + break; default: set_attenuation(0.0); } @@ -3329,7 +3462,7 @@ void self_test(int test) float p2, p1, p; in_selftest = true; // Spur search reset_settings(M_LOW); - test_prepare(4); + test_prepare(TEST_SILENCE); setting.auto_IF = false; setting.frequency_IF=433000000; setting.frequency_step = 30000; @@ -3368,18 +3501,17 @@ void self_test(int test) } else if (test == 2) { // Attenuator test in_selftest = true; reset_settings(M_LOW); - int i = 15; // calibrate attenuator at 30 MHz; float reference_peak_level = 0; - test_prepare(i); + test_prepare(TEST_RBW); for (int j= 0; j < 50; j++ ) { - test_prepare(i); + test_prepare(TEST_RBW); set_RBW(300); set_attenuation((float)j); float summed_peak_level = 0; for (int k=0; k<10; k++) { - test_acquire(i); // Acquire test - test_validate(i); // Validate test + test_acquire(TEST_RBW); // Acquire test + test_validate(TEST_RBW); // Validate test summed_peak_level += peakLevel; } peakLevel = summed_peak_level / 10; @@ -3394,15 +3526,13 @@ void self_test(int test) setting.auto_IF = false; setting.frequency_IF=433900000; ui_mode_normal(); -// int i = 13; // calibrate low mode power on 30 MHz; - int i = 15; // calibrate low mode power on 30 MHz; - test_prepare(i); + test_prepare(TEST_RBW); setting.step_delay = 8000; for (int j= 0; j < SI4432_RBW_count; j++ ) { if (setting.test_argument != 0) j = setting.test_argument; // do_again: - test_prepare(i); + test_prepare(TEST_RBW); setting.spur_removal = 0; #if 1 // Disable for offset baseline scanning setting.step_delay_mode = SD_NORMAL; @@ -3428,8 +3558,8 @@ void self_test(int test) else set_sweep_frequency(ST_SPAN, (uint32_t)(18000000)); #endif - test_acquire(i); // Acquire test - test_validate(i); // Validate test + test_acquire(TEST_RBW); // Acquire test + test_validate(TEST_RBW); // Validate test // if (test_value == 0) { // setting.step_delay = setting.step_delay * 4 / 5; // goto do_again; @@ -3443,7 +3573,7 @@ void self_test(int test) shell_printf("Start level = %f, ",peakLevel); #if 1 // Enable for step delay tuning while (setting.step_delay > 10 && test_value != 0 && test_value > saved_peakLevel - 0.5) { - test_prepare(i); + test_prepare(TEST_RBW); setting.spur_removal = 0; setting.step_delay_mode = SD_NORMAL; setting.step_delay = setting.step_delay * 4 / 5; @@ -3453,8 +3583,8 @@ void self_test(int test) set_sweep_frequency(ST_SPAN, (uint32_t)(18000000)); // setting.repeat = 10; - test_acquire(i); // Acquire test - test_validate(i); // Validate test + test_acquire(TEST_RBW); // Acquire test + test_validate(TEST_RBW); // Validate test // shell_printf(" Step %f, %d",peakLevel, setting.step_delay); } @@ -3468,7 +3598,7 @@ void self_test(int test) test_value = saved_peakLevel; if ((uint32_t)(setting.rbw_x10 * 1000) / (sweep_points) < 8000) { // fast mode possible while (setting.offset_delay > 0 && test_value != 0 && test_value > saved_peakLevel - 1.5) { - test_prepare(i); + test_prepare(TEST_RBW); setting.step_delay_mode = SD_FAST; setting.offset_delay /= 2; setting.spur_removal = 0; @@ -3477,8 +3607,8 @@ void self_test(int test) else set_sweep_frequency(ST_SPAN, (uint32_t)(18000000)); // Limit to 18MHz // setting.repeat = 10; - test_acquire(i); // Acquire test - test_validate(i); // Validate test + test_acquire(TEST_RBW); // Acquire test + test_validate(TEST_RBW); // Validate test // shell_printf(" Step %f, %d",peakLevel, setting.step_delay); } } @@ -3551,16 +3681,15 @@ void calibrate(void) in_selftest = true; reset_calibration(); reset_settings(M_LOW); - int i = 11; // calibrate low mode power on 30 MHz; for (int j= 0; j < CALIBRATE_RBWS; j++ ) { // set_RBW(power_rbw[j]); // set_sweep_points(21); - test_prepare(i); + test_prepare(TEST_POWER); setting.step_delay_mode = SD_PRECISE; setting.agc = S_OFF; setting.lna = S_OFF; - test_acquire(i); // Acquire test - local_test_status = test_validate(i); // Validate test + test_acquire(TEST_POWER); // Acquire test + local_test_status = test_validate(TEST_POWER); // Validate test // chThdSleepMilliseconds(1000); if (local_test_status != TS_PASS) { ili9341_set_foreground(BRIGHT_COLOR_RED); @@ -3573,22 +3702,20 @@ void calibrate(void) } #if 0 // No high input calibration as CAL OUTPUT is unreliable - i = 12; // Measure 270MHz in low mode set_RBW(100); - test_prepare(i); - test_acquire(i); // Acquire test + test_prepare(TEST_POWER+1); + test_acquire(TEST_POWER+1); // Acquire test float last_peak_level = peakLevel; - local_test_status = test_validate(i); // Validate test + local_test_status = test_validate(TEST_POWER+1); // Validate test chThdSleepMilliseconds(1000); config.high_level_offset = 0; /// Preliminary setting - i = 13; // Calibrate 270MHz in high mode for (int j = 0; j < CALIBRATE_RBWS; j++) { set_RBW(power_rbw[j]); - test_prepare(i); - test_acquire(i); // Acquire test - local_test_status = test_validate(i); // Validate test + test_prepare(TEST_POWER+2); + test_acquire(TEST_POWER+2); // Acquire test + local_test_status = test_validate(TEST_POWER+2); // Validate test // if (local_test_status != TS_PASS) { // Do not validate due to variations in SI4432 // ili9341_set_foreground(BRIGHT_COLOR_RED); // ili9341_drawstring_7x13("Calibration failed", 30, 120); diff --git a/si4432.c b/si4432.c index c8082b7..98054cd 100644 --- a/si4432.c +++ b/si4432.c @@ -254,6 +254,22 @@ void SI4432_Write_Byte(uint8_t ADR, uint8_t DATA ) // SI4432_guard = 0; } +void SI4432_Write_2_Byte(uint8_t ADR, uint8_t DATA1, uint8_t DATA2) +{ +// if (SI4432_guard) +// while(1) ; +// SI4432_guard = 1; +// SPI2_CLK_LOW; + palClearPad(GPIOC, SI_nSEL[SI4432_Sel]); +// chThdSleepMicroseconds(SELECT_DELAY); + ADR |= 0x80 ; // RW = 1 + shiftOut( ADR ); + shiftOut( DATA1 ); + shiftOut( DATA2 ); + palSetPad(GPIOC, SI_nSEL[SI4432_Sel]); +// SI4432_guard = 0; +} + void SI4432_Write_3_Byte(uint8_t ADR, uint8_t DATA1, uint8_t DATA2, uint8_t DATA3 ) { set_SPI_mode(SPI_MODE_SI); diff --git a/si4432.h b/si4432.h index 0f3d938..3aabe0c 100644 --- a/si4432.h +++ b/si4432.h @@ -120,6 +120,7 @@ extern int SI4432_frequency_changed; extern int SI4432_offset_changed; void SI4432_Write_Byte(uint8_t ADR, uint8_t DATA ); +void SI4432_Write_2_Byte(uint8_t ADR, uint8_t DATA1, uint8_t DATA2); uint8_t SI4432_Read_Byte( uint8_t ADR ); void SI4432_Transmit(int d); diff --git a/ui.c b/ui.c index 1811f7d..fae0040 100644 --- a/ui.c +++ b/ui.c @@ -190,9 +190,12 @@ static int btn_wait_release(void) uint16_t changed = last_button ^ cur_button; if (dt >= BUTTON_DOWN_LONG_TICKS && (cur_button & (1< 0) ili9341_fill(LCD_WIDTH-MENU_BUTTON_WIDTH, area_height, MENU_BUTTON_WIDTH, MENU_BUTTON_HEIGHT*MENU_BUTTON_MAX - area_height, DEFAULT_BG_COLOR); + if (get_waterfall()) + ili9341_fill(OFFSETX, graph_bottom, LCD_WIDTH - OFFSETX, CHART_BOTTOM - graph_bottom, 0); redraw_request|=REDRAW_AREA | REDRAW_FREQUENCY | REDRAW_CAL_STATUS | REDRAW_BATTERY; } @@ -2081,6 +2086,7 @@ lever_move_marker(int status) } markers[active_marker].frequency = frequencies[markers[active_marker].index]; redraw_marker(active_marker); + markers[active_marker].mtype &= ~M_TRACKING; // Disable tracking when dragging marker step++; } status = btn_wait_release(); @@ -2226,7 +2232,7 @@ ui_process_menu(void) const menuitem_t *menu = menu_stack[menu_current_level]; int status = btn_check(); if (status != 0) { - if (status & EVT_BUTTON_SINGLE_CLICK) { + if (selection >=0 && status & EVT_BUTTON_SINGLE_CLICK) { menu_invoke(selection); } else { do { @@ -2242,7 +2248,7 @@ ui_process_menu(void) } if (status & EVT_DOWN) { // skip menu item if disabled - while (menuDisabled(menu[selection-1].type)) + while (selection > 0 && menuDisabled(menu[selection-1].type)) selection--; // close menu if item is 0, else step down if (selection > 0) @@ -2492,7 +2498,7 @@ touch_pickup_marker(void) // select trace uistat.current_trace = t; select_lever_mode(LM_MARKER); - + markers[m].mtype &= ~M_TRACKING; // Disable tracking when dragging marker // drag marker until release drag_marker(t, m); return TRUE; diff --git a/ui_sa.c b/ui_sa.c index 535bc44..52db604 100644 --- a/ui_sa.c +++ b/ui_sa.c @@ -16,6 +16,9 @@ * the Free Software Foundation, Inc., 51 Franklin Street, * Boston, MA 02110-1301, USA. */ +#pragma GCC push_options +#pragma GCC optimize ("Os") + #define FORM_ICON_WIDTH 16 #define FORM_ICON_HEIGHT 16 @@ -403,7 +406,8 @@ static const keypads_t keypads_time[] = { 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_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_NONE // always at enum end }; @@ -425,7 +429,7 @@ static const struct { {keypads_positive , "DRIVE"}, // drive {keypads_plusmin , "LEVEL"}, // KM_LOWOUTLEVEL {keypads_positive , "SCANS"}, // KM_DECAY - {keypads_positive , "LEVEL"}, // KM_NOISE + {keypads_positive , "NOISE\nLEVEL"}, // KM_NOISE {keypads_freq , "FREQ"}, // KM_10MHz {keypads_positive , "SAMPLE\nREPEAT"}, // KM_REPEA {keypads_plusmin , "OFFSET"}, // KM_OFFSET @@ -434,6 +438,12 @@ static const struct { {keypads_time , "SWEEP\nSECONDS"}, // KM_SWEEP_TIME {keypads_positive , "OFFSET\nDELAY"}, // KM_OFFSET_DELAY {keypads_positive , "FAST\nSPEEDUP"}, // KM_FAST_SPEEDUP + {keypads_positive , "MINIMUM\nGRIDLINES"}, // KM_GRIDLINES + {keypads_freq , "MARKER\nFREQ"}, // KM_MARKER + {keypads_freq , "MODULATION\nFREQ"}, // KM_MODULATION + {keypads_plusmin , "COR\nAM"}, // KM_COR_AM + {keypads_plusmin , "COR\nWFM"}, // KM_COR_WFM + {keypads_plusmin , "COR\nNFM"}, // KM_COR_NFM }; // ===[MENU CALLBACKS]========================================================= @@ -499,7 +509,7 @@ static UI_FUNCTION_ADV_CALLBACK(menu_load_preset_acb) } if (caldata_recall(data) == -1) { if (data == 0) - reset_settings(setting.mode); // Restore all defaults + reset_settings(setting.mode); // Restore factory defaults else { draw_menu(); return; @@ -577,30 +587,34 @@ static UI_FUNCTION_ADV_CALLBACK(menu_scanning_speed_acb) ui_mode_normal(); } +#define CONFIG_MENUITEM_TOUCH_CAL 0 +#define CONFIG_MENUITEM_TOUCH_TEST 1 +#define CONFIG_MENUITEM_SELFTEST 2 +#define CONFIG_MENUITEM_VERSION 3 static UI_FUNCTION_CALLBACK(menu_config_cb) { - (void)data; - switch (item) { - case 0: + (void)item; + switch (data) { + case CONFIG_MENUITEM_TOUCH_CAL: touch_cal_exec(); redraw_frame(); request_to_redraw_grid(); draw_menu(); break; - case 1: + case CONFIG_MENUITEM_TOUCH_TEST: touch_draw_test(); redraw_frame(); request_to_redraw_grid(); draw_menu(); break; - case 2: + case CONFIG_MENUITEM_SELFTEST: sweep_mode = 0; // Suspend sweep to save time menu_move_back_and_leave_ui(); setting.test = 0; setting.test_argument = 0; sweep_mode = SWEEP_SELFTEST; break; - case 4: + case CONFIG_MENUITEM_VERSION: show_version(); redraw_frame(); request_to_redraw_grid(); @@ -616,8 +630,8 @@ static UI_FUNCTION_CALLBACK(menu_dfu_cb) } -// const int menu_modulation_value[]={MO_NONE,MO_AM_1, MO_NFM, MO_WFM, MO_EXTERNAL}; -const char *menu_modulation_text[]={"None", "AM 1kHz", "AM 10Hz", "Narrow FM", "Wide FM", "External"}; +// const int menu_modulation_value[]={MO_NONE,MO_AM, MO_NFM, MO_WFM, MO_EXTERNAL}; +const char *menu_modulation_text[]={"None", "AM", "NFM", "WFM", "External"}; static UI_FUNCTION_ADV_CALLBACK(menu_modulation_acb) { @@ -641,7 +655,12 @@ static UI_FUNCTION_ADV_CALLBACK(menu_smodulation_acb){ (void)item; (void)data; if(b){ - b->param_1.text = menu_modulation_text[setting.modulation]; + if (setting.modulation == MO_NONE || setting.modulation == MO_EXTERNAL) + b->param_1.text = menu_modulation_text[setting.modulation]; + else { + plot_printf(uistat.text, sizeof uistat.text, "%5.3fkHz %s", setting.modulation_frequency / 1000.0, menu_modulation_text[setting.modulation]); + b->param_1.text = uistat.text; + } return; } menu_push_submenu(menu_modulation); @@ -834,6 +853,35 @@ static UI_FUNCTION_ADV_CALLBACK(menu_measure_acb) set_measurement(M_LINEARITY); ui_mode_normal(); break; + case M_AM: // OIP3 + reset_settings(setting.mode); + for (int i = 0; i< 3; i++) { + markers[i].enabled = M_ENABLED; + markers[i].mtype = M_DELTA | M_TRACKING; + } + markers[0].mtype = M_REFERENCE | M_TRACKING; + kp_help_text = "Frequency of signal"; + ui_mode_keypad(KM_CENTER); + ui_process_keypad(); + set_sweep_frequency(ST_SPAN, 100000); // 100kHz + set_measurement(M_AM); + break; + case M_FM: // OIP3 + reset_settings(setting.mode); + for (int i = 0; i< 3; i++) { + markers[i].enabled = M_ENABLED; + markers[i].mtype = M_DELTA | M_TRACKING; + } + markers[0].mtype = M_REFERENCE | M_TRACKING; + kp_help_text = "Frequency of signal"; + ui_mode_keypad(KM_CENTER); + ui_process_keypad(); + kp_help_text = "Frequency deviation"; + ui_mode_keypad(KM_SPAN); + ui_process_keypad(); + set_sweep_frequency(ST_SPAN, uistat.value*30); + set_measurement(M_FM); + break; } #endif // selection = -1; @@ -948,6 +996,7 @@ static UI_FUNCTION_ADV_CALLBACK(menu_marker_select_acb) return; } markers[data-1].enabled = true; + markers[data-1].frequency = frequencies[markers[data-1].index]; active_marker_select(data-1); menu_push_submenu(menu_marker_modify); redraw_marker(active_marker); @@ -1141,6 +1190,19 @@ static UI_FUNCTION_ADV_CALLBACK(menu_settings_bpf_acb){ draw_menu(); } +#ifdef __HAM_BAND__ +static UI_FUNCTION_ADV_CALLBACK(menu_settings_ham_bands){ + (void)item; + (void)data; + if(b){ + b->icon = config.hambands ? BUTTON_ICON_CHECK : BUTTON_ICON_NOCHECK; + return; + } + toggle_hambands(); + draw_menu(); +} +#endif + static UI_FUNCTION_ADV_CALLBACK(menu_settings_below_if_acb){ (void)item; (void)data; @@ -1205,6 +1267,33 @@ static UI_FUNCTION_ADV_CALLBACK(menu_points_acb){ draw_menu(); } +#ifdef __USE_SERIAL_CONSOLE__ +static UI_FUNCTION_ADV_CALLBACK(menu_serial_speed_acb) +{ + (void)item; + if (b){ + b->icon = config._serial_speed == data ? BUTTON_ICON_GROUP_CHECKED : BUTTON_ICON_GROUP; + b->param_1.u = USART_GET_SPEED(data); + return; + } + config._serial_speed = data; + shell_update_speed(); + draw_menu(); +} + +static UI_FUNCTION_ADV_CALLBACK(menu_connection_acb) +{ + (void)item; + if (b){ + b->icon = (config._mode&_MODE_CONNECTION_MASK) == data ? BUTTON_ICON_GROUP_CHECKED : BUTTON_ICON_GROUP; + return; + } + config._mode&=~_MODE_CONNECTION_MASK; + config._mode|=data; + shell_reset_console(); + draw_menu(); +} +#endif // ===[MENU DEFINITION]========================================================= #if 0 static const menuitem_t menu_store_preset_high[8] = @@ -1301,11 +1390,11 @@ static const menuitem_t menu_drive_wide[] = { static const menuitem_t menu_modulation[] = { { MT_FORM | MT_TITLE, 0, "MODULATION",NULL}, { MT_FORM | MT_ADV_CALLBACK, MO_NONE, "None", menu_modulation_acb}, - { MT_FORM | MT_ADV_CALLBACK | MT_LOW, MO_AM_1kHz, "AM 1kHz", menu_modulation_acb}, - { MT_FORM | MT_ADV_CALLBACK | MT_LOW, MO_AM_10Hz, "AM 10Hz", menu_modulation_acb}, + { MT_FORM | MT_ADV_CALLBACK | MT_LOW, MO_AM, "AM", menu_modulation_acb}, { MT_FORM | MT_ADV_CALLBACK, MO_NFM, "Narrow FM", menu_modulation_acb}, { MT_FORM | MT_ADV_CALLBACK, MO_WFM, "Wide FM", menu_modulation_acb}, { MT_FORM | MT_ADV_CALLBACK | MT_LOW, MO_EXTERNAL, "External", menu_modulation_acb}, + { MT_FORM | MT_KEYPAD, KM_MODULATION, "FREQ: %s", "100Hz..6kHz"}, { MT_FORM | MT_CANCEL, 0, S_LARROW" BACK",NULL }, { MT_FORM | MT_NONE, 0, NULL, NULL } // sentinel }; @@ -1314,7 +1403,7 @@ 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, "MODULATION: %s", menu_smodulation_acb}, + { MT_FORM | MT_ADV_CALLBACK, 0, "MOD: %s", menu_smodulation_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"}, @@ -1326,7 +1415,7 @@ 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_ADV_CALLBACK, 0, "LEVEL: %+ddBm", menu_sdrive_acb}, - { MT_FORM | MT_ADV_CALLBACK, 0, "MODULATION: %s", menu_smodulation_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_CANCEL, 0, "MODE", NULL }, @@ -1427,6 +1516,7 @@ const menuitem_t menu_marker_search[] = { { MT_CALLBACK, 1, "MIN\n" S_RARROW" RIGHT", menu_marker_search_cb }, { MT_CALLBACK, 2, "MAX\n" S_LARROW" LEFT", menu_marker_search_cb }, { MT_CALLBACK, 3, "MAX\n" S_RARROW" RIGHT", menu_marker_search_cb }, + { MT_KEYPAD, KM_MARKER, "ENTER\nFREQUENCY", NULL}, { MT_ADV_CALLBACK, 0, "TRACKING",menu_marker_tracking_acb }, { MT_CANCEL, 0, S_LARROW" BACK", NULL }, { MT_NONE, 0, NULL, NULL } // sentinel @@ -1541,6 +1631,24 @@ static const menuitem_t menu_sweep_speed[] = { MT_NONE, 0, NULL, NULL } // sentinel }; +static const menuitem_t menu_settings3[] = +{ + { MT_KEYPAD, KM_10MHZ, "CORRECT\nFREQUENCY", "Enter actual l0MHz frequency"}, + { MT_KEYPAD, KM_GRIDLINES, "MINIMUM\nGRIDLINES", "Enter minimum horizontal grid divisions"}, +// { 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"}, +#ifdef __HAM_BAND__ + { MT_ADV_CALLBACK, 0, "HAM\nBANDS", menu_settings_ham_bands}, +#endif +#ifdef __ULTRA__ + { MT_SUBMENU,0, "HARMONIC", menu_harmonic}, +#endif + { MT_CANCEL, 0, S_LARROW" BACK", NULL }, + { MT_NONE, 0, NULL, NULL } // sentinel +}; + + static const menuitem_t menu_settings2[] = { { MT_ADV_CALLBACK, 0, "AGC", menu_settings_agc_acb}, @@ -1549,10 +1657,10 @@ static const menuitem_t menu_settings2[] = { MT_ADV_CALLBACK | MT_LOW, 0, "BELOW IF", menu_settings_below_if_acb}, { MT_KEYPAD, KM_DECAY, "HOLD\nSWEEPS", "1..1000 sweeps"}, { MT_KEYPAD, KM_NOISE, "NOISE\nLEVEL", "2..20 dB"}, - { MT_KEYPAD, KM_10MHZ, "CORRECT\nFREQUENCY", "Enter actual l0MHz frequency"}, #ifdef __ULTRA__ { MT_SUBMENU,0, "HARMONIC", menu_harmonic}, #endif + { MT_SUBMENU, 0, S_RARROW" MORE", menu_settings3}, { MT_CANCEL, 0, S_LARROW" BACK", NULL }, { MT_NONE, 0, NULL, NULL } // sentinel }; @@ -1570,14 +1678,22 @@ static const menuitem_t menu_settings[] = { MT_NONE, 0, NULL, NULL } // sentinel }; -static const menuitem_t menu_measure[] = { - { MT_ADV_CALLBACK, M_OFF, "OFF", menu_measure_acb}, - { MT_ADV_CALLBACK, M_IMD, "HARMONIC", menu_measure_acb}, - { MT_ADV_CALLBACK, M_OIP3, "OIP3", menu_measure_acb}, - { MT_ADV_CALLBACK, M_PHASE_NOISE,"PHASE\nNOISE", menu_measure_acb}, -// { MT_ADV_CALLBACK, M_STOP_BAND, "STOP\nBAND", menu_measure_acb}, -// { MT_ADV_CALLBACK, M_PASS_BAND, "PASS\nBAND", menu_measure_acb}, +static const menuitem_t menu_measure2[] = { // { MT_ADV_CALLBACK | MT_LOW, M_LINEARITY, "LINEAR", menu_measure_acb}, + { MT_ADV_CALLBACK, M_AM, "AM", menu_measure_acb}, + { MT_ADV_CALLBACK, M_FM, "FM", menu_measure_acb}, + { MT_CANCEL, 0, S_LARROW" BACK", NULL }, + { MT_NONE, 0, NULL, NULL } // sentinel +}; + +static const menuitem_t menu_measure[] = { + { MT_ADV_CALLBACK, M_OFF, "OFF", menu_measure_acb}, + { MT_ADV_CALLBACK, M_IMD, "HARMONIC", menu_measure_acb}, + { MT_ADV_CALLBACK, M_OIP3, "OIP3", menu_measure_acb}, + { MT_ADV_CALLBACK, M_PHASE_NOISE,"PHASE\nNOISE", menu_measure_acb}, + { MT_ADV_CALLBACK, M_STOP_BAND, "SNR", menu_measure_acb}, + { MT_ADV_CALLBACK, M_PASS_BAND, "-6dB\nWIDTH", menu_measure_acb}, + { MT_SUBMENU, 0, S_RARROW" MORE", menu_measure2}, { MT_CANCEL, 0, S_LARROW" BACK", NULL }, { MT_NONE, 0, NULL, NULL } // sentinel }; @@ -1591,12 +1707,57 @@ static const menuitem_t menu_calibrate[] = { MT_FORM | MT_NONE, 0, NULL, NULL } // sentinel }; +#ifdef __USE_SERIAL_CONSOLE__ +//19200, 38400, 57600, 74800, 115200, 230400, 460800, 921600, 1843200, 3686400 +#if 0 +const menuitem_t menu_serial_speed2[] = { + { MT_ADV_CALLBACK, USART_SPEED_SETTING( 460800), "%u", menu_serial_speed_acb }, + { MT_ADV_CALLBACK, USART_SPEED_SETTING( 921600), "%u", menu_serial_speed_acb }, + { MT_ADV_CALLBACK, USART_SPEED_SETTING(1843200), "%u", menu_serial_speed_acb }, + { MT_ADV_CALLBACK, USART_SPEED_SETTING(3686400), "%u", menu_serial_speed_acb }, + { MT_CANCEL, 0, S_LARROW" BACK", NULL }, + { MT_NONE, 0, NULL, NULL } // sentinel +}; +#endif + +const menuitem_t menu_serial_speed[] = { + { MT_ADV_CALLBACK, USART_SPEED_SETTING( 19200), "%u", menu_serial_speed_acb }, + { MT_ADV_CALLBACK, USART_SPEED_SETTING( 38400), "%u", menu_serial_speed_acb }, + { MT_ADV_CALLBACK, USART_SPEED_SETTING( 57600), "%u", menu_serial_speed_acb }, +// { MT_ADV_CALLBACK, USART_SPEED_SETTING( 76800), "%u", menu_serial_speed_acb }, + { MT_ADV_CALLBACK, USART_SPEED_SETTING(115200), "%u", menu_serial_speed_acb }, + { MT_ADV_CALLBACK, USART_SPEED_SETTING(230400), "%u", menu_serial_speed_acb }, +// { MT_SUBMENU, 0, S_RARROW" MORE", menu_serial_speed2 }, + { MT_ADV_CALLBACK, USART_SPEED_SETTING( 460800), "%u", menu_serial_speed_acb }, + { MT_ADV_CALLBACK, USART_SPEED_SETTING( 921600), "%u", menu_serial_speed_acb }, + { MT_CANCEL, 0, S_LARROW" BACK", NULL }, + { MT_NONE, 0, NULL, NULL } // sentinel +}; + +const menuitem_t menu_connection[] = { + { MT_ADV_CALLBACK, _MODE_USB, "USB", menu_connection_acb }, + { MT_ADV_CALLBACK, _MODE_SERIAL, "SERIAL", menu_connection_acb }, + { MT_SUBMENU, 0, "SERIAL\nSPEED", menu_serial_speed }, + { MT_CANCEL, 0, S_LARROW" BACK", NULL }, + { MT_NONE, 0, NULL, NULL } // sentinel +}; +#endif + +const menuitem_t menu_touch[] = { + { MT_CALLBACK, CONFIG_MENUITEM_TOUCH_CAL, "TOUCH CAL", menu_config_cb}, + { MT_CALLBACK, CONFIG_MENUITEM_TOUCH_TEST, "TOUCH TEST", menu_config_cb}, + { MT_CANCEL, 0, S_LARROW" BACK", NULL }, + { MT_NONE, 0, NULL, NULL } // sentinel +}; + static const menuitem_t menu_config[] = { - { MT_CALLBACK, 0, "TOUCH CAL", menu_config_cb}, - { MT_CALLBACK, 0, "TOUCH TEST", menu_config_cb}, - { MT_CALLBACK, 0, "SELF TEST", menu_config_cb}, - { MT_SUBMENU, 0, "LEVEL CAL", menu_calibrate}, - { MT_CALLBACK, 0, "VERSION", menu_config_cb}, + { MT_SUBMENU, 0, "TOUCH", menu_touch}, + { MT_CALLBACK, CONFIG_MENUITEM_SELFTEST, "SELF TEST", menu_config_cb}, + { MT_SUBMENU, 0, "LEVEL CAL", menu_calibrate}, + { MT_CALLBACK, CONFIG_MENUITEM_VERSION, "VERSION", menu_config_cb}, +#ifdef __USE_SERIAL_CONSOLE__ + { MT_SUBMENU, 0, "CONNECTION", menu_connection}, +#endif { MT_SUBMENU, 0, "EXPERT\nCONFIG", menu_settings}, { MT_SUBMENU, 0, S_RARROW" DFU", menu_dfu}, { MT_CANCEL, 0, S_LARROW" BACK", NULL }, @@ -1686,6 +1847,8 @@ static const menuitem_t menu_mode[] = { { MT_FORM | MT_ADV_CALLBACK | MT_ICON, I_LOW_OUTPUT+I_SINUS, "%s to LOW out", menu_mode_acb}, { MT_FORM | MT_ADV_CALLBACK | MT_ICON, I_HIGH_OUTPUT+I_GEN, "%s to HIGH out", menu_mode_acb}, { MT_FORM | MT_ADV_CALLBACK | MT_ICON, I_CONNECT+I_GEN, "Cal. output: %s", menu_sreffer_acb}, +// { MT_SUBMENU, 0, "EXPERT\nCONFIG", menu_settings3}, + #ifdef __ULTRA__ { MT_FORM | MT_CALLBACK | MT_ICON, I_LOW_INPUT+I_SA, "ULTRA HIGH INPUT",menu_mode_cb}, #endif @@ -1858,7 +2021,18 @@ static void fetch_numeric_target(void) uistat.value = setting.trigger_level; plot_printf(uistat.text, sizeof uistat.text, "%.1fdB", uistat.value); break; - + case KM_MARKER: + if (active_marker >=0) { + uistat.value = markers[active_marker].frequency; + plot_printf(uistat.text, sizeof uistat.text, "%3.3fMHz", uistat.value / 1000000.0); + } + break; + case KM_MODULATION: + if (active_marker >=0) { + uistat.value = setting.modulation_frequency; + plot_printf(uistat.text, sizeof uistat.text, "%7.0fHz", uistat.value); + } + break; } { @@ -1956,6 +2130,28 @@ set_numeric_value(void) completed = true; break; + case KM_GRIDLINES: + set_gridlines(uistat.value); + break; + case KM_MARKER: + set_marker_frequency(active_marker, (uint32_t)uistat.value); + break; + case KM_MODULATION: + set_modulation_frequency((int)uistat.value); + break; + case KM_COR_AM: + config.cor_am =(int)uistat.value; + config_save(); + break; + case KM_COR_WFM: + config.cor_wfm =(int)uistat.value; + config_save(); + break; + case KM_COR_NFM: + config.cor_nfm =(int)uistat.value; + config_save(); + break; + } } @@ -1966,3 +2162,4 @@ menu_move_top(void) menu_move_back(); } +#pragma GCC pop_options