Files
TX/source/menu.c
2025-06-11 10:55:00 -05:00

1638 lines
35 KiB
C

/*
* menu.c
*
* Created on: Mar 8, 2022
* Author: Brian.Bailey
*/
#include <assert.h>
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <stdint.h>
//Drivers
#include "fsl_common.h"
#include "fsl_gpio.h"
#include "Fonts\fontLibrary.h"
#include "Graphics\graphicsLibrary.h"
#include "lcd.h"
#include "keys.h"
#include "timer.h"
#include "frq.h"
#include "Graphics\icons.h"
#include "System\system.h"
#include "mode.h"
#include "adc.h"
#include "testMenu.h"
#include "hwFixes.h"
#include "menu.h"
#include "ports.h"
#include "display.h"
#include "io.h"
/*******************************************************************************
* Definitions
******************************************************************************/
#define MENU_TIMER_PERIOD_MS (100) //100mS for 10Hz update
/*******************************************************************************
* Variables
******************************************************************************/
static MenuData_t _menuData;
MENU_t menu;
MenuItem_t mainMenu[MAIN_MENU_NUM_TX10];
MenuItem_t linkMenu[LINK_MENU_NUM];
MenuItem_t langMenu[LANG_MENU_NUM];
extern const char *languageNames[];
extern char tempString[40];
char tempstr2[10]; // Todo move
extern SYSTEM_DATA_t sys;
extern uint8_t Cur_Mode;
extern uint8_t frequency,psu_failed;
extern uint8_t Dds_Pot_Val[];
extern uint8_t Port_State[];
extern HARDWARE_FIX_t hwf;
extern uint32_t systemTime;
#define MENU_ITEM_SIZE 50
MenuItem_t _menuItems[MENU_ITEM_SIZE];
int _menuItemsIndex;
/*******************************************************************************
* Static Function Declarations
******************************************************************************/
static Menu_t* getNewMenu(MenuHandler_t handler);
static Menu_t* getCurrentMenu(void);
static int handleSystemInfoMenu(Menu_t *menu);
static int handleAutoShutdown(Menu_t *menu);
static int handleFrequencies(Menu_t *menu);
static void ClearMenuItems(MenuItem_t items[], uint32_t num);
static void DrawMenuScrollBar(uint32_t displayIndex, uint32_t numItems);
static void DisplaySystemInfo(void);
static void DisplayDiagnostics(void);
static void DisplayDiagnostics2(void);
static void LinkRadioMenu(void);
static void DisplayLinkRadioMenu(uint32_t selected);
static void FrequenciesMenu(void);
static void DisplayFrequenciesMenu(uint32_t selected);
static void LanguageMenu(void);
static void DisplayLanguageMenu(uint32_t selected);
static void DisplayRegulatoryInfo(void);
/*******************************************************************************
* Static Functions
******************************************************************************/
static void createMenuItem(MenuItemId_t id, MenuItem_t *item)
{
item->id = id;
item->handler = NULL;
switch (id)
{
case MENU_ID_SYSINFO:
{
item->pMonoIcon = (uint32_t*)menuMore;
strcpy(item->text, "System Information");
item->handler = handleSystemInfoMenu;
break;
}
case MENU_ID_FREQUENCIES:
{
item->pMonoIcon = (uint32_t*)menuMore;
strcpy(item->text, "Frequencies");
item->handler = handleFrequencies;
break;
}
case MENU_ID_AUTOSHUTDOWN:
{
item->pMonoIcon = 0;
strcpy(item->text, "Auto Shutdown");
item->handler = handleAutoShutdown;
break;
}
case MENU_ID_LANGUAGE:
{
item->pMonoIcon = (uint32_t*)menuMore;
strcpy(item->text, "Language");
break;
}
case MENU_ID_FREQUENCY:
{
item->pMonoIcon = NULL;
strcpy(item->text, "Language");
break;
}
}
}
static void handleMenuKeys(uint32_t pressed, Menu_t *menu)
{
switch (menu->longPress)
{
case (KEY_UP << KEY_LONG_PRESS):
{
if (!GPIO_READ(PIN_KEY_UP))
{
if (systemTime >= menu->nextRepeat)
{
pressed = KEY_UP;
menu->nextRepeat = systemTime + KEY_REPEAT_TIME;
}
}
else
{
menu->longPress = 0;
}
break;
}
case (KEY_DOWN << KEY_LONG_PRESS):
{
if (!GPIO_READ(PIN_KEY_DOWN))
{
if (systemTime >= menu->nextRepeat)
{
pressed = KEY_DOWN;
menu->nextRepeat = systemTime + 100;
}
}
else
{
menu->longPress = 0;
}
break;
}
}
switch(pressed)
{
case KEY_HOME:
{
menu->exitCode = MENU_HOME;
break;
}
case KEY_UP:
{
menu->selected--;
if(menu->selected < 0)
{
menu->selected = 0;
}
menu->draw = true;
break;
}
case KEY_DOWN:
{
menu->selected++;
if(menu->selected >= menu->itemCount)
{
menu->selected = menu->itemCount - 1;
}
menu->draw = true;
break;
}
case (KEY_UP << KEY_LONG_PRESS):
case (KEY_DOWN << KEY_LONG_PRESS):
{
menu->longPress = pressed;
menu->nextRepeat = 0;
break;
}
case KEY_BACK:
{
menu->exitCode = MENU_EXIT;
break;
}
}
if (menu->draw)
{
if(menu->selected >= (menu->displayIndex + MENU_MAX_LINES_DISPLAYED))
{
menu->displayIndex++;
}
else if(menu->selected < menu->displayIndex)
{
menu->displayIndex--;
}
}
if (pressed == KEY_ENTER)
{
if (menu->items[menu->selected].handler != NULL)
{
menu->items[menu->selected].handler(NULL);
}
}
}
static void drawScrollBar(Menu_t *menu)
{
DrawMenuScrollBar(menu->displayIndex, menu->itemCount);
}
static Menu_t* getCurrentMenu(void)
{
return &_menuData.menuStack[_menuData.stackCount-1];
}
static Menu_t* getNewMenu(MenuHandler_t handler)
{
Menu_t *menu = NULL;
if (_menuData.stackCount < MENU_STACK_SIZE)
{
menu = &_menuData.menuStack[_menuData.stackCount];
menu->handler = handler;
menu->init = true;
menu->selected = 0;
menu->displayIndex = 0;
menu->exitCode = MENU_OK;
_menuData.currentMenu = menu;
_menuData.stackCount++;
}
return menu;
}
static int handleAutoShutdown(Menu_t *menu)
{
// cycle through selections
tmr_ChangeAutoSDTimer();
menu = getCurrentMenu();
menu->draw = true;
}
static int handleFrequencies(Menu_t *menu)
{
if (menu == NULL)
{
menu = getNewMenu(handleFrequencies);
if (menu == NULL)
{
return MENU_EXIT;
}
}
if (menu->init)
{
int itemCount = 0;
menu->items = &_menuItems[_menuItemsIndex];
MenuItem_t *item;
int numFreq = FREQ_GetNumFrequencies();
for (int i=0; i<numFreq; ++i)
{
item = &menu->items[itemCount++];
item->id = MENU_ID_FREQUENCY;
item->handler = NULL;
FREQ_GetFrequencyName(i, item->text);
item->data = (void*)FREQ_GetFreqPointerByIndex(i);
}
_menuItemsIndex += itemCount;
menu->itemCount = itemCount;
menu->init = false;
menu->draw = true;
}
uint32_t pressed = KEY_GetPressed();
handleMenuKeys(pressed, menu);
if (pressed == KEY_ENTER)
{
FREQUENCY_t *freq = (FREQUENCY_t*)menu->items[menu->selected].data;
freq->enabled ^= 1;
menu->draw = true;
}
if (menu->draw)
{
LCD_Clear();
// Draw menu items
MenuItem_t *item;
for(uint32_t i = menu->displayIndex; i < menu->displayIndex + menu->itemCount; i++) //this can draw extra lines off the screen but we don't care
{
item = &menu->items[i];
//Frequency name
FL_DrawString(item->text, MENU_MAIN_TEXT_X, MENU_MAIN_TEXT_Y_START + (i - menu->displayIndex)*MENU_LINE_HEIGHT, MENU_FONT, LCD_DRAW_SET, FL_ALIGN_LEFT);
//checkBoxes
if(FREQ_GetFreqByIndex(i).enabled)
{
GL_DrawMonoBitmap(box_checked, MENU_MAIN_STATUS_X, MENU_MAIN_TEXT_Y_START +2+ (i - menu->displayIndex)*MENU_LINE_HEIGHT, LCD_DRAW_SET);
}
else
{
GL_DrawMonoBitmap(box_unchecked, MENU_MAIN_STATUS_X, MENU_MAIN_TEXT_Y_START +2+ (i - menu->displayIndex)*MENU_LINE_HEIGHT, LCD_DRAW_SET);
}
}
//Draw selection bar
uint32_t selRectY0 = MENU_MAIN_TEXT_Y_START + (menu->selected - menu->displayIndex)*MENU_LINE_HEIGHT;
GL_DrawFilledRectangle(MENU_SEL_RECT_X0, selRectY0, MENU_SEL_RECT_X1, selRectY0 + MENU_LINE_HEIGHT, LCD_DRAW_XOR);
drawScrollBar(menu);
LCD_Update();
menu->draw = false;
}
return menu->exitCode;
}
static int handleSystemInfoMenu(Menu_t *menu)
{
if (menu == NULL)
{
menu = getNewMenu(handleSystemInfoMenu);
if (menu == NULL)
{
return MENU_EXIT;
}
}
if (menu->init)
{
menu->items = NULL;
menu->itemCount = 2;
menu->init = false;
menu->draw = true;
}
uint32_t pressed = KEY_GetPressed();
handleMenuKeys(pressed, menu);
if (menu->draw)
{
LCD_Clear();
if (menu->selected == 0)
{
FL_DrawString("Menu 1", MENU_MAIN_TEXT_X, MENU_MAIN_TEXT_Y_START, MENU_FONT, LCD_DRAW_SET, FL_ALIGN_LEFT);
}
else
if (menu->selected == 1)
{
FL_DrawString("Menu 2", MENU_MAIN_TEXT_X, MENU_MAIN_TEXT_Y_START, MENU_FONT, LCD_DRAW_SET, FL_ALIGN_LEFT);
}
LCD_Update();
menu->draw = false;
}
return menu->exitCode;
}
static int handleMainMenu(Menu_t *menu)
{
if (menu == NULL)
{
// get new menu on stack and init
menu = getNewMenu(handleMainMenu);
//menu->handler = handleMainMenu;
}
if (menu->init)
{
int itemCount = 0;
menu->items = &_menuItems[_menuItemsIndex];
createMenuItem(MENU_ID_SYSINFO , &menu->items[itemCount++]);
createMenuItem(MENU_ID_FREQUENCIES , &menu->items[itemCount++]);
createMenuItem(MENU_ID_AUTOSHUTDOWN , &menu->items[itemCount++]);
createMenuItem(MENU_ID_LANGUAGE , &menu->items[itemCount++]);
_menuItemsIndex += itemCount;
menu->itemCount = itemCount;
menu->init = false;
menu->draw = true;
}
uint32_t pressed = KEY_GetPressed();
handleMenuKeys(pressed, menu);
// if (pressed == KEY_BACK)
// {
// menu->exitCode = MENU_EXIT;
// }
// else
// if (pressed == KEY_ENTER)
// {
// if (menu->items[menu->selected].handler != NULL)
// {
// menu->items[menu->selected].handler(NULL);
// //return MENU_OK;
// }
// }
if (menu->draw)
{
LCD_Clear();
// Draw menu items
MenuItem_t *item;
for(uint32_t i = menu->displayIndex; i < menu->displayIndex + menu->itemCount; i++) //this can draw extra lines off the screen but we don't care
{
item = &menu->items[i];
//Menu strings
FL_DrawTranslatedString(item->text, MENU_MAIN_TEXT_X, MENU_MAIN_TEXT_Y_START + (i-menu->displayIndex)*MENU_LINE_HEIGHT, MENU_FONT, LCD_DRAW_SET, FL_ALIGN_LEFT);
// Draw item status
if (item->pMonoIcon != NULL)
{
GL_DrawMonoBitmap(item->pMonoIcon, MENU_MAIN_STATUS_X, MENU_MAIN_TEXT_Y_START + (i-menu->displayIndex)*MENU_LINE_HEIGHT + MENU_MAIN_STATUS_Y_OFF, LCD_DRAW_SET);
}
if (item->id == MENU_ID_AUTOSHUTDOWN)
{
FL_DrawTranslatedString(tmr_GetAutoSDTimerString(), MENU_MAIN_STATUS_X, MENU_MAIN_TEXT_Y_START + (i - menu->displayIndex)*MENU_LINE_HEIGHT, MENU_FONT, LCD_DRAW_SET, FL_ALIGN_LEFT);
}
}
//Draw selection bar
uint32_t selRectY0 = MENU_MAIN_TEXT_Y_START + (menu->selected - menu->displayIndex)*MENU_LINE_HEIGHT;
GL_DrawFilledRectangle(MENU_SEL_RECT_X0, selRectY0, MENU_SEL_RECT_X1, selRectY0 + MENU_LINE_HEIGHT, LCD_DRAW_XOR);
drawScrollBar(menu);
LCD_Update();
menu->draw = false;
}
return menu->exitCode;
}
//Clear an array of MENU_ITEM_t
static void ClearMenuItems(MenuItem_t items[], uint32_t num)
{
for(uint32_t i = 0; i < num; i++)
{
items[i].pMonoIcon = NULL; //Init mono icon pointer to null
items[i].text[0] = '\0'; //Init first char to null
}
}
//Draw menu scroll bar on right side
static void DrawMenuScrollBar(uint32_t displayIndex, uint32_t numItems)
{
//Exit if scroll bar not needed
if(numItems <= MENU_MAX_LINES_DISPLAYED)
{
return;
}
//numItems = 30; // 18
//vertical line
const uint32_t lineWidth = 5;
const uint32_t lineX = LCD_X_MAX - 10;
const uint32_t lineYStart = 20;
const uint32_t lineYStop = LCD_Y_MAX - 20;
const uint32_t lineHeight = lineYStop - lineYStart;
//rectangle
const uint32_t rectWidth = 20;
const uint32_t rectX = lineX;
uint32_t rectHeight = lineHeight * ((double)MENU_MAX_LINES_DISPLAYED / numItems);
uint32_t rectYStart = lineYStart + (lineHeight - rectHeight) * ((double)displayIndex / (numItems - MENU_MAX_LINES_DISPLAYED));
uint32_t rectYStop = rectYStart + rectHeight;
//Draw line
GL_DrawLine(lineX, lineYStart, lineX, lineYStop, lineWidth, LCD_DRAW_SET);
//Draw Rectangle
GL_DrawLine(rectX, rectYStart, rectX, rectYStop, rectWidth, LCD_DRAW_SET);
}
static void SystemInfoMenu(void)
{
uint32_t selected = 0;
uint32_t menuExit = 0;
while(1)
{
if(KEY_IsKeyPressed(KEY_ALL))
{
//use keys to change selected
uint32_t pressed = KEY_WaitForKeyPress(KEY_ALL);
switch(pressed) //This won't work if multiple keys pressed, but it'll clear them
{
case KEY_UP:
if(--selected > MENU_SYS_INFO_NUM)
{
selected = 0;
}
break;
case KEY_DOWN:
if(++selected >= MENU_SYS_INFO_NUM)
{
selected = MENU_SYS_INFO_NUM - 1;
}
break;
case KEY_BACK:
menuExit = true;
break;
case ON_OFF_KEY:
menu.exitToMainScreen = true;
break;
case KEY_POWER: //Look for test menu key sequence: HOLD POWER,
if(selected == 1) //Must be in Diagnostics to enter test menu
{
uint32_t mode = 0;
uint32_t up = 0;
uint32_t down = 0;
while(KEY_GetPowerKeyHeld())
{
if(KEY_GetModeKeyHeld())
{
mode++;
while(KEY_GetModeKeyHeld());
}
if(KEY_GetUpKeyHeld())
{
up++;
while(KEY_GetUpKeyHeld());
}
if(KEY_GetDownKeyHeld())
{
down++;
while(KEY_GetDownKeyHeld());
}
Delay_Ticks(10); //100mS
}
if((mode == 2) && (up == 2) && (down == 1))
{
TM_TestMenu();
}
}
}
}
#if 1 //Update info for diagnostics screens.
//ACCEL_Update();
//RTC_Update();
#endif
//Display selected screen
switch(selected)
{
case 0:
DisplaySystemInfo();
break;
case 1:
DisplayDiagnostics();
break;
case 2:
DisplayDiagnostics2();
break;
default:
break;
}
if(menuExit || menu.exitToMainScreen)
{
return;
}
Delay_Ticks(10); //100mS delay for screen display
}
}
static void DisplaySystemInfo(void)
{
uint32_t xCol1 = 0;
uint32_t xCol2 = 145;
uint32_t yStart = 17;//22;
uint32_t yPos = yStart;
uint32_t yInc = 18;//7;
LCD_Clear();
//Title
FL_DrawTranslatedString("SYSTEM INFO", LCD_X_MID, 0, MENU_FONT, LCD_DRAW_SET, FL_ALIGN_CENTER);
//Column 1
yPos = yStart;
if(Read_Model_type() != LEICA)
FL_DrawTranslatedString(sys.manufacturer, xCol1, yPos, MENU_FONT, LCD_DRAW_SET, FL_ALIGN_LEFT);
else
{
// tempstr2[10] = " 1005573";
// sprintf(sys.manufacturer, "%s%s",sys.manufacturer,tempstr2);
FL_DrawTranslatedString(sys.manufacturer, xCol1, yPos, MENU_FONT, LCD_DRAW_SET, FL_ALIGN_LEFT);
FL_DrawTranslatedString(" 1005573", xCol1 + 64, yPos, MENU_FONT, LCD_DRAW_SET, FL_ALIGN_LEFT);
}
yPos += yInc;
FL_DrawTranslatedString("Model Name", xCol1, yPos, MENU_FONT, LCD_DRAW_SET, FL_ALIGN_LEFT);
yPos += yInc;
FL_DrawTranslatedString("Serial Number", xCol1, yPos, MENU_FONT, LCD_DRAW_SET, FL_ALIGN_LEFT);
yPos += yInc;
FL_DrawTranslatedString("Loader Version", xCol1, yPos, MENU_FONT, LCD_DRAW_SET, FL_ALIGN_LEFT);
yPos += yInc;
FL_DrawTranslatedString("Software Version", xCol1, yPos, MENU_FONT, LCD_DRAW_SET, FL_ALIGN_LEFT);
yPos += yInc;
FL_DrawTranslatedString("Manufacture Date", xCol1, yPos, MENU_FONT, LCD_DRAW_SET, FL_ALIGN_LEFT);
yPos += yInc;
//Column 2
yPos = yStart;
if(strncmp(sys.manufacturer, "Underground", 10) == 0 || strncmp(sys.manufacturer, "Goldenland", 9) == 0) //If MFG is "Underground...", move modelNumber to the right
{
FL_DrawString(sys.modelNumber, LCD_X_MAX, yPos, MENU_FONT, LCD_DRAW_SET, FL_ALIGN_RIGHT);
yPos += yInc;
}
else
{
FL_DrawString(sys.modelNumber, xCol2, yPos, MENU_FONT, LCD_DRAW_SET, FL_ALIGN_LEFT);
yPos += yInc;
}
if(Read_Model_type() == UMAG)
FL_DrawString("10W", xCol2, yPos, MENU_FONT, LCD_DRAW_SET, FL_ALIGN_LEFT);
else
FL_DrawString(sys.modelName, xCol2, yPos, MENU_FONT, LCD_DRAW_SET, FL_ALIGN_LEFT);
yPos += yInc;
FL_DrawString(sys.serialNumber, xCol2, yPos, MENU_FONT, LCD_DRAW_SET, FL_ALIGN_LEFT);
yPos += yInc;
sprintf(tempString, "%d", sys.bootloaderVersion);
FL_DrawString(tempString, xCol2, yPos, MENU_FONT, LCD_DRAW_SET, FL_ALIGN_LEFT);
yPos += yInc;
FL_DrawString(SW_VERSION, xCol2, yPos, MENU_FONT, LCD_DRAW_SET, FL_ALIGN_LEFT);
yPos += yInc;
FL_DrawString(sys.mfgDate, xCol2, yPos, MENU_FONT, LCD_DRAW_SET, FL_ALIGN_LEFT);
yPos += yInc;
LCD_Update();
}
static void DisplayDiagnostics(void)
{
uint32_t xCol1 = 2;
uint32_t xCol2 = 100;
uint32_t yStart = 25;
uint32_t yPos = yStart;
uint32_t yInc = 16;
LCD_Clear();
//Title
FL_DrawString("DIAGNOSTICS 1", LCD_X_MID, 0, MENU_FONT, LCD_DRAW_SET, FL_ALIGN_CENTER);
//Show Main PCBA PN top right
sprintf(tempString, "%d", hwf.mainPcbaPN);
FL_DrawString(tempString, LCD_X_MAX, yStart, MENU_FONT, LCD_DRAW_SET, FL_ALIGN_RIGHT);
//Column 1: Headings
yPos = yStart;
FL_DrawString("Output", xCol1, yPos, MENU_FONT, LCD_DRAW_SET, FL_ALIGN_LEFT);
yPos += yInc;
FL_DrawString("Frequency", xCol1, yPos, MENU_FONT, LCD_DRAW_SET, FL_ALIGN_LEFT);
yPos += yInc;
#if 0
FL_DrawString("Voltage", xCol1, yPos, MENU_FONT, LCD_DRAW_SET, FL_ALIGN_LEFT);
yPos += yInc;
FL_DrawString("Current", xCol1, yPos, MENU_FONT, LCD_DRAW_SET, FL_ALIGN_LEFT);
yPos += yInc;
FL_DrawString("Power", xCol1, yPos, MENU_FONT, LCD_DRAW_SET, FL_ALIGN_LEFT);
yPos += yInc;
#endif
yPos += yInc;
yPos += yInc;
FL_DrawString("Ios", xCol1, yPos, MENU_FONT, LCD_DRAW_SET, FL_ALIGN_LEFT); //current offset
yPos += yInc;
FL_DrawString("Vos", xCol1, yPos, MENU_FONT, LCD_DRAW_SET, FL_ALIGN_LEFT); //voltage offset
yPos += yInc;
//Column 2: values
yPos = yStart;
switch(Cur_Mode) //Show text for MODE
{
case BROADCAST:
sprintf(tempString, "INDUCTION");
break;
case PORT1_A:
sprintf(tempString, "PORT 1A");
break;
case PORT1_B:
sprintf(tempString, "PORT 1B");
break;
case PORT2_A:
sprintf(tempString, "PORT 2A");
break;
case PORT2_B:
sprintf(tempString, "PORT 1B");
break;
default:
sprintf(tempString, "Taco");
break;
}
FL_DrawString(tempString, xCol2, yPos, MENU_FONT, LCD_DRAW_SET, FL_ALIGN_LEFT);
yPos += yInc;
FREQ_GetFrequencyName(frequency, tempString);
FL_DrawString(tempString, xCol2, yPos, MENU_FONT, LCD_DRAW_SET, FL_ALIGN_LEFT); //Frequency
yPos += yInc;
#if 0
FL_DrawString(tempString, xCol2, yPos, MENU_FONT, LCD_DRAW_SET, FL_ALIGN_LEFT); //voltage
yPos += yInc;
FL_DrawString(tempString, xCol2, yPos, MENU_FONT, LCD_DRAW_SET, FL_ALIGN_LEFT); //current
yPos += yInc;
FL_DrawString(tempString, xCol2, yPos, MENU_FONT, LCD_DRAW_SET, FL_ALIGN_LEFT); //power
yPos += yInc;
#endif
sprintf(tempString, "POT %d", Dds_Pot_Val[1]);
FL_DrawString(tempString, xCol1, yPos, MENU_FONT, LCD_DRAW_SET, FL_ALIGN_LEFT);
if(psu_failed)
{
sprintf(tempString, "PSU Error1");
FL_DrawString(tempString, xCol2, yPos, MENU_FONT, LCD_DRAW_SET, FL_ALIGN_LEFT);
}
yPos += yInc;
if((Port_State[MID_SR] & 0x40) > 0)
sprintf(tempString, "Gain HI");
else
sprintf(tempString, "Gain LO");
FL_DrawString(tempString, xCol1, yPos, MENU_FONT, LCD_DRAW_SET, FL_ALIGN_LEFT);
yPos += yInc;
// yPos += yInc;
sprintf(tempString, "%d", sys.adc.V_OffsetAdc);
FL_DrawString(tempString, xCol2, yPos, MENU_FONT, LCD_DRAW_SET, FL_ALIGN_LEFT); //voltage offset
if(!sys.adc.vosOK)
{
FL_DrawString("ERR", xCol1 + 30, yPos, MENU_FONT, LCD_DRAW_SET, FL_ALIGN_LEFT);
}
yPos += yInc;
sprintf(tempString, "%d", sys.adc.I_OffsetAdc);
FL_DrawString(tempString, xCol2, yPos, MENU_FONT, LCD_DRAW_SET, FL_ALIGN_LEFT); //current offset
if(!sys.adc.iosOK)
{
FL_DrawString("ERR", xCol1 + 30, yPos, MENU_FONT, LCD_DRAW_SET, FL_ALIGN_LEFT);
}
yPos += yInc;
LCD_Update();
}
static void DisplayDiagnostics2(void)
{
uint32_t xCol1 = 2;
uint32_t xCol2 = 100;
uint32_t yStart = 25;
uint32_t yPos = yStart;
uint32_t yInc = 16;
LCD_Clear();
//Title
FL_DrawString("DIAGNOSTICS 2", LCD_X_MID, 0, MENU_FONT, LCD_DRAW_SET, FL_ALIGN_CENTER);
#if 0
//Column 1: Headings
yPos = yStart;
FL_DrawString("Output", xCol1, yPos, MENU_FONT, LCD_DRAW_SET, FL_ALIGN_LEFT);
yPos += yInc;
//Column 2: values
yPos = yStart;
switch(Cur_Mode) //Show text for MODE
{
case BROADCAST:
sprintf(tempString, "INDUCTION");
break;
case PORT1_A:
sprintf(tempString, "PORT 1A");
break;
case PORT1_B:
sprintf(tempString, "PORT 1B");
break;
case PORT2_A:
sprintf(tempString, "PORT 2A");
break;
case PORT2_B:
sprintf(tempString, "PORT 1B");
break;
default:
sprintf(tempString, "Taco");
break;
}
FL_DrawString(tempString, xCol2, yPos, MENU_FONT, LCD_DRAW_SET, FL_ALIGN_LEFT);
yPos += yInc;
#endif
LCD_Update();
}
static void LinkRadioMenu(void)
{
}
static void DisplayLinkRadioMenu(uint32_t selected)
{
}
static void FrequenciesMenu(void)
{
static uint32_t selected = 0; //static = menu selection persists - Is this a good thing?
uint32_t menuExit = 0;
uint32_t numFrequencies = FREQ_GetNumFrequencies();
//Draw screen first time
DisplayFrequenciesMenu(selected);
while(1)
{
//use keys to change selected
uint32_t pressed = KEY_WaitForKeyPress(KEY_ALL);
switch(pressed) //This won't work if multiple keys pressed, but it'll clear them
{
case KEY_BACK:
menuExit = true;
break;
case ON_OFF_KEY:
menu.exitToMainScreen = true;
break;
case KEY_UP:
if(--selected > numFrequencies)
{
selected = 0;
}
DisplayFrequenciesMenu(selected);
break;
case (KEY_UP << KEY_LONG_PRESS):
do
{
if(--selected > numFrequencies)
{
selected = 0;
}
DisplayFrequenciesMenu(selected);
Delay_Ticks(MENU_KEY_HOLD_SCROLL_DELAY);
}
while(KEY_GetUpKeyHeld());
break;
case KEY_DOWN:
if(++selected >= numFrequencies)
{
selected = numFrequencies - 1;
}
DisplayFrequenciesMenu(selected);
break;
case (KEY_DOWN << KEY_LONG_PRESS):
do
{
if(++selected >= numFrequencies)
{
selected = numFrequencies - 1;
}
DisplayFrequenciesMenu(selected);
Delay_Ticks(MENU_KEY_HOLD_SCROLL_DELAY);
}
while(KEY_GetDownKeyHeld());
break;
case KEY_ENTER:
//Toggle enable on selected frequency
FREQ_ToggleEnable(selected); //selected is same as frequency index
DisplayFrequenciesMenu(selected); //Redraw menu after any changes
break;
}
if(menuExit || menu.exitToMainScreen)
{
return;
}
}
}
static void DisplayFrequenciesMenu(uint32_t selected)
{
#if 1
uint32_t numFrequencies = FREQ_GetNumFrequencies();
static char displayIndex = 0; //index of first menu line to draw
LCD_Clear();
//Title
//FL_DrawString("FREQUENCIES", LCD_X_MID, 0, MENU_FONT, LCD_DRAW_SET, FL_ALIGN_CENTER);
//Update displayIndex
if(selected >= (displayIndex + MENU_MAX_LINES_DISPLAYED))
{
displayIndex++;
}
else if(selected < displayIndex)
{
displayIndex--;
}
//Draw menu items
for(uint32_t i = displayIndex; i < displayIndex + numFrequencies; i++) //this could draw lots of frequencies off the screen but we don't care
{
//Frequency name
FREQ_GetFrequencyName(i, tempString);
FL_DrawString(tempString, MENU_MAIN_TEXT_X, MENU_MAIN_TEXT_Y_START + (i - displayIndex)*MENU_LINE_HEIGHT, MENU_FONT, LCD_DRAW_SET, FL_ALIGN_LEFT);
//checkBoxes
if(FREQ_GetFreqByIndex(i).enabled)
{
GL_DrawMonoBitmap(box_checked, MENU_MAIN_STATUS_X, MENU_MAIN_TEXT_Y_START +2+ (i - displayIndex)*MENU_LINE_HEIGHT, LCD_DRAW_SET);
}
else
{
GL_DrawMonoBitmap(box_unchecked, MENU_MAIN_STATUS_X, MENU_MAIN_TEXT_Y_START +2+ (i - displayIndex)*MENU_LINE_HEIGHT, LCD_DRAW_SET);
}
}
//Draw selection bar
uint32_t selRectY0 = MENU_MAIN_TEXT_Y_START + (selected - displayIndex)*MENU_LINE_HEIGHT;
//GL_DrawFilledRoundedRectangle(MENU_SEL_RECT_X0, selRectY0, MENU_SEL_RECT_X1, selRectY0 + MENU_LINE_HEIGHT, MENU_SEL_RECT_RADIUS, LCD_DRAW_XOR);
GL_DrawFilledRectangle(MENU_SEL_RECT_X0, selRectY0, MENU_SEL_RECT_X1A, selRectY0 + MENU_LINE_HEIGHT, LCD_DRAW_XOR);
//Draw menu icons
//Use DrawMenuBitmap(mainMenu[i], x, y)
DrawMenuScrollBar(displayIndex, numFrequencies);
LCD_Update();
#endif
}
static void LanguageMenu(void)
{
static uint32_t selected = 0; //static = start language menu where we left off
uint32_t menuExit = 0;
//Draw screen first time
DisplayLanguageMenu(selected);
KEY_ClearAll();
while(1)
{
//use keys to changes selected
uint32_t pressed = KEY_WaitForKeyPress(KEY_ALL);
switch(pressed) //This won't work if multiple keys pressed, but it'll clear them
{
case KEY_BACK:
menuExit = true;
break;
case ON_OFF_KEY:
menu.exitToMainScreen = true;
break;
case KEY_UP:
selected--;
if(selected > LANG_NUM)
{
selected = 0;
}
DisplayLanguageMenu(selected);
break;
case (KEY_UP << KEY_LONG_PRESS):
do
{
if(--selected > LANG_NUM)
{
selected = 0;
}
DisplayLanguageMenu(selected);
Delay_Ticks(MENU_KEY_HOLD_SCROLL_DELAY);
}
while(KEY_GetUpKeyHeld());
break;
case KEY_DOWN:
selected++;
if(selected >= LANG_NUM)
{
selected = LANG_NUM - 1;
}
DisplayLanguageMenu(selected);
break;
case (KEY_DOWN << KEY_LONG_PRESS):
do
{
if(++selected >= LANG_NUM)
{
selected = LANG_NUM - 1;
}
DisplayLanguageMenu(selected);
Delay_Ticks(MENU_KEY_HOLD_SCROLL_DELAY);
}
while(KEY_GetDownKeyHeld()); // Bug fixed KL 6/26/24
break;
case KEY_ENTER:
sys.language = selected; //Change language
DisplayLanguageMenu(selected);
break;
}
if(menuExit || menu.exitToMainScreen)
{
return;
}
}
}
static void DisplayLanguageMenu(uint32_t selected)
{
static char displayIndex = 0; //index of first menu line to draw
LCD_Clear();
//Title
//FL_DrawString("LANGUAGE MENU", 240, 0, MENU_FONT, LCD_DRAW_SET, FL_ALIGN_CENTER);
if(selected >= (displayIndex + MENU_MAX_LINES_DISPLAYED))
{
displayIndex++;
}
else if(selected < displayIndex)
{
displayIndex--;
}
//Draw menu strings
uint32_t lastIndex = displayIndex + MENU_MAX_LINES_DISPLAYED;
for(uint32_t i = displayIndex; i < lastIndex; i++)
{
//Language name
if(i == LANG_CHINESE || i == LANG_KOREAN) //Simsun for Chinese and Korean
{
FL_DrawTranslatedString(languageNames[i], MENU_MAIN_TEXT_X, MENU_MAIN_TEXT_Y_START + (i - displayIndex)*MENU_LINE_HEIGHT, fontSimsun, LCD_DRAW_SET, FL_ALIGN_LEFT);
}
else
{
FL_DrawTranslatedString(languageNames[i], MENU_MAIN_TEXT_X, MENU_MAIN_TEXT_Y_START + (i - displayIndex)*MENU_LINE_HEIGHT, MENU_FONT, LCD_DRAW_SET, FL_ALIGN_LEFT);
}
//checkBoxes
if(SYS_GetLanguage() == i) //language enum matches index
{
GL_DrawMonoBitmap(box_checked, MENU_MAIN_STATUS_X, MENU_MAIN_TEXT_Y_START +2+ (i - displayIndex)*MENU_LINE_HEIGHT, LCD_DRAW_SET);
}
else
{
GL_DrawMonoBitmap(box_unchecked, MENU_MAIN_STATUS_X, MENU_MAIN_TEXT_Y_START +2+ (i - displayIndex)*MENU_LINE_HEIGHT, LCD_DRAW_SET);
}
}
//Draw selection bar
uint32_t selRectY0 = MENU_MAIN_TEXT_Y_START + (selected - displayIndex)*MENU_LINE_HEIGHT;
GL_DrawFilledRectangle(MENU_SEL_RECT_X0, selRectY0, MENU_SEL_RECT_X1A, selRectY0 + MENU_LINE_HEIGHT, LCD_DRAW_XOR);
DrawMenuScrollBar(displayIndex, LANG_MENU_NUM);
LCD_Update();
}
static void DisplayRegulatoryInfo(void)
{
uint32_t caretX = 35;
uint32_t menuX = 50;
uint32_t menuYStart = 30;
uint32_t yInc = 30;
LCD_Clear();
//Title
FL_DrawTranslatedString("REGULATORY INFO", 240, 0, MENU_FONT, LCD_DRAW_SET, FL_ALIGN_CENTER);
//TODO: Display radio info here (Tx25 ONLY)
LCD_Update();
while(1)
{
//use keys to changes selected
uint32_t pressed = KEY_WaitForKeyPress(KEY_ALL);
if((pressed) == KEY_BACK || ON_OFF_KEY)
{
if(pressed == ON_OFF_KEY)
{
menu.exitToMainScreen = true;
}
return;
}
}
}
/*******************************************************************************
* Public Functions
******************************************************************************/
void MENU_Init(void)
{
//Init testMenu
TM_Init();
//Clear menu items
ClearMenuItems(mainMenu, MAIN_MENU_NUM_TX10);
ClearMenuItems(langMenu, LANG_MENU_NUM);
_menuItemsIndex = 0;
for (int i=0; i < MENU_STACK_SIZE; ++i)
{
_menuData.menuStack[i].selected = 0;
_menuData.menuStack[i].handler = NULL;
}
//main menu
uint32_t i = 0;
mainMenu[i].pMonoIcon = 0;
strcpy(mainMenu[i++].text, "System Information"); //System info screen
mainMenu[i].pMonoIcon = 0;
strcpy(mainMenu[i++].text, "Frequencies"); //Frequency Selection Menu
mainMenu[i].pMonoIcon = 0;
strcpy(mainMenu[i++].text, "Auto Shutdown"); //Auto Shutdown selection
mainMenu[i].pMonoIcon = 0;
strcpy(mainMenu[i++].text, "Language"); //Language Selection Menu
#if 0
mainMenu[i].pMonoIcon = 0;
strcpy(mainMenu[i++].text, "Link Radio"); //Link Radio Menu
//no regulatory info on the Tx10
mainMenu[i].pMonoIcon = 0;
strcpy(mainMenu[i++].text, "Regulatory Info"); //Reset - Needs a new name
#endif
//check for array over run
if(i > MAIN_MENU_NUM_TX10)
{
while(1);
}
//language menu
i = 0;
langMenu[i].pMonoIcon = 0;
strcpy(langMenu[i].text, languageNames[i++]);
langMenu[i].pMonoIcon = 0;
strcpy(langMenu[i].text, languageNames[i++]);
langMenu[i].pMonoIcon = 0;
strcpy(langMenu[i].text, languageNames[i++]);
langMenu[i].pMonoIcon = 0;
strcpy(langMenu[i].text, languageNames[i++]);
//check for array over run
if(i > LANG_MENU_NUM)
{
while(1);
}
}
void MENU_Main(void)
{
static uint32_t selected = 0; //static = menu selection persists - Is this a good thing?
uint32_t menuNum = MAIN_MENU_NUM_TX10;
uint32_t menuExit = 0;
//Draw screen first time
MENU_DisplayMain(selected);
while(1)
{
//use keys to changes selected
uint32_t pressed = KEY_WaitForKeyPress(KEY_ALL);
switch(pressed) //This won't work if multiple keys pressed, but it'll clear them
{
case KEY_BACK:
menuExit = true;
break;
case ON_OFF_KEY:
menu.exitToMainScreen = true;
break;
case KEY_UP:
if(--selected > menuNum)
{
selected = 0;
}
MENU_DisplayMain(selected);
break;
case (KEY_UP << KEY_LONG_PRESS):
do
{
if(--selected > menuNum)
{
selected = 0;
}
MENU_DisplayMain(selected);
Delay_Ticks(MENU_KEY_HOLD_SCROLL_DELAY);
}
while(KEY_GetUpKeyHeld());
break;
case KEY_DOWN:
if(++selected >= menuNum)
{
selected = menuNum - 1;
}
MENU_DisplayMain(selected);
break;
case (KEY_DOWN << KEY_LONG_PRESS):
do
{
if(++selected >= menuNum)
{
selected = menuNum - 1;
}
MENU_DisplayMain(selected);
Delay_Ticks(MENU_KEY_HOLD_SCROLL_DELAY);
}
while(KEY_GetDownKeyHeld());
break;
case KEY_ENTER:
switch(selected)
{
case(0): //System Info Menu
SystemInfoMenu();
break;
case(1): //Frequency menu
FrequenciesMenu();
break;
case(2): //Auto shut down
tmr_ChangeAutoSDTimer();
break;
case(3): //Language menu
LanguageMenu();
break;
case(4): //Link Radio
//LinkRadioMenu();
break;
case(5): //Regulatory
DisplayRegulatoryInfo();
break;
default:
break;
}
if(!menu.exitToMainScreen)
{
MENU_DisplayMain(selected); //Redraw menu after any changes
}
break;
}
if(menuExit || menu.exitToMainScreen)
{
menu.exitToMainScreen = false;
//SYS_SaveSettings();
return;
}
}
}
void MENU_DisplayMain(uint32_t selected)
{
char displayIndex = 0; //index of first menu line to draw
uint32_t menuNum = MAIN_MENU_NUM_TX10;
LCD_Clear();
//Title
//'FL_DrawString("MAIN MENU", 240, 0, MENU_FONT, LCD_DRAW_SET, FL_ALIGN_CENTER);
//Update displayIndex
if(selected >= (displayIndex + MENU_MAX_LINES_DISPLAYED))
{
displayIndex++;
}
else if(selected < displayIndex)
{
displayIndex--;
}
//Draw menu items
for(uint32_t i = displayIndex; i < displayIndex + menuNum; i++) //this can draw extra lines off the screen but we don't care
{
//Menu strings
FL_DrawTranslatedString(mainMenu[i].text, MENU_MAIN_TEXT_X, MENU_MAIN_TEXT_Y_START + (i-displayIndex)*MENU_LINE_HEIGHT, MENU_FONT, LCD_DRAW_SET, FL_ALIGN_LEFT);
//Draw item status
switch(i)
{
case(0): //System Info screen
GL_DrawMonoBitmap(menuMore, MENU_MAIN_STATUS_X, MENU_MAIN_TEXT_Y_START + (i-displayIndex)*MENU_LINE_HEIGHT + MENU_MAIN_STATUS_Y_OFF, LCD_DRAW_SET);
break;
case(1): //Frequency
GL_DrawMonoBitmap(menuMore, MENU_MAIN_STATUS_X, MENU_MAIN_TEXT_Y_START + (i-displayIndex)*MENU_LINE_HEIGHT + MENU_MAIN_STATUS_Y_OFF, LCD_DRAW_SET);
break;
case(2): //Auto Shutdown
FL_DrawTranslatedString(tmr_GetAutoSDTimerString(), MENU_MAIN_STATUS_X, MENU_MAIN_TEXT_Y_START + (i - displayIndex)*MENU_LINE_HEIGHT, MENU_FONT, LCD_DRAW_SET, FL_ALIGN_LEFT);
break;
case(3): //Language
GL_DrawMonoBitmap(menuMore, MENU_MAIN_STATUS_X, MENU_MAIN_TEXT_Y_START + (i-displayIndex)*MENU_LINE_HEIGHT + MENU_MAIN_STATUS_Y_OFF, LCD_DRAW_SET);
break;
case(4): //Link radio
GL_DrawMonoBitmap(menuMore, MENU_MAIN_STATUS_X, MENU_MAIN_TEXT_Y_START + (i-displayIndex)*MENU_LINE_HEIGHT + MENU_MAIN_STATUS_Y_OFF, LCD_DRAW_SET);
break;
case(5): //Regulatory
break;
case(6): //Not used
break;
default:
break;
}
}
//Draw selection bar
uint32_t selRectY0 = MENU_MAIN_TEXT_Y_START + (selected - displayIndex)*MENU_LINE_HEIGHT;
//GL_DrawFilledRoundedRectangle(MENU_SEL_RECT_X0, selRectY0, MENU_SEL_RECT_X1, selRectY0 + MENU_LINE_HEIGHT, MENU_SEL_RECT_RADIUS, LCD_DRAW_XOR);
GL_DrawFilledRectangle(MENU_SEL_RECT_X0, selRectY0, MENU_SEL_RECT_X1, selRectY0 + MENU_LINE_HEIGHT, LCD_DRAW_XOR);
//Draw menu icons
//Use DrawMenuBitmap(mainMenu[i], x, y)
DrawMenuScrollBar(displayIndex, menuNum);
LCD_Update();
}
void Menu_init(void)
{
_menuData.currentMenu = NULL;
_menuData.stackCount = 0;
for (int i=0; i<MENU_STACK_SIZE; ++i)
{
_menuData.menuStack[i].displayIndex = 0;
_menuData.menuStack[i].exitCode = MENU_OK;
}
for (int j=0; j<MENU_ITEM_SIZE; ++j)
{
//_menuData.menuStack[i].items[j].id = MENU_ID_NONE;
//_menuData.menuStack[i].items[j].handler = NULL;
_menuItems[j].id = MENU_ID_NONE;
_menuItems[j].handler = NULL;
}
}
void Menu_mainMenu(void)
{
sys.guiMode = GUI_MODE_MENU;
// menu at top of stack is always "Main Menu"
_menuData.stackCount = 0;
getNewMenu(handleMainMenu);
}
void Menu_service(void)
{
int exitCode = MENU_OK;
Menu_t *menu;
// run the menu state machine and prevent blocking
if (_menuData.currentMenu != NULL)
{
exitCode = _menuData.currentMenu->handler(_menuData.currentMenu);
switch (exitCode)
{
case MENU_HOME:
{
_menuData.stackCount = 0;
_menuItemsIndex = 0;
break;
}
case MENU_EXIT:
{
menu = getCurrentMenu();
_menuItemsIndex -= (menu->items != NULL ? menu->itemCount : 0);
// pop the menu off the stack
_menuData.stackCount--;
if (_menuData.stackCount > 0)
{
_menuData.currentMenu = getCurrentMenu();
_menuData.currentMenu->draw = true;
}
break;
}
}
if (_menuData.stackCount == 0)
{
sys.guiMode = GUI_MODE_NORMAL;
}
}
}