/* * 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 "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" #include "utils.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 DrawMenuScrollBar(uint32_t displayIndex, uint32_t numItems); /******************************************************************************* * 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 = fgen_getNumFrequencies(); for (int i=0; iitems[itemCount++]; item->id = MENU_ID_FREQUENCY; item->handler = NULL; item->data = (void*)fgen_getByIndex(i); fgen_getFrequencyName(item->data, item->text); } _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 (fgen_getByIndex(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; } //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); } /******************************************************************************* * 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_init(void) { _menuData.currentMenu = NULL; _menuData.stackCount = 0; for (int i=0; ihandler(_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; } } }