/* * menu.c * * Created on: Mar 8, 2022 * Author: Brian.Bailey */ #include #include #include #include #include //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 ADC_t adc; 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; /******************************************************************************* * Static Function Declarations ******************************************************************************/ static Menu_t* getNewMenu(MenuHandler_t handler); static int handleSystemInfoMenu(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; switch (id) { case MENU_ID_SYSINFO: { item->pMonoIcon = menuMore; strcpy(item->text, "System Information"); item->handler = handleSystemInfoMenu; break; } case MENU_ID_FREQUENCIES: { item->pMonoIcon = menuMore; strcpy(item->text, "Frequencies"); break; } case MENU_ID_AUTOSHUTDOWN: { item->pMonoIcon = 0; strcpy(item->text, "Auto Shutdown"); break; } case MENU_ID_LANGUAGE: { item->pMonoIcon = menuMore; strcpy(item->text, "Language"); break; } } } static void handleUpDown(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 + 100; } } 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_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; } } if (menu->draw) { if(menu->selected >= (menu->displayIndex + MENU_MAX_LINES_DISPLAYED)) { menu->displayIndex++; } else if(menu->selected < menu->displayIndex) { menu->displayIndex--; } } } static void drawScrollBar(Menu_t *menu) { DrawMenuScrollBar(menu->displayIndex, menu->itemCount); } 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 handleSystemInfoMenu(Menu_t *menu) { if (menu == NULL) { menu = getNewMenu(handleSystemInfoMenu); if (menu == NULL) { return MENU_EXIT; } } if (menu->init) { int itemCount = 0; createMenuItem(MENU_ID_SYSINFO , &menu->items[itemCount++]); createMenuItem(MENU_ID_FREQUENCIES , &menu->items[itemCount++]); menu->itemCount = itemCount; menu->init = false; menu->draw = true; } uint32_t pressed = KEY_GetPressed(); handleUpDown(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); } } 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); } } //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; //SystemInfoMenu(); } 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; 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++]); 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++]); menu->itemCount = itemCount; menu->init = false; menu->draw = true; } uint32_t pressed = KEY_GetPressed(); handleUpDown(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] = NULL; //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", adc.V_OffsetAdc); FL_DrawString(tempString, xCol2, yPos, MENU_FONT, LCD_DRAW_SET, FL_ALIGN_LEFT); //voltage offset if(!adc.vosOK) { FL_DrawString("ERR", xCol1 + 30, yPos, MENU_FONT, LCD_DRAW_SET, FL_ALIGN_LEFT); } yPos += yInc; sprintf(tempString, "%d", adc.I_OffsetAdc); FL_DrawString(tempString, xCol2, yPos, MENU_FONT, LCD_DRAW_SET, FL_ALIGN_LEFT); //current offset if(!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); 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; ihandler(_menuData.currentMenu); switch (exitCode) { case MENU_HOME: { _menuData.stackCount = 0; break; } case MENU_EXIT: { // pop the menu off the stack _menuData.stackCount--; if (_menuData.stackCount > 0) { _menuData.currentMenu = &_menuData.menuStack[_menuData.stackCount-1]; _menuData.currentMenu->draw = true; } break; } } if (_menuData.stackCount == 0) { sys.guiMode = GUI_MODE_NORMAL; } } }