1 Star 0 Fork 1

niubileni / NanoVNA-D

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
ui.c 78.77 KB
一键复制 编辑 原始数据 按行查看 历史
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848
/*
* Copyright (c) 2019-2020, Dmitry (DiSlord) dislordlive@gmail.com
* Based on TAKAHASHI Tomohiro (TTRFTECH) edy555@gmail.com
* All rights reserved.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3, or (at your option)
* any later version.
*
* The software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Radio; see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street,
* Boston, MA 02110-1301, USA.
*/
#include "ch.h"
#include "hal.h"
#include "chprintf.h"
#include "nanovna.h"
#include "si5351.h"
#include <string.h>
#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
#define BUTTON_DOWN_LONG_TICKS 5000 /* 500ms */
#define BUTTON_DOUBLE_TICKS 2500 /* 250ms */
#define BUTTON_REPEAT_TICKS 400 /* 10ms */
#define BUTTON_DEBOUNCE_TICKS 400 /* 40ms */
/* lever switch assignment */
#define BIT_UP1 3
#define BIT_PUSH 2
#define BIT_DOWN1 1
#define READ_PORT() palReadPort(GPIOA)
#define BUTTON_MASK 0b1111
static uint16_t last_button = 0b0000;
static systime_t last_button_down_ticks;
static systime_t last_button_repeat_ticks;
uint8_t operation_requested = OP_NONE;
#ifdef __USE_SD_CARD__
#if SPI_BUFFER_SIZE < 2048
#error "SPI_BUFFER_SIZE for SD card support need size >= 2048"
#else
// Fat file system work area (at the end of spi_buffer)
static FATFS *fs_volume = (FATFS *)(((uint8_t*)(&spi_buffer[SPI_BUFFER_SIZE])) - sizeof(FATFS));
// FatFS file object (at the end of spi_buffer)
static FIL *fs_file = ( FIL*)(((uint8_t*)(&spi_buffer[SPI_BUFFER_SIZE])) - sizeof(FATFS) - sizeof(FIL));
// Filename object (at the end of spi_buffer)
static char *fs_filename = ( char*)(((uint8_t*)(&spi_buffer[SPI_BUFFER_SIZE])) - sizeof(FATFS) - sizeof(FIL) - FF_LFN_BUF - 4);
#endif
#endif
enum {
UI_NORMAL, UI_MENU, UI_NUMERIC, UI_KEYPAD
};
// Keypad structures
// Enum for keypads_list
enum {
KM_START, KM_STOP, KM_CENTER, KM_SPAN, KM_CW, KM_SCALE, KM_REFPOS, KM_EDELAY, KM_VELOCITY_FACTOR, KM_SCALEDELAY, KM_NONE
};
typedef struct {
uint8_t x:4;
uint8_t y:4;
uint8_t c;
} keypads_t;
typedef struct {
const keypads_t *keypad_type;
const char *name;
} keypads_list;
// Max keyboard input length
#define NUMINPUT_LEN 10
static uint8_t ui_mode = UI_NORMAL;
static const keypads_t *keypads;
static uint8_t keypad_mode;
static char kp_buf[NUMINPUT_LEN+1];
static int8_t kp_index = 0;
static uint8_t menu_current_level = 0;
static int8_t selection = 0;
// UI menu structure
// Type of menu item:
#define MT_NONE 0x00
#define MT_BLANK 0x01
#define MT_SUBMENU 0x02
#define MT_CALLBACK 0x03
#define MT_CANCEL 0x04
#define MT_CLOSE 0x05
#define MT_ADV_CALLBACK 0x06
// Button definition (used in MT_ADV_CALLBACK for custom)
#define BUTTON_ICON_NONE -1
#define BUTTON_ICON_NOCHECK 0
#define BUTTON_ICON_CHECK 1
#define BUTTON_ICON_GROUP 2
#define BUTTON_ICON_GROUP_CHECKED 3
#define BUTTON_ICON_CHECK_AUTO 4
#define BUTTON_ICON_CHECK_MANUAL 5
#define BUTTON_BORDER_NONE 0x00
#define BUTTON_BORDER_WIDTH_MASK 0x0F
// Define mask for draw border (if 1 use light color, if 0 dark)
#define BUTTON_BORDER_TYPE_MASK 0xF0
#define BUTTON_BORDER_TOP 0x10
#define BUTTON_BORDER_BOTTOM 0x20
#define BUTTON_BORDER_LEFT 0x40
#define BUTTON_BORDER_RIGHT 0x80
#define BUTTON_BORDER_FLAT 0x00
#define BUTTON_BORDER_RISE (BUTTON_BORDER_TOP|BUTTON_BORDER_RIGHT)
#define BUTTON_BORDER_FALLING (BUTTON_BORDER_BOTTOM|BUTTON_BORDER_LEFT)
typedef struct {
uint16_t bg;
uint16_t fg;
uint8_t border;
int8_t icon;
union {
int32_t i;
uint32_t u;
const char *text;
} p1, p2; // void data for label printf
} button_t;
// Call back functions for MT_CALLBACK type
typedef void (*menuaction_cb_t)(uint16_t data);
#define UI_FUNCTION_CALLBACK(ui_function_name) void ui_function_name(uint16_t data)
typedef void (*menuaction_acb_t)(uint16_t data, button_t *b);
#define UI_FUNCTION_ADV_CALLBACK(ui_function_name) void ui_function_name(uint16_t data, button_t *b)
// Set structure align as WORD (save flash memory)
#pragma pack(push, 2)
typedef struct {
uint8_t type;
uint8_t data;
char *label;
const void *reference;
} menuitem_t;
#pragma pack(pop)
// Touch screen
#define EVT_TOUCH_NONE 0
#define EVT_TOUCH_DOWN 1
#define EVT_TOUCH_PRESSED 2
#define EVT_TOUCH_RELEASED 3
#define TOUCH_INTERRUPT_ENABLED 1
static uint8_t touch_status_flag = 0;
static uint8_t last_touch_status = EVT_TOUCH_NONE;
static int16_t last_touch_x;
static int16_t last_touch_y;
#define KP_CONTINUE 0
#define KP_DONE 1
#define KP_CANCEL 2
static void ui_mode_normal(void);
static void ui_mode_menu(void);
static void ui_mode_keypad(int _keypad_mode);
static void draw_menu(void);
static void ui_process_keypad(void);
static void touch_position(int *x, int *y);
static void menu_move_back(bool leave_ui);
static void menu_push_submenu(const menuitem_t *submenu);
static void drawMessageBox(char *header, char *text, uint32_t delay);
#ifdef UI_USE_NUMERIC_INPUT
static void ui_mode_numeric(int _keypad_mode);
#endif
static int btn_check(void)
{
systime_t ticks;
// Debounce input
while(TRUE){
ticks = chVTGetSystemTimeX();
if(ticks - last_button_down_ticks > BUTTON_DEBOUNCE_TICKS)
break;
chThdSleepMilliseconds(10);
}
int status = 0;
uint16_t cur_button = READ_PORT() & BUTTON_MASK;
// Detect only changed and pressed buttons
uint16_t button_set = (last_button ^ cur_button) & cur_button;
last_button_down_ticks = ticks;
last_button = cur_button;
if (button_set & (1<<BIT_PUSH))
status |= EVT_BUTTON_SINGLE_CLICK;
if (button_set & (1<<BIT_UP1))
status |= EVT_UP;
if (button_set & (1<<BIT_DOWN1))
status |= EVT_DOWN;
return status;
}
static int btn_wait_release(void)
{
while (TRUE) {
systime_t ticks = chVTGetSystemTimeX();
systime_t dt = ticks - last_button_down_ticks;
// Debounce input
// if (dt < BUTTON_DEBOUNCE_TICKS){
// chThdSleepMilliseconds(10);
// continue;
// }
chThdSleepMilliseconds(10);
uint16_t cur_button = READ_PORT() & BUTTON_MASK;
uint16_t changed = last_button ^ cur_button;
if (dt >= BUTTON_DOWN_LONG_TICKS && (cur_button & (1<<BIT_PUSH)))
return EVT_BUTTON_DOWN_LONG;
if (changed & (1<<BIT_PUSH)) // release
return EVT_BUTTON_SINGLE_CLICK;
if (changed) {
// finished
last_button = cur_button;
last_button_down_ticks = ticks;
return 0;
}
if (dt > BUTTON_DOWN_LONG_TICKS &&
ticks > last_button_repeat_ticks) {
int status = 0;
if (cur_button & (1<<BIT_DOWN1))
status |= EVT_DOWN | EVT_REPEAT;
if (cur_button & (1<<BIT_UP1))
status |= EVT_UP | EVT_REPEAT;
last_button_repeat_ticks = ticks + BUTTON_REPEAT_TICKS;
return status;
}
}
}
#if 0
static void bubbleSort(uint16_t *v, int n) {
bool swapped = true;
int i = 0, j;
while (i < n - 1 && swapped) { // keep going while we swap in the unordered part
swapped = false;
for (j = n - 1; j > i; j--) { // unordered part
if (v[j] < v[j - 1]) {
SWAP(uint16_t, v[j], v[j - 1]);
swapped = true;
}
}
i++;
}
}
#endif
#define SOFTWARE_TOUCH
//*******************************************************************************
// Software Touch module
//*******************************************************************************
#ifdef SOFTWARE_TOUCH
// ADC read count for measure X and Y (2^N count)
#define TOUCH_X_N 2
#define TOUCH_Y_N 2
static int
touch_measure_y(void)
{
// drive low to high on X line (At this state after touch_prepare_sense)
// palSetPadMode(GPIOB, GPIOB_XN, PAL_MODE_OUTPUT_PUSHPULL); //
// palSetPadMode(GPIOA, GPIOA_XP, PAL_MODE_OUTPUT_PUSHPULL); //
// drive low to high on X line (coordinates from top to bottom)
palClearPad(GPIOB, GPIOB_XN);
// palSetPad(GPIOA, GPIOA_XP);
// open Y line (At this state after touch_prepare_sense)
// palSetPadMode(GPIOB, GPIOB_YN, PAL_MODE_INPUT); // Hi-z mode
palSetPadMode(GPIOA, GPIOA_YP, PAL_MODE_INPUT_ANALOG); // <- ADC_TOUCH_Y channel
// chThdSleepMilliseconds(20);
uint32_t v = 0, cnt = 1<<TOUCH_Y_N;
do{v+=adc_single_read(ADC_TOUCH_Y);}while(--cnt);
return v>>TOUCH_Y_N;
}
static int
touch_measure_x(void)
{
// drive high to low on Y line (coordinates from left to right)
palSetPad(GPIOB, GPIOB_YN);
palClearPad(GPIOA, GPIOA_YP);
// Set Y line as output
palSetPadMode(GPIOB, GPIOB_YN, PAL_MODE_OUTPUT_PUSHPULL);
palSetPadMode(GPIOA, GPIOA_YP, PAL_MODE_OUTPUT_PUSHPULL);
// Set X line as input
palSetPadMode(GPIOB, GPIOB_XN, PAL_MODE_INPUT); // Hi-z mode
palSetPadMode(GPIOA, GPIOA_XP, PAL_MODE_INPUT_ANALOG); // <- ADC_TOUCH_X channel
uint32_t v = 0, cnt = 1<<TOUCH_X_N;
do{v+=adc_single_read(ADC_TOUCH_X);}while(--cnt);
return v>>TOUCH_X_N;
}
// Manually measure touch event
static inline int
touch_status(void)
{
return adc_single_read(ADC_TOUCH_Y) > TOUCH_THRESHOLD;
}
static void
touch_prepare_sense(void)
{
// Set Y line as input
palSetPadMode(GPIOB, GPIOB_YN, PAL_MODE_INPUT); // Hi-z mode
palSetPadMode(GPIOA, GPIOA_YP, PAL_MODE_INPUT_PULLDOWN); // Use pull
// drive high on X line (for touch sense on Y)
palSetPad(GPIOB, GPIOB_XN);
palSetPad(GPIOA, GPIOA_XP);
// force high X line
palSetPadMode(GPIOB, GPIOB_XN, PAL_MODE_OUTPUT_PUSHPULL);
palSetPadMode(GPIOA, GPIOA_XP, PAL_MODE_OUTPUT_PUSHPULL);
// chThdSleepMilliseconds(10); // Wait 10ms for denounce touch
}
static void
touch_start_watchdog(void)
{
if (touch_status_flag&TOUCH_INTERRUPT_ENABLED) return;
touch_status_flag^=TOUCH_INTERRUPT_ENABLED;
adc_start_analog_watchdog();
}
static void
touch_stop_watchdog(void)
{
if (!(touch_status_flag&TOUCH_INTERRUPT_ENABLED)) return;
touch_status_flag^=TOUCH_INTERRUPT_ENABLED;
adc_stop_analog_watchdog();
}
// Touch panel timer check (check press frequency 20Hz)
static const GPTConfig gpt3cfg = {
20, // 200Hz timer clock. 200/10 = 20Hz touch check
NULL, // Timer callback.
0x0020, // CR2:MMS=02 to output TRGO
0
};
//
// Touch init function init timer 3 trigger adc for check touch interrupt, and run measure
//
static void touch_init(void){
// Prepare pin for measure touch event
touch_prepare_sense();
// Start touch interrupt, used timer_3 ADC check threshold:
gptStart(&GPTD3, &gpt3cfg); // Init timer 3
gptStartContinuous(&GPTD3, 10); // Start timer 3 vs timer 10 interval
touch_start_watchdog(); // Start ADC watchdog (measure by timer 3 interval and trigger interrupt if touch pressed)
}
// Main software touch function, should:
// set last_touch_x and last_touch_x
// return touch status
static int
touch_check(void)
{
touch_stop_watchdog();
int stat = touch_status();
if (stat) {
int y = touch_measure_y();
int x = touch_measure_x();
touch_prepare_sense();
if (touch_status())
{
last_touch_x = x;
last_touch_y = y;
}
}
if (stat != last_touch_status) {
last_touch_status = stat;
return stat ? EVT_TOUCH_PRESSED : EVT_TOUCH_RELEASED;
}
return stat ? EVT_TOUCH_DOWN : EVT_TOUCH_NONE;
}
//*******************************************************************************
// End Software Touch module
//*******************************************************************************
#endif // end SOFTWARE_TOUCH
static inline void
touch_wait_release(void)
{
while (touch_check() != EVT_TOUCH_RELEASED)
;
}
static inline void
touch_wait_pressed(void)
{
while (touch_check() != EVT_TOUCH_PRESSED)
;
}
void
touch_cal_exec(void)
{
int x1, x2, y1, y2;
ili9341_set_foreground(LCD_FG_COLOR);
ili9341_set_background(LCD_BG_COLOR);
ili9341_clear_screen();
ili9341_line(0, 0, 0, 32);
ili9341_line(0, 0, 32, 0);
ili9341_drawstring("TOUCH UPPER LEFT", 10, 10);
touch_wait_release();
x1 = last_touch_x;
y1 = last_touch_y;
ili9341_clear_screen();
ili9341_line(LCD_WIDTH-1, LCD_HEIGHT-1, LCD_WIDTH-1, LCD_HEIGHT-32);
ili9341_line(LCD_WIDTH-1, LCD_HEIGHT-1, LCD_WIDTH-32, LCD_HEIGHT-1);
ili9341_drawstring("TOUCH LOWER RIGHT", LCD_WIDTH-17*(FONT_WIDTH)-10, LCD_HEIGHT-FONT_GET_HEIGHT-10);
touch_wait_release();
x2 = last_touch_x;
y2 = last_touch_y;
config._touch_cal[0] = x1;
config._touch_cal[1] = y1;
config._touch_cal[2] = (x2 - x1) * 16 / LCD_WIDTH;
config._touch_cal[3] = (y2 - y1) * 16 / LCD_HEIGHT;
}
void
touch_draw_test(void)
{
int x0, y0;
int x1, y1;
ili9341_set_foreground(LCD_FG_COLOR);
ili9341_set_background(LCD_BG_COLOR);
ili9341_clear_screen();
ili9341_drawstring("TOUCH TEST: DRAG PANEL, PRESS BUTTON TO FINISH", OFFSETX, LCD_HEIGHT - FONT_GET_HEIGHT);
do {
if (touch_check() == EVT_TOUCH_PRESSED){
touch_position(&x0, &y0);
do {
chThdSleepMilliseconds(50);
touch_position(&x1, &y1);
ili9341_line(x0, y0, x1, y1);
x0 = x1;
y0 = y1;
} while (touch_check() != EVT_TOUCH_RELEASED);
}
}while (!(btn_check() & EVT_BUTTON_SINGLE_CLICK));
}
static void
touch_position(int *x, int *y)
{
int tx = (last_touch_x - config._touch_cal[0]) * 16 / config._touch_cal[2];
if (tx<0) tx = 0; else if (tx>=LCD_WIDTH ) tx = LCD_WIDTH -1;
int ty = (last_touch_y - config._touch_cal[1]) * 16 / config._touch_cal[3];
if (ty<0) ty = 0; else if (ty>=LCD_HEIGHT) ty = LCD_HEIGHT-1;
*x = tx;
*y = ty;
}
static void
show_version(void)
{
int x = 5, y = 5, i = 1;
ili9341_set_foreground(LCD_FG_COLOR);
ili9341_set_background(LCD_BG_COLOR);
ili9341_clear_screen();
uint16_t shift = 0b000100000;
ili9341_drawstring_size(BOARD_NAME, x , y, 3);
y+=FONT_GET_HEIGHT*3+3-5;
while (info_about[i]) {
do {shift>>=1; y+=5;} while (shift&1);
ili9341_drawstring(info_about[i++], x, y+=FONT_STR_HEIGHT+3-5);
}
// Update battery and time
y+=3*FONT_STR_HEIGHT;
uint16_t cnt = 0;
while (true) {
if (touch_check() == EVT_TOUCH_PRESSED)
break;
if (btn_check() & EVT_BUTTON_SINGLE_CLICK)
break;
chThdSleepMilliseconds(40);
if ((cnt++)&0x07) continue; // Not update time so fast
char buffer[32];
#ifdef __USE_RTC__
uint32_t tr = rtc_get_tr_bin(); // TR read first
uint32_t dr = rtc_get_dr_bin(); // DR read second
plot_printf(buffer, sizeof(buffer), "Time: 20%02d/%02d/%02d %02d:%02d:%02d" " (LS%c)",
RTC_DR_YEAR(dr),
RTC_DR_MONTH(dr),
RTC_DR_DAY(dr),
RTC_TR_HOUR(dr),
RTC_TR_MIN(dr),
RTC_TR_SEC(dr),
(RCC->BDCR & STM32_RTCSEL_MASK) == STM32_RTCSEL_LSE ? 'E' : 'I');
ili9341_drawstring(buffer, x, y);
#endif
#if 1
uint32_t vbat=adc_vbat_read();
plot_printf(buffer, sizeof(buffer), "Batt: %d.%03dV", vbat/1000, vbat%1000);
ili9341_drawstring(buffer, x, y + FONT_STR_HEIGHT + 2);
#endif
}
}
void
enter_dfu(void)
{
#ifdef __DFU_SOFTWARE_MODE__
touch_stop_watchdog();
int x = 5, y = 20;
ili9341_set_foreground(LCD_FG_COLOR);
ili9341_set_background(LCD_BG_COLOR);
// leave a last message
ili9341_clear_screen();
ili9341_drawstring("DFU: Device Firmware Update Mode\n"
"To exit DFU mode, please reset device yourself.", x, y);
// see __early_init in ./NANOVNA_STM32_F072/board.c
*((unsigned long *)BOOT_FROM_SYTEM_MEMORY_MAGIC_ADDRESS) = BOOT_FROM_SYTEM_MEMORY_MAGIC;
NVIC_SystemReset();
#endif
}
static void
select_lever_mode(int mode)
{
if (lever_mode != mode) {
lever_mode = mode;
request_to_redraw(REDRAW_FREQUENCY | REDRAW_MARKER);
}
}
static UI_FUNCTION_ADV_CALLBACK(menu_calop_acb)
{
static const struct {uint8_t mask, next;} c_list[5]={
[CAL_LOAD] = {CALSTAT_LOAD, 3},
[CAL_OPEN] = {CALSTAT_OPEN, 1},
[CAL_SHORT]= {CALSTAT_SHORT, 2},
[CAL_THRU] = {CALSTAT_THRU, 5},
[CAL_ISOLN]= {CALSTAT_ISOLN, 4},
};
if (b){
if (cal_status & c_list[data].mask) b->icon = BUTTON_ICON_CHECK;
return;
}
// TODO: Hack! reset button state
last_button = 0;
cal_collect(data);
selection = c_list[data].next;
}
static UI_FUNCTION_CALLBACK(menu_caldone_cb)
{
extern const menuitem_t menu_save[];
(void)data;
cal_done();
menu_move_back(false);
menu_push_submenu(menu_save);
}
static UI_FUNCTION_CALLBACK(menu_cal_reset_cb)
{
(void)data;
// RESET
cal_status = 0;
set_power(SI5351_CLK_DRIVE_STRENGTH_AUTO);
}
static UI_FUNCTION_ADV_CALLBACK(menu_cal_apply_acb)
{
(void)data;
if (b){
b->icon = (cal_status&CALSTAT_APPLY) ? BUTTON_ICON_CHECK : BUTTON_ICON_NOCHECK;
return;
}
// toggle applying correction
cal_status ^= CALSTAT_APPLY;
request_to_redraw(REDRAW_CAL_STATUS);
}
static UI_FUNCTION_ADV_CALLBACK(menu_recall_acb)
{
if (b){
b->p1.i = data;
if (lastsaveid == data) b->icon = BUTTON_ICON_CHECK;
return;
}
load_properties(data);
}
#define MENU_CONFIG_TOUCH_CAL 0
#define MENU_CONFIG_TOUCH_TEST 1
#define MENU_CONFIG_VERSION 2
static UI_FUNCTION_CALLBACK(menu_config_cb)
{
switch (data) {
case MENU_CONFIG_TOUCH_CAL:
touch_cal_exec();
break;
case MENU_CONFIG_TOUCH_TEST:
touch_draw_test();
break;
case MENU_CONFIG_VERSION:
show_version();
break;
}
ui_mode_normal();
request_to_redraw(REDRAW_CLRSCR | REDRAW_AREA | REDRAW_BATTERY | REDRAW_CAL_STATUS | REDRAW_FREQUENCY);
}
static UI_FUNCTION_CALLBACK(menu_config_save_cb)
{
(void)data;
config_save();
menu_move_back(true);
}
#ifdef __DFU_SOFTWARE_MODE__
static UI_FUNCTION_CALLBACK(menu_dfu_cb)
{
(void)data;
enter_dfu();
}
#endif
static UI_FUNCTION_ADV_CALLBACK(menu_save_acb)
{
if (b){
b->p1.u = data;
return;
}
if (caldata_save(data) == 0) {
menu_move_back(true);
request_to_redraw(REDRAW_CAL_STATUS);
}
}
static UI_FUNCTION_ADV_CALLBACK(menu_trace_acb)
{
if (b){
if (trace[data].enabled){
b->bg = LCD_TRACE_1_COLOR + data;
if (data == selection) b->bg = LCD_MENU_ACTIVE_COLOR;
if (current_trace == data)
b->icon = BUTTON_ICON_CHECK;
}
b->p1.u = data;
return;
}
if (trace[data].enabled) {
if (data == current_trace) {
trace[data].enabled = FALSE; // disable if active trace is selected
current_trace = TRACE_INVALID; // invalidate current
for (int i = 0; i < TRACES_MAX; i++) // set first enabled as current trace
if (trace[i].enabled) {current_trace = i; break;}
} else {
// make active selected trace
current_trace = data;
}
} else {
trace[data].enabled = TRUE;
current_trace = data;
}
request_to_redraw(REDRAW_AREA);
}
static UI_FUNCTION_ADV_CALLBACK(menu_format_acb)
{
if (current_trace == TRACE_INVALID) return;
if (b){
if (trace[current_trace].type == data)
b->icon = BUTTON_ICON_CHECK;
return;
}
set_trace_type(current_trace, data);
ui_mode_normal();
}
static UI_FUNCTION_ADV_CALLBACK(menu_channel_acb)
{
if (current_trace == TRACE_INVALID) return;
if (b){
if (trace[current_trace].channel == data)
b->icon = BUTTON_ICON_CHECK;
return;
}
set_trace_channel(current_trace, data);
menu_move_back(true);
}
static UI_FUNCTION_ADV_CALLBACK(menu_transform_window_acb)
{
if(b){
b->icon = (domain_mode & TD_WINDOW) == data ? BUTTON_ICON_GROUP_CHECKED : BUTTON_ICON_GROUP;
return;
}
domain_mode = (domain_mode & ~TD_WINDOW) | data;
ui_mode_normal();
}
static UI_FUNCTION_ADV_CALLBACK(menu_transform_acb)
{
(void)data;
if(b){
if (domain_mode & DOMAIN_TIME) b->icon = BUTTON_ICON_CHECK;
return;
}
domain_mode ^= DOMAIN_TIME;
select_lever_mode(LM_MARKER);
ui_mode_normal();
}
static UI_FUNCTION_ADV_CALLBACK(menu_transform_filter_acb)
{
if(b){
b->icon = (domain_mode & TD_FUNC) == data ? BUTTON_ICON_GROUP_CHECKED : BUTTON_ICON_GROUP;
return;
}
domain_mode = (domain_mode & ~TD_FUNC) | data;
ui_mode_normal();
}
static UI_FUNCTION_ADV_CALLBACK(menu_bandwidth_acb)
{
if (b){
b->icon = config._bandwidth == data ? BUTTON_ICON_GROUP_CHECKED : BUTTON_ICON_GROUP;
b->p1.u = get_bandwidth_frequency(data);
return;
}
set_bandwidth(data);
}
#ifdef __USE_SMOOTH__
static UI_FUNCTION_ADV_CALLBACK(menu_smooth_func_acb)
{
(void)data;
if (b){
b->p1.text = (config._vna_mode&VNA_SMOOTH_FUNCTION) ? "Arith" : "Geom";
return;
}
config._vna_mode^=VNA_SMOOTH_FUNCTION;
}
static UI_FUNCTION_ADV_CALLBACK(menu_smooth_acb)
{
if (b){
b->icon = get_smooth_factor() == data ? BUTTON_ICON_GROUP_CHECKED : BUTTON_ICON_GROUP;
b->p1.u = data;
return;
}
set_smooth_factor(data);
}
#endif
static const uint16_t point_counts_set[POINTS_SET_COUNT] = POINTS_SET;
static UI_FUNCTION_ADV_CALLBACK(menu_points_acb)
{
uint16_t p_count = point_counts_set[data];
if (b){
b->icon = sweep_points == p_count ? BUTTON_ICON_GROUP_CHECKED : BUTTON_ICON_GROUP;
b->p1.u = p_count;
return;
}
set_sweep_points(p_count);
}
static UI_FUNCTION_ADV_CALLBACK(menu_power_acb)
{
if (b){
b->icon = current_props._power == data ? BUTTON_ICON_GROUP_CHECKED : BUTTON_ICON_GROUP;
b->p1.u = 2+data*2;
return;
}
set_power(data);
}
static UI_FUNCTION_CALLBACK(menu_keyboard_cb)
{
if (data == KM_SCALE && trace[current_trace].type == TRC_DELAY) {
data = KM_SCALEDELAY;
}
#ifdef UI_USE_NUMERIC_INPUT
if (btn_wait_release() & EVT_BUTTON_DOWN_LONG) {
ui_mode_numeric(data);
// ui_process_numeric();
}
else
#endif
{
ui_mode_keypad(data);
ui_process_keypad();
}
}
#ifdef __USE_GRID_VALUES__
static UI_FUNCTION_ADV_CALLBACK(menu_grid_acb)
{
if (b){
b->icon = VNA_mode & data ? BUTTON_ICON_CHECK : BUTTON_ICON_NOCHECK;
return;
}
VNA_mode^=data;
request_to_redraw(REDRAW_AREA);
}
#endif
static UI_FUNCTION_ADV_CALLBACK(menu_pause_acb)
{
(void)data;
if (b){
b->icon = sweep_mode&SWEEP_ENABLE ? BUTTON_ICON_NOCHECK : BUTTON_ICON_CHECK;
return;
}
sweep_mode^= SWEEP_ENABLE;
}
#define UI_MARKER_EDELAY 4
static UI_FUNCTION_CALLBACK(menu_marker_op_cb)
{
freq_t freq = get_marker_frequency(active_marker);
if (freq == 0)
return; // no active marker
switch (data) {
case ST_START:
case ST_STOP:
case ST_CENTER:
set_sweep_frequency(data, freq);
break;
case ST_SPAN:
{
if (previous_marker == MARKER_INVALID || active_marker == previous_marker) {
// if only 1 marker is active, keep center freq and make span the marker comes to the edge
freq_t center = get_sweep_frequency(ST_CENTER);
freq_t span = center > freq ? center - freq : freq - center;
set_sweep_frequency(ST_SPAN, span * 2);
} else {
// if 2 or more marker active, set start and stop freq to each marker
freq_t freq2 = get_marker_frequency(previous_marker);
if (freq2 == 0)
return;
if (freq > freq2) SWAP(freq_t, freq2, freq);
set_sweep_frequency(ST_START, freq);
set_sweep_frequency(ST_STOP, freq2);
}
}
break;
case UI_MARKER_EDELAY:
{
if (current_trace == TRACE_INVALID)
break;
float (*array)[2] = measured[trace[current_trace].channel];
float v = groupdelay_from_array(markers[active_marker].index, array);
set_electrical_delay(electrical_delay + (v / 1e-12));
}
break;
}
ui_mode_normal();
}
#define MENU_MARKER_S_MAX 0
#define MENU_MARKER_S_MIN VNA_MODE_SEARCH_MIN
static UI_FUNCTION_ADV_CALLBACK(menu_marker_search_mode_acb)
{
if (b){
b->icon = ((VNA_mode & VNA_MODE_SEARCH_MASK) == data) ? BUTTON_ICON_GROUP_CHECKED : BUTTON_ICON_GROUP;
return;
}
VNA_mode = (VNA_mode & ~VNA_MODE_SEARCH_MASK) | data;
marker_search(true);
#ifdef UI_USE_LEVELER_SEARCH_MODE
select_lever_mode(LM_SEARCH);
#endif
}
static UI_FUNCTION_CALLBACK(menu_marker_search_dir_cb)
{
marker_search_dir(markers[active_marker].index, data == MK_SEARCH_RIGHT ? MK_SEARCH_RIGHT : MK_SEARCH_LEFT);
VNA_mode&=~VNA_MODE_MARKER_TRACK;
#ifdef UI_USE_LEVELER_SEARCH_MODE
select_lever_mode(LM_SEARCH);
#endif
}
static UI_FUNCTION_ADV_CALLBACK(menu_marker_tracking_acb)
{
(void)data;
if (b){
b->icon = (VNA_mode & VNA_MODE_MARKER_TRACK) ? BUTTON_ICON_CHECK : BUTTON_ICON_NOCHECK;
return;
}
VNA_mode^= VNA_MODE_MARKER_TRACK;
}
static UI_FUNCTION_ADV_CALLBACK(menu_marker_smith_acb)
{
if (b){
b->icon = marker_smith_format == data ? BUTTON_ICON_GROUP_CHECKED : BUTTON_ICON_GROUP;
return;
}
marker_smith_format = data;
request_to_redraw(REDRAW_MARKER);
}
#ifdef __USE_LC_MATCHING__
static UI_FUNCTION_ADV_CALLBACK(menu_marker_lc_match_acb)
{
(void)data;
if (b){
b->icon = domain_mode & TD_LC_MATH ? BUTTON_ICON_CHECK : BUTTON_ICON_NOCHECK;
return;
}
domain_mode^=TD_LC_MATH;
ui_mode_normal();
}
#endif
static void
active_marker_check(void)
{
int i;
// Auto select active marker if disabled
if (active_marker == MARKER_INVALID)
for (i = 0; i < MARKERS_MAX; i++)
if (markers[i].enabled) active_marker = i;
// Auto select previous marker if disabled
if (previous_marker == active_marker) previous_marker = MARKER_INVALID;
if (previous_marker == MARKER_INVALID){
for (i = 0; i < MARKERS_MAX; i++)
if (markers[i].enabled && i != active_marker) previous_marker = i;
}
}
static UI_FUNCTION_ADV_CALLBACK(menu_marker_sel_acb)
{
if (b){
if (data < MARKERS_MAX){
if (data == active_marker) b->icon = BUTTON_ICON_CHECK_AUTO;
else if (markers[data].enabled) b->icon = BUTTON_ICON_CHECK;
b->p1.u = data + 1;
}
return;
}
// Marker select click
if (data < MARKERS_MAX) {
int mk = data;
if (markers[mk].enabled) { // Marker enabled
if (mk == active_marker) { // If active marker:
markers[mk].enabled = FALSE; // disable it
mk = previous_marker; // set select from previous marker
active_marker = MARKER_INVALID; // invalidate active
}
} else {
markers[mk].enabled = TRUE; // Enable marker
}
previous_marker = active_marker; // set previous marker as current active
active_marker = mk; // set new active marker
active_marker_check();
}
request_to_redraw(REDRAW_MARKER);
}
#if MARKERS_MAX < 6
static UI_FUNCTION_CALLBACK(menu_marker_disable_all_cb)
{
(void)data;
int i;
for (i = 0; i < MARKERS_MAX; i++)
markers[i].enabled = FALSE; // all off
previous_marker = MARKER_INVALID;
active_marker = MARKER_INVALID;
request_to_redraw(REDRAW_MARKER);
}
#endif
static UI_FUNCTION_ADV_CALLBACK(menu_marker_delta_acb)
{
(void)data;
if (b){
b->icon = VNA_mode & VNA_MODE_MARKER_DELTA ? BUTTON_ICON_CHECK : BUTTON_ICON_NOCHECK;
return;
}
VNA_mode^= VNA_MODE_MARKER_DELTA;
request_to_redraw(REDRAW_MARKER);
}
#ifdef __USE_SERIAL_CONSOLE__
static const uint32_t usart_speed[] = {19200, 38400, 57600, 115200, 230400, 460800, 921600};
static UI_FUNCTION_ADV_CALLBACK(menu_serial_speed_acb)
{
uint32_t speed = usart_speed[data];
if (b){
b->icon = config._serial_speed == speed ? BUTTON_ICON_GROUP_CHECKED : BUTTON_ICON_GROUP;
b->p1.u = speed;
return;
}
config._serial_speed = speed;
shell_update_speed();
}
static UI_FUNCTION_ADV_CALLBACK(menu_connection_acb)
{
if (b){
b->icon = (VNA_mode & VNA_MODE_CONNECTION_MASK) == data ? BUTTON_ICON_GROUP_CHECKED : BUTTON_ICON_GROUP;
return;
}
VNA_mode = (VNA_mode & ~VNA_MODE_CONNECTION_MASK) | data;
shell_reset_console();
}
#endif
#ifdef __LCD_BRIGHTNESS__
static UI_FUNCTION_CALLBACK(menu_brightness_cb)
{
(void)data;
int16_t value = config._brightness;
ili9341_set_foreground(LCD_MENU_TEXT_COLOR);
ili9341_set_background(LCD_MENU_COLOR);
ili9341_fill(LCD_WIDTH/2-80, LCD_HEIGHT/2-20, 160, 40);
ili9341_drawstring("BRIGHTNESS", LCD_WIDTH/2-35, LCD_HEIGHT/2-13);
ili9341_drawstring(S_LARROW" USE LEVELER BUTTON "S_RARROW, LCD_WIDTH/2-72, LCD_HEIGHT/2+2);
while (TRUE) {
int status = btn_check();
if (status & (EVT_UP|EVT_DOWN)) {
do {
if (status & EVT_UP ) value+=5;
if (status & EVT_DOWN) value-=5;
if (value < 0) value = 0;
if (value > 100) value = 100;
lcd_setBrightness(value);
status = btn_wait_release();
} while (status != 0);
}
if (status == EVT_BUTTON_SINGLE_CLICK)
break;
}
config._brightness = (uint8_t)value;
lcd_setBrightness(value);
request_to_redraw(REDRAW_AREA);
ui_mode_normal();
}
#endif
#ifdef __USE_SD_CARD__
#define SAVE_S1P_FILE 1
#define SAVE_S2P_FILE 2
static const char s1_file_header[] =
"!File created by NanoVNA\r\n"\
"# Hz S RI R 50\r\n";
static const char s1_file_param[] =
"%10u % f % f\r\n";
static const char s2_file_header[] =
"!File created by NanoVNA\r\n"\
"# Hz S RI R 50\r\n";
static const char s2_file_param[] =
"%10u % f % f % f % f 0 0 0 0\r\n";
static UI_FUNCTION_CALLBACK(menu_sdcard_cb)
{
char *buf = (char *)spi_buffer;
// shell_printf("S file\r\n");
FRESULT res = f_mount(fs_volume, "", 1);
// shell_printf("Mount = %d\r\n", res);
if (res != FR_OK)
return;
// Prepare filename = .s1p or .s2p and open for write
#if FF_USE_LFN >= 1
uint32_t tr = rtc_get_tr_bcd(); // TR read first
uint32_t dr = rtc_get_dr_bcd(); // DR read second
plot_printf(fs_filename, FF_LFN_BUF, "VNA_%06X_%06X.s%dp", dr, tr, data);
#else
plot_printf(fs_filename, FF_LFN_BUF, "%08X.s%dp", rtc_get_FAT(), data);
#endif
int i;
UINT size;
// UINT total_size = 0;
// systime_t time = chVTGetSystemTimeX();
res = f_open(fs_file, fs_filename, FA_CREATE_ALWAYS | FA_READ | FA_WRITE);
// shell_printf("Open %s, = %d\r\n", fs_filename, res);
if (res == FR_OK){
// Write S1P file
if (data == SAVE_S1P_FILE){
// write s1p header (not write NULL terminate at end)
res = f_write(fs_file, s1_file_header, sizeof(s1_file_header)-1, &size);
// total_size+=size;
// Write all points data
for (i = 0; i < sweep_points && res == FR_OK; i++) {
size = plot_printf(buf, 128, s1_file_param, frequencies[i], measured[0][i][0], measured[0][i][1]);
// total_size+=size;
res = f_write(fs_file, buf, size, &size);
}
}
// Write S2P file
else if (data == SAVE_S2P_FILE){
// Write s2p header (not write NULL terminate at end)
res = f_write(fs_file, s2_file_header, sizeof(s2_file_header)-1, &size);
// total_size+=size;
// Write all points data
for (i = 0; i < sweep_points && res == FR_OK; i++) {
size = plot_printf(buf, 128, s2_file_param, frequencies[i], measured[0][i][0], measured[0][i][1], measured[1][i][0], measured[1][i][1]);
// total_size+=size;
res = f_write(fs_file, buf, size, &size);
}
}
res = f_close(fs_file);
// shell_printf("Close = %d\r\n", res);
// testLog();
// time = chVTGetSystemTimeX() - time;
// shell_printf("Total time: %dms (write %d byte/sec)\r\n", time/10, total_size*10000/time);
}
drawMessageBox("SAVE TRACE", res == FR_OK ? fs_filename : " Fail write ", 2000);
request_to_redraw(REDRAW_AREA);
ui_mode_normal();
}
static const menuitem_t menu_sdcard[] = {
{ MT_CALLBACK, SAVE_S1P_FILE, "SAVE S1P", menu_sdcard_cb },
{ MT_CALLBACK, SAVE_S2P_FILE, "SAVE S2P", menu_sdcard_cb },
{ MT_CANCEL, 0, S_LARROW" BACK", NULL },
{ MT_NONE, 0, NULL, NULL } // sentinel
};
#endif
static const menuitem_t menu_calop[] = {
{ MT_ADV_CALLBACK, CAL_OPEN, "OPEN", menu_calop_acb },
{ MT_ADV_CALLBACK, CAL_SHORT, "SHORT", menu_calop_acb },
{ MT_ADV_CALLBACK, CAL_LOAD, "LOAD", menu_calop_acb },
{ MT_ADV_CALLBACK, CAL_ISOLN, "ISOLN", menu_calop_acb },
{ MT_ADV_CALLBACK, CAL_THRU, "THRU", menu_calop_acb },
{ MT_CALLBACK, 0, "DONE", menu_caldone_cb },
{ MT_CANCEL, 0, S_LARROW" BACK", NULL },
{ MT_NONE, 0, NULL, NULL } // sentinel
};
const menuitem_t menu_save[] = {
{ MT_ADV_CALLBACK, 0, "SAVE %d", menu_save_acb },
{ MT_ADV_CALLBACK, 1, "SAVE %d", menu_save_acb },
{ MT_ADV_CALLBACK, 2, "SAVE %d", menu_save_acb },
#if SAVEAREA_MAX > 3
{ MT_ADV_CALLBACK, 3, "SAVE %d", menu_save_acb },
#endif
#if SAVEAREA_MAX > 4
{ MT_ADV_CALLBACK, 4, "SAVE %d", menu_save_acb },
#endif
#if SAVEAREA_MAX > 5
{ MT_ADV_CALLBACK, 5, "SAVE %d", menu_save_acb },
#endif
#if SAVEAREA_MAX > 6
{ MT_ADV_CALLBACK, 6, "SAVE %d", menu_save_acb },
#endif
{ MT_CANCEL, 0, S_LARROW" BACK", NULL },
{ MT_NONE, 0, NULL, NULL } // sentinel
};
const menuitem_t menu_recall[] = {
{ MT_ADV_CALLBACK, 0, "RECALL %d", menu_recall_acb },
{ MT_ADV_CALLBACK, 1, "RECALL %d", menu_recall_acb },
{ MT_ADV_CALLBACK, 2, "RECALL %d", menu_recall_acb },
#if SAVEAREA_MAX > 3
{ MT_ADV_CALLBACK, 3, "RECALL %d", menu_recall_acb },
#endif
#if SAVEAREA_MAX > 4
{ MT_ADV_CALLBACK, 4, "RECALL %d", menu_recall_acb },
#endif
#if SAVEAREA_MAX > 5
{ MT_ADV_CALLBACK, 5, "RECALL %d", menu_recall_acb },
#endif
#if SAVEAREA_MAX > 6
{ MT_ADV_CALLBACK, 6, "RECALL %d", menu_recall_acb },
#endif
{ MT_CANCEL, 0, S_LARROW" BACK", NULL },
{ MT_NONE, 0, NULL, NULL } // sentinel
};
const menuitem_t menu_power[] = {
{ MT_ADV_CALLBACK, SI5351_CLK_DRIVE_STRENGTH_AUTO, "AUTO", menu_power_acb },
{ MT_ADV_CALLBACK, SI5351_CLK_DRIVE_STRENGTH_2MA, "%u mA", menu_power_acb },
{ MT_ADV_CALLBACK, SI5351_CLK_DRIVE_STRENGTH_4MA, "%u mA", menu_power_acb },
{ MT_ADV_CALLBACK, SI5351_CLK_DRIVE_STRENGTH_6MA, "%u mA", menu_power_acb },
{ MT_ADV_CALLBACK, SI5351_CLK_DRIVE_STRENGTH_8MA, "%u mA", menu_power_acb },
{ MT_CANCEL, 0, S_LARROW" BACK", NULL },
{ MT_NONE, 0, NULL, NULL } // sentinel
};
const menuitem_t menu_cal[] = {
{ MT_SUBMENU, 0, "CALIBRATE", menu_calop },
{ MT_SUBMENU, 0, "POWER", menu_power },
{ MT_SUBMENU, 0, "SAVE", menu_save },
{ MT_CALLBACK, 0, "RESET", menu_cal_reset_cb },
{ MT_ADV_CALLBACK, 0, "APPLY", menu_cal_apply_acb },
{ MT_CANCEL, 0, S_LARROW" BACK", NULL },
{ MT_NONE, 0, NULL, NULL } // sentinel
};
const menuitem_t menu_trace[] = {
{ MT_ADV_CALLBACK, 0, "TRACE %d", menu_trace_acb },
{ MT_ADV_CALLBACK, 1, "TRACE %d", menu_trace_acb },
{ MT_ADV_CALLBACK, 2, "TRACE %d", menu_trace_acb },
{ MT_ADV_CALLBACK, 3, "TRACE %d", menu_trace_acb },
{ MT_CANCEL, 0, S_LARROW" BACK", NULL },
{ MT_NONE, 0, NULL, NULL } // sentinel
};
const menuitem_t menu_format2[] = {
{ MT_ADV_CALLBACK, TRC_POLAR, "POLAR", menu_format_acb },
{ MT_ADV_CALLBACK, TRC_LINEAR, "LINEAR", menu_format_acb },
{ MT_ADV_CALLBACK, TRC_REAL, "REAL", menu_format_acb },
{ MT_ADV_CALLBACK, TRC_IMAG, "IMAG", menu_format_acb },
{ MT_ADV_CALLBACK, TRC_R, "RESISTANCE", menu_format_acb },
{ MT_ADV_CALLBACK, TRC_X, "REACTANCE", menu_format_acb },
{ MT_ADV_CALLBACK, TRC_Q, "Q FACTOR", menu_format_acb },
{ MT_CANCEL, 0, S_LARROW" BACK", NULL },
{ MT_NONE, 0, NULL, NULL } // sentinel
};
const menuitem_t menu_format[] = {
{ MT_ADV_CALLBACK, TRC_LOGMAG, "LOGMAG", menu_format_acb },
{ MT_ADV_CALLBACK, TRC_PHASE, "PHASE", menu_format_acb },
{ MT_ADV_CALLBACK, TRC_DELAY, "DELAY", menu_format_acb },
{ MT_ADV_CALLBACK, TRC_SMITH, "SMITH", menu_format_acb },
{ MT_ADV_CALLBACK, TRC_SWR, "SWR", menu_format_acb },
{ MT_ADV_CALLBACK, TRC_Z, "|Z|", menu_format_acb },
{ MT_SUBMENU, 0, S_RARROW" MORE", menu_format2 },
{ MT_CANCEL, 0, S_LARROW" BACK", NULL },
{ MT_NONE, 0, NULL, NULL } // sentinel
};
const menuitem_t menu_scale[] = {
{ MT_CALLBACK, KM_SCALE, "SCALE/DIV", menu_keyboard_cb },
{ MT_CALLBACK, KM_REFPOS, "REFERENCE\nPOSITION", menu_keyboard_cb },
{ MT_CALLBACK, KM_EDELAY, "ELECTRICAL\nDELAY", menu_keyboard_cb },
#ifdef __USE_GRID_VALUES__
{ MT_ADV_CALLBACK, VNA_MODE_SHOW_GRID, "SHOW GRID\nVALUES", menu_grid_acb },
{ MT_ADV_CALLBACK, VNA_MODE_DOT_GRID , "DOT GRID", menu_grid_acb },
#endif
{ MT_CANCEL, 0, S_LARROW" BACK", NULL },
{ MT_NONE, 0, NULL, NULL } // sentinel
};
const menuitem_t menu_channel[] = {
{ MT_ADV_CALLBACK, 0, "CH0\nREFLECT", menu_channel_acb },
{ MT_ADV_CALLBACK, 1, "CH1\nTHROUGH", menu_channel_acb },
{ MT_CANCEL, 0, S_LARROW" BACK", NULL },
{ MT_NONE, 0, NULL, NULL } // sentinel
};
const menuitem_t menu_transform_window[] = {
{ MT_ADV_CALLBACK, TD_WINDOW_MINIMUM, "MINIMUM", menu_transform_window_acb },
{ MT_ADV_CALLBACK, TD_WINDOW_NORMAL, "NORMAL", menu_transform_window_acb },
{ MT_ADV_CALLBACK, TD_WINDOW_MAXIMUM, "MAXIMUM", menu_transform_window_acb },
{ MT_CANCEL, 0, S_LARROW" BACK", NULL },
{ MT_NONE, 0, NULL, NULL } // sentinel
};
const menuitem_t menu_transform[] = {
{ MT_ADV_CALLBACK, 0, "TRANSFORM\nON", menu_transform_acb },
{ MT_ADV_CALLBACK, TD_FUNC_LOWPASS_IMPULSE, "LOW PASS\nIMPULSE", menu_transform_filter_acb },
{ MT_ADV_CALLBACK, TD_FUNC_LOWPASS_STEP, "LOW PASS\nSTEP", menu_transform_filter_acb },
{ MT_ADV_CALLBACK, TD_FUNC_BANDPASS, "BANDPASS", menu_transform_filter_acb },
{ MT_SUBMENU, 0, "WINDOW", menu_transform_window },
{ MT_CALLBACK, KM_VELOCITY_FACTOR, "VELOCITY\nFACTOR", menu_keyboard_cb },
{ MT_CANCEL, 0, S_LARROW" BACK", NULL },
{ MT_NONE, 0, NULL, NULL } // sentinel
};
const menuitem_t menu_bandwidth[] = {
#ifdef BANDWIDTH_8000
{ MT_ADV_CALLBACK, BANDWIDTH_8000, "%u Hz", menu_bandwidth_acb },
#endif
#ifdef BANDWIDTH_4000
{ MT_ADV_CALLBACK, BANDWIDTH_4000, "%u Hz", menu_bandwidth_acb },
#endif
#ifdef BANDWIDTH_2000
{ MT_ADV_CALLBACK, BANDWIDTH_2000, "%u Hz", menu_bandwidth_acb },
#endif
#ifdef BANDWIDTH_1000
{ MT_ADV_CALLBACK, BANDWIDTH_1000, "%u Hz", menu_bandwidth_acb },
#endif
#ifdef BANDWIDTH_333
{ MT_ADV_CALLBACK, BANDWIDTH_333, "%u Hz", menu_bandwidth_acb },
#endif
#ifdef BANDWIDTH_100
{ MT_ADV_CALLBACK, BANDWIDTH_100, "%u Hz", menu_bandwidth_acb },
#endif
#ifdef BANDWIDTH_30
{ MT_ADV_CALLBACK, BANDWIDTH_30, "%u Hz", menu_bandwidth_acb },
#endif
#ifdef BANDWIDTH_10
{ MT_ADV_CALLBACK, BANDWIDTH_10, "%u Hz", menu_bandwidth_acb },
#endif
{ MT_CANCEL, 0, S_LARROW" BACK", NULL },
{ MT_NONE, 0, NULL, NULL } // sentinel
};
#ifdef __USE_SMOOTH__
const menuitem_t menu_smooth_count[] = {
{ MT_ADV_CALLBACK, 0, "SMOOTH\n%s avg",menu_smooth_func_acb },
{ MT_ADV_CALLBACK, 0, "SMOOTH\nOFF",menu_smooth_acb },
{ MT_ADV_CALLBACK, 1, "x%d", menu_smooth_acb },
{ MT_ADV_CALLBACK, 2, "x%d", menu_smooth_acb },
{ MT_ADV_CALLBACK, 4, "x%d", menu_smooth_acb },
{ MT_ADV_CALLBACK, 5, "x%d", menu_smooth_acb },
{ MT_ADV_CALLBACK, 6, "x%d", menu_smooth_acb },
{ MT_CANCEL, 0, S_LARROW" BACK", NULL },
{ MT_NONE, 0, NULL, NULL } // sentinel
};
#endif
const menuitem_t menu_display[] = {
{ MT_SUBMENU, 0, "TRACE", menu_trace },
{ MT_SUBMENU, 0, "FORMAT", menu_format },
{ MT_SUBMENU, 0, "SCALE", menu_scale },
{ MT_SUBMENU, 0, "CHANNEL", menu_channel },
{ MT_SUBMENU, 0, "TRANSFORM", menu_transform },
{ MT_SUBMENU, 0, "BANDWIDTH", menu_bandwidth },
#ifdef __USE_SMOOTH__
{ MT_SUBMENU, 0, "DATA\nSMOOTH", menu_smooth_count },
#endif
{ MT_CANCEL, 0, S_LARROW" BACK", NULL },
{ MT_NONE, 0, NULL, NULL } // sentinel
};
const menuitem_t menu_sweep_points[] = {
{ MT_ADV_CALLBACK, 0, "%d point", menu_points_acb },
#if POINTS_SET_COUNT > 1
{ MT_ADV_CALLBACK, 1, "%d point", menu_points_acb },
#endif
#if POINTS_SET_COUNT > 2
{ MT_ADV_CALLBACK, 2, "%d point", menu_points_acb },
#endif
#if POINTS_SET_COUNT > 3
{ MT_ADV_CALLBACK, 3, "%d point", menu_points_acb },
#endif
#if POINTS_SET_COUNT > 4
{ MT_ADV_CALLBACK, 4, "%d point", menu_points_acb },
#endif
{ MT_CANCEL, 0, S_LARROW" BACK", NULL },
{ MT_NONE, 0, NULL, NULL } // sentinel
};
const menuitem_t menu_stimulus[] = {
{ MT_CALLBACK, KM_START, "START", menu_keyboard_cb },
{ MT_CALLBACK, KM_STOP, "STOP", menu_keyboard_cb },
{ MT_CALLBACK, KM_CENTER, "CENTER", menu_keyboard_cb },
{ MT_CALLBACK, KM_SPAN, "SPAN", menu_keyboard_cb },
{ MT_CALLBACK, KM_CW, "CW FREQ", menu_keyboard_cb },
{ MT_ADV_CALLBACK, 0, "PAUSE\nSWEEP", menu_pause_acb },
{ MT_CANCEL, 0, S_LARROW" BACK", NULL },
{ MT_NONE, 0, NULL, NULL } // sentinel
};
const menuitem_t menu_marker_sel[] = {
{ MT_ADV_CALLBACK, 0, "MARKER %d", menu_marker_sel_acb },
#if MARKERS_MAX >=2
{ MT_ADV_CALLBACK, 1, "MARKER %d", menu_marker_sel_acb },
#endif
#if MARKERS_MAX >=3
{ MT_ADV_CALLBACK, 2, "MARKER %d", menu_marker_sel_acb },
#endif
#if MARKERS_MAX >=4
{ MT_ADV_CALLBACK, 3, "MARKER %d", menu_marker_sel_acb },
#endif
#if MARKERS_MAX >=5
{ MT_ADV_CALLBACK, 4, "MARKER %d", menu_marker_sel_acb },
#endif
#if MARKERS_MAX >=6
{ MT_ADV_CALLBACK, 5, "MARKER %d", menu_marker_sel_acb },
#endif
#if MARKERS_MAX < 6
{ MT_CALLBACK, 0, "ALL OFF", menu_marker_disable_all_cb },
#endif
{ MT_ADV_CALLBACK, 0, "DELTA", menu_marker_delta_acb },
{ MT_CANCEL, 0, S_LARROW" BACK", NULL },
{ MT_NONE, 0, NULL, NULL } // sentinel
};
const menuitem_t menu_marker_ops[] = {
{ MT_CALLBACK, ST_START, S_RARROW"START", menu_marker_op_cb },
{ MT_CALLBACK, ST_STOP, S_RARROW"STOP", menu_marker_op_cb },
{ MT_CALLBACK, ST_CENTER, S_RARROW"CENTER", menu_marker_op_cb },
{ MT_CALLBACK, ST_SPAN, S_RARROW"SPAN", menu_marker_op_cb },
{ MT_CALLBACK, UI_MARKER_EDELAY, S_RARROW"EDELAY", menu_marker_op_cb },
{ MT_CANCEL, 0, S_LARROW" BACK", NULL },
{ MT_NONE, 0, NULL, NULL } // sentinel
};
const menuitem_t menu_marker_search[] = {
//{ MT_CALLBACK, "OFF", menu_marker_search_cb },
{ MT_ADV_CALLBACK, MENU_MARKER_S_MAX, "MAXIMUM", menu_marker_search_mode_acb },
{ MT_ADV_CALLBACK, MENU_MARKER_S_MIN, "MINIMUM", menu_marker_search_mode_acb },
{ MT_CALLBACK, MK_SEARCH_LEFT, "SEARCH\n" S_LARROW" LEFT", menu_marker_search_dir_cb },
{ MT_CALLBACK, MK_SEARCH_RIGHT, "SEARCH\n" S_RARROW" RIGHT", menu_marker_search_dir_cb },
{ MT_ADV_CALLBACK, 0, "TRACKING", menu_marker_tracking_acb },
{ MT_CANCEL, 0, S_LARROW" BACK", NULL },
{ MT_NONE, 0, NULL, NULL } // sentinel
};
const menuitem_t menu_marker_smith[] = {
{ MT_ADV_CALLBACK, MS_LIN, "LIN", menu_marker_smith_acb },
{ MT_ADV_CALLBACK, MS_LOG, "LOG", menu_marker_smith_acb },
{ MT_ADV_CALLBACK, MS_REIM,"Re+Im", menu_marker_smith_acb },
{ MT_ADV_CALLBACK, MS_RX, "R+jX", menu_marker_smith_acb },
{ MT_ADV_CALLBACK, MS_RLC, "R+L/C", menu_marker_smith_acb },
#ifdef __USE_LC_MATCHING__
{ MT_ADV_CALLBACK, 0, "L/C MATCH", menu_marker_lc_match_acb },
#endif
{ MT_CANCEL, 0, S_LARROW" BACK", NULL },
{ MT_NONE, 0, NULL, NULL } // sentinel
};
const menuitem_t menu_marker[] = {
{ MT_SUBMENU, 0, "SELECT\nMARKER", menu_marker_sel },
{ MT_SUBMENU, 0, "SEARCH", menu_marker_search },
{ MT_SUBMENU, 0, "OPERATIONS", menu_marker_ops },
{ MT_SUBMENU, 0, "SMITH\nVALUE", menu_marker_smith },
{ MT_CANCEL, 0, S_LARROW" BACK", NULL },
{ MT_NONE, 0, NULL, NULL } // sentinel
};
#ifdef __DFU_SOFTWARE_MODE__
const menuitem_t menu_dfu[] = {
{ MT_CALLBACK, 0, "RESET AND\nENTER DFU", menu_dfu_cb },
{ MT_CANCEL, 0, S_LARROW"CANCEL", NULL },
{ MT_NONE, 0, NULL, NULL } // sentinel
};
#endif
#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, 6, "%u", menu_serial_speed_acb },
{ MT_ADV_CALLBACK, 7, "%u", menu_serial_speed_acb },
{ MT_ADV_CALLBACK, 8, "%u", menu_serial_speed_acb },
{ MT_ADV_CALLBACK, 9, "%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, 0, "%u", menu_serial_speed_acb },
{ MT_ADV_CALLBACK, 1, "%u", menu_serial_speed_acb },
{ MT_ADV_CALLBACK, 2, "%u", menu_serial_speed_acb },
{ MT_ADV_CALLBACK, 3, "%u", menu_serial_speed_acb },
{ MT_ADV_CALLBACK, 4, "%u", menu_serial_speed_acb },
{ MT_ADV_CALLBACK, 5, "%u", menu_serial_speed_acb },
{ MT_ADV_CALLBACK, 6, "%u", menu_serial_speed_acb },
// { MT_SUBMENU, 0, S_RARROW" MORE", menu_serial_speed2 },
{ MT_CANCEL, 0, S_LARROW" BACK", NULL },
{ MT_NONE, 0, NULL, NULL } // sentinel
};
const menuitem_t menu_connection[] = {
{ MT_ADV_CALLBACK, VNA_MODE_USB, "USB", menu_connection_acb },
{ MT_ADV_CALLBACK, VNA_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_config[] = {
{ MT_CALLBACK, MENU_CONFIG_TOUCH_CAL, "TOUCH CAL", menu_config_cb },
{ MT_CALLBACK, MENU_CONFIG_TOUCH_TEST, "TOUCH TEST", menu_config_cb },
{ MT_CALLBACK, 0, "SAVE", menu_config_save_cb },
{ MT_SUBMENU, 0, "SWEEP\nPOINTS", menu_sweep_points },
#ifdef __USE_SERIAL_CONSOLE__
{ MT_SUBMENU, 0, "CONNECTION", menu_connection },
#endif
{ MT_CALLBACK, MENU_CONFIG_VERSION, "VERSION", menu_config_cb },
#ifdef __LCD_BRIGHTNESS__
{ MT_CALLBACK, 0, "BRIGHTNESS", menu_brightness_cb },
#endif
#ifdef __DFU_SOFTWARE_MODE__
{ MT_SUBMENU, 0, S_RARROW"DFU", menu_dfu },
#endif
{ MT_CANCEL, 0, S_LARROW" BACK", NULL },
{ MT_NONE, 0, NULL, NULL } // sentinel
};
const menuitem_t menu_top[] = {
{ MT_SUBMENU, 0, "DISPLAY", menu_display },
{ MT_SUBMENU, 0, "MARKER", menu_marker },
{ MT_SUBMENU, 0, "STIMULUS", menu_stimulus },
{ MT_SUBMENU, 0, "CALIBRATE", menu_cal },
{ MT_SUBMENU, 0, "RECALL", menu_recall },
#ifdef __USE_SD_CARD__
{ MT_SUBMENU, 0, "SD CARD", menu_sdcard },
#endif
{ MT_SUBMENU, 0, "CONFIG", menu_config },
{ MT_NONE, 0, NULL, NULL } // sentinel
};
#define MENU_STACK_DEPTH_MAX 4
const menuitem_t *menu_stack[MENU_STACK_DEPTH_MAX] = {
menu_top, NULL, NULL, NULL
};
static void
ensure_selection(void)
{
const menuitem_t *menu = menu_stack[menu_current_level];
int i;
for (i = 0; menu[i].type != MT_NONE; i++)
;
if (selection < 0)
selection = -1;
else if (selection >= i)
selection = i-1;
}
static void
menu_move_back(bool leave_ui)
{
if (menu_current_level == 0)
return;
menu_current_level--;
ensure_selection();
if (leave_ui)
ui_mode_normal();
}
static void
menu_push_submenu(const menuitem_t *submenu)
{
if (menu_current_level < MENU_STACK_DEPTH_MAX-1)
menu_current_level++;
menu_stack[menu_current_level] = submenu;
ensure_selection();
}
/*
static void
menu_move_top(void)
{
if (menu_current_level == 0)
return;
menu_current_level = 0;
ensure_selection();
}
*/
static void
menu_invoke(int item)
{
const menuitem_t *menu = menu_stack[menu_current_level];
menu = &menu[item];
switch (menu->type) {
case MT_NONE:
case MT_BLANK:
case MT_CLOSE:
ui_mode_normal();
break;
case MT_CANCEL:
menu_move_back(false);
break;
case MT_CALLBACK: {
menuaction_cb_t cb = (menuaction_cb_t)menu->reference;
if (cb) (*cb)(menu->data);
break;
}
case MT_ADV_CALLBACK: {
menuaction_acb_t cb = (menuaction_acb_t)menu->reference;
if (cb) (*cb)(menu->data, NULL);
break;
}
case MT_SUBMENU:
menu_push_submenu((const menuitem_t*)menu->reference);
break;
}
// Redraw menu after if UI in menu mode
if (ui_mode == UI_MENU)
draw_menu();
}
// Key names (use numfont16x22.c glyph)
#define KP_0 0
#define KP_1 1
#define KP_2 2
#define KP_3 3
#define KP_4 4
#define KP_5 5
#define KP_6 6
#define KP_7 7
#define KP_8 8
#define KP_9 9
#define KP_PERIOD 10
#define KP_MINUS 11
#define KP_X1 12
#define KP_K 13
#define KP_M 14
#define KP_G 15
#define KP_BS 16
#define KP_INF 17
#define KP_DB 18
#define KP_PLUSMINUS 19
#define KP_KEYPAD 20
#define KP_N 21
#define KP_P 22
// Stop
#define KP_NONE 255
static const keypads_t keypads_freq[] = {
{ 1, 3, KP_PERIOD },
{ 0, 3, KP_0 },
{ 0, 2, KP_1 },
{ 1, 2, KP_2 },
{ 2, 2, KP_3 },
{ 0, 1, KP_4 },
{ 1, 1, KP_5 },
{ 2, 1, KP_6 },
{ 0, 0, KP_7 },
{ 1, 0, KP_8 },
{ 2, 0, KP_9 },
{ 3, 0, KP_G },
{ 3, 1, KP_M },
{ 3, 2, KP_K },
{ 3, 3, KP_X1 },
{ 2, 3, KP_BS },
{ 0, 0, KP_NONE}
};
static const keypads_t keypads_scale[] = {
{ 1, 3, KP_PERIOD },
{ 0, 3, KP_0 },
{ 0, 2, KP_1 },
{ 1, 2, KP_2 },
{ 2, 2, KP_3 },
{ 0, 1, KP_4 },
{ 1, 1, KP_5 },
{ 2, 1, KP_6 },
{ 0, 0, KP_7 },
{ 1, 0, KP_8 },
{ 2, 0, KP_9 },
{ 3, 3, KP_X1 },
{ 2, 3, KP_BS },
{ 0, 0, KP_NONE }
};
static const keypads_t keypads_time[] = {
{ 1, 3, KP_PERIOD },
{ 0, 3, KP_0 },
{ 0, 2, KP_1 },
{ 1, 2, KP_2 },
{ 2, 2, KP_3 },
{ 0, 1, KP_4 },
{ 1, 1, KP_5 },
{ 2, 1, KP_6 },
{ 0, 0, KP_7 },
{ 1, 0, KP_8 },
{ 2, 0, KP_9 },
{ 3, 1, KP_N },
{ 3, 2, KP_P },
{ 3, 3, KP_MINUS },
{ 2, 3, KP_BS },
{ 0, 0, KP_NONE }
};
static const keypads_list keypads_mode_tbl[KM_NONE] = {
[KM_START] = {keypads_freq , "START" }, // start
[KM_STOP] = {keypads_freq , "STOP" }, // stop
[KM_CENTER] = {keypads_freq , "CENTER" }, // center
[KM_SPAN] = {keypads_freq , "SPAN" }, // span
[KM_CW] = {keypads_freq , "CW FREQ" }, // cw freq
[KM_SCALE] = {keypads_scale, "SCALE" }, // scale
[KM_REFPOS] = {keypads_scale, "REFPOS" }, // refpos
[KM_EDELAY] = {keypads_time , "EDELAY" }, // electrical delay
[KM_VELOCITY_FACTOR] = {keypads_scale, "VELOCITY%"}, // velocity factor
[KM_SCALEDELAY] = {keypads_time , "DELAY" } // scale of delay
};
static void
draw_button(uint16_t x, uint16_t y, uint16_t w, uint16_t h, button_t *b)
{
uint16_t bw = b->border&BUTTON_BORDER_WIDTH_MASK;
ili9341_set_foreground(b->fg);
ili9341_set_background(b->bg);ili9341_fill(x + bw, y + bw, w - (bw * 2), h - (bw * 2));
if (bw==0) return;
uint16_t br = LCD_RISE_EDGE_COLOR;
uint16_t bd = LCD_FALLEN_EDGE_COLOR;
uint16_t type = b->border;
ili9341_set_background(type&BUTTON_BORDER_TOP ? br : bd);ili9341_fill(x, y, w, bw); // top
ili9341_set_background(type&BUTTON_BORDER_RIGHT ? br : bd);ili9341_fill(x + w - bw, y, bw, h); // right
ili9341_set_background(type&BUTTON_BORDER_LEFT ? br : bd);ili9341_fill(x, y, bw, h); // left
ili9341_set_background(type&BUTTON_BORDER_BOTTOM ? br : bd);ili9341_fill(x, y + h - bw, w, bw); // bottom
// Set colors for button text after
ili9341_set_background(b->bg);
}
static void drawMessageBox(char *header, char *text, uint32_t delay){
button_t b;
b.bg = LCD_MENU_COLOR;
b.fg = LCD_MENU_TEXT_COLOR;
b.border = BUTTON_BORDER_FLAT|1;
// Draw header
draw_button((LCD_WIDTH-MESSAGE_BOX_WIDTH)/2, LCD_HEIGHT/2-40, MESSAGE_BOX_WIDTH, 60, &b);
ili9341_drawstring(header, (LCD_WIDTH-MESSAGE_BOX_WIDTH)/2 + 10, LCD_HEIGHT/2-40 + 5);
// Draw window
ili9341_set_background(LCD_FG_COLOR);
ili9341_fill((LCD_WIDTH-MESSAGE_BOX_WIDTH)/2+3, LCD_HEIGHT/2-40+FONT_STR_HEIGHT+8, MESSAGE_BOX_WIDTH-6, 60-FONT_STR_HEIGHT-8-3);
ili9341_drawstring(text, (LCD_WIDTH-MESSAGE_BOX_WIDTH)/2 + 20, LCD_HEIGHT/2-40 + FONT_STR_HEIGHT + 8 + 14);
chThdSleepMilliseconds(delay);
}
static void
draw_keypad(void)
{
int i = 0;
button_t button;
button.fg = LCD_MENU_TEXT_COLOR;
do {
if (i == selection){
button.bg = LCD_MENU_ACTIVE_COLOR;
button.border = KEYBOARD_BUTTON_BORDER|BUTTON_BORDER_FALLING;
}
else{
button.bg = LCD_MENU_COLOR;
button.border = KEYBOARD_BUTTON_BORDER|BUTTON_BORDER_RISE;
}
int x = KP_GET_X(keypads[i].x);
int y = KP_GET_Y(keypads[i].y);
draw_button(x, y, KP_WIDTH, KP_HEIGHT, &button);
ili9341_drawfont(keypads[i].c,
x + (KP_WIDTH - NUM_FONT_GET_WIDTH) / 2,
y + (KP_HEIGHT - NUM_FONT_GET_HEIGHT) / 2);
}while (keypads[++i].c != KP_NONE);
}
static void
draw_numeric_area_frame(void)
{
ili9341_set_foreground(LCD_INPUT_TEXT_COLOR);
ili9341_set_background(LCD_INPUT_BG_COLOR);
ili9341_fill(0, LCD_HEIGHT-NUM_INPUT_HEIGHT, LCD_WIDTH, NUM_INPUT_HEIGHT);
ili9341_drawstring(keypads_mode_tbl[keypad_mode].name, 10, LCD_HEIGHT-(FONT_GET_HEIGHT+NUM_INPUT_HEIGHT)/2);
//ili9341_drawfont(KP_KEYPAD, 300, 216);
}
static void
draw_numeric_input(const char *buf)
{
int i;
int x;
int focused = FALSE;
uint16_t xsim = 0b0010010000000000;
for (i = 0, x = 10 + 10 * FONT_WIDTH + 4; i < 10 && buf[i]; i++, xsim<<=1) {
uint16_t fg = LCD_INPUT_TEXT_COLOR;
uint16_t bg = LCD_INPUT_BG_COLOR;
int c = buf[i];
if (c == '.')
c = KP_PERIOD;
else if (c == '-')
c = KP_MINUS;
else// if (c >= '0' && c <= '9')
c = c - '0';
#ifdef UI_USE_NUMERIC_INPUT
if (ui_mode == UI_NUMERIC && uistat.digit == 8-i) {
fg = LCD_SPEC_INPUT_COLOR;
focused = true;
if (uistat.digit_mode){
bg = LCD_SPEC_INPUT_COLOR;
fg = LCD_INPUT_TEXT_COLOR;
}
}
#endif
ili9341_set_foreground(fg);
ili9341_set_background(bg);
if (c < 0 && focused) c = 0;
if (c >= 0) // c is number
ili9341_drawfont(c, x, LCD_HEIGHT-NUM_INPUT_HEIGHT+4);
else // erase
break;
x += xsim&0x8000 ? NUM_FONT_GET_WIDTH+2+8 : NUM_FONT_GET_WIDTH+2;
}
// erase last
ili9341_set_background(LCD_INPUT_BG_COLOR);
ili9341_fill(x, LCD_HEIGHT-NUM_INPUT_HEIGHT+4, NUM_FONT_GET_WIDTH+2+8, NUM_FONT_GET_WIDTH+2+8);
}
static int
menu_is_multiline(const char *label)
{
int n = 1;
while (*label)
if (*label++ == '\n')
n++;
return n;
}
/*
* Button icons bitmaps
*/
#define ICON_WIDTH 16
#define ICON_HEIGHT 11
#define ICON_GET_DATA(i) (&button_icons[2*ICON_HEIGHT*(i)])
static const uint8_t button_icons[] = {
_BMP16(0b0011111111110000),
_BMP16(0b0010000000010000),
_BMP16(0b0010000000010000),
_BMP16(0b0010000000010000),
_BMP16(0b0010000000010000),
_BMP16(0b0010000000010000),
_BMP16(0b0010000000010000),
_BMP16(0b0010000000010000),
_BMP16(0b0010000000010000),
_BMP16(0b0010000000010000),
_BMP16(0b0011111111110000),
_BMP16(0b0011111111110000),
_BMP16(0b0010000000001000),
_BMP16(0b0010000000011000),
_BMP16(0b0010000000110000),
_BMP16(0b0010000001100000),
_BMP16(0b0010100011010000),
_BMP16(0b0010110110010000),
_BMP16(0b0010011100010000),
_BMP16(0b0010001000010000),
_BMP16(0b0010000000010000),
_BMP16(0b0011111111110000),
_BMP16(0b0000000000000000),
_BMP16(0b0000011110000000),
_BMP16(0b0000100001000000),
_BMP16(0b0001000000100000),
_BMP16(0b0010000000010000),
_BMP16(0b0010000000010000),
_BMP16(0b0010000000010000),
_BMP16(0b0010000000010000),
_BMP16(0b0001000000100000),
_BMP16(0b0000100001000000),
_BMP16(0b0000011110000000),
_BMP16(0b0000000000000000),
_BMP16(0b0000011110000000),
_BMP16(0b0000100001000000),
_BMP16(0b0001001100100000),
_BMP16(0b0010011110010000),
_BMP16(0b0010111111010000),
_BMP16(0b0010111111010000),
_BMP16(0b0010011110010000),
_BMP16(0b0001001100100000),
_BMP16(0b0000100001000000),
_BMP16(0b0000011110000000),
_BMP16(0b0011111111111000),
_BMP16(0b0010000000001000),
_BMP16(0b0010001111101000),
_BMP16(0b0010011001101000),
_BMP16(0b0010110001101000),
_BMP16(0b0010110001101000),
_BMP16(0b0010111111101000),
_BMP16(0b0010110001101000),
_BMP16(0b0010110001101000),
_BMP16(0b0010000000001000),
_BMP16(0b0011111111111000),
_BMP16(0b0011111111111000),
_BMP16(0b0010000000001000),
_BMP16(0b0010110001101000),
_BMP16(0b0010110001101000),
_BMP16(0b0010111011101000),
_BMP16(0b0010111111101000),
_BMP16(0b0010110101101000),
_BMP16(0b0010110101101000),
_BMP16(0b0010110001101000),
_BMP16(0b0010000000001000),
_BMP16(0b0011111111111000),
};
static void
draw_menu_buttons(const menuitem_t *menu)
{
int i, y;
for (i = 0, y = 1; i < MENU_BUTTON_MAX; i++, y+=MENU_BUTTON_HEIGHT) {
if (menu[i].type == MT_NONE)
break;
if (menu[i].type == MT_BLANK)
continue;
button_t button;
button.fg = LCD_MENU_TEXT_COLOR;
button.icon = BUTTON_ICON_NONE;
// focus only in MENU mode but not in KEYPAD mode
if (ui_mode == UI_MENU && i == selection){
button.bg = LCD_MENU_ACTIVE_COLOR;
button.border = MENU_BUTTON_BORDER|BUTTON_BORDER_FALLING;
}
else{
button.bg = LCD_MENU_COLOR;
button.border = MENU_BUTTON_BORDER|BUTTON_BORDER_RISE;
}
// Custom button, apply custom settings from callback
if (menu[i].type == MT_ADV_CALLBACK){
menuaction_acb_t cb = (menuaction_acb_t)menu[i].reference;
if (cb) (*cb)(menu[i].data, &button);
}
draw_button(LCD_WIDTH-MENU_BUTTON_WIDTH, y, MENU_BUTTON_WIDTH, MENU_BUTTON_HEIGHT, &button);
uint16_t text_offs = LCD_WIDTH-MENU_BUTTON_WIDTH+MENU_BUTTON_BORDER + 5;
if (button.icon >=0){
ili9341_blitBitmap(LCD_WIDTH-MENU_BUTTON_WIDTH+MENU_BUTTON_BORDER + 1, y+(MENU_BUTTON_HEIGHT-ICON_HEIGHT)/2, ICON_WIDTH, ICON_HEIGHT, ICON_GET_DATA(button.icon));
text_offs=LCD_WIDTH-MENU_BUTTON_WIDTH+MENU_BUTTON_BORDER+1+ICON_WIDTH;
}
// Apply custom text, from button label and
char button_text[32];
plot_printf(button_text, sizeof(button_text), menu[i].label, button.p1.u, button.p2.u);
int lines = menu_is_multiline(button_text);
ili9341_drawstring(button_text, text_offs, y+(MENU_BUTTON_HEIGHT-lines*FONT_GET_HEIGHT)/2);
}
// Erase empty buttons
ili9341_set_background(LCD_BG_COLOR);
for (; i < MENU_BUTTON_MAX; i++, y+=MENU_BUTTON_HEIGHT) {
ili9341_fill(LCD_WIDTH-MENU_BUTTON_WIDTH, y, MENU_BUTTON_WIDTH, MENU_BUTTON_HEIGHT);
}
}
static void
menu_select_touch(int i)
{
selection = i;
draw_menu();
touch_wait_release();
selection = -1;
menu_invoke(i);
}
static void
menu_apply_touch(int touch_x, int touch_y)
{
const menuitem_t *menu = menu_stack[menu_current_level];
int i, y;
for (i = 0, y = 1; i < MENU_BUTTON_MAX; i++, y+=MENU_BUTTON_HEIGHT) {
if (menu[i].type == MT_NONE)
break;
if (menu[i].type == MT_BLANK)
continue;
if (y < touch_y && touch_y < y+MENU_BUTTON_HEIGHT && LCD_WIDTH-MENU_BUTTON_WIDTH < touch_x) {
menu_select_touch(i);
return;
}
}
touch_wait_release();
ui_mode_normal();
}
static void
draw_menu(void)
{
draw_menu_buttons(menu_stack[menu_current_level]);
}
#if 0
static void
erase_menu_buttons(void)
{
ili9341_set_background(LCD_BG_COLOR);
ili9341_fill(LCD_WIDTH-MENU_BUTTON_WIDTH, 0, MENU_BUTTON_WIDTH, MENU_BUTTON_HEIGHT*MENU_BUTTON_MAX);
}
#endif
static void
ui_mode_menu(void)
{
if (ui_mode == UI_MENU)
return;
ui_mode = UI_MENU;
/* narrowen plotting area */
area_width = AREA_WIDTH_NORMAL - MENU_BUTTON_WIDTH;
area_height = AREA_HEIGHT_NORMAL;
ensure_selection();
draw_menu();
}
#ifdef UI_USE_NUMERIC_INPUT
static void
erase_numeric_input(void)
{
ili9341_set_background(LCD_BG_COLOR);
ili9341_fill(0, LCD_HEIGHT-NUM_INPUT_HEIGHT, LCD_WIDTH, NUM_INPUT_HEIGHT);
}
static void
fetch_numeric_target(void)
{
switch (keypad_mode) {
case KM_START:
uistat.value = get_sweep_frequency(ST_START);
break;
case KM_STOP:
uistat.value = get_sweep_frequency(ST_STOP);
break;
case KM_CENTER:
uistat.value = get_sweep_frequency(ST_CENTER);
break;
case KM_SPAN:
uistat.value = get_sweep_frequency(ST_SPAN);
break;
case KM_CW:
uistat.value = get_sweep_frequency(ST_CW);
break;
case KM_SCALE:
uistat.value = get_trace_scale(current_trace) * 1000;
break;
case KM_REFPOS:
uistat.value = get_trace_refpos(current_trace) * 1000;
break;
case KM_EDELAY:
uistat.value = get_electrical_delay();
break;
case KM_VELOCITY_FACTOR:
uistat.value = velocity_factor * 100;
break;
case KM_SCALEDELAY:
uistat.value = get_trace_scale(current_trace) * 1e12;
break;
}
{
uint32_t x = uistat.value;
int n = 0;
for (; x >= 10 && n < 9; n++)
x /= 10;
uistat.digit = n;
}
// uistat.previous_value = uistat.value;
}
static void
set_numeric_value(void)
{
switch (keypad_mode) {
case KM_START:
set_sweep_frequency(ST_START, uistat.value);
break;
case KM_STOP:
set_sweep_frequency(ST_STOP, uistat.value);
break;
case KM_CENTER:
set_sweep_frequency(ST_CENTER, uistat.value);
break;
case KM_SPAN:
set_sweep_frequency(ST_SPAN, uistat.value);
break;
case KM_CW:
set_sweep_frequency(ST_CW, uistat.value);
break;
case KM_SCALE:
set_trace_scale(current_trace, uistat.value / 1000.0);
break;
case KM_REFPOS:
set_trace_refpos(current_trace, uistat.value / 1000.0);
break;
case KM_EDELAY:
set_electrical_delay(uistat.value);
break;
case KM_VELOCITY_FACTOR:
velocity_factor = uistat.value/100.0;
break;
}
}
static void
draw_numeric_area(void)
{
char buf[10];
plot_printf(buf, sizeof buf, "%9d", uistat.value);
draw_numeric_input(buf);
}
static void
ui_mode_numeric(int _keypad_mode)
{
if (ui_mode == UI_NUMERIC)
return;
leave_ui_mode();
// keypads array
keypad_mode = _keypad_mode;
ui_mode = UI_NUMERIC;
area_width = AREA_WIDTH_NORMAL;
area_height = LCD_HEIGHT-NUM_INPUT_HEIGHT;//AREA_HEIGHT_NORMAL - 32;
draw_numeric_area_frame();
fetch_numeric_target();
draw_numeric_area();
}
static void
ui_process_numeric(void)
{
int status = btn_check();
if (status != 0) {
if (status == EVT_BUTTON_SINGLE_CLICK) {
status = btn_wait_release();
if (uistat.digit_mode) {
if (status & (EVT_BUTTON_SINGLE_CLICK | EVT_BUTTON_DOWN_LONG)) {
uistat.digit_mode = FALSE;
draw_numeric_area();
}
} else {
if (status & EVT_BUTTON_DOWN_LONG) {
uistat.digit_mode = TRUE;
draw_numeric_area();
} else if (status & EVT_BUTTON_SINGLE_CLICK) {
set_numeric_value();
ui_mode_normal();
}
}
} else {
do {
if (uistat.digit_mode) {
if (status & EVT_DOWN) {
if (uistat.digit < 8)
uistat.digit++;
else
goto exit;
}
if (status & EVT_UP) {
if (uistat.digit > 0)
uistat.digit--;
else
goto exit;
}
} else {
int32_t step = 1;
int n;
for (n = uistat.digit; n > 0; n--)
step *= 10;
if (status & EVT_DOWN)
uistat.value += step;
if (status & EVT_UP)
uistat.value -= step;
}
draw_numeric_area();
status = btn_wait_release();
} while (status != 0);
}
}
return;
exit:
// cancel operation
ui_mode_normal();
}
static void
numeric_apply_touch(int touch_x, int touch_y)
{
if (touch_x < 64) {
ui_mode_normal();
return;
}
if (touch_x > 64+9*20+8+8) {
ui_mode_keypad(keypad_mode);
ui_process_keypad();
return;
}
if (touch_y > LCD_HEIGHT-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;
}
#endif
static void
ui_mode_keypad(int _keypad_mode)
{
if (ui_mode == UI_KEYPAD)
return;
// keypads array
keypad_mode = _keypad_mode;
keypads = keypads_mode_tbl[keypad_mode].keypad_type;
ui_mode = UI_KEYPAD;
draw_menu();
draw_keypad();
draw_numeric_area_frame();
}
static void
ui_mode_normal(void)
{
if (ui_mode == UI_NORMAL)
return;
area_width = AREA_WIDTH_NORMAL;
area_height = AREA_HEIGHT_NORMAL;
#ifdef UI_USE_NUMERIC_INPUT
if (ui_mode == UI_NUMERIC) {
request_to_draw_cells_behind_numeric_input();
erase_numeric_input();
}
if (ui_mode == UI_MENU)
#endif
{
request_to_draw_cells_behind_menu();
}
request_to_redraw(REDRAW_FREQUENCY);
ui_mode = UI_NORMAL;
}
#define MARKER_SPEEDUP (808 / POINTS_COUNT)
static void
lever_move_marker(int status)
{
uint16_t step = 1<<MARKER_SPEEDUP;
do {
if (active_marker != MARKER_INVALID && markers[active_marker].enabled) {
int idx = (int)markers[active_marker].index;
if (status & EVT_DOWN) {
idx-= step>>MARKER_SPEEDUP;
if (idx < 0) idx = 0;
}
if (status & EVT_UP) {
idx+= step>>MARKER_SPEEDUP;
if (idx > sweep_points-1)
idx = sweep_points-1 ;
}
set_marker_index(active_marker, idx);
redraw_marker(active_marker);
step++;
}
status = btn_wait_release();
} while (status != 0);
}
#ifdef UI_USE_LEVELER_SEARCH_MODE
static void
lever_search_marker(int status)
{
if (active_marker == active_marker) return;
if (status & EVT_DOWN)
marker_search_dir(markers[active_marker].index, MK_SEARCH_LEFT);
else if (status & EVT_UP)
marker_search_dir(markers[active_marker].index, MK_SEARCH_RIGHT);
}
#endif
// ex. 10942 -> 10000
// 6791 -> 5000
// 341 -> 200
static uint32_t
step_round(uint32_t v)
{
// decade step
uint32_t x = 1;
for (x = 1; x*10 < v; x*= 10)
;
// 1-2-5 step
if (x * 2 > v)
return x;
else if (x * 5 > v)
return x * 2;
else
return x * 5;
}
static void
lever_zoom_span(int status)
{
freq_t span = get_sweep_frequency(ST_SPAN);
if (status & EVT_UP) {
span = step_round(span - 1);
} else if (status & EVT_DOWN) {
span = step_round(span + 1);
span = step_round(span * 3);
}
set_sweep_frequency(ST_SPAN, span);
}
static void
lever_move(int status, int mode)
{
freq_t center = get_sweep_frequency(mode);
freq_t span = get_sweep_frequency(ST_SPAN);
span = step_round(span / 3);
if (status & EVT_UP) {
set_sweep_frequency(mode, center + span);
} else if (status & EVT_DOWN) {
set_sweep_frequency(mode, center - span);
}
}
#define STEPRATIO 0.2
static void
lever_edelay(int status)
{
float value = electrical_delay;
float ratio = STEPRATIO;
if (value < 0)
ratio = -ratio;
if (status & EVT_UP) {
value = (1 - ratio) * value;
} else if (status & EVT_DOWN) {
value = (1 + ratio) * value;
}
set_electrical_delay(value);
}
static void
ui_process_normal(void)
{
int status = btn_check();
if (status != 0) {
if (status & EVT_BUTTON_SINGLE_CLICK) {
ui_mode_menu();
} else {
switch (lever_mode) {
case LM_MARKER: lever_move_marker(status); break;
#ifdef UI_USE_LEVELER_SEARCH_MODE
case LM_SEARCH: lever_search_marker(status); break;
#endif
case LM_CENTER:
lever_move(status, FREQ_IS_STARTSTOP() ? ST_START : ST_CENTER);
break;
case LM_SPAN:
if (FREQ_IS_STARTSTOP())
lever_move(status, ST_STOP);
else
lever_zoom_span(status);
break;
case LM_EDELAY:
lever_edelay(status);
break;
}
}
}
}
static void
ui_process_menu(void)
{
int status = btn_check();
if (status != 0) {
if (status & EVT_BUTTON_SINGLE_CLICK) {
menu_invoke(selection);
return;
}
do {
if (status & EVT_UP)
selection++;
if (status & EVT_DOWN)
selection--;
// close menu if next item is sentinel or less
if (selection < 0 || menu_stack[menu_current_level][selection].type == MT_NONE){
ui_mode_normal();
return;
}
draw_menu();
chThdSleepMilliseconds(200);
} while ((status = btn_wait_release()) != 0);
}
return;
}
static int
keypad_click(int key)
{
int c = keypads[key].c;
if ((c >= KP_X1 && c <= KP_G) || c == KP_N || c == KP_P) {
int32_t scale = 1;
if (c >= KP_X1 && c <= KP_G) {
int n = c - KP_X1;
while (n-- > 0)
scale *= 1000;
} else if (c == KP_N) {
scale *= 1000;
}
/* numeric input done */
double value = my_atof(kp_buf) * scale;
switch (keypad_mode) {
case KM_START:
set_sweep_frequency(ST_START, value);
break;
case KM_STOP:
set_sweep_frequency(ST_STOP, value);
break;
case KM_CENTER:
set_sweep_frequency(ST_CENTER, value);
break;
case KM_SPAN:
set_sweep_frequency(ST_SPAN, value);
break;
case KM_CW:
set_sweep_frequency(ST_CW, value);
break;
case KM_SCALE:
set_trace_scale(current_trace, value);
break;
case KM_REFPOS:
set_trace_refpos(current_trace, value);
break;
case KM_EDELAY:
set_electrical_delay(value); // pico seconds
break;
case KM_VELOCITY_FACTOR:
velocity_factor = value / 100.0;
break;
case KM_SCALEDELAY:
set_trace_scale(current_trace, value * 1e-12); // pico second
break;
}
return KP_DONE;
}
if (c <= 9 && kp_index < NUMINPUT_LEN) {
kp_buf[kp_index++] = '0' + c;
} else if (c == KP_PERIOD && kp_index < NUMINPUT_LEN) {
// check period in former input
int j;
for (j = 0; j < kp_index && kp_buf[j] != '.'; j++)
;
// append period if there are no period
if (kp_index == j)
kp_buf[kp_index++] = '.';
} else if (c == KP_MINUS) {
if (kp_index == 0)
kp_buf[kp_index++] = '-';
} else if (c == KP_BS) {
if (kp_index == 0) {
return KP_CANCEL;
}
--kp_index;
}
kp_buf[kp_index] = '\0';
draw_numeric_input(kp_buf);
return KP_CONTINUE;
}
static int
keypad_apply_touch(void)
{
int touch_x, touch_y;
int i = 0;
touch_position(&touch_x, &touch_y);
do {
int x = KP_GET_X(keypads[i].x);
int y = KP_GET_Y(keypads[i].y);
if (x < touch_x && touch_x < x+KP_WIDTH && y < touch_y && touch_y < y+KP_HEIGHT) {
// draw focus
selection = i;
draw_keypad();
touch_wait_release();
// erase focus
selection = -1;
draw_keypad();
return i;
}
}while (keypads[++i].c != KP_NONE);
return -1;
}
static void
ui_process_keypad(void)
{
int status;
int keypads_last_index;
for (keypads_last_index = 0; keypads[keypads_last_index+1].c != KP_NONE; keypads_last_index++)
;
kp_index = 0; // Hide input index in keyboard mode
while (TRUE) {
status = btn_check();
if (status & (EVT_UP|EVT_DOWN)) {
do {
if (status & EVT_DOWN)
if (--selection < 0)
selection = keypads_last_index;
if (status & EVT_UP)
if (++selection > keypads_last_index)
selection = 0;
draw_keypad();
chThdSleepMilliseconds(200);
status = btn_wait_release();
} while (status != 0);
}
else if (status == EVT_BUTTON_SINGLE_CLICK) {
if (keypad_click(selection))
/* exit loop on done or cancel */
break;
}
else if (touch_check() == EVT_TOUCH_PRESSED) {
int key = keypad_apply_touch();
if (key >= 0 && keypad_click(key))
/* exit loop on done or cancel */
break;
}
}
request_to_redraw(REDRAW_CLRSCR | REDRAW_AREA | REDRAW_BATTERY | REDRAW_CAL_STATUS | REDRAW_FREQUENCY);
ui_mode_normal();
}
static void
ui_process_lever(void)
{
switch (ui_mode) {
case UI_NORMAL:
ui_process_normal();
break;
case UI_MENU:
ui_process_menu();
break;
#ifdef UI_USE_NUMERIC_INPUT
case UI_NUMERIC:
ui_process_numeric();
break;
#endif
case UI_KEYPAD:
ui_process_keypad();
break;
}
}
static void
drag_marker(int t, int8_t m)
{
/* wait touch release */
do {
int touch_x, touch_y;
int index;
touch_position(&touch_x, &touch_y);
touch_x -= OFFSETX;
touch_y -= OFFSETY;
index = search_nearest_index(touch_x, touch_y, t);
if (index >= 0) {
set_marker_index(m, index);
redraw_marker(m);
}
} while (touch_check()!= EVT_TOUCH_RELEASED);
}
static bool
touch_pickup_marker(int touch_x, int touch_y)
{
touch_x -= OFFSETX;
touch_y -= OFFSETY;
int i = MARKER_INVALID, mt, m, t;
int min_dist = MARKER_PICKUP_DISTANCE * MARKER_PICKUP_DISTANCE;
// Search closest marker to touch position
for (t = 0; t < TRACES_MAX; t++) {
if (!trace[t].enabled)
continue;
for (m = 0; m < MARKERS_MAX; m++) {
if (!markers[m].enabled)
continue;
// Get distance to marker from touch point
int dist = distance_to_index(t, markers[m].index, touch_x, touch_y);
if (dist < min_dist) {
min_dist = dist;
i = m;
mt = t;
}
}
}
// Marker not found
if (i == MARKER_INVALID)
return FALSE;
// Marker found, set as active and start drag it
if (active_marker != i) {
previous_marker = active_marker;
active_marker = i;
}
// Disable tracking
VNA_mode&= ~VNA_MODE_MARKER_DELTA;
// Leveler mode = marker move
select_lever_mode(LM_MARKER);
// select trace
current_trace = mt;
// drag marker until release
drag_marker(mt, i);
return TRUE;
}
#ifdef __USE_SD_CARD__
//*******************************************************************************************
// Bitmap file header for LCD_WIDTH x LCD_HEIGHT image 16bpp (v4 format allow set RGB mask)
//*******************************************************************************************
#define BMP_UINT32(val) ((val)>>0)&0xFF, ((val)>>8)&0xFF, ((val)>>16)&0xFF, ((val)>>24)&0xFF
#define BMP_H1_SIZE (14) // BMP header 14 bytes
#define BMP_V4_SIZE (56) // v4 header 56 bytes
#define BMP_HEAD_SIZE (BMP_H1_SIZE + BMP_V4_SIZE) // Size of all headers
#define BMP_SIZE (2*LCD_WIDTH*LCD_HEIGHT) // Bitmap size = 2*w*h
#define BMP_FILE_SIZE (BMP_SIZE + BMP_HEAD_SIZE) // File size = headers + bitmap
static const uint8_t bmp_header_v4[14+56] = {
// BITMAPFILEHEADER (14 byte size)
0x42, 0x4D, // BM signature
BMP_UINT32(BMP_FILE_SIZE), // File size (h + v4 + bitmap)
0x00, 0x00, // reserved
0x00, 0x00, // reserved
BMP_UINT32(BMP_HEAD_SIZE), // Size of all headers (h + v4)
// BITMAPINFOv4 (56 byte size)
BMP_UINT32(BMP_V4_SIZE), // Data offset after this point (v4 size)
BMP_UINT32(LCD_WIDTH), // Width
BMP_UINT32(LCD_HEIGHT), // Height
0x01, 0x00, // Planes
0x10, 0x00, // 16bpp
0x03, 0x00, 0x00, 0x00, // Compression (BI_BITFIELDS)
BMP_UINT32(BMP_SIZE), // Bitmap size (w*h*2)
0xC4, 0x0E, 0x00, 0x00, // x Resolution (96 DPI = 96 * 39.3701 inches per metre = 0x0EC4)
0xC4, 0x0E, 0x00, 0x00, // y Resolution (96 DPI = 96 * 39.3701 inches per metre = 0x0EC4)
0x00, 0x00, 0x00, 0x00, // Palette size
0x00, 0x00, 0x00, 0x00, // Palette used
// Extend v4 header data (color mask for RGB565)
0x00, 0xF8, 0x00, 0x00, // R mask = 0b11111000 00000000
0xE0, 0x07, 0x00, 0x00, // G mask = 0b00000111 11100000
0x1F, 0x00, 0x00, 0x00, // B mask = 0b00000000 00011111
0x00, 0x00, 0x00, 0x00 // A mask = 0b00000000 00000000
};
static bool
made_screenshot(int touch_x, int touch_y)
{
int y, i;
UINT size;
if (touch_y < HEIGHT || touch_x < FREQUENCIES_XPOS3 || touch_x > FREQUENCIES_XPOS2)
return FALSE;
touch_wait_release();
// uint32_t time = chVTGetSystemTimeX();
// shell_printf("Screenshot\r\n");
FRESULT res = f_mount(fs_volume, "", 1);
// fs_volume, fs_file and fs_filename stored at end of spi_buffer!!!!!
uint16_t *buf = (uint16_t *)spi_buffer;
// shell_printf("Mount = %d\r\n", res);
if (res != FR_OK)
return TRUE;
#if FF_USE_LFN >= 1
uint32_t tr = rtc_get_tr_bcd(); // TR read first
uint32_t dr = rtc_get_dr_bcd(); // DR read second
plot_printf(fs_filename, FF_LFN_BUF, "VNA_%06X_%06X.bmp", dr, tr);
#else
plot_printf(fs_filename, FF_LFN_BUF, "%08X.bmp", rtc_get_FAT());
#endif
res = f_open(fs_file, fs_filename, FA_CREATE_ALWAYS | FA_READ | FA_WRITE);
// shell_printf("Open %s, result = %d\r\n", fs_filename, res);
if (res == FR_OK){
res = f_write(fs_file, bmp_header_v4, sizeof(bmp_header_v4), &size);
for (y = LCD_HEIGHT-1; y >= 0 && res == FR_OK; y--) {
ili9341_read_memory(0, y, LCD_WIDTH, 1, buf);
for (i = 0; i < LCD_WIDTH; i++)
buf[i] = __REVSH(buf[i]); // swap byte order (example 0x10FF to 0xFF10)
res = f_write(fs_file, buf, LCD_WIDTH*sizeof(uint16_t), &size);
}
res = f_close(fs_file);
// shell_printf("Close %d\r\n", res);
// testLog();
}
// time = chVTGetSystemTimeX() - time;
// shell_printf("Total time: %dms (write %d byte/sec)\r\n", time/10, (LCD_WIDTH*LCD_HEIGHT*sizeof(uint16_t)+sizeof(bmp_header_v4))*10000/time);
drawMessageBox("SCREENSHOT", res == FR_OK ? fs_filename : " Fail write ", 2000);
request_to_redraw(REDRAW_AREA);
return TRUE;
}
#endif
static bool
touch_lever_mode_select(int touch_x, int touch_y)
{
if (touch_y > HEIGHT) {
select_lever_mode(touch_x < FREQUENCIES_XPOS2 ? LM_CENTER : LM_SPAN);
return TRUE;
}
if (touch_y < 25) {
select_lever_mode((touch_x < FREQUENCIES_XPOS2 && electrical_delay != 0.0) ? LM_EDELAY : LM_MARKER);
return TRUE;
}
return FALSE;
}
static
void ui_process_touch(void)
{
int touch_x, touch_y;
int status = touch_check();
if (status == EVT_TOUCH_PRESSED || status == EVT_TOUCH_DOWN) {
touch_position(&touch_x, &touch_y);
switch (ui_mode) {
case UI_NORMAL:
// Try drag marker
if (touch_pickup_marker(touch_x, touch_y))
break;
#ifdef __USE_SD_CARD__
if (made_screenshot(touch_x, touch_y))
break;
#endif
// Try select lever mode (top and bottom screen)
if (touch_lever_mode_select(touch_x, touch_y)) {
touch_wait_release();
break;
}
// switch menu mode after release
touch_wait_release();
selection = -1; // hide keyboard mode selection
ui_mode_menu();
break;
case UI_MENU:
menu_apply_touch(touch_x, touch_y);
break;
#ifdef UI_USE_NUMERIC_INPUT
case UI_NUMERIC:
numeric_apply_touch(touch_x, touch_y);
break;
#endif
}
}
}
void
ui_process(void)
{
if (operation_requested&OP_LEVER)
ui_process_lever();
if (operation_requested&OP_TOUCH)
ui_process_touch();
touch_start_watchdog();
operation_requested = OP_NONE;
}
/* Triggered when the button is pressed or released. The LED4 is set to ON.*/
static void extcb1(EXTDriver *extp, expchannel_t channel)
{
(void)extp;
(void)channel;
operation_requested|=OP_LEVER;
//cur_button = READ_PORT() & BUTTON_MASK;
}
//static systime_t t_time = 0;
// Triggered touch interrupt call
void handle_touch_interrupt(void)
{
operation_requested|= OP_TOUCH;
// systime_t n_time = chVTGetSystemTimeX();
// shell_printf("%d\r\n", n_time - t_time);
// t_time = n_time;
}
static const EXTConfig extcfg = {
{
{EXT_CH_MODE_DISABLED, NULL},
{EXT_CH_MODE_RISING_EDGE | EXT_CH_MODE_AUTOSTART | EXT_MODE_GPIOA, extcb1},
{EXT_CH_MODE_RISING_EDGE | EXT_CH_MODE_AUTOSTART | EXT_MODE_GPIOA, extcb1},
{EXT_CH_MODE_RISING_EDGE | EXT_CH_MODE_AUTOSTART | EXT_MODE_GPIOA, extcb1},
{EXT_CH_MODE_DISABLED, NULL},
{EXT_CH_MODE_DISABLED, NULL},
{EXT_CH_MODE_DISABLED, NULL},
{EXT_CH_MODE_DISABLED, NULL},
{EXT_CH_MODE_DISABLED, NULL},
{EXT_CH_MODE_DISABLED, NULL},
{EXT_CH_MODE_DISABLED, NULL},
{EXT_CH_MODE_DISABLED, NULL},
{EXT_CH_MODE_DISABLED, NULL},
{EXT_CH_MODE_DISABLED, NULL},
{EXT_CH_MODE_DISABLED, NULL},
{EXT_CH_MODE_DISABLED, NULL},
{EXT_CH_MODE_DISABLED, NULL},
{EXT_CH_MODE_DISABLED, NULL},
{EXT_CH_MODE_DISABLED, NULL},
{EXT_CH_MODE_DISABLED, NULL},
{EXT_CH_MODE_DISABLED, NULL},
{EXT_CH_MODE_DISABLED, NULL},
{EXT_CH_MODE_DISABLED, NULL}
}
};
void
ui_init()
{
adc_init();
// Activates the EXT driver 1.
extStart(&EXTD1, &extcfg);
// Init touch subsystem
touch_init();
}
1
https://gitee.com/niubileni/NanoVNA-D.git
git@gitee.com:niubileni/NanoVNA-D.git
niubileni
NanoVNA-D
NanoVNA-D
master

搜索帮助