// ----------------------------------------------------------------------------- /// @file repairMenu.c /// @brief Description // ----------------------------------------------------------------------------- // Micro-Key bv // Industrieweg 28, 9804 TG Noordhorn // Postbus 92, 9800 AB Zuidhorn // The Netherlands // Tel: +31 594 503020 // Fax: +31 594 505825 // Email: support@microkey.nl // Web: www.microkey.nl // ----------------------------------------------------------------------------- /// $Revision$ /// $Author$ /// $Date$ // (c) 2017 Micro-Key bv // ----------------------------------------------------------------------------- /// @file repairMenu.c /// @ingroup {group_name} // ----------------------------------------------------------------------------- // Include files // ----------------------------------------------------------------------------- #include "stdio.h" #include "string.h" #include "repairMenu.h" #include "RepairPreset.h" #include "repairProcess.h" #include "repairProcesses.h" #include "ADConverters.h" #include "CathodeMCP.h" #include "DAConverters.h" #include "Display.h" #include "Error.h" #include "hsb-mrts.h" #include "CoverSolenoid.h" #include "Logger.h" #include "Interlock.h" #include "internalADC.h" #include "MAX5715.h" #include "TeslaGunSafety.h" #include "KeyboardDevice.h" #include "PCBA.h" #include "rtc.h" #include "storm700.h" // ----------------------------------------------------------------------------- // Constant and macro definitions // ----------------------------------------------------------------------------- #define MENU_HAS_CURSOR (true) #define MENU_HAS_NO_CURSOR (false) #define REPAIRMENU_POPUPSCREEN_TIME (3) // ----------------------------------------------------------------------------- // Type definitions // ----------------------------------------------------------------------------- // ----------------------------------------------------------------------------- // File-scope variables // ----------------------------------------------------------------------------- static const char cursorValue[2] = {0x7E, '\0'}; // ----------------------------------------------------------------------------- // Function declarations // ----------------------------------------------------------------------------- static void repairMenu_task(void* parameters); static void repairMenu_changeState(struct RepairMenu* self, T_MenuState newState); static void repairMenu_printError(struct RepairMenu* self); static void repairMenu_printWarning(struct RepairMenu* self); static void repairMenu_printRepair(struct RepairMenu* self); static void repairMenu_printAskPause(struct RepairMenu* self); static void repairMenu_printPause(struct RepairMenu* self); static void repairMenu_printFinish(struct RepairMenu* self); static void repairMenu_printPreset(struct RepairMenu* self); static void repairMenu_printMenu(struct RepairMenu* self); static void repairMenu_printCursor(struct RepairMenu* self); static ErrorStatus repairMenu_performAction(struct RepairMenu* self, char key, Keypad_KeyState keyState); static struct KeyActionBinding repairMenu_findKeyAction(struct RepairMenu* self, char key, Keypad_KeyState keyState); static void repairMenu_scrollIndexHandlerReset (struct RepairMenu* self); static void repairMenu_scrollUpIndexHandler(struct RepairMenu* self); static void repairMenu_scrollDownIndexHandler(struct RepairMenu* self); static void repairMenu_selectCathodeRepair(struct RepairMenu* self, int cursorIndex); static void repairMenu_selectMCPRepair(struct RepairMenu* self, int cursorIndex); static void repairMenu_selectPreset(struct RepairMenu* self, int cursorIndex); static void repairMenu_solenoidLock(struct RepairMenu* self, int cursorIndex); static void repairMenu_solenoidUnlock(struct RepairMenu* self, int cursorIndex); static void repairMenu_startRepairProcess(struct RepairMenu* self, int cursorIndex); static void repairMenu_stopRepairProcess(struct RepairMenu* self, int cursorIndex); static void repairMenu_abortRepairProcessAndGotoMainMenu(struct RepairMenu* self, int cursorIndex); static void repairMenu_pauseRepairProcess(struct RepairMenu* self, int cursorIndex); static void repairMenu_continueRepairProcess(struct RepairMenu* self, int cursorIndex); static ErrorStatus repairMenu_createMenu(struct RepairMenu* self); static ErrorStatus repairMenu_createMenuPage (struct MenuPage* self, bool hasCursor, int maxNumberOfRows); static ErrorStatus repairMenu_addMenuPageRow (struct MenuPage* self, char* text, int newState, RepairMenuFunctionCall actionCall); static ErrorStatus repairMenu_addKeyAction_HOTKEYSELECT (struct MenuPage* self, char key, Keypad_KeyState keyState, int rowToSelect); static ErrorStatus repairMenu_addKeyAction_SELECT (struct MenuPage* self, char key, Keypad_KeyState keyState); static ErrorStatus repairMenu_addKeyAction_GOTOSTATE (struct MenuPage* self, char key, Keypad_KeyState keyState, T_MenuState state); static ErrorStatus repairMenu_addKeyAction_EXECUTEFUNCTION (struct MenuPage* self, char key, Keypad_KeyState keyState, RepairMenuFunctionCall actionPointer); static ErrorStatus repairMenu_addKeyAction_SCROLLUP (struct MenuPage* self, char key, Keypad_KeyState keyState); static ErrorStatus repairMenu_addKeyAction_SCROLLDOWN (struct MenuPage* self, char key, Keypad_KeyState keyState); // ----------------------------------------------------------------------------- // Function definitions // ----------------------------------------------------------------------------- ErrorStatus repairMenu_construct(struct RepairMenu* self, struct Display* display, struct KeyboardDevice* keyboardDevice, struct MemoryDevice* memoryDevice, int taskPriority, uint16_t stackSize, Observer repairScreenUpdateObserver) { ErrorStatus returnValue = SUCCESS; if (!self->initialized) { if (returnValue == SUCCESS) { if (display->initialized) { self->display = display; } else { returnValue = ERROR; } } if (returnValue == SUCCESS) { if (keyboardDevice->initialized) { self->keyboardDevice = keyboardDevice; } else { returnValue = ERROR; } } if (returnValue == SUCCESS) { if (memoryDevice->initialized) { self->memoryDevice = memoryDevice; self->presetStorage.initialized = false; } else { returnValue = ERROR; } } if (returnValue == SUCCESS) { if (PCBA_getInstance()->pcba == PCBA_CathodeMCP) { // Loading of presets is done when selecting either Cathode or MCP repair } else if (PCBA_getInstance()->pcba == PCBA_Anode) { RepairPresets_loadPresets(REPAIR_PRESETS_ANODE); self->repairPreset = RepairPresets_getPreset(1); } else if (PCBA_getInstance()->pcba == PCBA_Tesla) { RepairPresets_loadPresets(REPAIR_PRESETS_TESLA); self->repairPreset = RepairPresets_getPreset(1); } // Construct the menu based on PCBA information returnValue = repairMenu_createMenu(self); repairMenu_changeState(self, MAINMENU); self->runTask = true; BaseType_t rv = xTaskCreate(repairMenu_task, "RepairMenu", stackSize, self, taskPriority, &self->taskHandle); if (rv != pdTRUE) { returnValue = ERROR; LOGGER_ERROR(mainLog, "FAILED to start repair Menu with code %d", (int)rv); } else { vSemaphoreCreateBinary(self->repairScreenUpdateSemaphore); self->observer = repairScreenUpdateObserver; self->initialized = true; self->cursorIndex = 1; self->scrollOffset = 0; LOGGER_INFO(mainLog, "Repair Menu task started"); } } } else { returnValue = ERROR; } return returnValue; } void repairMenu_destruct (struct RepairMenu* self) { repairProcesses_abortMainRepairProcess(); self->runTask = false; self->initialized = false; } void repairMenu_interlockFailed(struct RepairMenu* self, T_INTERLOCK_ID interlockID) { repairMenu_changeState(self, ERROR_STATE); if (interlockID == COMMON_INTERLOCK) { snprintf(self->errorMessage, sizeof(self->errorMessage) / sizeof(self->errorMessage[0]), "COVER OPEN"); } } void repairMenu_processFailed(struct RepairMenu* self) { repairMenu_changeState(self, ERROR_STATE); snprintf(self->errorMessage, sizeof(self->errorMessage) / sizeof(self->errorMessage[0]), "PROCESS FAILED"); } static void repairMenu_task(void* parameters) { struct RepairMenu* self = (struct RepairMenu*)parameters; // Clear the screen for a new menu Display_clearScreen(self->display); // Print menu content to output device repairMenu_printMenu(self); // Add cursor if necessary repairMenu_printCursor(self); int tempScreenCounter = 0; T_MenuState tempMenuState = MAINMENU; while(self->runTask) { char key; Keypad_KeyState keyState; // Catch ERROR state if (self->menuState == ERROR_STATE) { // Show ERROR message repairMenu_printError(self); // Handle error repairMenu_stopRepairProcess(self, 0); } else if (self->menuState == WARNING_STATE) { } else if (self->menuState == RM_PRESET_PRINT) { repairMenu_printPreset(self); } else if (self->menuState == REPAIR_RUNNING) { // Check the remaining repair time uint32_t remainingTime = repairProcess_getRemainingRepairTime(repairProcesses_getMainRepairProcess()); if (remainingTime > REPAIRMENU_POPUPSCREEN_TIME) { tempScreenCounter = remainingTime - REPAIRMENU_POPUPSCREEN_TIME; tempMenuState = self->menuState; } if (remainingTime == 0) { // repair is finished repairMenu_changeState(self, FINISH_CONTROL); } else { // Create the repair screen repairMenu_printRepair(self); } } else if (self->menuState == REPAIR_ASK_PAUSE) { uint32_t remainingTime = repairProcess_getRemainingRepairTime(repairProcesses_getMainRepairProcess()); repairMenu_printAskPause(self); if (tempScreenCounter >= remainingTime) { // POPUP screen time is over, return to previous state repairMenu_changeState(self, tempMenuState); } } else if (self->menuState == REPAIR_PAUSE) { repairMenu_printPause(self); } else if (self->menuState == FINISH_CONTROL) { repairMenu_stopRepairProcess(self, 0); repairMenu_changeState(self, FINISH); } else if (self->menuState == FINISH) { repairMenu_printFinish(self); } if (KeyboardDevice_read(&storm700->keyboardDevice, &key, &keyState) == SUCCESS) { if (repairMenu_performAction(self, key, keyState) == SUCCESS) { // The key had an action // Clear the screen for a new menu Display_clearScreen(self->display); // Print menu content to output device repairMenu_printMenu(self); // Add cursor if necessary repairMenu_printCursor(self); } } vTaskDelay(50); } LOGGER_INFO(mainLog, "Deleting RepairMenu task"); vTaskDelete(NULL); } static void repairMenu_changeState(struct RepairMenu* self, T_MenuState newState) { Display_clearScreen(self->display); self->menuState = newState; LOGGER_WARNING(mainLog, "New menu index is %d", self->menuState); } static void repairMenu_printError(struct RepairMenu* self) { Display_write(self->display, "!!ERROR!!", 2, 6); Display_write(self->display, self->errorMessage, 3, 1 + ((self->display->displayDevice->parameters.numberOfColumns - strlen(self->errorMessage)) / 2)); } static void repairMenu_printWarning(struct RepairMenu* self) { } static void repairMenu_printRepair(struct RepairMenu* self) { int loopCounter = 0; char buffer[20]; struct RepairProcess* repairProcess = repairProcesses_getMainRepairProcess(); if (repairProcess_isProcessRunning(repairProcess)) { if (xSemaphoreTake(self->repairScreenUpdateSemaphore, 0) != pdTRUE) { // Taking semaphore failed - no update on the screen } else { struct Time remainingTime; RTC_calculateTimeFromSeconds(repairProcess_getRemainingRepairTime(repairProcess), &remainingTime); snprintf(buffer, sizeof(buffer) / sizeof(buffer[0]), "%1d", self->repairPreset->presetNumber); Display_write(self->display, buffer, 1, 1); snprintf(buffer, sizeof(buffer) / sizeof(buffer[0]), "%02d:%02d:%02d remain ", remainingTime.hours, remainingTime.minutes, remainingTime.seconds); Display_write(self->display, buffer, 1, 4); // Regulation is unique for each row // For TESLA repair only row 1 (out of 0,1,2) is used // For ANODE and Cathode/MCP, all 3 rows are used for (loopCounter = ((PCBA_getInstance()->pcba == PCBA_Tesla) ? 1 : 0); loopCounter <= ((PCBA_getInstance()->pcba == PCBA_Tesla) ? 1 : 2); loopCounter++) { const struct RepairProcessRow* row; row = repairProcess_getRowInformation(repairProcess, loopCounter); snprintf (buffer, sizeof(buffer) / sizeof(buffer[0]), "R%d", loopCounter + 1); Display_write(self->display, buffer, 2, ((loopCounter * (self->display->displayDevice->parameters.numberOfColumns / REPAIRPROCESS_NUMBER_OF_ROWS) + loopCounter) + (self->display->displayDevice->parameters.numberOfColumns / REPAIRPROCESS_NUMBER_OF_ROWS) / strlen(buffer))); if (!row->errorData.rowHasError) { snprintf(buffer, sizeof(buffer) / sizeof(buffer[0]), "%5dV", row->lastADCValue); Display_write(self->display, buffer, 3, (loopCounter + (loopCounter * (self->display->displayDevice->parameters.numberOfColumns / REPAIRPROCESS_NUMBER_OF_ROWS)) + (self->display->displayDevice->parameters.numberOfColumns / REPAIRPROCESS_NUMBER_OF_ROWS) / strlen(buffer))); snprintf(buffer, sizeof(buffer) / sizeof(buffer[0]), "%4dER", row->pidError); Display_write(self->display, buffer, 4, (loopCounter + (loopCounter * (self->display->displayDevice->parameters.numberOfColumns / REPAIRPROCESS_NUMBER_OF_ROWS)) + (self->display->displayDevice->parameters.numberOfColumns / REPAIRPROCESS_NUMBER_OF_ROWS) / strlen(buffer))); } else { snprintf(buffer, sizeof(buffer) / sizeof(buffer[0]), " ROW "); Display_write(self->display, buffer, 3, (loopCounter + (loopCounter * (self->display->displayDevice->parameters.numberOfColumns / REPAIRPROCESS_NUMBER_OF_ROWS)) + (self->display->displayDevice->parameters.numberOfColumns / REPAIRPROCESS_NUMBER_OF_ROWS) / strlen(buffer))); snprintf(buffer, sizeof(buffer) / sizeof(buffer[0]), "ERROR "); Display_write(self->display, buffer, 4, (loopCounter + (loopCounter * (self->display->displayDevice->parameters.numberOfColumns / REPAIRPROCESS_NUMBER_OF_ROWS)) + (self->display->displayDevice->parameters.numberOfColumns / REPAIRPROCESS_NUMBER_OF_ROWS) / strlen(buffer))); } } } } else { snprintf(buffer, sizeof(buffer) / sizeof(buffer[0]), "Initialising"); Display_write(self->display, buffer, 1, 6); } } static void repairMenu_printAskPause(struct RepairMenu* self) { Display_write(self->display, "REPAIR BUSY", 2, 6); Display_write(self->display, "Hit X to PAUSE", 3, 2); } static void repairMenu_printPause(struct RepairMenu* self) { Display_write(self->display, "!!PAUSE!!", 2, 6); Display_write(self->display, "Hit ENT to continue", 3, 2); Display_write(self->display, "Hit X to RESET", 4, 2); } static void repairMenu_printFinish(struct RepairMenu* self) { Display_write(self->display, "REPAIR FINISHED", 2, 6); Display_write(self->display, "Hit ENT to continue", 4, 2); } static void repairMenu_printPreset(struct RepairMenu* self) { int loopCounter; char buffer[self->display->displayDevice->parameters.numberOfColumns]; // Print the preset information of the current preset under the cursor, NOT the preset that is currently selected snprintf(buffer, sizeof(buffer) / sizeof(buffer[0]), "Preset %d info", self->cursorIndex); // Always print Row1 (index0), ignoring the scrolling index Display_write(self->display, buffer, 1, 1); snprintf(buffer, sizeof(buffer) / sizeof(buffer[0]), "Start:"); Display_write(self->display, buffer, 2, 1); snprintf(buffer, sizeof(buffer) / sizeof(buffer[0]), "Time:"); Display_write(self->display, buffer, 3, 1); snprintf(buffer, sizeof(buffer) / sizeof(buffer[0]), "Volt:"); Display_write(self->display, buffer, 4, 1); for (loopCounter = 0; loopCounter < RepairPresets_getPreset(self->cursorIndex)->numberOfStages; loopCounter++) { snprintf(buffer, sizeof(buffer) / sizeof(buffer[0]), "%5dm", (RepairPresets_getPreset(self->cursorIndex)->preset[loopCounter].softstartDuration / 60)); Display_write(self->display, buffer, 2, 8 + loopCounter * 7); snprintf(buffer, sizeof(buffer) / sizeof(buffer[0]), "%5dm", (RepairPresets_getPreset(self->cursorIndex)->preset[loopCounter].duration / 60)); Display_write(self->display, buffer, 3, 8 + loopCounter * 7); snprintf(buffer, sizeof(buffer) / sizeof(buffer[0]), "%5dV", RepairPresets_getPreset(self->cursorIndex)->preset[loopCounter].voltage); Display_write(self->display, buffer, 4, 8 + loopCounter * 7); } } static void repairMenu_printMenu(struct RepairMenu* self) { int loopCounter; // Always print Row1 (index0), ignoring the scrolling index Display_write(self->display, self->menuArray[self->menuState].row[0].text, 1, 1); for (loopCounter = 1 ; loopCounter < self->display->displayDevice->parameters.numberOfRows; loopCounter++) { Display_write(self->display, self->menuArray[self->menuState].row[loopCounter + self->scrollOffset].text, loopCounter + 1, 1); } } static void repairMenu_printCursor(struct RepairMenu* self) { if (self->menuArray[self->menuState].hasCursor) { Display_write(self->display, cursorValue, 1 + self->cursorIndex - self->scrollOffset, 1); } } static ErrorStatus repairMenu_performAction(struct RepairMenu* self, char key, Keypad_KeyState keyState) { ErrorStatus returnValue = SUCCESS; struct KeyActionBinding keyAction = repairMenu_findKeyAction(self, key, keyState); LOGGER_DEBUG(mainLog, "Action: received key %c, action to perform %d,", key, keyAction.action); switch (keyAction.action) { case NO_ACTION: { LOGGER_INFO(mainLog, "This button has no action"); returnValue = ERROR; break; } case HOTKEY_SELECT: { LOGGER_INFO(mainLog, "HOTKEY SELECT ITEM: char %c, argument %d - Going to state %d", keyAction.key, keyAction.argument, self->menuArray[self->menuState].row[keyAction.argument].newState); T_MenuState tempState = self->menuState; repairMenu_changeState(self, self->menuArray[self->menuState].row[keyAction.argument].newState); if (self->menuArray[tempState].row[keyAction.argument].actionPointer != NULL) { self->menuArray[tempState].row[keyAction.argument].actionPointer(self, keyAction.argument); } repairMenu_scrollIndexHandlerReset(self); break; } case SELECT: { LOGGER_INFO(mainLog, "SELECT ITEM %d - going to state %d", self->cursorIndex, self->menuArray[self->menuState].row[self->cursorIndex].newState); T_MenuState tempState = self->menuState; repairMenu_changeState(self, self->menuArray[self->menuState].row[self->cursorIndex].newState); if (self->menuArray[tempState].row[self->cursorIndex].actionPointer != NULL) { self->menuArray[tempState].row[self->cursorIndex].actionPointer(self, self->cursorIndex); } repairMenu_scrollIndexHandlerReset(self); break; } case GOTO_STATE: { LOGGER_INFO(mainLog, "Going to new state %d directly", keyAction.argument); repairMenu_changeState(self, keyAction.argument); break; } case EXECUTE_FUNCTION: { LOGGER_INFO(mainLog, "Executing function directly"); if (keyAction.actionPointer != NULL) { keyAction.actionPointer(self, 0); } break; } case SCROLL_UP: { LOGGER_INFO(mainLog, "Scrolling up"); repairMenu_scrollUpIndexHandler(self); break; } case SCROLL_DOWN: { LOGGER_INFO(mainLog, "Scrolling down"); repairMenu_scrollDownIndexHandler(self); break; } case DIGIT_INSERT: { LOGGER_INFO(mainLog, "Key is allowed as insert"); break; } } return returnValue; } static struct KeyActionBinding repairMenu_findKeyAction(struct RepairMenu* self, char key, Keypad_KeyState keyState) { int loopCounter; struct KeyActionBinding returnValue; returnValue.action = NO_ACTION; for (loopCounter = 0; loopCounter < REPAIRMENU_MAX_NUMBER_OF_KEYS; loopCounter++) { if ((self->menuArray[self->menuState].keyActionBinding[loopCounter].key == key) && (self->menuArray[self->menuState].keyActionBinding[loopCounter].keyState == keyState)) { returnValue = self->menuArray[self->menuState].keyActionBinding[loopCounter]; break; } } return returnValue; } static void repairMenu_scrollIndexHandlerReset (struct RepairMenu* self) { self->cursorIndex = 1; self->scrollOffset = 0; } static void repairMenu_scrollUpIndexHandler(struct RepairMenu* self) { if (self->cursorIndex - self->scrollOffset > 1) { if (self->cursorIndex > 1) { self->cursorIndex--; } } else { if (self->cursorIndex > 1) { self->cursorIndex--; } if (self->scrollOffset > 0) { self->scrollOffset--; } } } static void repairMenu_scrollDownIndexHandler(struct RepairMenu* self) { if (self->cursorIndex < self->display->displayDevice->parameters.numberOfRows - 1) { if (self->cursorIndex < self->menuArray[self->menuState].numberOfRows - 1) { self->cursorIndex++; } } else { if (self->cursorIndex < self->menuArray[self->menuState].numberOfRows - 1) { self->cursorIndex++; } if (self->scrollOffset < (self->menuArray[self->menuState].numberOfRows - self->display->displayDevice->parameters.numberOfRows)) { self->scrollOffset++; } } } static void repairMenu_selectCathodeRepair(struct RepairMenu* self, int cursorIndex) { RepairPresets_loadPresets(REPAIR_PRESETS_CATHODE); self->repairPreset = RepairPresets_getPreset(1); CathodeMCP_switchToCathode(); } static void repairMenu_selectMCPRepair(struct RepairMenu* self, int cursorIndex) { RepairPresets_loadPresets(REPAIR_PRESETS_MCP); self->repairPreset = RepairPresets_getPreset(1); CathodeMCP_switchToMCP(); } static void repairMenu_selectPreset(struct RepairMenu* self, int cursorIndex) { self->repairPreset = RepairPresets_getPreset(cursorIndex); LOGGER_INFO(mainLog, "Preset %d selected", cursorIndex); Display_clearScreen(self->display); char buffer[20]; snprintf(buffer, sizeof(buffer) / sizeof(buffer[0]), "Preset %d selected", cursorIndex); Display_write(self->display, buffer, 2, 2); vTaskDelay(2000); } static void repairMenu_solenoidLock(struct RepairMenu* self, int cursorIndex) { CoverSolenoid_lock(); } static void repairMenu_solenoidUnlock(struct RepairMenu* self, int cursorIndex) { CoverSolenoid_unlock(); } static void repairMenu_startRepairProcess(struct RepairMenu* self, int cursorIndex) { ErrorStatus returnValue = SUCCESS; self->rpParameters.adcR1 = adcRow1; self->rpParameters.adcR2 = adcRow2; self->rpParameters.adcR3 = adcRow3; self->rpParameters.dacR1 = dacRow1; self->rpParameters.dacR2 = dacRow2; self->rpParameters.dacR3 = dacRow3; if (returnValue == SUCCESS) { // Enable all safety features of the HSB setup returnValue = hsb_enableSafety(); } if (returnValue == SUCCESS) { // In case of a TESLA repair, release the teslaGunSafety if (PCBA_getInstance()->pcba == PCBA_Tesla) { TeslaGunSafety_release(); } } // If all is OK, start the repair process if (returnValue == SUCCESS) { returnValue = repairProcesses_startMainRepairProcess(self->repairPreset, &self->rpParameters); if (returnValue != SUCCESS) { Error_postError(REPAIR_FAIL); } } if (returnValue == SUCCESS) { returnValue = repairProcesses_mainRepairProcessAddObserver(self->observer); if (returnValue == SUCCESS) { // repair process is running repairMenu_changeState(self, REPAIR_RUNNING); } else { Error_postError(REPAIR_FAIL); } } } static void repairMenu_stopRepairProcess(struct RepairMenu* self, int cursorIndex) { if (PCBA_getInstance()->pcba == PCBA_Tesla) { TeslaGunSafety_block(); } repairProcesses_mainRepairProcessRemoveObserver(self->observer); repairProcesses_abortMainRepairProcess(); hsb_disableSafety(); } static void repairMenu_abortRepairProcessAndGotoMainMenu(struct RepairMenu* self, int cursorIndex) { repairMenu_stopRepairProcess(self, cursorIndex); repairMenu_changeState(self, MAINMENU); } static void repairMenu_pauseRepairProcess(struct RepairMenu* self, int cursorIndex) { repairMenu_changeState(self, REPAIR_PAUSE); repairProcess_pauseProcess(repairProcesses_getMainRepairProcess()); hsb_disableSafety(); } static void repairMenu_continueRepairProcess(struct RepairMenu* self, int cursorIndex) { hsb_enableSafety(); repairMenu_changeState(self, REPAIR_RUNNING); repairProcess_continueProcess(repairProcesses_getMainRepairProcess()); } static ErrorStatus repairMenu_createMenu(struct RepairMenu* self) { ErrorStatus returnValue = SUCCESS; repairMenu_createMenuPage(&self->menuArray[MAINMENU], MENU_HAS_CURSOR, 4); repairMenu_addMenuPageRow(&self->menuArray[MAINMENU], PCBA_getInstance()->name, MAINMENU, NULL); if (PCBA_getInstance()->pcba == PCBA_CathodeMCP) { // For Cathode/MCP PCBA, the type of repair must be selected first repairMenu_addMenuPageRow(&self->menuArray[MAINMENU], " 1.Tube repair", RM_CATHODEMCP_SELECT, NULL); } else { repairMenu_addMenuPageRow(&self->menuArray[MAINMENU], " 1.Tube repair", REPAIRMENU, NULL); } repairMenu_addMenuPageRow(&self->menuArray[MAINMENU], " 2.Administrator", ADMINMENU, NULL); repairMenu_addMenuPageRow(&self->menuArray[MAINMENU], " 3.Calibration", CALIBRATIONMENU, NULL); repairMenu_addKeyAction_SCROLLUP(&self->menuArray[MAINMENU], 'U', PRESSED); repairMenu_addKeyAction_SCROLLDOWN(&self->menuArray[MAINMENU], 'D', PRESSED); repairMenu_addKeyAction_SELECT(&self->menuArray[MAINMENU], 'E', PRESSED); repairMenu_addKeyAction_HOTKEYSELECT(&self->menuArray[MAINMENU], '1', PRESSED, 1); repairMenu_addKeyAction_HOTKEYSELECT(&self->menuArray[MAINMENU], '2', PRESSED, 2); repairMenu_addKeyAction_HOTKEYSELECT(&self->menuArray[MAINMENU], '3', PRESSED, 3); repairMenu_addKeyAction_EXECUTEFUNCTION(&self->menuArray[MAINMENU], '0', PRESSED, repairMenu_solenoidUnlock); repairMenu_addKeyAction_EXECUTEFUNCTION(&self->menuArray[MAINMENU], '0', RELEASED, repairMenu_solenoidLock); repairMenu_createMenuPage(&self->menuArray[RM_CATHODEMCP_SELECT], MENU_HAS_CURSOR, 3); repairMenu_addMenuPageRow(&self->menuArray[RM_CATHODEMCP_SELECT], "Tube repair", RM_CATHODEMCP_SELECT, NULL); repairMenu_addMenuPageRow(&self->menuArray[RM_CATHODEMCP_SELECT], " 1.Cathode repair", REPAIRMENU, repairMenu_selectCathodeRepair); repairMenu_addMenuPageRow(&self->menuArray[RM_CATHODEMCP_SELECT], " 2.MCP repair", REPAIRMENU, repairMenu_selectMCPRepair); repairMenu_addKeyAction_SCROLLUP(&self->menuArray[RM_CATHODEMCP_SELECT], 'U', PRESSED); repairMenu_addKeyAction_SCROLLDOWN(&self->menuArray[RM_CATHODEMCP_SELECT], 'D', PRESSED); repairMenu_addKeyAction_SELECT(&self->menuArray[RM_CATHODEMCP_SELECT], 'E', PRESSED); repairMenu_addKeyAction_HOTKEYSELECT(&self->menuArray[RM_CATHODEMCP_SELECT], '1', PRESSED, 1); repairMenu_addKeyAction_HOTKEYSELECT(&self->menuArray[RM_CATHODEMCP_SELECT], '2', PRESSED, 2); repairMenu_addKeyAction_GOTOSTATE(&self->menuArray[RM_CATHODEMCP_SELECT], 'X', PRESSED, MAINMENU); repairMenu_addKeyAction_EXECUTEFUNCTION(&self->menuArray[RM_CATHODEMCP_SELECT], '0', PRESSED, repairMenu_solenoidUnlock); repairMenu_addKeyAction_EXECUTEFUNCTION(&self->menuArray[RM_CATHODEMCP_SELECT], '0', RELEASED, repairMenu_solenoidLock); repairMenu_createMenuPage(&self->menuArray[REPAIRMENU], MENU_HAS_CURSOR, 4); repairMenu_addMenuPageRow(&self->menuArray[REPAIRMENU], "Tube repair", REPAIRMENU, NULL); repairMenu_addMenuPageRow(&self->menuArray[REPAIRMENU], " 1.Select preset", PRESETMENU, NULL); repairMenu_addMenuPageRow(&self->menuArray[REPAIRMENU], " 2.Start", START_REPAIR, repairMenu_startRepairProcess); repairMenu_addKeyAction_SCROLLUP(&self->menuArray[REPAIRMENU], 'U', PRESSED); repairMenu_addKeyAction_SCROLLDOWN(&self->menuArray[REPAIRMENU], 'D', PRESSED); repairMenu_addKeyAction_SELECT(&self->menuArray[REPAIRMENU], 'E', PRESSED); repairMenu_addKeyAction_HOTKEYSELECT(&self->menuArray[REPAIRMENU], '1', PRESSED, 1); repairMenu_addKeyAction_HOTKEYSELECT(&self->menuArray[REPAIRMENU], '2', PRESSED, 2); if (PCBA_getInstance()->pcba == PCBA_CathodeMCP) { // For Cathode/MCP PCBA, the type of repair must can be selected repairMenu_addKeyAction_GOTOSTATE(&self->menuArray[REPAIRMENU], 'X', PRESSED, RM_CATHODEMCP_SELECT); } else { repairMenu_addKeyAction_GOTOSTATE(&self->menuArray[REPAIRMENU], 'X', PRESSED, MAINMENU); } repairMenu_addKeyAction_EXECUTEFUNCTION(&self->menuArray[REPAIRMENU], '0', PRESSED, repairMenu_solenoidUnlock); repairMenu_addKeyAction_EXECUTEFUNCTION(&self->menuArray[REPAIRMENU], '0', RELEASED, repairMenu_solenoidLock); repairMenu_createMenuPage(&self->menuArray[ADMINMENU], MENU_HAS_NO_CURSOR, 2); repairMenu_addMenuPageRow(&self->menuArray[ADMINMENU], "Administration", ADMINMENU, NULL); repairMenu_addMenuPageRow(&self->menuArray[ADMINMENU], " 1.Nothing", ADMINMENU, NULL); repairMenu_addKeyAction_GOTOSTATE(&self->menuArray[ADMINMENU], 'X', PRESSED, MAINMENU); repairMenu_createMenuPage(&self->menuArray[CALIBRATIONMENU], MENU_HAS_NO_CURSOR, 2); repairMenu_addMenuPageRow(&self->menuArray[CALIBRATIONMENU], "Calibration", CALIBRATIONMENU, NULL); repairMenu_addMenuPageRow(&self->menuArray[CALIBRATIONMENU], " 1.Nothing", CALIBRATIONMENU, NULL); repairMenu_addKeyAction_GOTOSTATE(&self->menuArray[CALIBRATIONMENU], 'X', PRESSED, MAINMENU); repairMenu_createMenuPage(&self->menuArray[PRESETMENU], MENU_HAS_CURSOR, 10); repairMenu_addMenuPageRow(&self->menuArray[PRESETMENU], "Select preset", PRESETMENU, NULL); repairMenu_addMenuPageRow(&self->menuArray[PRESETMENU], " 1.Preset1", REPAIRMENU, repairMenu_selectPreset); repairMenu_addMenuPageRow(&self->menuArray[PRESETMENU], " 2.Preset2", REPAIRMENU, repairMenu_selectPreset); repairMenu_addMenuPageRow(&self->menuArray[PRESETMENU], " 3.Preset3", REPAIRMENU, repairMenu_selectPreset); repairMenu_addMenuPageRow(&self->menuArray[PRESETMENU], " 4.Preset4", REPAIRMENU, repairMenu_selectPreset); repairMenu_addMenuPageRow(&self->menuArray[PRESETMENU], " 5.Preset5", REPAIRMENU, repairMenu_selectPreset); repairMenu_addMenuPageRow(&self->menuArray[PRESETMENU], " 6.Preset6", REPAIRMENU, repairMenu_selectPreset); repairMenu_addMenuPageRow(&self->menuArray[PRESETMENU], " 7.Preset7", REPAIRMENU, repairMenu_selectPreset); repairMenu_addMenuPageRow(&self->menuArray[PRESETMENU], " 8.Preset8", REPAIRMENU, repairMenu_selectPreset); repairMenu_addMenuPageRow(&self->menuArray[PRESETMENU], " 9.Preset9", REPAIRMENU, repairMenu_selectPreset); repairMenu_addKeyAction_SCROLLUP(&self->menuArray[PRESETMENU], 'U', PRESSED); repairMenu_addKeyAction_SCROLLDOWN(&self->menuArray[PRESETMENU], 'D', PRESSED); repairMenu_addKeyAction_SELECT(&self->menuArray[PRESETMENU], 'E', PRESSED); repairMenu_addKeyAction_HOTKEYSELECT(&self->menuArray[PRESETMENU], '1', PRESSED, 1); repairMenu_addKeyAction_HOTKEYSELECT(&self->menuArray[PRESETMENU], '2', PRESSED, 2); repairMenu_addKeyAction_HOTKEYSELECT(&self->menuArray[PRESETMENU], '3', PRESSED, 3); repairMenu_addKeyAction_HOTKEYSELECT(&self->menuArray[PRESETMENU], '4', PRESSED, 4); repairMenu_addKeyAction_HOTKEYSELECT(&self->menuArray[PRESETMENU], '5', PRESSED, 5); repairMenu_addKeyAction_HOTKEYSELECT(&self->menuArray[PRESETMENU], '6', PRESSED, 6); repairMenu_addKeyAction_HOTKEYSELECT(&self->menuArray[PRESETMENU], '7', PRESSED, 7); repairMenu_addKeyAction_HOTKEYSELECT(&self->menuArray[PRESETMENU], '8', PRESSED, 8); repairMenu_addKeyAction_HOTKEYSELECT(&self->menuArray[PRESETMENU], '9', PRESSED, 9); repairMenu_addKeyAction_GOTOSTATE(&self->menuArray[PRESETMENU], 'X', PRESSED, REPAIRMENU); repairMenu_addKeyAction_EXECUTEFUNCTION(&self->menuArray[PRESETMENU], '0', PRESSED, repairMenu_solenoidUnlock); repairMenu_addKeyAction_EXECUTEFUNCTION(&self->menuArray[PRESETMENU], '0', RELEASED, repairMenu_solenoidLock); repairMenu_addKeyAction_GOTOSTATE(&self->menuArray[PRESETMENU], 'R', PRESSED, RM_PRESET_PRINT); repairMenu_createMenuPage(&self->menuArray[RM_PRESET_PRINT], MENU_HAS_NO_CURSOR, 10); repairMenu_addKeyAction_GOTOSTATE(&self->menuArray[RM_PRESET_PRINT], 'X', PRESSED, PRESETMENU); repairMenu_addKeyAction_GOTOSTATE(&self->menuArray[RM_PRESET_PRINT], 'L', PRESSED, PRESETMENU); repairMenu_createMenuPage(&self->menuArray[REPAIR_RUNNING], MENU_HAS_NO_CURSOR, 4); repairMenu_addKeyAction_GOTOSTATE(&self->menuArray[REPAIR_RUNNING], 'X', PRESSED, REPAIR_ASK_PAUSE); repairMenu_createMenuPage(&self->menuArray[REPAIR_ASK_PAUSE], MENU_HAS_NO_CURSOR, 4); repairMenu_addKeyAction_EXECUTEFUNCTION(&self->menuArray[REPAIR_ASK_PAUSE], 'X', PRESSED, repairMenu_pauseRepairProcess); repairMenu_createMenuPage(&self->menuArray[REPAIR_PAUSE], MENU_HAS_NO_CURSOR, 4); repairMenu_addKeyAction_EXECUTEFUNCTION(&self->menuArray[REPAIR_PAUSE], 'X', PRESSED, repairMenu_abortRepairProcessAndGotoMainMenu); repairMenu_addKeyAction_EXECUTEFUNCTION(&self->menuArray[REPAIR_PAUSE], 'E', PRESSED, repairMenu_continueRepairProcess); repairMenu_addKeyAction_EXECUTEFUNCTION(&self->menuArray[REPAIR_PAUSE], '0', PRESSED, repairMenu_solenoidUnlock); repairMenu_addKeyAction_EXECUTEFUNCTION(&self->menuArray[REPAIR_PAUSE], '0', RELEASED, repairMenu_solenoidLock); repairMenu_createMenuPage(&self->menuArray[FINISH], MENU_HAS_NO_CURSOR, 4); repairMenu_addKeyAction_GOTOSTATE(&self->menuArray[FINISH], 'E', PRESSED, MAINMENU); repairMenu_createMenuPage(&self->menuArray[ERROR_STATE], MENU_HAS_NO_CURSOR, 4); repairMenu_addKeyAction_GOTOSTATE(&self->menuArray[ERROR_STATE], 'X', PRESSED, MAINMENU); return returnValue; } static ErrorStatus repairMenu_createMenuPage (struct MenuPage* self, bool hasCursor, int maxNumberOfRows) { ErrorStatus returnValue = SUCCESS; if (maxNumberOfRows <= REPAIRMENU_MAX_NUMBER_OF_ROWS) { self->maxNumberOfKeys = NUMBER_OF_KEY_EVENTS * REPAIRMENU_MAX_NUMBER_OF_KEYS; self->numberOfRows = 0; self->numberOfKeys = 0; self->maxNumberOfRows = maxNumberOfRows; self->hasCursor = hasCursor; } else { returnValue = ERROR; } return returnValue; } static ErrorStatus repairMenu_addMenuPageRow (struct MenuPage* self, char* text, int newState, RepairMenuFunctionCall actionCall) { ErrorStatus returnValue = SUCCESS; if (self->numberOfRows < self->maxNumberOfRows) { memcpy(self->row[self->numberOfRows].text, text, 20); self->row[self->numberOfRows].newState = newState; self->row[self->numberOfRows].actionPointer = actionCall; self->numberOfRows++; } else { returnValue = ERROR; } return returnValue; } static ErrorStatus repairMenu_addKeyAction_HOTKEYSELECT (struct MenuPage* self, char key, Keypad_KeyState keyState, int rowToSelect) { ErrorStatus returnValue = SUCCESS; if (self->numberOfKeys < self->maxNumberOfKeys) { self->keyActionBinding[self->numberOfKeys].key = key; self->keyActionBinding[self->numberOfKeys].keyState = keyState; self->keyActionBinding[self->numberOfKeys].action = HOTKEY_SELECT; self->keyActionBinding[self->numberOfKeys].argument = rowToSelect; self->keyActionBinding[self->numberOfKeys].actionPointer = NULL; self->numberOfKeys++; } else { returnValue = ERROR; } return returnValue; } static ErrorStatus repairMenu_addKeyAction_SELECT (struct MenuPage* self, char key, Keypad_KeyState keyState) { ErrorStatus returnValue = SUCCESS; if (self->numberOfKeys < self->maxNumberOfKeys) { self->keyActionBinding[self->numberOfKeys].key = key; self->keyActionBinding[self->numberOfKeys].keyState = keyState; self->keyActionBinding[self->numberOfKeys].action = SELECT; self->keyActionBinding[self->numberOfKeys].argument = 0; self->keyActionBinding[self->numberOfKeys].actionPointer = NULL; self->numberOfKeys++; } else { returnValue = ERROR; } return returnValue; } static ErrorStatus repairMenu_addKeyAction_GOTOSTATE (struct MenuPage* self, char key, Keypad_KeyState keyState, T_MenuState state) { ErrorStatus returnValue = SUCCESS; if (self->numberOfKeys < self->maxNumberOfKeys) { self->keyActionBinding[self->numberOfKeys].key = key; self->keyActionBinding[self->numberOfKeys].keyState = keyState; self->keyActionBinding[self->numberOfKeys].action = GOTO_STATE; self->keyActionBinding[self->numberOfKeys].argument = state; self->keyActionBinding[self->numberOfKeys].actionPointer = NULL; self->numberOfKeys++; } else { returnValue = ERROR; } return returnValue; } static ErrorStatus repairMenu_addKeyAction_EXECUTEFUNCTION (struct MenuPage* self, char key, Keypad_KeyState keyState, RepairMenuFunctionCall actionPointer) { ErrorStatus returnValue = SUCCESS; if (self->numberOfKeys < self->maxNumberOfKeys) { self->keyActionBinding[self->numberOfKeys].key = key; self->keyActionBinding[self->numberOfKeys].keyState = keyState; self->keyActionBinding[self->numberOfKeys].action = EXECUTE_FUNCTION; self->keyActionBinding[self->numberOfKeys].argument = 0; self->keyActionBinding[self->numberOfKeys].actionPointer = actionPointer; self->numberOfKeys++; } else { returnValue = ERROR; } return returnValue; } static ErrorStatus repairMenu_addKeyAction_SCROLLUP (struct MenuPage* self, char key, Keypad_KeyState keyState) { ErrorStatus returnValue = SUCCESS; if (self->numberOfKeys < self->maxNumberOfKeys) { self->keyActionBinding[self->numberOfKeys].key = key; self->keyActionBinding[self->numberOfKeys].keyState = keyState; self->keyActionBinding[self->numberOfKeys].action = SCROLL_UP; self->keyActionBinding[self->numberOfKeys].argument = 0; self->keyActionBinding[self->numberOfKeys].actionPointer = NULL; self->numberOfKeys++; } else { returnValue = ERROR; } return returnValue; } static ErrorStatus repairMenu_addKeyAction_SCROLLDOWN (struct MenuPage* self, char key, Keypad_KeyState keyState) { ErrorStatus returnValue = SUCCESS; if (self->numberOfKeys < self->maxNumberOfKeys) { self->keyActionBinding[self->numberOfKeys].key = key; self->keyActionBinding[self->numberOfKeys].keyState = keyState; self->keyActionBinding[self->numberOfKeys].action = SCROLL_DOWN; self->keyActionBinding[self->numberOfKeys].argument = 0; self->keyActionBinding[self->numberOfKeys].actionPointer = NULL; self->numberOfKeys++; } else { returnValue = ERROR; } return returnValue; }