simpleSA/ui.cpp
M0WID 1746058f31 Fixed TG CS pin define compile error
Corrected problem with CS pins floating if module installed but not initialised.
Also corrected compiler error if neither TG SI4432 defined
2020-10-09 21:14:58 +01:00

3493 lines
93 KiB
C++

/*
* "ui.cpp"
*
* This file implements the touch screen interface for the TinySA.
*
* Modifications through Version 2.5:
*
* Lots of general cleanup; removed a lot of the menu processing that was left
* over from the NanoVNA code but not used here including the "marker" and
* "calibration" stuff. For now some NanoVNA holdovers are left intact as they
* may be used in the future such as multiple "traces".
*
*
* Modifications in Version 2.6 by WA2FZW:
*
* Replaced the use of macros to define the menu items and replaced those with
* a class/object implementation; much neater!
*
*
* Modifications in Version 2.7 by WA2FZW:
*
* Eliminated the "kpf" array which contained the characters used to paint the numbers
* in the keypad keys and in the numerical input box. The "kpf" array is replaced with
* the "KP_Font" array, which contains bitmaps for the characters that make for a much
* better looking display! I also eliminated all the characters leftover from the
* NanoVNA code that aren't used here.
*/
#include <SPI.h> // SPI Bus handling library
#include "simpleSA.h"
#include "ui.h" // User interface definitions and prototypes
#include "cmd.h" // Command processing functions
#include "preferences.h" // Save/recall functions
#include <TFT_eSPI.h> // Display/Touch Screen header file
#include "menu.h" // "Menuitem" class definition
#include "marker.h" // Marker class definition
#include "si4432.h" // Si4432 class definition
extern Marker marker[MARKER_COUNT]; // Array of markers
extern void TouchCalibrate (); // Function is in "tinySA.ino"
extern char* FormatIPAddress (IPAddress ipAddress ); // Function in "TinySA_wifi.cpp"
extern IPAddress ipAddress; // Global in "tinySA.ino"
extern TFT_eSPI tft; // TFT Screen object
//extern void RedrawHisto ();
extern void menuExit();
extern void ClearDisplay ( void );
extern void DisplayError ( uint8_t severity, const char *l1, const char *l2, const char *l3, const char *l4 );
extern void SetRX ( int );
extern void setMode (uint16_t newMode);
extern int changedSetting; // Display needs updated
extern bool AGC_On; // Flag indicates if Preamp AGC is enabled
extern uint8_t AGC_Reg; // Fixed value for preampGain if not auto
extern Si4432 rcvr; // Si4432 Receiver object
extern Si4432 xmit; // Si4432 Transmitter object
#ifdef TG_IF_INSTALLED
extern Si4432 tg_if; // Si4432 Tracking Generator IF
#endif
#ifdef TG_LO_INSTALLED
extern Si4432 tg_lo; // Si4432 Tracking Generator LO
#endif
extern int VFO; // Selects transmitter or receiver Si4432
/*
* This might seem a bit weird, but I've had to do something like this in other projects!
* Sooner or later I'll figure out ir normal "true" and "false" can be used instead. As
* these are used in some of the logic that has to do with multiple traces which are not
* implemented (yet), it's impossible to tell if they can be replaced by the normal
* indicators.
*/
#define FALSE 0
#define TRUE -1
/*
* The "uistat" structure seems to contain information about the current state
* of the user interface, but I haven't figured out what the elements all mean
* yet.
*/
typedef struct {
int8_t digit; // Original comment said "0 to 5", but it gets initialized
// to '6' below!
int8_t digit_mode;
int8_t current_trace; // 0 to 3 ???
double value; // For editing at numeric input area
double previous_value;
} uistat_t;
/*
* Set the initial user interface status:
*/
uistat_t uistat = {
6, // digit - See note above
0, // digit_mode
0, // current_trace
0.0, // value
0.0 // previous_value
};
/*
* Create the "config" structure; not sure why in here and not in the main program file.
*/
config_t config;
/*
* Define the trace type structure. This is a NanoVNA holdover and needs to be eliminated,
* but for now, there are a lot of places where it is used. I'll get to it eventually!
*/
typedef struct
{
uint8_t enabled;
uint8_t type;
uint8_t channel;
uint8_t polar;
float scale;
float refpos;
} trace_t;
/*
* Then create an array of trace types (Note, "TRACE_COUNT" is currently defined as '1'
* in the "tinySA.h" file.
*/
trace_t trace[TRACE_COUNT];
/*
* These definitions are related to manipulation of the menu on the touch screen:
*/
#define NO_EVENT 0
#define EVT_BUTTON_SINGLE_CLICK 0x01
#define EVT_BUTTON_DOUBLE_CLICK 0x02
#define EVT_BUTTON_DOWN_LONG 0x04
#define EVT_UP 0x10
#define EVT_DOWN 0x20
#define EVT_REPEAT 0x40
/*
* Timing for touch screen button events:
*/
#define BUTTON_DOWN_LONG_TICKS 5000 // Original comment said 1 Second?
#define BUTTON_DOUBLE_TICKS 5000 // 500 mS
#define BUTTON_REPEAT_TICKS 1000 // 100 mS
#define BUTTON_DEBOUNCE_TICKS 200 // 20 mS
/*
* These look like timer values, but they aren't used anywhere; the code compiles
* fine with them commented out:
*/
static uint16_t last_button = 0;
static uint32_t last_button_down_ticks;
static uint32_t last_button_repeat_ticks;
static int8_t inhibit_until_release = FALSE;
/*
* Requested operations:
*/
enum { OP_NONE = 0, OP_TOUCH, OP_FREQCHANGE };
uint8_t operation_requested = OP_NONE; // No operations so far
/*
* These define the things that are entered using the keypad. The numbers are used as an
* index into the "keypad_mode_label" array which contains the strings that appear at
* the left of the numerical entry box and the "keypads_mode_tbl" in the "menu_invoke"
* function.
*/
enum { KM_START, KM_STOP, KM_CENTER, KM_SPAN, KM_FOCUS,
KM_REFPOS, KM_ATTENUATION, KM_ACTUALPOWER, KM_IFFREQ, KM_PREAMP,
KM_TUNE, KM_SGFREQ, KM_SGLEVEL, KM_SGLEVCAL, KM_IFSTART, KM_IFSTOP,
KM_IFSIG, KM_TGOFFSET, KM_TGFREQ, KM_TGLO_DRIVE, KM_TGIF_DRIVE, KM_BANDSCOPESTART,
KM_WFMIN, KM_WFGAIN, KM_BANDSCOPELEVEL, KM_RXSPAN, KM_RXSIG, KM_RBW,
KM_EXTERN };
/*
* These are the strings that appear in the numerical entry box under the keypad.
*
* The order of the labels corresponds to the "KM_" list above.
*
* WA2FZW - need to change the formatting as on some menus, the numerical entry
* box covers the "<- BACK" button.
*/
static const char * const keypad_mode_label[] =
{
"START", "STOP", "CENTER", "SPAN", "FOCUS",
"REFPOS", "ATTEN", "POWER", "IF FREQ", "PREAMP",
"XTAL CAL", "SG FREQ", "dBm", "Max dBm", "IF START", "IF STOP",
"IF Sig Freq", "TG OFFSET", "TG FREQ", "TG LO Drive", "TG IF Drive", "START",
"WF MIN", "WF GAIN", "REF LEVEL", "RX SPAN", "RX Sig Freq", "RBW",
"EXTERNAL"
};
uint8_t ui_mode = UI_NORMAL; // User interface in "NORMAL" mode for now
static uint8_t keypad_mode; // Current keypad mode
static int8_t selection = 0; // Current menu selection, I think
static int8_t last_touch_status = FALSE;
static int16_t last_touch_x;
static int16_t last_touch_y;
#define EVT_TOUCH_NONE 0 // Touch screen status condition
#define EVT_TOUCH_DOWN 1 // definitions
#define EVT_TOUCH_PRESSED 2
#define EVT_TOUCH_RELEASED 3
#define NUMINPUT_LEN 10 // Length of the mumeric input box
#define KP_CONTINUE 0 // Keypad entry status definitions
#define KP_DONE 1
#define KP_CANCEL 2
static char kp_buf[NUMINPUT_LEN+1]; // Buffer for numerical entry
static int8_t kp_index = 0; // Index to the above buffer
static uint8_t selectedMarker = 0; // Currently selected marker (default is 1st one)
static uint16_t bg = BLACK; // Background is normally black
/*
* The function prototypes are needed here as many of the functions are referenced in
* setting up the menu structure which is done outside the context of any of the
* actual program code.
*/
static void ui_mode_normal ( void );
static void ui_mode_menu ( void );
static void ui_mode_numeric ( int _keypad_mode );
static void ui_mode_keypad ( int _keypad_mode );
static void draw_menu ( void );
static void leave_ui_mode ( void );
static void erase_menu_buttons ( void );
static void ui_process_keypad ( void );
static void menu_push_submenu ( Menuitem *submenu );
static void menu_move_back ( void );
static void menu_mode_cb ( int item ); // M0WID added 3.0d
static void menu_save_cb ( int item );
static void menu_refer_cb ( int item );
static void menu_refer_cb2 ( int item );
static void menu_trace_cb ( int item ); // WA2FZW - Repurposed in Version 2.6
static void menu_format2_cb ( int item );
static void menu_format_cb ( int item );
static void menu_scale_cb ( int item );
static void menu_sweep_cb ( int item );
static void menu_IF_sweep_cb ( int item ); // M0WID added 3.0c
static void menu_RX_sweep_cb ( int item );
static void menu_recall_cb ( int item );
static void menu_version_cb (int item );
static void menu_generate_cb(int item); // WA2FZW - Added in M0WID's Version 05
// forward declarations for bandscope menu items
static void menu_BandscopeStart_cb ( int item );
static void menu_BandscopeRbw_cb ( int item );
static void menu_BandscopeSpan_cb ( int item );
static void menu_BandscopeLevel_cb ( int item );
static void menu_WaterfallMin_cb ( int item );
static void menu_WaterfallGain_cb ( int item );
static void menu_tracking_cb(int item); // M0WID - added in 3.0e
static void menu_tg_offset_cb(int item); // M0WID - added in 3.0e
static void menu_tg_frequency_cb(int item); // M0WID - added in 3.0e
static void menu_tgIF_drive_cb(int item); // M0WID - added in 3.0e
static void menu_tgLO_drive_cb(int item); // M0WID - added in 3.0e
static void menu_rbw_cb ( int item );
static void menu_dBper_cb ( int item );
static void menu_dBgain_cb (int item ); // M0WID
static void menu_autosettings_cb ( int item );
static void menu_average_cb (int item );
static void menu_spur_cb ( int item );
static void menu_actualpower_cb ( int item );
static void menu_storage_cb ( int item );
static void menu_IF_freq_cb ( int item ); // WA2FZW - Added in Version 2.5
static void menu_sig_freq_cb ( int item ); // M0WID - Added in Version 3.0a
static void menu_sig_levCal_cb ( int item ); // M0WID - Added in Version 3.0a
static void menu_sig_level_cb ( int item ); // M0WID - Added in Version 3.0b
static void menu_atten_cb ( int item ); // WA2FZW - Added in Version 2.6
static void menu_touch_cb ( int item ); // WA2FZW - Added in Version 2.6
static void menu_extern_cb ( int item ); // M0WID - added
static void KeyNumber ( int8_t key, int x, int y ); // WA2FZW - Added in Version 2.7
static void menu_tune_cb ( int item ); // WA2FZW - Added in Version 2.7
static void menu_save_config_cb ( int item ); // WA2FZW - Added in Version 2.7
static void menu_markers_cb ( int item ); // WA2FZW - Added in Version 2.7
static void menu_marker_select_cb ( int item ); // WA2FZW - Added in Version 2.9
static void menu_marker_color_cb ( int item ); // WA2FZW - Added in Version 2.9
static void StartMarkerMenu ( void ); // M0WID - push menu stack to start at marker level not root
static void StartSweepMenu ( void ); // M0WID - push menu stack to start at sweep level not root
static void StartDisplayMenu ( void ); // M0WID - push menu stack to start at display level not root
static void StartRBWMenu ( void ); // M0WID - push menu stack to start at rbw level not root
/*
* The "KN_xxx" definitions (for key number) replace the "KP_xxx" definitions
* previously used to paint the numbers on the keys and in the numerical entry
* box. I eliminated all the leftovers from the NanoVNA code that aren't used
* here.
*/
#define KN_PERIOD 10 // '.'
#define KN_MINUS 11 // '-'
#define KN_X 12 // 'X' (aka "Enter")
#define KN_K 13 // 'K' (for "Kilo")
#define KN_M 14 // 'M' (for "Mega")
#define KN_BS 15 // Backspace arrow
/*
* The "KP_Font" array contains the bitmaps for the characters used to paint the keypas
* keys and the numerical entry box. The array is indexed by the "KN_xxx" definitions
* above,
*/
uint16_t KP_Font[] = {
0x0FF0, 0x3FFC, 0x7FFE, 0x7C3E, 0xF83F, 0xF07F, 0xF07F, // '0' => index = 0
0xF0FF, 0xF0FF, 0xF1EF, 0xF1EF, 0xF3CF, 0xF3CF, 0xF78F,
0xF78F, 0xFF0F, 0xFF0F, 0xFE1F, 0x7E3E, 0x7FFE, 0x3FFC,
0x0FF0,
0x00F0, 0x01F0, 0x03F0, 0x07F0, 0x0FF0, 0x0FF0, 0x0EF0, // '1' => index = 1
0x0CF0, 0x00F0, 0x00F0, 0x00F0, 0x00F0, 0x00F0, 0x00F0,
0x00F0, 0x00F0, 0x00F0, 0x00F0, 0x00F0, 0x03FC, 0x03FC,
0x03FC,
0x0FF0, 0x3FFC, 0x7FFE, 0x7C3E, 0xF81F, 0xF00F, 0xF00F, // '2' => index = 2
0x001F, 0x003F, 0x007E, 0x00FC, 0x01F8, 0x03F0, 0x07E0,
0x0FC0, 0x1F80, 0x3F00, 0x7E00, 0xFC00, 0xFFFF, 0xFFFF,
0xFFFF,
0x0FF0, 0x3FFC, 0x7FFE, 0x7C3E, 0xF81F, 0xF00F, 0xF00F, // '3' => index = 3
0x001E, 0x003E, 0x01FC, 0x01F8, 0x01FC, 0x007E, 0x001F,
0x000F, 0xF00F, 0xF00F, 0xF81F, 0x7C3E, 0x7FFE, 0x3FFC,
0x0FF0,
0x01F8, 0x01F8, 0x03F8, 0x03F8, 0x07F8, 0x07F8, 0x0FF8, // '4' => index = 4
0x0F78, 0x1F78, 0x1E78, 0x3E78, 0x3C78, 0x7C78, 0x7878,
0xF878, 0xFFFF, 0xFFFF, 0xFFFF, 0x0078, 0x0078, 0x0078,
0x0078,
0xFFFF, 0xFFFF, 0xFFFF, 0xF000, 0xF000, 0xF000, 0xF000, // '5' => index = 5
0xF7F0, 0xFFFC, 0xFFFE, 0xFC3E, 0xF81F, 0x000F, 0x000F,
0x000F, 0x000F, 0xF00F, 0xF81F, 0x7C3E, 0x7FFE, 0x3FFC,
0x0FF0,
0x0FF0, 0x3FFC, 0x7FFE, 0x7C3E, 0xF81F, 0xF00F, 0xF000, // '6' => index = 6
0xF000, 0xF7F0, 0xFFFC, 0xFFFE, 0xFC3E, 0xF81F, 0xF00F,
0xF00F, 0xF00F, 0xF00F, 0xF81F, 0x7C3E, 0x7FFE, 0x3FFC,
0x0FF0,
0xFFFF, 0xFFFF, 0xFFFF, 0x001F, 0x003E, 0x007C, 0x00F8, // '7' => index = 7
0x01F0, 0x01E0, 0x03E0, 0x03C0, 0x07C0, 0x0780, 0x0780,
0x0F80, 0x0F00, 0x0F00, 0x0F00, 0x0F00, 0x0F00, 0x0F00,
0x0F00,
0x07E0, 0x1FF8, 0x3FFC, 0x7C3E, 0x781E, 0x781E, 0x781E, // '8' => index = 8
0x3C3C, 0x1FF8, 0x0FF0, 0x3FFC, 0x7C3E, 0x781E, 0xF00F,
0xF00F, 0xF00F, 0xF00F, 0xF81F, 0x7C3E, 0x7FFE, 0x3FFC,
0x0FF0,
0x0FF0, 0x3FFC, 0x7FFE, 0x7C3E, 0xF81F, 0xF00F, 0xF00F, // '9' => index = 9
0xF00F, 0xF00F, 0xF81F, 0x7C3F, 0x7FFF, 0x3FFF, 0x0FFF,
0x000F, 0x000F, 0xF00F, 0xF81F, 0x7C3E, 0x7FFE, 0x3FFC,
0x0FF0,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // '.' => index = KN_PERIOD
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0380, 0x07C0, 0x07C0, 0x0380,
0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // '-' => index = KN_MINUS
0x0000, 0x0000, 0x0000, 0x3FFC, 0x3FFC, 0x3FFC, 0x3FFC,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000,
0x0000, 0x0000, 0xF00F, 0x781E, 0x781E, 0x3C3C, 0x3C3C, // 'X' => index = KN_X
0x1E78, 0x1E78, 0x0FF0, 0x07E0, 0x0FF0, 0x0FF0, 0x1E78,
0x1E78, 0x3C3C, 0x3C3C, 0x781E, 0x781E, 0xF00F, 0x0000,
0x0000,
0xF01F, 0xF03E, 0xF07C, 0xF0F8, 0xF1F0, 0xF3E0, 0xF7C2, // 'K' => index = KN_K
0xFF80, 0xFF00, 0xFE00, 0xFC00, 0xFC00, 0xFE00, 0xFF00,
0xFFC0, 0xF7E0, 0xF3F0, 0xF1F0, 0xF0F8, 0xF07E, 0xF03F,
0xF01F,
0xF00F, 0xF00F, 0xF81F, 0xF81F, 0xFC3F, 0xFC3F, 0xFE7F, // 'M' => index = KN_M
0xFE7F, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xF7EF, 0xF7EF,
0xF3CF, 0xF3CF, 0xF18F, 0xF18F, 0xF00F, 0xF00F, 0xF00F,
0xF00F,
0x0000, 0x0000, 0x0040, 0x00C0, 0x01C0, 0x03C0, 0x07C0, // Backspace arrow => index = KN_BS
0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF, 0x7FFF, 0x3FFF,
0x1FFF, 0x0FFF, 0x07C0, 0x03C0, 0x01C0, 0x00C0, 0x0040,
0x0000
};
/*
* Define the actual menu item text and associated callback functions for all the menus.
*
* Modified in Version 2.6 by WA2FZW:
*
* Replaced all the "MENUITEM_xxxx" macros with the "Menuitem" class/object implementation.
* This not only affects the menu definitions, but how things are handled throughout the
* module.
*
* Note, that while it would be nice to have the main menu at the top of the list followed
* by any sub-menus, the compiler doesn't like that. The sub-menus have to be defined before
* they are referenced in a higher level menu. This was also the case with the original
* macro implementation.
*/
static Menuitem menu_mode[] = // Select mode menu
{
Menuitem ( MT_FUNC, "\2SWEEP\0LOW", menu_mode_cb ),
Menuitem ( MT_FUNC, "\2SIG\0GEN", menu_mode_cb ),
Menuitem ( MT_FUNC, "\2BAND\0SCOPE",menu_mode_cb ),
Menuitem ( MT_FUNC, "\2IF\0SWEEP", menu_mode_cb ),
Menuitem ( MT_FUNC, "\2RX\0SWEEP", menu_mode_cb ),
Menuitem ( MT_BACK, "<-BACK" ), // Next level up
Menuitem ( MT_END ) // End marker
};
static Menuitem menu_average[] = // Enables averaging and sets value
{
Menuitem ( MT_FUNC, "OFF", menu_average_cb ), // No averaging
Menuitem ( MT_FUNC, "MIN", menu_average_cb ), // Not sure about
Menuitem ( MT_FUNC, "MAX", menu_average_cb ), // These two
Menuitem ( MT_FUNC, " 2 ", menu_average_cb ), // Divide by 2
Menuitem ( MT_FUNC, " 4 ", menu_average_cb ), // By 4
Menuitem ( MT_FUNC, " 8 ", menu_average_cb ), // By 8
Menuitem ( MT_BACK, "<-BACK" ), // Next level up
Menuitem ( MT_END ) // End marker
};
static Menuitem menu_storage[] = // Sweep storage options
{
Menuitem ( MT_FUNC, "STORE", menu_storage_cb ), // Save current sweep
Menuitem ( MT_FUNC, "CLEAR", menu_storage_cb ), // Erase saved sweep
Menuitem ( MT_FUNC, "SUBTRACT", menu_storage_cb ), // Not sure what this does!
Menuitem ( MT_BACK, "<-BACK" ), // Next level up
Menuitem ( MT_END ) // End marker
};
static Menuitem menu_generate[] = // Frequency generator mode
{
// Menuitem ( MT_FUNC, "OFF", menu_generate_cb ),
Menuitem ( MT_FUNC, "ON", menu_generate_cb ),
Menuitem ( MT_BACK, "<-BACK" ), // Next level up
Menuitem ( MT_END ) // End marker
};
#ifdef TG_IF_INSTALLED
static Menuitem menu_tracking[] = // Tracking generator mode
{
Menuitem ( MT_FUNC, "OFF", menu_tracking_cb ),
Menuitem ( MT_FUNC, "ON", menu_tracking_cb ),
#ifdef TG_LO_INSTALLED
Menuitem ( MT_FUNC, "GENERATE", menu_tracking_cb ),
Menuitem ( MT_FUNC, "FREQUENCY",menu_tg_frequency_cb ),
Menuitem ( MT_FUNC, "OFFSET", menu_tg_offset_cb ),
Menuitem ( MT_FUNC, "\2LO\0DRIVE", menu_tgLO_drive_cb ),
#endif
Menuitem ( MT_FUNC, "\2IF\0DRIVE", menu_tgIF_drive_cb ),
Menuitem ( MT_BACK, "<-BACK" ), // Next level up
Menuitem ( MT_END ) // End marker
};
#endif
static Menuitem menu_spur[] = // Turn spurious suppression on or off
{
Menuitem ( MT_FUNC, "OFF", menu_spur_cb ),
Menuitem ( MT_FUNC, "ON", menu_spur_cb ),
Menuitem ( MT_BACK, "<-BACK" ), // Next level up
Menuitem ( MT_END ) // End marker
};
static Menuitem menu_rbw[] = // Resolution bandwidth settings
{
Menuitem ( MT_FUNC, " AUTO", menu_rbw_cb ), // In auto mode, there are many
Menuitem ( MT_FUNC, " 3kHz", menu_rbw_cb ), // more available settings that
Menuitem ( MT_FUNC, " 10kHz", menu_rbw_cb ), // are roughly the sweep range
Menuitem ( MT_FUNC, " 30kHz", menu_rbw_cb ), // divided by 300.
Menuitem ( MT_FUNC, "100kHz", menu_rbw_cb ),
Menuitem ( MT_FUNC, "300kHz", menu_rbw_cb ),
Menuitem ( MT_BACK, "<-BACK" ), // Next level up
Menuitem ( MT_END ) // End marker
};
static Menuitem menu_dBper[] = // Scale setting menu
{
Menuitem ( MT_FUNC, " 1dB/", menu_dBper_cb ),
Menuitem ( MT_FUNC, " 2dB/", menu_dBper_cb ),
Menuitem ( MT_FUNC, " 5dB/", menu_dBper_cb ),
Menuitem ( MT_FUNC, " 10dB/", menu_dBper_cb ),
Menuitem ( MT_FUNC, " 20dB/", menu_dBper_cb ),
Menuitem ( MT_BACK, "<-BACK" ), // Next level up
Menuitem ( MT_END ) // End marker
};
/*
* Menu to set the gain overide register (REG_AGCOR 0x69) in the SI4432 transceiver.
* See app note AN440 for the full explanation.
*
* Modified in Version 2.6 by WA2FZW:
*
* The original code had set values in a sub-menu. Now we use the keypad to set
* any value one likes!. But here are rules! See the documentation for the
* explanation.
*/
static Menuitem menu_dBgain[] =
{
Menuitem ( MT_FUNC, "AGC ON", menu_dBgain_cb ), //0x60
Menuitem ( MT_FUNC, "\2SET\0VALUE", menu_dBgain_cb ), //Set actual value
Menuitem ( MT_BACK, "<-BACK" ), // Next level up
Menuitem ( MT_END ) // End marker
};
static Menuitem menu_save[] = // Setting save options
{
Menuitem ( MT_FUNC, "SAVE 0", menu_save_cb ), // This works like the NanoVNA
Menuitem ( MT_FUNC, "SAVE 1", menu_save_cb ), // where you an save a number of
Menuitem ( MT_FUNC, "SAVE 2", menu_save_cb ), // different configurations
Menuitem ( MT_FUNC, "SAVE 3", menu_save_cb ),
Menuitem ( MT_FUNC, "SAVE 4", menu_save_cb ),
Menuitem ( MT_BACK, "<-BACK" ), // Next level up
Menuitem ( MT_END ) // End marker
};
static Menuitem menu_recall[] = // For recalling saved configurations
{
Menuitem ( MT_FUNC, "RECALL 0", menu_recall_cb ),
Menuitem ( MT_FUNC, "RECALL 1", menu_recall_cb ),
Menuitem ( MT_FUNC, "RECALL 2", menu_recall_cb ),
Menuitem ( MT_FUNC, "RECALL 3", menu_recall_cb ),
Menuitem ( MT_FUNC, "RECALL 4", menu_recall_cb ),
Menuitem ( MT_BACK, "<-BACK" ), // Next level up
Menuitem ( MT_END ) // End marker
};
static Menuitem menu_save_recall[] = // Save or recall options
{
Menuitem ( MT_MENU, "SAVE", menu_save ), // Show save options
Menuitem ( MT_MENU, "RECALL", menu_recall ), // Show recall options
Menuitem ( MT_BACK, "<-BACK" ), // Next level up
Menuitem ( MT_END ) // End marker
};
int menu_refer_value[] = { -1, 0, 1, 2, 3, 4, 5, 6 }; // Actual values for the register
static Menuitem menu_refer2[] = // Part 2 of the reference values
{
Menuitem ( MT_FUNC, "3MHz", menu_refer_cb2 ),
Menuitem ( MT_FUNC, "2MHz", menu_refer_cb2 ),
Menuitem ( MT_FUNC, "1MHz", menu_refer_cb2 ),
Menuitem ( MT_BACK, "<-BACK" ), // Next level up
Menuitem ( MT_END ) // End marker
};
static Menuitem menu_refer[] = // GPIO2 reference frequency values
{
Menuitem ( MT_FUNC, "OFF", menu_refer_cb ),
Menuitem ( MT_FUNC, "30MHz", menu_refer_cb ),
Menuitem ( MT_FUNC, "15MHz", menu_refer_cb ),
Menuitem ( MT_FUNC, "10MHz", menu_refer_cb ),
Menuitem ( MT_FUNC, "4MHz", menu_refer_cb ),
Menuitem ( MT_MENU, " MORE->", menu_refer2 ),
Menuitem ( MT_BACK, "<-BACK" ), // Next level up
Menuitem ( MT_END ) // End marker
};
static Menuitem menu_traces[] = // Toggle display traces on and off
{
Menuitem ( MT_FUNC, "\2dB\0On/Off", menu_trace_cb ),
Menuitem ( MT_FUNC, "\2GAIN\0On/Off", menu_trace_cb ),
Menuitem ( MT_MENU, "AVERAGE", menu_average ), // The sub menu allows values to be set
Menuitem ( MT_BACK, "<-BACK" ), // Next level up
Menuitem ( MT_END ) // End marker
};
static Menuitem menu_select_marker[] =
{
Menuitem ( MT_FUNC, "MKR #1", menu_marker_select_cb ),
Menuitem ( MT_FUNC, "MKR #2", menu_marker_select_cb ),
Menuitem ( MT_FUNC, "MKR #3", menu_marker_select_cb ),
Menuitem ( MT_FUNC, "MKR #4", menu_marker_select_cb ),
Menuitem ( MT_BACK, "<-BACK" ), // Next level up
Menuitem ( MT_END ) // End marker
};
static Menuitem menu_marker_color[] =
{
Menuitem ( MT_FUNC, "WHITE", menu_marker_color_cb ),
Menuitem ( MT_FUNC, "RED", menu_marker_color_cb ),
Menuitem ( MT_FUNC, "BLUE", menu_marker_color_cb ),
Menuitem ( MT_FUNC, "GREEN", menu_marker_color_cb ),
Menuitem ( MT_FUNC, "YELLOW", menu_marker_color_cb ),
Menuitem ( MT_FUNC, "ORANGE", menu_marker_color_cb ),
Menuitem ( MT_BACK, "<-BACK" ), // Next level up
Menuitem ( MT_END ) // End marker
};
static Menuitem menu_markers[] =
{
Menuitem ( MT_MENU, "\2SELECT\0MARKER", menu_select_marker ),
Menuitem ( MT_MENU, "\2SELECT\0COLOR", menu_marker_color ),
Menuitem ( MT_FUNC, "\2ENABLE/\0DISABLE", menu_markers_cb ),
Menuitem ( MT_FUNC, "\2ENABLE\0ALL", menu_markers_cb ),
Menuitem ( MT_FUNC, "\2DISABLE\0ALL", menu_markers_cb ),
Menuitem ( MT_BACK, "<-BACK" ), // Next level up
Menuitem ( MT_END ) // End marker
};
static Menuitem menu_display[] = // Display menu
{
Menuitem ( MT_MENU, "TRACES", menu_traces ), // Turn display traces on and off
Menuitem ( MT_MENU, "\2PREAMP\0GAIN", menu_dBgain ), // Set preamp gain
Menuitem ( MT_FUNC, "\2REF\0LEVEL", menu_scale_cb ), // Set top line of the grid
Menuitem ( MT_MENU, "dB/DIV", menu_dBper ), // Menu to set vertical grid scale
Menuitem ( MT_MENU, "\2SPUR\0REDUCTION", menu_spur ), // Enable or disable spur reduction
Menuitem ( MT_FUNC, "\2DEFAULT\0SETTINGS",menu_autosettings_cb ),
Menuitem ( MT_BACK, "<-BACK" ), // Next level up
Menuitem ( MT_END ) // End marker
};
static Menuitem menu_sweep2[] =
{
Menuitem ( MT_MENU, "RBW", menu_rbw ), // Set the resolution bandwidth
Menuitem ( MT_FUNC, "ATTEN", menu_atten_cb ), // Set the attenuation
Menuitem ( MT_FUNC, "EXTERN", menu_extern_cb ), // Set the external gain
Menuitem ( MT_MENU, "MARKERS", menu_markers ), // Marker sub menu
Menuitem ( MT_BACK, "<-BACK" ), // Next level up
Menuitem ( MT_END ) // End marker
};
static Menuitem menu_sweep[] = // This is the main "SWEEP" menu
{
Menuitem ( MT_FUNC, "\2SWEEP\0START", menu_sweep_cb ),
Menuitem ( MT_FUNC, "\2SWEEP\0STOP", menu_sweep_cb ),
Menuitem ( MT_FUNC, "\2SWEEP\0CENTER", menu_sweep_cb ),
Menuitem ( MT_FUNC, "\2SWEEP\0SPAN", menu_sweep_cb ),
Menuitem ( MT_FUNC, "\2FOCUS\0FREQ", menu_sweep_cb ),
Menuitem ( MT_MENU, "MORE->", menu_sweep2 ), // Additional options above
Menuitem ( MT_BACK, "<-BACK" ), // Next level up
Menuitem ( MT_END ) // End marker
};
static Menuitem menu_output[] = // The "OUTPUT" menu
{
Menuitem ( MT_MENU, "REFERENCE", menu_refer ), // Select GPIO2 reference frequency
Menuitem ( MT_FUNC, "GENERATOR", menu_generate_cb ), // Turn generator mode on or off
#ifdef TG_IF_INSTALLED
Menuitem ( MT_MENU, "TRACKING", menu_tracking ), // Tracking generator control
#endif
Menuitem ( MT_BACK, "<-BACK" ), // Next level up
Menuitem ( MT_END ) // End marker
};
static Menuitem menu_touchscreen[] =
{
Menuitem ( MT_FUNC, "\2TOUCH\0CAL", menu_touch_cb ), // Calibrate touch screen
Menuitem ( MT_FUNC, "\2TOUCH\0TEST", menu_touch_cb ), // Test touch screen calibration
Menuitem ( MT_BACK, "<-BACK" ), // Next level up
Menuitem ( MT_END ) // End marker
};
/*
* WA2FZW - Still to do - Add items to do the frequency calibrations.
*/
static Menuitem menu_calibrate[] =
{
Menuitem ( MT_FUNC, "TX FREQ", menu_tune_cb ),
Menuitem ( MT_FUNC, "RX FREQ", menu_tune_cb ),
Menuitem ( MT_FUNC, "\2ACTUAL\0POWER", menu_actualpower_cb ), // Calibrate power setting
Menuitem ( MT_BACK, "<-BACK" ), // Next level up
Menuitem ( MT_END ) // End marker
};
static Menuitem menu_config[] = // The "CONFIG" menu
{
Menuitem ( MT_MENU, "CALIBRATE", menu_calibrate ), // Calibration menu
Menuitem ( MT_MENU, "\2TOUCH\0SCREEN", menu_touchscreen ), // Calibrate & test the touch screen
Menuitem ( MT_FUNC, "\2IF\0FREQ", menu_IF_freq_cb ), // Set the IF frequency
Menuitem ( MT_FUNC, "\2SAVE\0CONFIG", menu_save_config_cb ), // Save "config" structure
Menuitem ( MT_FUNC, "VERSION", menu_version_cb ), // Display "About" information
Menuitem ( MT_BACK, "<-BACK" ), // Next level up
Menuitem ( MT_END ) // End marker
};
static Menuitem menu_sig_gen[] = // The "CONFIG" menu
{
Menuitem ( MT_MENU, "MODE", menu_mode ),
Menuitem ( MT_FUNC, "\2SET\0FREQ", menu_sig_freq_cb ), // Set the output frequency
Menuitem ( MT_FUNC, "\2SET\0dBm", menu_sig_level_cb ), // Set the output level
Menuitem ( MT_FUNC, "\2CAL\0dBm", menu_sig_levCal_cb ), // Calibrate the sig gen output level
Menuitem ( MT_END ) // End marker
};
static Menuitem menu_IFsweep_top[] = // This is the main "IF_SWEEP" menu
{
Menuitem ( MT_MENU, "MODE", menu_mode ),
Menuitem ( MT_FUNC, "\2SWEEP\0START", menu_IF_sweep_cb ),
Menuitem ( MT_FUNC, "\2SWEEP\0STOP", menu_IF_sweep_cb ),
Menuitem ( MT_FUNC, "\2SWEEP\0SIG", menu_IF_sweep_cb ),
Menuitem ( MT_MENU, "REFERENCE", menu_refer ), // Select GPIO2 reference frequency
Menuitem ( MT_END ) // End marker
};
static Menuitem menu_RXsweep_top[] = // This is the main "IF_SWEEP" menu
{
Menuitem ( MT_MENU, "MODE", menu_mode ),
Menuitem ( MT_FUNC, "\2SWEEP\0SPAN", menu_RX_sweep_cb ),
Menuitem ( MT_FUNC, "\2SWEEP\0SIG", menu_RX_sweep_cb ),
Menuitem ( MT_FUNC, "RBW", menu_RX_sweep_cb ),
Menuitem ( MT_MENU, "REFERENCE", menu_refer ), // Select GPIO2 reference frequency
Menuitem ( MT_END ) // End marker
};
static Menuitem menu_BandscopeSpan[] = // Badscope Span settings
{
Menuitem ( MT_FUNC, "200kHz", menu_BandscopeSpan_cb ),
Menuitem ( MT_FUNC, "400kHz", menu_BandscopeSpan_cb ),
Menuitem ( MT_BACK, "<-BACK" ), // Next level up
Menuitem ( MT_END ) // End marker
};
static Menuitem menu_BandscopeRBW[] = // Resolution bandwidth settings
{
Menuitem ( MT_FUNC, "2.6kHz", menu_BandscopeRbw_cb ), // In auto mode, there are many
Menuitem ( MT_FUNC, "2.8kHz", menu_BandscopeRbw_cb ), // more available settings that
Menuitem ( MT_FUNC, "3.1kHz", menu_BandscopeRbw_cb ), // are roughly the sweep range
Menuitem ( MT_FUNC, "3.7kHz", menu_BandscopeRbw_cb ), // divided by 300.
Menuitem ( MT_FUNC, "4.2kHz", menu_BandscopeRbw_cb ),
Menuitem ( MT_FUNC, "5.4kHz", menu_BandscopeRbw_cb ),
Menuitem ( MT_BACK, "<-BACK" ), // Next level up
Menuitem ( MT_END ) // End marker
};
static Menuitem menu_Bandscope_top[] = // This is the main "IF_SWEEP" menu
{
Menuitem ( MT_MENU, "MODE", menu_mode ),
Menuitem ( MT_FUNC, "\2SWEEP\0START", menu_BandscopeStart_cb ),
Menuitem ( MT_MENU, "\2SWEEP\0SPAN", menu_BandscopeSpan ),
Menuitem ( MT_MENU, "RBW", menu_BandscopeRBW ),
Menuitem ( MT_FUNC, "\2REF\0LEVEL", menu_BandscopeLevel_cb ), // Set top line of the grid
Menuitem ( MT_FUNC, "\2W'FALL\0MIN", menu_WaterfallMin_cb ),
Menuitem ( MT_FUNC, "\2W'FALL\0GAIN", menu_WaterfallGain_cb ),
Menuitem ( MT_END ) // End marker
};
/*
* And last but not least the main menu!
*/
static Menuitem menu_top[] =
{
Menuitem ( MT_MENU, "MODE", menu_mode ),
Menuitem ( MT_MENU, "SWEEP", menu_sweep ),
Menuitem ( MT_MENU, "DISPLAY", menu_display ),
Menuitem ( MT_MENU, "STORAGE", menu_storage ),
Menuitem ( MT_MENU, "OUTPUT", menu_output ),
Menuitem ( MT_MENU, "\2SAVE/\0RECALL", menu_save_recall ),
Menuitem ( MT_MENU, "CONFIG", menu_config ),
Menuitem ( MT_END ) // End marker
};
static uint8_t menu_current_level = 0; // Current level (MAIN)
static Menuitem *menu_stack[MENU_STACK_DEPTH] = // Initialize the stack
{ menu_top, // Main menu is on top
NULL, // These get set as we
NULL, // go along
NULL
};
/*
* Some definitions and more variables associated with the menu handling:
*/
#define OFFSETX 15 // "X" offset (from what?)
#define OFFSETY 0 // "Y" offset
/*
* Menu handling functions:
*/
static int touch_check ( void );
static void touch_wait_release ( void ) // Wait for touch screen release
{
int tstatus;
do
{
tstatus = touch_check (); // Check the touch screen status
} while ( tstatus != EVT_TOUCH_RELEASED ); // Loop until released
}
static int touch_status ( void ) // Get the touch screen status
{
return ( tft.getTouchRawZ() > TS_MINIMUM_Z ); // "RawZ" is a measure of touch pressure
}
#define RAWERR 20 // Deadband error allowed in successive position samples
/*
* "validTouch" - Added by M0WID in Version 05:
*
* Adds a lot of checking to make sure that the user actually intended to touch
* something as opposed to a shaky-hand touch!
*
* WA2FZW - Why use the un-calibrated touch values here and the convert them
* to calibrated values in "getTouch"?
*/
uint8_t validTouch ( uint16_t *x, uint16_t *y, uint16_t threshold )
{
uint16_t x_tmp, y_tmp; // "X" and "Y coordinates
static uint16_t x_tmp2, y_tmp2; // Second "X" and "Y coordinates
/*
* Wait until pressure stops increasing to debounce pressure, but only?
*/
uint16_t z1 = 1;
uint16_t z2 = 0;
while ( z1 > z2 )
{
z2 = z1; // Old pressure = last pressure
z1 = tft.getTouchRawZ (); // Read new pressure
if ( z1 <= threshold ) // return immediately
return false;
}
// Serial.print ( "Z = " ); Serial.println ( z1 ); // Debugging
if ( z1 <= threshold ) // If pressure less than the specified threshold
return false; // It's not a valid touch
// x_tmp2 = x_tmp; // Save values from last scan
// y_tmp2 = y_tmp;
tft.getTouchRaw ( &x_tmp, &y_tmp ); // Get touch coordinates
// Serial.print ( "Sample 1 x,y = " ); // Debugging
// Serial.print ( x_tmp );
// Serial.print ( "," );
// Serial.print ( y_tmp );
// Serial.print ( "Z = " );
// Serial.println ( z1 );
delayMicroseconds ( 1000 ); // Small delay to the next sample
if ( tft.getTouchRawZ() <= threshold ) // Threshold not met?
return false; // Then not a valid touch
delayMicroseconds ( 1000 ); // Small delay to the next sample
tft.getTouchRaw ( &x_tmp2, &y_tmp2 ); // Get 2nd set of coordinates
// Serial.print ( "Sample 2 x,y = " ); // More debugging
// Serial.print ( x_tmp2 );
// Serial.print ( ", " );
// Serial.println ( y_tmp2 );
// Serial.print ( "Sample difference = " );
// Serial.print ( abs ( x_tmp - x_tmp2 ));
// Serial.print ( "," );
// Serial.println ( abs (y_tmp - y_tmp2 ));
if ( abs ( x_tmp - x_tmp2 ) > RAWERR ) // Error limit exceeded?
return false; // Then invalid touch
if ( abs (y_tmp - y_tmp2 ) > RAWERR ) // Same check for "Y" values
return false;
*x = x_tmp; // Set good
*y = y_tmp; // Coordinates
return true; // And indicate valid touch
}
/*
* "getTouch" - Added by M0WID in Version 05:
*
* Replaces the TFT_eSPI library function. Returns false if not a valid touch.
* If it is a valid touch, the calibrated x and y values returned in the
* arguments.
*/
#define RELEASE_COUNT 10
#define PRESS_COUNT 3
uint8_t getTouch ( uint16_t *x, uint16_t *y )
{
uint16_t x_tmp, y_tmp; // Temporary touch coordinates
static unsigned long pressTime;
static int lastState;
static uint16_t threshold = TS_MINIMUM_Z;
uint8_t n;
if ( lastState )
{
threshold = 50; // Change threshold limit if valid to provide hysteresis
n = RELEASE_COUNT; // Need this no of not pressed read results to return not pressed
}
else
{
threshold = TS_MINIMUM_Z; // Higher limit to indicate pressed
n = PRESS_COUNT; // Lower number of counts needed
}
int valid = 0; // Non zero if valid touch seen
while ( n-- )
{
if ( validTouch ( &x_tmp, &y_tmp, threshold ))
valid++; // WA2FZW - Removed extra semicolon
else
valid--; // M0WID - add check that it is really released
}
// Serial.printf ( "last %i valid %i\n", lastState, valid );
if (( lastState && (valid <= -RELEASE_COUNT+1)) || (!lastState && (valid < PRESS_COUNT-1))) // Not a valid touch
{
// pressTime = 0; // Time = '0'
lastState = false;
return false; // Indicate invalid touch
}
/*
* If we get this far touch is valid
*/
// pressTime = millis() + 50; // Debounce?
tft.convertRawXY ( &x_tmp, &y_tmp ); // Calibrate the readings
if ( x_tmp >= tft.width () || y_tmp >= tft.height ()) // Off the chart?
{
lastState = false;
return false; // Then bad touch
}
*x = x_tmp; // Set return values
*y = y_tmp;
lastState = true;
return true; // Indicate touch is valid
}
static int touch_check ( void ) // Check for TS touched
{
uint16_t x = 0; // Used to store the "X" and
uint16_t y = 0; // "Y" coordinates
int stat = getTouch ( &x, &y ); // Read the touch screen
// Serial.printf ( "TouchCheck stat=%i, x=%i, y=%i \n", stat, x, y ); // Debugging
if ( stat ) // Valid touch if non-zero
{
last_touch_x = x; // Save coordinates for ???
last_touch_y = y;
}
if ( stat != last_touch_status ) // Did the status change?
{
last_touch_status = stat; // Yes make new status old
if ( stat ) // If non-zero screen was touched
return EVT_TOUCH_PRESSED; // Indicate that fact
else
return EVT_TOUCH_RELEASED;
}
else // Status didn't change
{
if ( stat ) // If non-zero
return EVT_TOUCH_DOWN; // Must still be touched
else // If "stat" is zero
return EVT_TOUCH_NONE; // Nothing happening!
}
}
/*
* "DrawString" - Paint a character in a specified size and color:
*
* "t" The character
* "x & y" Coordinates
* "tc" Text color
* "size" Font size
*
* Modified in Version 2.2 by WA2FZW:
*
* Changed the name from "DrawStringSize" to "DrawString" and eliminated the
* "DrawString_5x7" function and replaced all calls to that with calls to this one.
*
* Eliminated the "bc" (background color) argument, so everything displays with
* a transparent background.
*/
void DrawString ( const char *t, int x, int y, int tc, int size )
{
//Serial.println ( t ); // Debugging
tft.setCursor ( x, y ); // Set location
tft.setTextColor ( tc ); // Set text color
tft.setTextSize ( size ); // and font size
tft.print ( t ); // Paint the character
}
/*
* "touch_cal_exec" - Runs the calibration procedure built into the "TFT_eSPI"
* library.
*/
void touch_cal_exec ( void )
{
TouchCalibrate (); // Function is in "tinySA.cpp"
}
/*
* "touch_position" returns the calibrated x/y value corrected for screen rotation setting
* when using the "ESP_eSPI" library.
*/
void touch_position ( int *x, int *y )
{
*x = last_touch_x;
*y = last_touch_y;
// Serial.print ( "TP = " );
// Serial.print ( *x );
// Serial.print ( ", " );
// Serial.println ( *y );
}
/*
* "touch_draw_test" lets you scribble on the display
*/
void touch_draw_test ( void )
{
int status; // Touch screen status
int x0, y0; // Point '0'
int x1, y1; // Point '1'
tft.fillRect ( 0, 0, 320, 240, 0 ); // Fade to black
DrawString ( "TOUCH TEST: DRAG PANEL", OFFSETX, 233, WHITE, 1 );
do
{
status = touch_check();
} while ( status != EVT_TOUCH_PRESSED );
touch_position ( &x0, &y0 );
do
{
status = touch_check ();
touch_position ( &x1, &y1 );
tft.drawLine ( x0, y0, x1, y1, WHITE );
x0 = x1;
y0 = y1;
} while ( status != EVT_TOUCH_RELEASED );
}
void ShowVersion ( void )
{
char ipBuff[60]; // To format IP address
ShowSplash (); // Like "Help - About"
tft.setTextDatum ( TC_DATUM ); // Top center text position datum
sprintf ( ipBuff, "IP address %s", FormatIPAddress ( ipAddress ));
tft.drawString ( ipBuff, 160, 140 );
tft.setTextDatum ( TL_DATUM ); // Back to default top left
while ( true )
{
if ( touch_check () == EVT_TOUCH_PRESSED ) // Wait for screen to be touched
break; // And bail out
}
}
/*
* "ShowSplash" displays a screen like a "Help - About" screen
*/
void ShowSplash ( void )
{
ClearDisplay (); // Fade to black!
tft.setTextDatum ( TC_DATUM ); // Top center text position datum
tft.setTextColor ( MAGENTA );
tft.setFreeFont ( &FreeSerifBoldItalic18pt7b ); // Select Free Serif 9 point font
tft.drawString ( "simpleSA for ESP32", 160, 20 );
tft.setTextColor ( WHITE );
tft.setFreeFont ( &FreeSansBold9pt7b ); // Select Free Serif 9 point font
tft.drawString ( "By WA2FZW, M0WID,", 160, 60 );
tft.drawString ( "VK3PE and G3ZQC", 160, 80 );
tft.drawString ( PROGRAM_VERSION, 160, 100 );
tft.drawString ( "Original tinySA by Erik (PD0EK)", 160, 120 );
tft.setTextDatum ( TL_DATUM ); // Back to default top left
tft.setCursor ( 0, 120 ); // Position cursor for any more messages
tft.setFreeFont ( NULL ); // Select default font
}
void enter_dfu(void) {} // Do nothing function
void request_to_redraw_grid() // Clear the display and update
{
ClearDisplay ();
changedSetting = true;
menuExit(); // Handle the return from the menu
// RedrawHisto ();
}
void draw_frequencies() {} // Do nothing
/*
* "menu_mode_cb" - handles the process of setting the operating mode
*/
void menu_mode_cb ( int item )
{
switch ( item )
{
case 0: // Set Sweep low range
setMode(SA_LOW_RANGE);
ui_mode_normal (); // No menu displayed
break;
case 1: // Set Signal Generator
setMode(SIG_GEN_LOW_RANGE);
ui_mode_normal (); // No menu displayed
break;
case 2: // Set IF Sweep mode
setMode(BANDSCOPE);
ui_mode_normal (); // No menu displayed
break;
case 3: // Set IF Sweep mode
setMode(IF_SWEEP);
ui_mode_normal (); // No menu displayed
break;
case 4: // Set RX Sweep mode
setMode(RX_SWEEP);
ui_mode_normal (); // No menu displayed
break;
}
changedSetting = true;
}
/*
* "menu_save_config_cb" - Saves the "config" structure (for use after calibration)
*/
void menu_save_config_cb ( int item )
{
WriteConfig (); // Simple enough!
menu_move_back();
ui_mode_normal();
}
/*
* "menu_tune_cb" - handles the process of calibrating frequencies of the Si4432
* modules. See the documentation for an explanation of how to perform the calibration.
*/
void menu_tune_cb ( int item )
{
switch ( item )
{
case 0: // Calibrate TX
VFO = TX_4432; // Select transmitter module
break;
case 1: // Calibrate RX
VFO = RX_4432; // Select receiver module
break;
}
int km = KM_TUNE;
ui_mode_keypad ( km );
ui_process_keypad ();
}
void menu_marker_color_cb ( int item )
{
char colors[6] = { 'W', 'R', 'B', 'G', 'Y', 'O' };
UpdateMarker ( selectedMarker, colors[item] );
draw_menu ();
menu_move_back();
}
void menu_marker_select_cb ( int item )
{
selectedMarker = item;
draw_menu ();
menu_move_back();
}
/*
* "menu_markers_cb" - Turn markers on or off
*/
void menu_markers_cb ( int item )
{
switch ( item )
{
case 0: // Now handled by "menu_marker_select_cb"
break; // So do othing
case 2: // Toggle the currently selected marker
marker[selectedMarker].Toggle();
draw_menu ();
break;
case 3: // Turn them all on
for ( int i = 0; i < MARKER_COUNT; i++ )
marker[i].Enable();
ui_mode_normal();
break;
case 4: // Turn them all off
for ( int i = 0; i < MARKER_COUNT; i++ )
marker[i].Disable();
ui_mode_normal();
break;
}
for ( int i = 0; i < MARKER_COUNT; i++ )
setting.MkrStatus[i] = marker[i].Status ();
WriteSettings ();
}
/*
* "menu_IF_freq_cb" - Handles setting the IF Frequency
*/
void menu_IF_freq_cb ( int item )
{
int km = KM_IFFREQ;
ui_mode_keypad ( km );
ui_process_keypad ();
}
/*
* "menu_sig_freq_cb" - Handles setting the signal generator Frequency
*/
void menu_sig_freq_cb ( int item )
{
int km = KM_SGFREQ;
tft.fillScreen ( bg );
ui_mode_keypad ( km );
ui_process_keypad ();
}
/*
* "menu_sig_level_cb" - Handles setting the signal generator output level
*/
void menu_sig_level_cb ( int item )
{
int km = KM_SGLEVEL;
tft.fillScreen ( bg );
ui_mode_keypad ( km );
ui_process_keypad ();
}
/*
* "menu_sig_levCal_cb" - Handles setting the signal generator max level (no attenuation)
*/
void menu_sig_levCal_cb ( int item )
{
int km = KM_SGLEVCAL;
tft.fillScreen ( bg );
ui_mode_keypad ( km );
ui_process_keypad ();
}
/*
* "menu_tg_offset_cb" - Handles setting the tracking generator offset from SA IF
*/
void menu_tg_offset_cb ( int item )
{
int km = KM_TGOFFSET;
tft.fillScreen ( bg );
ui_mode_keypad ( km );
ui_process_keypad ();
}
/*
* "menu_tg_frequency_cb" - Handles setting the tracking generator frequency when in sig gen mode
*/
void menu_tg_frequency_cb ( int item )
{
int km = KM_TGFREQ;
tft.fillScreen ( bg );
ui_mode_keypad ( km );
ui_process_keypad ();
}
/*
* "menu_tgIF_drive_cb" - Handles setting the tracking generator IF drive
*/
void menu_tgIF_drive_cb ( int item )
{
int km = KM_TGIF_DRIVE;
tft.fillScreen ( bg );
ui_mode_keypad ( km );
ui_process_keypad ();
}
/*
* "menu_tgLo_drive_cb" - Handles setting the tracking generator LO drive
*/
void menu_tgLO_drive_cb ( int item )
{
int km = KM_TGLO_DRIVE;
tft.fillScreen ( bg );
ui_mode_keypad ( km );
ui_process_keypad ();
}
/*
* "menu_generate_cb" - M0WID Version 05; replaces the function "menu_output_cb"
* from previous versions.
*/
static void menu_generate_cb ( int item )
{
SetGenerate ( 1 ); // Item 0 is off, 1 is on
// selection = item;
// draw_menu ();
// menu_move_back();
ui_mode_normal (); // No menu displayed
}
/*
* menu_tracking_cb handles settings for the tracking generator
*/
static void menu_tracking_cb (int item )
{
switch ( item )
{
case 0: // Turn Off
SetTracking (0);
ui_mode_normal (); // Back to sweep
break;
case 1: // Turn On
SetTracking (1);
ui_mode_normal (); // Back to sweep
break;
case 2: // Turn Sig gen mode
SetTracking (2);
ui_mode_normal (); // Back to sweep
break;
}
}
/*
* "menu_autosettings_cb" sets defaults then clears the menu
* from the display.
*
* Modified in Version 2.5 by WA2FZW:
*
* Added definitions in "My_SA.h" to allow the user to customize the "AUTO" settings.
*/
static void menu_autosettings_cb ( int item )
{
SetSweepStart ( AUTO_SWEEP_START ); // Scan limits
SetSweepStop ( AUTO_SWEEP_STOP );
SetPowerGrid ( AUTO_PWR_GRID );
SetPreampGain ( AUTO_LNA );
SetRefLevel ( AUTO_REF_LEVEL );
SetRefOutput ( AUTO_REF_OUTPUT );
SetAttenuation ( AUTO_ATTEN );
// SetPowerLevel ( 100 ); // Removed - Screws up calibration
SetRBW ( AUTO_RBW ); // Auto mode
SetRX ( 0 );
setting.ShowGain = 1; // Gain trace on
setting.ShowSweep = 1; // Main sweep trace on
menu_move_back ();
ui_mode_normal (); // No menu displayed
}
/*
* "menu_touch_cb" is the dispatcher for part of the "TOUCH SCREEN" menu
*/
static void menu_touch_cb ( int item )
{
switch ( item )
{
case 0: // Touch calibrate
touch_cal_exec ();
request_to_redraw_grid ();
draw_menu ();
break;
case 1: // Touch Draw test
touch_draw_test ();
request_to_redraw_grid ();
draw_menu ();
break;
}
}
/*
* "menu_version_cb" handles displaying the "About" screen
*/
static void menu_version_cb ( int item )
{
ShowVersion ();
request_to_redraw_grid ();
draw_menu ();
}
/*
* "menu_save_cb" saves the current "setting" structure in a named location in the
* flash memory. The "preferences Save" function adds the "item" number to the string
* "Save" to create the saved name.
*/
static void menu_save_cb ( int item )
{
if ( item < 0 || item > 4 ) // Legal "item" number?
return; // Nope
Save ( item );
menu_move_back();
ui_mode_normal();
}
/*
* "menu_recall_cb" - Works like "menu_save_cb" in reverse
*/
static void menu_recall_cb ( int item )
{
if ( item < 0 || item > 4 ) // Test for illegal "item"
return;
Recall ( item );
menu_move_back();
ui_mode_normal();
}
/*
* "menu_refer_cb" - Set reference level from 1st page of the "REFERENCE" menu
*/
static void menu_refer_cb ( int item )
{
// Serial.println ( item ); // Debugging
SetRefOutput ( menu_refer_value[item] );
menu_move_back();
ui_mode_normal();
}
/*
* "menu_refer_cb2" - Set reference output frequency from 2nd page
* of the "REFERENCE" menu
*/
static void menu_refer_cb2 ( int item )
{
// Serial.println ( item ); // Debugging
SetRefOutput ( menu_refer_value[item+5] ); // Items 0 - 4 are on page 1
menu_move_back ();
ui_mode_normal ();
}
/*
* "menu_spur_cb" - Handles the "Spur Reduction" menu item.
*/
static void menu_spur_cb ( int item )
{
SetSpur ( item );
menu_move_back ();
ui_mode_normal ();
}
/*
* "menu_storage_cb" - Handles the "STORAGE" menu item.
*/
static void menu_storage_cb ( int item )
{
switch ( item )
{
case 0: // "STORE"
SetStorage ();
break;
case 1:
SetClearStorage (); // "CLEAR"
break;
case 2: // "SUBTRACT" - What does this mean?
SetSubtractStorage ();
break;
}
menu_move_back ();
ui_mode_normal ();
}
/*
* "menu_average_cb" - Handles the "AVERAGE" menu item.
*/
static void menu_average_cb ( int item )
{
SetAverage ( item );
menu_move_back ();
ui_mode_normal ();
}
/*
* "menu_rbw_cb" - Handles the "RBW" menu item.
*
* WA2FZW - Moved the "rbwsel" choices into the function; they were previously
* defined in global space.
*/
static void menu_rbw_cb ( int item )
{
const int rbwsel[] = { 0, 31, 106, 322, 1121, 3355 }; // Resolution bandwidth choices (in KHz * 10)
SetRBW ( rbwsel[item] );
menu_move_back ();
ui_mode_normal ();
}
/*
* "menu_dBper_cb" - Handles the "SCALE/DIV" menu item
*/
static void menu_dBper_cb ( int item )
{
int menu_dBper_value[] = { 1, 2, 5, 10, 20 }; // Scale setting values (dB/division)
SetPowerGrid ( menu_dBper_value[item] );
menu_move_back ();
ui_mode_normal ();
}
/*
* "menu_dBgain_cb" - Handles the "PREAMP GAIN" menu item.
*/
static void menu_dBgain_cb ( int item )
{
if ( item == 0 ) // Turn the AGC on
{
SetPreampGain ( 0x60 ); // ACG on value
menu_move_back ();
ui_mode_normal ();
}
else // Get value from the keypad
{
int km = KM_PREAMP;
ui_mode_keypad ( km );
ui_process_keypad ();
}
}
/*
* "choose_active_trace" - Holdover from NanoVNA but left in as it might be used
* in the future in the TinySA.
*/
static void choose_active_trace ( void )
{
int i;
if ( trace[uistat.current_trace].enabled ) // If true
return; // Do nothing
for ( i = 0; i < TRACE_COUNT ; i++ ) // "TRACE_COUNT" is set to '1' somewhere
if ( trace[i].enabled ) // Find first "enabled: trace
{
uistat.current_trace = i; // Save the index
return;
}
}
/*
* Repurposed in Version 2.6 by WA2FZW:
*
* Now toggles the main sweep trace or the gain trace on or off.
*
*
* Like so many other of these functions "item" is the position of the item in the
* menu; this has to be fixed!
*
* Here, item '0' is the main sweep trace and item '1' is the gain trace.
*/
static void menu_trace_cb ( int item )
{
switch ( item )
{
case 0: // Toggle the main sweep
setting.ShowSweep = !setting.ShowSweep;
break;
case 1: // Toggle the gain trace
setting.ShowGain = !setting.ShowGain;
break;
}
WriteSettings ();
menu_move_back ();
ui_mode_normal ();
}
static void menu_atten_cb ( int item )
{
int km = KM_ATTENUATION;
ui_mode_keypad ( km );
ui_process_keypad ();
}
/*
* "menu_scale_cb" - Handles the "REF LEVEL" menu item.
*/
static void menu_scale_cb ( int item )
{
int km = KM_REFPOS;
ui_mode_keypad ( km );
ui_process_keypad ();
}
/*
* "menu_actualpower_cb" - Handles the "ACTUAL POWER" menu item.
*/
static void menu_actualpower_cb ( int item )
{
int km = KM_ACTUALPOWER;
ui_mode_keypad ( km );
ui_process_keypad ();
}
/*
* "menu_sweep_cb" - Handles the menu items under the "SCAN" menu.
*
* Modified in Version 2.5 by WA2FZW:
*
* Eliminated "case 5" which was the handler for "Pause Sweep". That menu
* choice really didn't do anything, so it was eliminated altogether. I left
* the switch intact should we wish to add something to the "Scan" menu list.
*
*
* Modified in Version 2.9 by WA2FZW:
*
* Totally eliminated the "switch" as all the menu items that set frequencies
* are handled the same.
*/
static void menu_sweep_cb ( int item )
{
ui_mode_keypad ( item );
ui_process_keypad ();
}
static void menu_IF_sweep_cb ( int item )
{
ui_mode_keypad ( item + KM_IFSTART - 1 ); // item = 1 -> KM_IFSTART, 2 -> KM_IFSTOP, 3-> KM_IFSIG
ui_process_keypad ();
}
static void menu_RX_sweep_cb ( int item )
{
ui_mode_keypad ( item + KM_RXSPAN - 1 ); // item = 1 -> KM_RXSPAN, 2 -> KM_RXSIG
ui_process_keypad ();
}
static void menu_extern_cb ( int item )
{
int km = KM_EXTERN;
ui_mode_keypad ( km );
ui_process_keypad ();
}
/*
* *********************************************
* BANDSCOPE MENU ITEMS
* *********************************************
*/
/*
* Handles the Bandscope RBW menu item.
*
*/
static void menu_BandscopeRbw_cb ( int item )
{
const int rbwsel[] = { 0, 26, 28, 31, 37 , 42, 54 }; // Resolution bandwidth choices (in KHz * 10)
SetBandscopeRBW ( rbwsel[item] );
menu_move_back ();
ui_mode_normal ();
}
/*
* Set the span for the bandscope
*/
static void menu_BandscopeSpan_cb ( int item )
{
switch ( item )
{
case 0: // 200kHz
setting.BandscopeSpan = 200000;
break;
case 1: // 400kHz
setting.BandscopeSpan = 400000;
break;
}
WriteSettings ();
menu_move_back ();
ui_mode_normal ();
}
/*
* Set the level of the top of the bandscope scale
*/
static void menu_BandscopeLevel_cb ( int item )
{
ui_mode_keypad ( KM_BANDSCOPELEVEL );
ui_process_keypad ();
}
/*
* Set the min for the bandscope waterfall colours
*/
static void menu_WaterfallMin_cb ( int item )
{
ui_mode_keypad ( KM_WFMIN );
ui_process_keypad ();
}
/*
* Set the gain for the bandscope waterfall colours
*/
static void menu_WaterfallGain_cb ( int item )
{
ui_mode_keypad ( KM_WFGAIN );
ui_process_keypad ();
}
/*
* Set the start frequency of the bandscope sweep
*/
static void menu_BandscopeStart_cb ( int item )
{
ui_mode_keypad ( KM_BANDSCOPESTART );
ui_process_keypad ();
}
/*
* "ensure_selection" - Validates that a menu selection is valid
*/
static void ensure_selection ( void )
{
Menuitem *menu = menu_stack[menu_current_level];
int i;
for ( i = 0; menu[i].Type() != MT_END; i++ ) {} // Drops out when the "END" is found
if ( selection >= i )
selection = i - 1;
}
/*
* "menu_move_back" - Go back to the previous menu level
*/
static void menu_move_back ( void )
{
if ( menu_current_level == 0 )
return;
// Serial.print ( "Poplevel=" );
// Serial.println ( menu_current_level );
menu_current_level--;
ensure_selection (); // Make sure valid
erase_menu_buttons (); // Erase old buttons
draw_menu (); // Paint new ones
}
/*
* "menu_push_submenu" - Paint a new sub-menu
*/
static void menu_push_submenu ( Menuitem *submenu )
{
// Serial.print( "Pushlevel=" );
// Serial.println ( menu_current_level );
if ( menu_current_level < MENU_STACK_DEPTH - 1 )
menu_current_level++;
menu_stack[menu_current_level] = submenu;
ensure_selection ();
erase_menu_buttons ();
draw_menu ();
}
/*
* "menu_invoke" -
*/
static void menu_invoke ( int item )
{
Menuitem *menu = menu_stack[menu_current_level];
menu = &menu[item];
// Serial.print ( "Invoke=" );
// Serial.print ( item );
// Serial.print ( ", type=" );
// Serial.print ( menu->type );
// Serial.print ( ", label= " );
// Serial.println ( menu->label );
switch ( menu->Type() )
{
case MT_END:
ui_mode_normal (); // Clear menu display
break;
case MT_BACK: // Go up one level
menu_move_back ();
break;
case MT_FUNC: // Call function to process selection
{
menu->Call ( item );
break;
}
case MT_MENU: // Display a sub-menu
menu_push_submenu ( menu->GetSubmenu () );
break;
}
}
/*
* All the following stuff has to do with the keypad. The first two definitions
* are the 'x' and 'y' coordinates of the entire keypad. The "KP_X" and "KP_Y"
* macros set the 'x' and 'y' pixel coordinates for the key based on its row
* and column in the keypad; pretty clever!
*/
#define KP_X(x) ( 48 * ( x ) + 2 + ( 320 - 64 - 192 ))
#define KP_Y(y) ( 48 * ( y ) + 2 )
typedef struct
{
uint16_t x, y; // X and Y coordinates of a key
int8_t c; // Index to the "kpf" array of characters?
} keypads_t;
static const keypads_t *keypads; // Pointer to array of keypads
static uint8_t keypads_last_index; // Index into the array
/*
* There are different keypads for different things.
*
* The numbers in the "KP_X(n)" and "KP_Y(n) macro calls are the X and Y positions
* of the keys the columns (X) are numbered from left to right as 0 to 3 and the
* rows (Y) are numbered from top to bottom as 0 to 3.
*
* WA2FZW - Some space can be saved by creating one generic keypad with the digits
* and decimal point and then individual supplemental ones for the special keys on
* eash of the following.
*
* The first one is for entering frequencies.
*/
static const keypads_t keypads_freq[] = // Keypad array for frequencies
{
{ KP_X(1), KP_Y(3), KN_PERIOD }, // Decimal point
{ KP_X(0), KP_Y(3), 0 }, // '0' digit
{ KP_X(0), KP_Y(2), 1 }, // '1' digit
{ KP_X(1), KP_Y(2), 2 },
{ KP_X(2), KP_Y(2), 3 },
{ KP_X(0), KP_Y(1), 4 },
{ KP_X(1), KP_Y(1), 5 },
{ KP_X(2), KP_Y(1), 6 },
{ KP_X(0), KP_Y(0), 7 },
{ KP_X(1), KP_Y(0), 8 },
{ KP_X(2), KP_Y(0), 9 },
{ KP_X(3), KP_Y(1), KN_M }, // Megahertz
{ KP_X(3), KP_Y(2), KN_K }, // Kilohertz
{ KP_X(3), KP_Y(3), KN_X }, // Enter
{ KP_X(2), KP_Y(3), KN_BS }, // Backspace
{ 0, 0, -1 } // Array end marker
};
static const keypads_t keypads_signed_freq[] = // Keypad array for signed frequencies
{
{ KP_X(1), KP_Y(3), KN_PERIOD }, // Decimal point
{ KP_X(0), KP_Y(3), 0 }, // '0' digit
{ KP_X(0), KP_Y(2), 1 }, // '1' digit
{ KP_X(1), KP_Y(2), 2 },
{ KP_X(2), KP_Y(2), 3 },
{ KP_X(0), KP_Y(1), 4 },
{ KP_X(1), KP_Y(1), 5 },
{ KP_X(2), KP_Y(1), 6 },
{ KP_X(0), KP_Y(0), 7 },
{ KP_X(1), KP_Y(0), 8 },
{ KP_X(2), KP_Y(0), 9 },
{ KP_X(3), KP_Y(0), KN_MINUS },
{ KP_X(3), KP_Y(1), KN_M }, // Megahertz
{ KP_X(3), KP_Y(2), KN_K }, // Kilohertz
{ KP_X(3), KP_Y(3), KN_X }, // Enter
{ KP_X(2), KP_Y(3), KN_BS }, // Backspace
{ 0, 0, -1 } // Array end marker
};
static const keypads_t keypads_integer[] = // Keypad array for integers (no decimal point)
{
{ KP_X(1), KP_Y(3), 0 },
{ KP_X(1), KP_Y(2), 1 },
{ KP_X(2), KP_Y(2), 2 },
{ KP_X(3), KP_Y(2), 3 },
{ KP_X(1), KP_Y(1), 4 },
{ KP_X(2), KP_Y(1), 5 },
{ KP_X(3), KP_Y(1), 6 },
{ KP_X(1), KP_Y(0), 7 },
{ KP_X(2), KP_Y(0), 8 },
{ KP_X(3), KP_Y(0), 9 },
{ KP_X(3), KP_Y(3), KN_X },
{ KP_X(2), KP_Y(3), KN_BS },
{ 0, 0, -1 }
};
static const keypads_t keypads_level[] = // Used for "ACTUAL POWER" input
{
{ KP_X(1), KP_Y(3), KN_PERIOD },
{ KP_X(0), KP_Y(3), 0 },
{ KP_X(0), KP_Y(2), 1 },
{ KP_X(1), KP_Y(2), 2 },
{ KP_X(2), KP_Y(2), 3 },
{ KP_X(0), KP_Y(1), 4 },
{ KP_X(1), KP_Y(1), 5 },
{ KP_X(2), KP_Y(1), 6 },
{ KP_X(0), KP_Y(0), 7 },
{ KP_X(1), KP_Y(0), 8 },
{ KP_X(2), KP_Y(0), 9 },
{ KP_X(3), KP_Y(2), KN_MINUS },
{ KP_X(3), KP_Y(3), KN_X },
{ KP_X(2), KP_Y(3), KN_BS },
{ 0, 0, -1 }
};
/*
* This array is indexed by the enum at the top of the file that defines the values for
* "KM_START", KM_STOP, etc.
*/
static const keypads_t * const keypads_mode_tbl[] =
{
keypads_freq, // KM_START..........Sweep start frequency
keypads_freq, // KM_STOP...........Sweep stop frequency
keypads_freq, // KM_CENTER.........Sweep center frequency
keypads_freq, // KM_SPAN...........Sweep frequency span
keypads_freq, // KM_FOCUS..........Focus Frequency
keypads_level, // KM_REFPOS.........Grid reference level (top line)
keypads_integer, // KM_ATTENUATION....Attenuation
keypads_level, // KM_ACTUALPOWER....Power level calibration
keypads_freq, // KM_IFFREQ.........IF frequency
keypads_integer, // KM_PREAMP.........Preamp gain
keypads_integer, // KM_TUNE...........Transceiver crystal load
keypads_freq, // KM_SGFREQ.........Sig Gen frequency
keypads_level, // KM_SGLEVEL........Sig Gen Power level
keypads_level, // KM_SGLEVCAL.......Power level calibration
keypads_freq, // KM_IFSTART........IF Sweep start frequency
keypads_freq, // KM_IFSTOP.........IF Sweep stop frequency
keypads_freq, // KM_IFSIG..........IF Sweep signal frequency
keypads_signed_freq, // KM_TGOFFSET.......Offset Frequency of TG IF compared to SA IF
keypads_freq, // KM_TGFREQ.........Frequency of TG in sig gen mode
keypads_level, // KM_TGLO_DRIVE.....Tracking generator LO drive
keypads_level, // KM_TGIF_DRIVE.....Tracking generator IF drive
keypads_freq, // KM_BANDSCOPESTART.IF Sweep start frequency
keypads_integer, // KM_WFMIN..........Waterfall min level (RSSI)
keypads_level, // KM_WFGAIN.........Waterfall Gain
keypads_level, // KM_BANDSCOPELEVEL.Grid reference level
keypads_freq, // KM_RXSPAN.........RX Sweep span frequency
keypads_freq, // KM_RXSIG..........RX Sweep signal frequency
keypads_freq, // KM_RBW............RX Sweep RBW
keypads_level // KM_EXTERN.........External gain
};
/*
* "draw_keypad" - Seems pretty self-explanatory!
*
* Modified in Version 2.7 by WA2FZW:
*
* Instead of simply painting reqular characters from the (no longer existing)
* "kpf" array, the characters used in the keypad keys and in the number box are
* now painted using bitmaps in the "KP_Font" array.
*
* The "KeyNumber" function replaces the "DrawFont" function to paint the bitmaps.
*/
static void draw_keypad ( void )
{
int i = 0;
while ( keypads[i].x ) // Non zero "X" location
{
uint16_t bg = config.menu_normal_color; // Color when key is not selected
if ( i == selection )
bg = config.menu_active_color; // Color when a key is selected
tft.fillRect ( keypads[i].x, keypads[i].y, 44, 44, bg ); // Set background color
KeyNumber ( keypads[i].c, keypads[i].x+12, keypads[i].y+10 ); // Paint the character
i++; // Next
}
}
/*
/*
* "KeyNumber" uses the "KP_Font" array to draw a number in a keypad key.
*/
static void KeyNumber ( int8_t key, int x, int y )
{
uint16_t bits; // Holds the bitmap for one line
uint16_t* font = &KP_Font[key * 22]; // Calculate pointer to desired bitmap
for ( int line = 0; line < 22; line++ ) // Do line by line; top to bottom
{
bits = font[line]; // Get the bit pattern for a line
for ( int column = 0; column < 16; column++ ) // horizontally left to right
{
if ( bits & 0x8000 ) // Is the next pixel turned on?
tft.drawPixel ( column+x, line+y, BLACK ); // Yes, always black
bits <<= 1; // Shift the bitmap byte one place left
}
} // Next line
}
/*
* "draw_numeric_area_frame" - Draws the numerical box uncer the keypad
*/
static void draw_numeric_area_frame ( void )
{
tft.fillRect ( 0, 208, 256, 32, WHITE ); // White background
DrawString ( keypad_mode_label[keypad_mode], 5, 220, BLACK, 1 );
tft.setCursor(5,230);
tft.printf("%.0f",uistat.previous_value);
}
/*
* "draw_numeric_input" - Puts numbers in the numerical entry box
*
* Modified in Version 2.7 by WA2FZW:
*
* Instead of using characters from the (no longer exists) "kpf" array to write
* in the numerical input box, the characters are now defined by bitmaps in the
* "KP_Font" array. The "KeyNumber" replaces the (no longer exists) "DrawFont"
* function.
*
* Also re-did how it decides to add space after every third digit. A leading
* minus sign no longer counts and if a decimal point is entered, we no longer
* add the extra space between digits.
*/
static void draw_numeric_input ( const char *buf )
{
int i = 0; // Buffer index
int x = 64; // 'X' coordinate for first character
int nextX = 20; // Normal character spacing
bool sawDot = false; // True if decimal entered
uint8_t digits = 0; // Digit counter
for ( i = 0; i < 10 && buf[i]; i++ )
{
nextX = 18; // Normal character spacing
uint16_t fg = BLACK; // Foreground is black
uint16_t bg = WHITE; // Background is white
int c = buf[i]; // Get a character
if ( c == '.' ) // Decimal point?
{
c = KN_PERIOD; // Index to '.' in the "KP_Font" array
sawDot = true; // Decimal seen
}
else if ( c == '-' ) // Minus sign"
c = KN_MINUS; // Index to '_' in the "KP_Font" array
else if ( isDigit ( c )) // Digit?
c = c - '0'; // Quick & dirty "atoi"
else // None of the above
c = -1;
if ( c >= 0 ) // 'c' was found
{
KeyNumber ( c, x, 208+4 ); // Paint the character
// addIx++;
if ( c <= 9 ) // Is it a number?
{
digits++; // Increment the digit counter
if ( !sawDot ) // No decimal yet
if (( digits % 3 ) == 0 ) // Every third digit
nextX += 6; // Add extra space
}
}
else
tft.fillRect ( x, 208+4, 20, 24, bg ); // If not found, erase it
x += nextX; // Place for next digit
} // End of for loop
if ( i < 10 )
tft.fillRect ( x, 208+4, 20 * ( 10-i ), 24, WHITE ); // Fill something with white
}
/*
* "draw_menu_buttons" - Paint the menu buttons
*/
static void draw_menu_buttons ( Menuitem *menu )
{
int i = 0;
//Serial.println( "----------------------------" ); // Debugging
for ( i = 0; i < 7; i++ ) // Maximum number of menu buttons is 7
{
if ( menu[i].Type() == MT_END ) // End of the menu
break; // So no need to look any further
int y = 32 * i; // "Y" coordinate in pixels?
uint16_t bg = config.menu_normal_color; // Background is unselected color
uint16_t fg = BLACK; // Text is in black
if ( ui_mode == UI_MENU && i == selection ) // focus only in MENU mode but not in KEYPAD mode
bg = config.menu_active_color; // Set background to selected color
tft.fillRect ( 320-60, y, 60, 30, bg ); // These hard coded numbers have to go!
if ( menu[i].isMultiline ()) // Multi-line label?
{
DrawString ( menu[i].Text1(), 320-54, y+6, fg, 1 ); // First line
DrawString ( menu[i].Text2(), 320-54, y+17, fg, 1 ); // Second line
}
else // Single line label
DrawString ( menu[i].Text1(), 320-54, y+12, fg, 1 );
} // End of for loop
}
/*
* "menu_select_touch" - Wait for a menu button to be pushed
*/
static void menu_select_touch ( int i )
{
selection = i;
draw_menu (); // Draw the menu buttons
// Serial.println ( "Before wait release" ); // Debugging
touch_wait_release (); // Wait for a release indication
// Serial.println ( "After wait release" );
selection = -1; // Don't understand this ???
menu_invoke ( i );
}
/*
* "menu_apply_touch" - Figure out which button was touched
*/
static void menu_apply_touch ( void )
{
int touch_x, touch_y; // Touch coordinates
Menuitem *menu = menu_stack[menu_current_level];
int i;
touch_position ( &touch_x, &touch_y ); // Get coordinates
for ( i = 0; i < 7; i++ ) // Up to 7 buttons
{
int y = 32 * i; // "Y" coordinate of button in pixels
if ( y-2 < touch_y && touch_y < y+30+2 && 320-60 < touch_x )
{
menu_select_touch ( i ); // This is the button that was selected
return; // We're done!
}
} // End of for loop
touch_wait_release (); // Wait for button release
ui_mode_normal (); // No more menu
}
/*
* "draw_menu" - Paint the entire menu
*/
static void draw_menu ( void )
{
// Serial.println ( "draw menu" ); // Debugging
draw_menu_buttons ( menu_stack[menu_current_level] ); // Paint the buttons
}
/*
* "erase_menu_buttons" - Self explanatory
*/
static void erase_menu_buttons ( void )
{
// Serial.println ( "erase buttons" ); // Debugging
tft.fillRect ( 320-60, 0, 60, 32*7, bg );
}
/*
* "erase_numeric_input" - Erase the numerical input box below the keypad
*/
static void erase_numeric_input ( void )
{
tft.fillRect ( 0, 240-32, 320, 32, bg ); // Poof!
}
/*
* "request_to_draw_cells_behind_menu" - Do nothing function
*/
void request_to_draw_cells_behind_menu () {}
/*
* "leave_ui_mode" - Cleanup after using the touch screen.
*
* Modified in Version 2.1 by WA2FZW:
*
* Eliminated "changedSetting" test and "WriteSettings". Because savings the
* settings was also being handled in some of the functions that set the members
* of the "setting" structure, the structure was sometimes being saved twice. It
* was also being saved when the parameters didn't actually change. This was
* all fixed in "Cmd.cpp".
*/
static void leave_ui_mode ( void )
{
if ( ui_mode == UI_MENU ) // In menu mode?
{
erase_menu_buttons (); // Erase the menu area
request_to_redraw_grid();
}
else if ( ui_mode == UI_NUMERIC ) // Using the keypad?
erase_numeric_input (); // Erase the number box
// Serial.println ( "leave UI" ); // Debugging
}
/*
* "fetch_numeric_target" - Gets one of the scan frequency parameters. The
* "GetSweepStart()" etc functions are in the cmd.cpp file.
*/
static void fetch_numeric_target ( void )
{
switch ( keypad_mode )
{
case KM_START:
uistat.value = GetSweepStart ();
break;
case KM_STOP:
uistat.value = GetSweepStop ();
break;
case KM_CENTER:
uistat.value = GetSweepCenter ();
break;
case KM_SPAN:
uistat.value = GetSweepSpan ();
break;
case KM_FOCUS:
uistat.value = GetSweepCenter ();
break;
case KM_REFPOS:
// uistat.value = get_trace_refpos ( uistat.current_trace ) * 1000;
break;
case KM_ATTENUATION:
uistat.value = setting.Attenuate;
break;
case KM_ACTUALPOWER:
// uistat.value = velocity_factor;
break;
case KM_IFFREQ:
uistat.value = setting.IF_Freq;
break;
case KM_SGFREQ:
uistat.value = sigGenSetting.Frequency;
break;
case KM_SGLEVEL:
uistat.value = sigGenSetting.Power;
break;
case KM_SGLEVCAL:
uistat.value = sigGenSetting.Calibration;
break;
case KM_PREAMP:
uistat.value = GetPreampGain ( &AGC_On, &AGC_Reg );
break;
case KM_IFSTART:
uistat.value = GetIFsweepStart();
break;
case KM_IFSTOP:
uistat.value = GetIFsweepStop();
break;
case KM_IFSIG:
uistat.value = GetIFsweepSigFreq();
break;
case KM_TGOFFSET:
uistat.value = trackGenSetting.Offset;
break;
case KM_TGFREQ:
uistat.value = trackGenSetting.Frequency;
break;
case KM_TGIF_DRIVE:
uistat.value = trackGenSetting.IF_Drive;
break;
case KM_TGLO_DRIVE:
uistat.value = trackGenSetting.LO_Drive;
break;
case KM_BANDSCOPESTART:
uistat.value = setting.BandscopeStart;
break;
case KM_WFMIN:
uistat.value = setting.WaterfallMin;
break;
case KM_WFGAIN:
uistat.value = setting.WaterfallGain;
break;
case KM_BANDSCOPELEVEL:
uistat.value = setting.BandscopeMaxGrid;
break;
case KM_RXSPAN:
uistat.value = GetRXsweepSpan();
break;
case KM_RXSIG:
uistat.value = GetRXsweepSigFreq();
break;
case KM_RBW:
uistat.value = (double)setting.Bandwidth10 / 10.0;
break;
case KM_EXTERN:
uistat.value = setting.ExternalGain;
break;
}
uint32_t x = uistat.value;
int n = 0;
for (; x >= 10 && n < 9; n++ )
x /= 10;
uistat.digit = n;
uistat.previous_value = uistat.value;
// Serial.printf("uistat previous value %f\n", uistat.previous_value );
}
/*
* "draw_numeric_area" - Paints adds the appropriate text to the numeric entry box
* and requests it to be painted.
*/
static void draw_numeric_area ( void )
{
char buf[10];
snprintf ( buf, sizeof buf, "%9d", uistat.value );
draw_numeric_input ( buf );
}
/*
* "ui_mode_menu" - Sets menu mode and paints the menu
*/
static void ui_mode_menu ( void )
{
if ( ui_mode == UI_MENU ) // If already in menu mode
return; // Nothing to do here
ui_mode = UI_MENU; // Set menu mode
Serial.println("ui_mode_menu");
// area_width = AREA_WIDTH_NORMAL - ( 64 - 8 ); // Narrower plotting area
// area_height = HEIGHT;
ensure_selection (); // Validate current selection
draw_menu (); // And paint the menu
}
/*
* "ui_mode_numeric" - Puts the UI into numeric mode
*/
static void ui_mode_numeric ( int _keypad_mode )
{
if ( ui_mode == UI_NUMERIC ) // Already in numeric mode?
return; // Nothing to do
leave_ui_mode (); // Get out of previous mode?
keypad_mode = _keypad_mode; // Set numeric mode
ui_mode = UI_NUMERIC;
// area_width = AREA_WIDTH_NORMAL;
// area_height = 240 - 32; // HEIGHT - 32;
draw_numeric_area_frame ();
fetch_numeric_target ();
draw_numeric_area ();
}
/*
* "ui_mode_keypad" - Puts us in keypad mode
*/
static void ui_mode_keypad ( int _keypad_mode )
{
if ( ui_mode == UI_KEYPAD ) // Already here?
return; // Nuttin to do
keypad_mode = _keypad_mode; // Pick the proper keypad format
keypads = keypads_mode_tbl[_keypad_mode];
int i;
for ( i = 0; keypads[i+1].c >= 0; i++ ) {}
keypads_last_index = i; // Fall out of loop when found
ui_mode = UI_KEYPAD; // Set keypad mode
// area_width = AREA_WIDTH_NORMAL - ( 64 - 8 );
// area_height = HEIGHT - 32;
draw_menu (); // Paint the menu
draw_keypad (); // Then the keypad
fetch_numeric_target (); //!!!!!
draw_numeric_area_frame (); // Then the numeric entry area
draw_numeric_input (""); // Blanked out?
}
/*
* "ui_mode_normal" - Puts the UI into normal mode
*/
static void ui_mode_normal ( void )
{
if ( ui_mode == UI_NORMAL ) // Already there?
return; // Done
//**HERE2
// area_width = AREA_WIDTH_NORMAL;
// area_height = HEIGHT;
menu_current_level = 0;
leave_ui_mode();
ui_mode = UI_NORMAL;
}
/*
* "my_atof" - A homebrew ascii to double function; not sure why needed?
*/
double my_atof ( const char *p )
{
int neg = FALSE;
if ( *p == '-' ) // If first character is a minus sign
neg = TRUE; // Number is negative
if ( *p == '-' || *p == '+' ) // If first character is a plus or minus sign
p++; // Skip over it
double x = atoi ( p ); // ???
while ( isdigit ( (int) *p )) // If next character is a digit
p++; // Bump the pointer
if ( *p == '.' ) // If it's a decimal point
{
double d = 1.0f; // "d" = '1' in floating point
p++; // Next character
while ( isdigit ( (int) *p )) // As long as we see digits
{
d /= 10; // Divide "d" by 10
x += d * ( *p - '0' ); // Then add in the next digit
p++; // Next character
}
}
if ( *p == 'e' || *p == 'E' ) // Not a digit then is it an exponent?
{
p++; // Next character
int exp = atoi ( p ); // Convert exponent to integer
while ( exp > 0 ) // If exponent positive
{
x *= 10; // Multiply the number by 10
exp--; // And decrement the exponent
}
while ( exp < 0 ) // If the exponent is negative
{
x /= 10; // Divide the number by 10
exp++; // And increment the exponent
}
}
if ( neg ) // If the whole answer is negative
x = -x; // Make the number negative
return x; // And send it back
}
/*
* "keypad_click" -
*/
static int keypad_click ( int key )
{
int c = keypads[key].c; // Index to the "KP_Font" array
char fBuff[20]; // Frequency string
if (( c >= KN_X && c <= KN_M )) // 'X', 'K' or 'M' key pressed?
{
int32_t scale = 1; // Default "scale"?
if ( c >= KN_X && c <= KN_M ) // Redundent test? Why?
{
int n = c - KN_X; // 'X' -> 0, 'K' _> 1, 'M' -> 2
while ( n-- > 0 ) // Multiplier will be 1K or 1M
scale *= 1000;
}
/*
* When we get here, the numeric input has completed. We convert the number to
* a "double" and multiply it by the "scale".
*/
if (kp_index ==0) // no entry - treat same as <-
return KP_CANCEL;
double value = my_atof ( kp_buf ) * ( double ) scale;
switch ( keypad_mode )
{
case KM_START: // Start frequency entered?
SetSweepStart (( int32_t ) value );
break;
case KM_STOP: // Stop frequency entered?
SetSweepStop (( int32_t ) value );
break;
case KM_CENTER: // Center frequency entered?
SetSweepCenter (( int32_t ) value, WIDE );
break;
case KM_SPAN: // Frequency span entered?
SetSweepSpan (( int32_t ) value );
break;
case KM_FOCUS: // Focus frequency entered?
SetSweepCenter ((int32_t ) value, NARROW );
break;
case KM_REFPOS: // Reference level
SetRefLevel (value );
break;
case KM_ATTENUATION: // Attenuator setting
if ( value > PE4302_MAX ) // Too high?
{
DisplayError ( ERR_WARN,
"Illegal attenuator setting!",
"Ignored!", NULL, NULL );
break;
}
SetAttenuation ( value );
break;
case KM_ACTUALPOWER: // Power level
RequestSetPowerLevel ( value );
break;
case KM_IFFREQ:
if ( !SetIFFrequency (( uint32_t ) value )) // Bad frequency?
{
strcpy ( fBuff, FormatFrequency (( uint32_t ) value ));
DisplayError ( ERR_WARN,
fBuff,
"Invalid IF Frequency!",
"IF Frequency set to:",
FormatFrequency ( setting.IF_Freq ));
}
break;
case KM_SGFREQ:
if ( (value > MAX_SIGLO_FREQ) || (value < MIN_SIGLO_FREQ) )
{
strcpy ( fBuff, FormatFrequency (( uint32_t ) value ));
DisplayError ( ERR_WARN,
fBuff,
"Invalid Frequency!",
NULL,
NULL );
}
else
sigGenSetting.Frequency = value;
break;
case KM_SGLEVEL:
if ( (value > sigGenSetting.Calibration) || (value < sigGenSetting.Calibration - ATTENUATOR_RANGE) )
{
DisplayError ( ERR_WARN,
"Invalid Level!",
NULL, NULL,
NULL );
}
else
sigGenSetting.Power = value;
break;
case KM_SGLEVCAL:
if ( (value > 20) || (value < -30) )
{
DisplayError ( ERR_WARN,
"Invalid Level!",
NULL, NULL,
NULL );
}
else
sigGenSetting.Calibration = value;
break;
case KM_IFSTART: // IF Start frequency entered?
SetIFsweepStart (( int32_t ) value );
break;
case KM_IFSTOP: // IF Stop frequency entered?
SetIFsweepStop (( int32_t ) value );
break;
case KM_IFSIG: // IF Signal frequency entered?
SetIFsweepSigFreq (( int32_t ) value );
break;
case KM_PREAMP:
if (( value < 5 ) || ( value > 49 )) // Range check
{
DisplayError ( ERR_WARN,
"Illegal preamp gain setting!",
"Ignored!", NULL, NULL );
break;
}
SetPreampGain ( value );
break;
case KM_TUNE:
if ( value > 255 ) // Illegal value?
{
DisplayError ( ERR_WARN,
"Illegal calibration factor!",
"Ignored!", NULL, NULL );
break; // Done!
}
if ( VFO == TX_4432 ) // Transmitter module selected?
{
xmit.Tune ( ( uint8_t ) value ); // Tune it
config.RX_capacitance = ( uint8_t ) value; // And save it
}
else if ( VFO == RX_4432 ) // Receiver module selected?
{
rcvr.Tune ( ( uint8_t ) value ); // Tune it
config.RX_capacitance = ( uint8_t ) value; // And save it
}
#ifdef TG_IF_INSTALLED
else if ( VFO == TGIF_4432 ) // Tracking generator IF module selected?
{
tg_if.Tune ( ( uint8_t ) value ); // Tune it
config.tgIF_capacitance = ( uint8_t ) value; // And save it
}
#endif
#ifdef TG_LO_INSTALLED
else if ( VFO == TGLO_4432 ) // Tracking generator LO module selected?
{
tg_lo.Tune ( ( uint8_t ) value ); // Tune it
config.tgLO_capacitance = ( uint8_t ) value; // And save it
}
#endif
break;
case KM_TGOFFSET:
if ( (value > MAX_TG_OFFSET) || (value < MIN_TG_OFFSET) )
{
strcpy ( fBuff, FormatSignedFrequency (( int32_t ) value ));
DisplayError ( ERR_WARN,
fBuff,
"Invalid Frequency!",
NULL,
NULL );
}
else
SetTGOffset ( (int32_t)value );
break;
case KM_TGFREQ:
if ( (value > MAX_SIGLO_FREQ) || (value < MIN_SIGLO_FREQ) )
{
strcpy ( fBuff, FormatSignedFrequency (( int32_t ) value ));
DisplayError ( ERR_WARN,
fBuff,
"Invalid Frequency!",
NULL,
NULL );
}
else
SetTGFreq ( (int32_t)value );
break;
#ifdef TG_IF_INSTALLED
case KM_TGIF_DRIVE:
if ( (value > MAX_DRIVE) || (value < MIN_DRIVE) )
{
DisplayError ( ERR_WARN,
"Invalid drive level!",
"(0-7)",
NULL,
NULL );
}
else
SetTGIfDrive ( (uint8_t)value );
break;
#endif
#ifdef TG_LO_INSTALLED
case KM_TGLO_DRIVE:
if ( (value > MAX_DRIVE) || (value < MIN_DRIVE) )
{
DisplayError ( ERR_WARN,
"Invalid drive level!",
"(0-7)",
NULL,
NULL );
}
else
SetTGLoDrive ( (uint8_t)value );
break;
#endif
case KM_BANDSCOPESTART: // Bandscope Start frequency entered?
SetBandscopeStart (( int32_t ) value );
break;
case KM_WFMIN: // Bandscope span entered?
if ( (value >= 0) && (value <= 200 ) )
setting.WaterfallMin = ( int16_t )value ;
else
{
DisplayError ( ERR_WARN,
"Invalid minimum level!",
"(0 - 200)",
NULL,
NULL );
}
break;
case KM_WFGAIN: // Bandscope span entered?
if ( (value >= 0.1) && (value <= 4.0 ) )
setting.WaterfallGain = value ;
else
{
DisplayError ( ERR_WARN,
"Invalid gain!",
"(0.1 - 4)",
NULL,
NULL );
}
break;
case KM_BANDSCOPELEVEL: // Bandscope level entered?
SetBandscopeLevel (( int32_t ) value );
break;
case KM_RXSPAN: // RX Span frequency entered?
Serial.printf( "Value = %f\n", value );
SetRXsweepSpan (( int32_t ) value );
break;
case KM_RXSIG: // RX Signal frequency entered?
SetRXsweepSigFreq (( int32_t ) value );
break;
case KM_RBW: // RBW
SetRBW (( int32_t ) (value * 10) );
break;
case KM_EXTERN:
SetExtGain ( value );
break;
} // End of "switch"
return KP_DONE; // Indicate finished with the keypad
}
else if ( c <= 9 && kp_index < NUMINPUT_LEN )
kp_buf[kp_index++] = '0' + c;
else if ( c == KN_PERIOD && kp_index < NUMINPUT_LEN )
{
/*
* Check period in former input
*/
int j;
for ( j = 0; j < kp_index && kp_buf[j] != '.'; j++ ) {}
if ( kp_index == j )
kp_buf[kp_index++] = '.'; // Append period if there was no period
}
else if ( c == KN_MINUS )
{
if ( kp_index == 0 )
kp_buf[kp_index++] = '-';
}
else if ( c == KN_BS )
{
if ( kp_index == 0 )
return KP_CANCEL;
--kp_index;
}
kp_buf[kp_index] = '\0'; // NULL terminator
draw_numeric_input ( kp_buf );
return KP_CONTINUE; // Still more to process
}
/*
* "keypad_apply_touch" - Figures out which keypad pad was touched
*/
static int keypad_apply_touch ( void )
{
int touch_x, touch_y; // Touch coordinates
int i = 0;
touch_position ( &touch_x, &touch_y ); // Get touch coordinates
while ( keypads[i].x )
{
if (keypads[i].x-2 < touch_x && touch_x < keypads[i].x+44+2
&& keypads[i].y-2 < touch_y && touch_y < keypads[i].y+44+2)
{
selection = i; // Set focus
draw_keypad (); // Repaint with selected pad highlighted
touch_wait_release (); // Wait for pad released
selection = -1; // Erase focus
draw_keypad (); // And repaint again
return i; // Return selected pad index
}
i++; // Try the next one
} // End of "while" loop
if ( touch_y > 48 * 4 )
return -2; // Exit keypad mode
return -1;
}
/*
* "numeric_apply_touch" -
*/
static void numeric_apply_touch ( void )
{
int touch_x, touch_y; // Touch coordinates
touch_position ( &touch_x, &touch_y ); // Get coordinates
if ( touch_x < 64 ) // Out of touch area?
{ // Hard-coded numbers have to go!
ui_mode_normal ();
return;
}
if ( touch_x > 64 + 9 * 20 + 8 + 8 ) // Your guess is as good as mine!
{
ui_mode_keypad ( keypad_mode );
ui_process_keypad ();
return;
}
if ( touch_y > 240 - 40 )
{
int n = 9 - ( touch_x - 64 ) / 20;
uistat.digit = n;
uistat.digit_mode = TRUE;
}
else
{
int step, n;
if ( touch_y < 100 )
step = 1;
else
step = -1;
for (n = uistat.digit; n > 0; n-- )
step *= 10;
uistat.value += step;
}
draw_numeric_area ();
touch_wait_release ();
uistat.digit_mode = FALSE;
draw_numeric_area ();
return;
}
/*
* "ui_process_keypad" -
*/
static void ui_process_keypad ( void )
{
int status;
kp_index = 0;
while ( TRUE ) // "TRUE = '-1" in this program
{
status = touch_check (); // Look for screen touched
if ( status == EVT_TOUCH_PRESSED ) // If it was touched
{
int key = keypad_apply_touch (); // Process it
if ( key >= 0 && keypad_click ( key ))
break; // Exit loop on done or cancel
else if ( key == -2 )
{
// xxx; // ???????
// return;
}
}
}
//**HERE3
request_to_redraw_grid ();
ui_mode_normal ();
// draw_menu ();
// menu_move_back();
}
/*
* "UiProcessTouch" -
*/
void UiProcessTouch ( void )
{
int tstatus = touch_check(); // Look for screen touch
if ( tstatus == EVT_TOUCH_PRESSED || tstatus == EVT_TOUCH_DOWN )
{
// Serial.printf( "process Touch status = %i, UImode = %i \n", tstatus, ui_mode );
switch ( ui_mode )
{
case UI_NORMAL:
// Serial.println( "waiting for release" );
int touch_x, touch_y; // Touch coordinates
touch_position ( &touch_x, &touch_y ); // Get coordinates
Serial.printf("x:%i y:%i\n", touch_x, touch_y);
touch_wait_release ();
/*
* Some touchscreen areas have fast access to the submenu levels, depends on the mode
*/
if ( setting.Mode == SA_LOW_RANGE )
{
// test to see if the touch is in the marker area
if ( (touch_y < 10) && (touch_x < 160) )
{
marker[0].Toggle(); // marker 1
setting.MkrStatus[0] = marker[0].Status();
return;
}
else if ( (touch_y < 10) && (touch_x > 160) )
{
marker[2].Toggle(); // marker 3
setting.MkrStatus[2] = marker[2].Status();
return;
}
else if ( (touch_y < 20) && (touch_x < 160) )
{
marker[1].Toggle(); // marker 2
setting.MkrStatus[1] = marker[1].Status();
return;
}
else if ( (touch_y < 20) && (touch_x > 160) )
{
marker[3].Toggle(); // marker 4
setting.MkrStatus[3] = marker[3].Status();
return;
}
else if ( (touch_y < 40) && (touch_x > 30) )
StartMarkerMenu();
else if ( touch_y > 210 )
StartSweepMenu();
else if ( (touch_x < 30) && (touch_y < 60) )
StartRBWMenu();
else if ( (touch_x < 30) && (touch_y > CHAR_HEIGHT * 20 ) && ( touch_y < CHAR_HEIGHT * 22 ) )
{
SetSpur (!setting.Spur);
return;
}
else if ( (touch_x < 30) )
StartDisplayMenu();
}
selection = -1; // Switch menu mode
bg = BLACK; // black background
ui_mode_menu ();
break;
case UI_MENU:
menu_apply_touch ();
break;
case UI_NUMERIC:
numeric_apply_touch ();
break;
}
}
}
/*
* Function to enter menu at certain level and selection
* HERE
* static uint8_t menu_current_level = 0; // Current level (MAIN)
*
* static Menuitem *menu_stack[MENU_STACK_DEPTH] = // Initialize the stack
* { menu_top, // Main menu is on top
* NULL, // These get set as we
* NULL, // go along
* NULL
* };
*
* // helpers for setting menus from outside
* enum { MENU_TOP, MENU_SWEEP, MENU_DISPLAY, MENU_STORAGE, MENU_OUTPUT, MENU_SAVE, MENU_CONFIG }; // Root Menu
* enum { SWEEP_START, SWEEP_STOP, SWEEP_CENTRE, SWEEP_SPAN, FOCUS }; // Sweep menu - level 1
* enum { RBW, ATTEN, MARKERS }; // Sweep more menu - level 2
* enum { TRACES, PREAMP, REF_LEVEL, DB_DIV, SPUR, DEFAULT_SETTINGS }; // Display menu - level 1
*
*/
void StartSigGenMenu ( void )
{
tft.unloadFont();
selection = -1; // Switch menu mode
menu_current_level = 0;
menu_stack[0] = menu_sig_gen;
bg = SIG_BACKGROUND_COLOR;
tft.fillRect ( 320-60, 0, 60, 32*ELEMENTS(menu_sig_gen), bg );
ui_mode_menu ();
}
void StartSigGenFreq ( void )
{
tft.unloadFont();
selection = -1; // Switch menu mode
// menu_current_level = 0;
// menu_stack[0] = menu_sig_gen;
bg = SIG_BACKGROUND_COLOR;
tft.fillScreen ( bg );
menu_sig_freq_cb ( 0 );
}
static void StartMarkerMenu ( void )
{
selection = -1; // Switch menu mode
menu_current_level = 3;
menu_stack[1] = menu_sweep;
menu_stack[2] = menu_sweep2;
menu_stack[3] = menu_markers;
}
static void StartSweepMenu ( void )
{
selection = -1; // Switch menu mode
menu_current_level = 1;
menu_stack[1] = menu_sweep;
menu_stack[2] = NULL;
menu_stack[3] = NULL;
}
static void StartDisplayMenu ( void )
{
selection = -1; // Switch menu mode
menu_current_level = 1;
menu_stack[1] = menu_display;
menu_stack[2] = NULL;
menu_stack[3] = NULL;
}
static void StartRBWMenu ( void )
{
selection = -1; // Switch menu mode
menu_current_level = 3;
menu_stack[1] = menu_sweep;
menu_stack[2] = menu_sweep2;
menu_stack[3] = menu_rbw;
}
/*
* Resets the menu stack to root level for SA mode
*/
void ResetSAMenuStack (void)
{
tft.unloadFont();
selection = -1; // Switch menu mode
menu_current_level = 0;
menu_stack[0] = menu_top;
menu_stack[1] = NULL;
menu_stack[2] = NULL;
menu_stack[3] = NULL;
if (ui_mode != UI_NORMAL)
ui_mode_normal ();
}
/*
* Resets the menu stack to root level for IF_SWEEP mode
*/
void ResetIFsweepMenuStack (void)
{
tft.unloadFont();
selection = -1; // Switch menu mode
menu_current_level = 0;
menu_stack[0] = menu_IFsweep_top;
menu_stack[1] = NULL;
menu_stack[2] = NULL;
menu_stack[3] = NULL;
if (ui_mode != UI_NORMAL)
ui_mode_normal ();
}
/*
* Resets the menu stack to root level for RX_SWEEP mode
*/
void ResetRXsweepMenuStack (void)
{
tft.unloadFont();
selection = -1; // Switch menu mode
menu_current_level = 0;
menu_stack[0] = menu_RXsweep_top;
menu_stack[1] = NULL;
menu_stack[2] = NULL;
menu_stack[3] = NULL;
if (ui_mode != UI_NORMAL)
ui_mode_normal ();
}
/*
* Resets the menu stack to root level for Bandscope mode
*/
void ResetBandscopeMenuStack (void)
{
tft.unloadFont();
selection = -1; // Switch menu mode
menu_current_level = 0;
menu_stack[0] = menu_Bandscope_top;
menu_stack[1] = NULL;
menu_stack[2] = NULL;
menu_stack[3] = NULL;
if (ui_mode != UI_NORMAL)
ui_mode_normal ();
}
/*
* "ui_process" -
*/
void ui_process ( void )
{
switch ( operation_requested ) // Only one case???
{
case OP_TOUCH:
UiProcessTouch ();
break;
}
operation_requested = OP_NONE;
}