Repository for import to local machine

Dependencies:   DMBasicGUI DMSupport

Revision:
1:a5258871b33d
Parent:
0:47c880c1463d
Child:
4:6840cf2b153a
--- a/TouchPanelPageSelector.cpp	Wed Jan 13 13:17:05 2016 +0000
+++ b/TouchPanelPageSelector.cpp	Thu Jul 20 08:42:29 2017 +0000
@@ -1,5 +1,26 @@
 #include "TouchPanelPageSelector.h"
 
+#include "EasyGUITouchAreaIndices.h"
+#include "ServiceInterval.h"
+#include "ColumnDHAutoCalibrationPageHandler.h"
+#include "DetectorIgnitionHandler.h"
+
+
+//#define FORCE_DIRECTLY_HEATED_COLUMN // For testing/debugging - pretend we have a directly heated column
+                                     // (regardless of what we actually have)
+
+#define USE_DH_COLUMN_AUTO_CALIBRATION_PAGE // Otherwise (i.e. if commented out) use manual calibration page
+
+/*
+    TouchPanelPageSelector class
+*/
+
+/*
+    static members
+*/
+bool TouchPanelPageSelector::pageChangeEnabled = true;
+
+    
 // The default constructor exists purely to satisfy the compiler - it is not intended to be used
 TouchPanelPageSelector::TouchPanelPageSelector()
 {
@@ -15,40 +36,440 @@
     pageNumber = page;
 }
 
-// TouchPanelPageSelectors class members
+
+/*
+    TouchPanelDetectorPageSelector class
+*/
+
+// The default constructor exists purely to satisfy the compiler - it is not intended to be used
+TouchPanelDetectorPageSelector::TouchPanelDetectorPageSelector() : TouchPanelPageSelector()
+{
+}
+
+// We do not use the base class' page number in this class - we calculate it 'on the fly' - see below
+TouchPanelDetectorPageSelector::TouchPanelDetectorPageSelector(int index) : TouchPanelPageSelector(index, -1)
+{
+}
+
+/*
+    For the detector, the page number varies according to the detector type.
+    This function calculates the correct page number, and returns it.
+    
+    Params: USBDeviceConnected and USBHostGC corresponding to the GC
+*/
+int TouchPanelDetectorPageSelector::GetPageNumber(USBDeviceConnected* usbDevice, USBHostGC* usbHostGC)
+{
+    switch(GetDetectorType(usbDevice, usbHostGC)) {
+        case FID_DETECTOR:
+            return GuiStruct_DetectorFIDPage_4;
+        case TCD_DETECTOR:
+            return GuiStruct_DetectorTCDPage_11;
+        case ECD_DETECTOR:
+            return GuiStruct_DetectorECDPage_12;
+        case TXL_DETECTOR:
+            return GuiStruct_DetectorTXLPage_27;
+        // case 4 is "None" - leave for default
+        case NPD_DETECTOR:
+            return GuiStruct_DetectorNPDPage_28;
+        case PID_DETECTOR:
+            return GuiStruct_DetectorPIDPage_29;
+        case FPD_DETECTOR:
+            return GuiStruct_DetectorFPDPage_14;
+        case SPDID_DETECTOR:
+            return GuiStruct_DetectorSPDIDPage_30;
+        default: // i.e. all other types (including "None")
+            break; // Return default (see below)
+    }
+    
+    // Default return code
+    return GuiStruct_DetectorNonePage_31;
+}
+
+/*
+    Gets the detector type from the GC, and returns it as a DetectorType enumeration.
+    
+    Params: USBDeviceConnected and USBHostGC corresponding to the GC
+*/
+DetectorType TouchPanelDetectorPageSelector::GetDetectorType(USBDeviceConnected* usbDevice, USBHostGC* usbHostGC) 
+{
+    char response[50];
+    while(usbHostGC->ExecutingSetDeviceReport()) {}
+
+    usbHostGC->SetDeviceReport(usbDevice, "GDTY", response);
+
+    // We expect a response like this: "DDTY0000" for FID, "DDTY0001" for TCD,
+    // "DDTY0002" for ECD, "DDTY0003" for TXL, "DDTY0004" for "None", "DDTY0005" for NPD, 
+    // "DDTY0006" for PID, "DDTY0007" for FPD, "DDTY0008" for SPDID. 
+    // We assume any other "DDTY00nn" value means "None".
+    
+    // We convert the final two digits to an integer
+    int type;
+    sscanf(&response[6], "%d", &type);
+    
+    // Now we convert the integer value to a DetectorType
+    DetectorType detectorType;
+    if((type < MIN_DETECTOR_TYPE) || (type > MAX_DETECTOR_TYPE)) {
+        detectorType = NO_DETECTOR;
+    } else {
+        detectorType = (DetectorType) type;
+    }
+    
+    return detectorType;
+}
+
+
+/*
+    TouchPanelColumnPageSelector class
+*/
+
+// The default constructor exists purely to satisfy the compiler - it is not intended to be used
+TouchPanelColumnPageSelector::TouchPanelColumnPageSelector() : TouchPanelPageSelector()
+{
+}
+
+// We do not use the base class' page number in this class - we calculate it 'on the fly' - see below
+TouchPanelColumnPageSelector::TouchPanelColumnPageSelector(int index) : TouchPanelPageSelector(index, -1)
+{
+}
+
+/*
+    For the column, the page number varies according to the column type.
+    This function calculates the correct page number, and returns it.
+    
+    Note that we are assuming that the caller only wants to display column page 1, not page 2, etc -
+    this works since page 1 (conventional or DH) is the only column page accessible 
+    from the home page - all the others are accessed using the left and right arrows 
+    on each of the column pages.
+    
+    Params: USBDeviceConnected and USBHostGC corresponding to the GC
+*/
+int TouchPanelColumnPageSelector::GetPageNumber(USBDeviceConnected* usbDevice, USBHostGC* usbHostGC)
+{
+    if(GetColumnType(usbDevice, usbHostGC) == DIRECTLY_HEATED_COLUMN) {
+        return GuiStruct_ColumnDHPage1_40;
+    } 
+    
+    // 'else'...
+    return GuiStruct_ColumnPage1_2;
+}
+
+/*
+    Gets the column type from the GC, and returns it as a ColumnType enumeration.
+    
+    Params: USBDeviceConnected and USBHostGC corresponding to the GC
+*/
+ColumnType TouchPanelColumnPageSelector::GetColumnType(USBDeviceConnected* usbDevice, USBHostGC* usbHostGC) 
+{
+#ifdef FORCE_DIRECTLY_HEATED_COLUMN
+    return DIRECTLY_HEATED_COLUMN;
+#else
+    char response[50];
+    while(usbHostGC->ExecutingSetDeviceReport()) {}
+
+    usbHostGC->SetDeviceReport(usbDevice, "GCTY", response);
+
+    // We expect a response like this: "DCTY0000" for None, "DCTY0001" for Conventional,
+    // "DCTY0002" for Directly Heated
+    
+    // Convert the final two digits to an integer
+    int type;
+    sscanf(&response[6], "%d", &type);
+    
+    // Now we convert the integer value to a ColumnType
+    ColumnType columnType;
+    if((type < MIN_COLUMN_TYPE) || (type > MAX_COLUMN_TYPE)) {
+        columnType = NO_COLUMN;
+    } else {
+        columnType = (ColumnType) type;
+    }
+    
+    return columnType;
+#endif
+}
+
+
+/*
+    TouchPanelAbortRunPageSelector class
+*/
+
+// The default constructor exists purely to satisfy the compiler - it is not intended to be used
+TouchPanelAbortRunPageSelector::TouchPanelAbortRunPageSelector() : TouchPanelPageSelector()
+{
+}
+
+// We do not use the base class' page number in this class - we calculate it 'on the fly' - see below
+TouchPanelAbortRunPageSelector::TouchPanelAbortRunPageSelector(int index) : TouchPanelPageSelector(index, -1)
+{
+}
+
+/*
+    When the user aborts the run, we will normally display the Home page. But if any components 
+    now require servicing (since even an aborted run counts as one 'cycle', and some components 
+    require servicing after a particular number of cycles), we want to display 
+    the 'Servicing Required' page instead. This function decides which page to display, 
+    and returns its number.
+    
+    Params: USBDeviceConnected and USBHostGC corresponding to the GC
+            (these are not used in this class)
+*/
+int TouchPanelAbortRunPageSelector::GetPageNumber(USBDeviceConnected* usbDevice, USBHostGC* usbHostGC)
+{
+    if(ServiceInterval::AtLeastOneServiceIntervalHasExpired()) {
+        return GuiStruct_ServicingRequired_Def;
+    }
+    
+    // 'else'...
+    return GuiStruct_HomePage_1;
+}
+
+
+
+    
+
+
+/*
+    TouchPanelReturnPageSelector class
+*/
+
+// The default constructor exists purely to satisfy the compiler - it is not intended to be used
+TouchPanelReturnPageSelector::TouchPanelReturnPageSelector() : TouchPanelPageSelector()
+{
+    thisIsTheReturnInstance = false;
+}
+
+/*
+    In this constructor, 'index' is the number of the easyGUI touch area to which this instance corresponds, 'pageToDisplayNow' is the easyGUI page("structure") number to which this instance corresponds, 
+    and 'thisWillBeTheReturnInstance' is a boolean that, if false, says that this instance's 'GetPageNumber' function records 'pageToReturnTo' as the page to be returned to, 
+    then tells the caller 'go to pageToDisplayNow' - or, if true, says that this instance's 'GetPageNumber' function returns the number of the page to be returned to.
+*/
+TouchPanelReturnPageSelector::TouchPanelReturnPageSelector(int index, int pageToReturnTo, int pageToDisplayNow, bool thisWillBeTheReturnInstance) : TouchPanelPageSelector(index, pageToDisplayNow)
+{
+    thisReturnPage = pageToReturnTo;
+    
+    thisIsTheReturnInstance = thisWillBeTheReturnInstance;
+}
+
+int TouchPanelReturnPageSelector::GetPageNumber(USBDeviceConnected* usbDevice, USBHostGC* usbHostGC)
+{
+    if(thisIsTheReturnInstance) {
+        if(theReturnPage == -1) {
+            // Return page not yet set - as a default, return the page number we were given when we were constructed
+            return thisReturnPage;
+        }
+        // 'else' we have a return page number
+        return theReturnPage;
+    }
+    
+    // 'else' this is a 'calling' instance - record our return page 
+    // as the one to return to, then return (to the caller) the page to display now
+    
+    theReturnPage = thisReturnPage;
+        
+    return GetBasePageNumber();
+}
+
+// Static variable - all instances of TouchPanelReturnPageSelector share the same return page.
+// (Note that this is only one variable, not a stack - if we want 'overlapping' return pages
+//  at some point, this will have to be changed.)
+int TouchPanelReturnPageSelector::theReturnPage = -1;
+
+
+/*
+    TouchPanelPageSelectors class
+*/
+
+// TouchPanelPageSelectors constructor - set up the array of page selectors
 TouchPanelPageSelectors::TouchPanelPageSelectors()
 {
     // Note that the touch area indexes, etc, below
     // are hardcoded to match those set up in easyGUI. 
-    // There seems to be no way to get these values from easyGUI at runtime
+    // There seems to be no way to get these values from easyGUI at runtime.
+    // See EasyGUITouchAreaIndices.h for the actual numerical values.
+    
+    // Note also that we have two touch areas each for the Column, Injector,
+    // Detector and Gas (which overlap in each case - see the easyGUI project). 
+    // This is so that we can (nearly) fill the relevant rectangle on the Home Page 
+    // with touch areas, without overlapping the Run button at the centre.
+    
+    // The TouchCallback function (main.cpp) is the main user of this. As well as getting, from this class, 
+    // the page to be displayed in response to the user touching a particular touch area, it also performs 
+    // any other actions (e.g. telling the GC to abort the run, etc) that may be required before we can display the new page. 
+    
+    // Another note - there are multiple Abort Run pages, which are all identical apart from the touch index of the No button (this is of course invisible to the user). 
+    // Each one is invoked from the Abort Run button on a different 'Running xxx' page, where 'xxx' is one of the components (Column, Injector, etc).
+    // This is so that we know which page to return to if the user presses 'No' - the index of the 'No' button tells us which Abort Run page the user is on,
+    // therefore which page he pressed the 'Abort Run' button on - and that is the page we need to return to. Otherwise (i.e. if we had a single Abort Run page),
+    // the code here would be much more complicated.
+    
+    // And another... The Column and Detector pages are different for the different column/detector types. This is why, for these pages, we use 
+    // the TouchPanelColumnPageSelector and TouchPanelDetectorPageSelector classes, derived from TouchPanelPageSelector, 
+    // which find out the column/detector type at runtime, and return the corresponding page numbers.
+    
+    tppsArray[0]  = new TouchPanelPageSelector(HOME_BUTTON,   GuiStruct_HomePage_1);
+    tppsArray[1]  = new TouchPanelPageSelector(SETTINGS_BUTTON,   GuiStruct_SettingsPage_5);
+//    tppsArray[2]  = new TouchPanelPageSelector(3,   GuiStruct_ColumnPage1_2);  
+    tppsArray[2]  = new TouchPanelColumnPageSelector(COLUMN_TOUCH_AREA_1);
+    tppsArray[3]  = new TouchPanelPageSelector(INJECTOR_TOUCH_AREA_1,   GuiStruct_InjectorPage1_3);
+//    tppsArray[4]  = new TouchPanelPageSelector(5,   GuiStruct_DefaultDetectorPage1_4);
+    tppsArray[4]  = new TouchPanelDetectorPageSelector(DETECTOR_TOUCH_AREA_1); 
+    tppsArray[5]  = new TouchPanelPageSelector(GAS_TOUCH_AREA_1,   GuiStruct_GasInformationPage_6);
+//    tppsArray[6]  = new TouchPanelPageSelector(7,   GuiStruct_ColumnPage1_2);
+    tppsArray[6]  = new TouchPanelColumnPageSelector(COLUMN_TOUCH_AREA_2);      // Second (overlapping) 'Column' touch area on Home page
+    tppsArray[7]  = new TouchPanelPageSelector(INJECTOR_TOUCH_AREA_2,   GuiStruct_InjectorPage1_3); // Second (overlapping) 'Injector' touch area on Home page
+//    tppsArray[8]  = new TouchPanelPageSelector(9,   GuiStruct_DefaultDetectorPage1_4);
+    tppsArray[8]  = new TouchPanelDetectorPageSelector(DETECTOR_TOUCH_AREA_2);                     // Second (overlapping) 'Detector' touch area on Home page
+    tppsArray[9]  = new TouchPanelPageSelector(GAS_TOUCH_AREA_2,  GuiStruct_GasInformationPage_6);     // Second (overlapping) 'Gas' touch area on Home page
+   
+    tppsArray[10] = new TouchPanelReturnPageSelector(RUNNING_PAGE1_ABORT_RUN, GuiStruct_RunningPage1_7, GuiStruct_AbortRunPage_19, false);
+    tppsArray[11] = new TouchPanelReturnPageSelector(RUNNING_COLUMN_ABORT_RUN, GuiStruct_RunningColumnPage_25, GuiStruct_AbortRunPage_19, false);
+    tppsArray[12] = new TouchPanelReturnPageSelector(RUNNING_INJECTOR_ABORT_RUN, GuiStruct_RunningInjectorPage_26, GuiStruct_AbortRunPage_19, false);
+    tppsArray[13] = new TouchPanelReturnPageSelector(RUNNING_DETECTOR_ABORT_RUN, GuiStruct_RunningDetectorPage_27, GuiStruct_AbortRunPage_19, false);
+    tppsArray[14] = new TouchPanelReturnPageSelector(RUNNING_GAS_ABORT_RUN, GuiStruct_RunningGasPage_28, GuiStruct_AbortRunPage_19, false);
+    tppsArray[15] = new TouchPanelReturnPageSelector(RUNNING_INJECTOR_PROFILE_ABORT_RUN, GuiStruct_RunningInjectorProfilePage_Def, GuiStruct_AbortRunPage_19, false);
+    tppsArray[16] = new TouchPanelAbortRunPageSelector(ABORT_RUN_YES);
+    tppsArray[17] = new TouchPanelReturnPageSelector(ABORT_RUN_NO, GuiStruct_AbortRunPage_19, GuiStruct_RunningPage1_7, true);
+
+    tppsArray[18] = new TouchPanelPageSelector(GAS_INFO_LEFT_ARROW, GuiStruct_GasProfilePage_15);
+    tppsArray[19] = new TouchPanelPageSelector(GAS_INFO_RIGHT_ARROW, GuiStruct_GasProfilePage_15);
+    tppsArray[20] = new TouchPanelPageSelector(GAS_PROFILE_LEFT_ARROW, GuiStruct_GasInformationPage_6);
+    tppsArray[21] = new TouchPanelPageSelector(GAS_PROFILE_RIGHT_ARROW, GuiStruct_GasInformationPage_6);
+
+    tppsArray[22] = new TouchPanelPageSelector(GAS_SAVER_RETURN_TO_READY, GuiStruct_HomePage_1);      // 'Return to ready state' touch area on Gas Saver page (covers entire page)
+
+    // Pages for conventional (not directly heated) column
+    tppsArray[23] = new TouchPanelPageSelector(COLUMN_PAGE1_LEFT_ARROW, GuiStruct_ColumnTempProfilePage_60);
+    tppsArray[24] = new TouchPanelPageSelector(COLUMN_PAGE1_RIGHT_ARROW, GuiStruct_ColumnPage2_9);          
+    tppsArray[25] = new TouchPanelPageSelector(COLUMN_PAGE2_LEFT_ARROW, GuiStruct_ColumnPage1_2);   
+    tppsArray[26] = new TouchPanelPageSelector(COLUMN_PAGE2_RIGHT_ARROW, GuiStruct_ColumnTempProfilePage_60);
+    tppsArray[27] = new TouchPanelPageSelector(COLUMN_PROFILE_LEFT_ARROW, GuiStruct_ColumnPage2_9);
+    tppsArray[28] = new TouchPanelPageSelector(COLUMN_PROFILE_RIGHT_ARROW, GuiStruct_ColumnPage1_2);
     
-    tppsArray[0]  = TouchPanelPageSelector(1, GuiStruct_HomePage_1);
-    tppsArray[1]  = TouchPanelPageSelector(2, GuiStruct_SettingsPage_5);
-    tppsArray[2]  = TouchPanelPageSelector(3, GuiStruct_ColumnPage1_2);
-    tppsArray[3]  = TouchPanelPageSelector(4, GuiStruct_InjectorPage1_3);
-    tppsArray[4]  = TouchPanelPageSelector(5, GuiStruct_DetectorPage1_4);
-    tppsArray[5]  = TouchPanelPageSelector(6, GuiStruct_GasPage1_6);
-    tppsArray[6]  = TouchPanelPageSelector(202, GuiStruct_RunningSettings_8);
-    tppsArray[7]  = TouchPanelPageSelector(200, GuiStruct_HomePage_1);
-    tppsArray[8]  = TouchPanelPageSelector(203, GuiStruct_RunningPage_7);
-    tppsArray[9]  = TouchPanelPageSelector(400, GuiStruct_HomePage_1);
-    tppsArray[10] = TouchPanelPageSelector(500, GuiStruct_ColumnPage2_9);
-    tppsArray[11] = TouchPanelPageSelector(501, GuiStruct_ColumnPage1_2);
-    tppsArray[12] = TouchPanelPageSelector(502, GuiStruct_ColumnPage3_10);
-    tppsArray[13] = TouchPanelPageSelector(503, GuiStruct_ColumnPage2_9);
-    tppsArray[14] = TouchPanelPageSelector(600, GuiStruct_HomePage_1);
+    // Pages for directly heated column
+    tppsArray[29] = new TouchPanelPageSelector(COLUMN_DH_PAGE1_LEFT_ARROW, GuiStruct_ColumnDHTempProfilePage_61);
+    tppsArray[30] = new TouchPanelPageSelector(COLUMN_DH_PAGE1_RIGHT_ARROW, GuiStruct_ColumnDHPage2_50);
+    tppsArray[31] = new TouchPanelPageSelector(COLUMN_DH_PAGE2_LEFT_ARROW, GuiStruct_ColumnDHPage1_40); 
+    tppsArray[32] = new TouchPanelPageSelector(COLUMN_DH_PAGE2_RIGHT_ARROW, GuiStruct_ColumnDHTempProfilePage_61);
+    tppsArray[33] = new TouchPanelPageSelector(COLUMN_DH_PROFILE_LEFT_ARROW, GuiStruct_ColumnDHPage2_50);         
+    tppsArray[34] = new TouchPanelPageSelector(COLUMN_DH_PROFILE_RIGHT_ARROW, GuiStruct_ColumnDHPage1_40);        
+
+    tppsArray[35] = new TouchPanelPageSelector(CLEAR_ERRORS_BUTTON, GuiStruct_HomePage_1);      // 'Clear Errors' button on 'GC in fault state' page
+
+    tppsArray[36] = new TouchPanelPageSelector(INJECTOR_PAGE1_LEFT_ARROW, GuiStruct_InjectorConsumablesPage_20);
+    tppsArray[37] = new TouchPanelPageSelector(INJECTOR_PAGE1_RIGHT_ARROW, GuiStruct_InjectorTempProfilePage_25);
+    tppsArray[38] = new TouchPanelPageSelector(INJECTOR_PROFILE_LEFT_ARROW, GuiStruct_InjectorPage1_3);          
+    tppsArray[39] = new TouchPanelPageSelector(INJECTOR_PROFILE_RIGHT_ARROW, GuiStruct_InjectorGasStatusPage_30);
+    tppsArray[40] = new TouchPanelPageSelector(INJECTOR_GAS_STATUS_LEFT_ARROW, GuiStruct_InjectorTempProfilePage_25);
+    tppsArray[41] = new TouchPanelPageSelector(INJECTOR_GAS_STATUS_RIGHT_ARROW, GuiStruct_InjectorConsumablesPage_20);
+    tppsArray[42] = new TouchPanelPageSelector(INJECTOR_CONSUMABLES_LEFT_ARROW, GuiStruct_InjectorGasStatusPage_30);
+    tppsArray[43] = new TouchPanelPageSelector(INJECTOR_CONSUMABLES_RIGHT_ARROW, GuiStruct_InjectorPage1_3);          
+
+    tppsArray[44] = new TouchPanelPageSelector(RUNNING_PAGE1_RIGHT_ARROW, GuiStruct_RunningColumnPage_25);
+    tppsArray[45] = new TouchPanelPageSelector(RUNNING_PAGE1_LEFT_ARROW, GuiStruct_RunningGasPage_28);    
+    tppsArray[46] = new TouchPanelPageSelector(RUNNING_COLUMN_RIGHT_ARROW, GuiStruct_RunningInjectorPage_26);
+    tppsArray[47] = new TouchPanelPageSelector(RUNNING_COLUMN_LEFT_ARROW, GuiStruct_RunningPage1_7);         
+    tppsArray[48] = new TouchPanelPageSelector(RUNNING_INJECTOR_RIGHT_ARROW, GuiStruct_RunningInjectorProfilePage_Def);
+    tppsArray[49] = new TouchPanelPageSelector(RUNNING_INJECTOR_LEFT_ARROW, GuiStruct_RunningColumnPage_25);   
+    tppsArray[50] = new TouchPanelPageSelector(RUNNING_INJECTOR_PROFILE_RIGHT_ARROW, GuiStruct_RunningDetectorPage_27);
+    tppsArray[51] = new TouchPanelPageSelector(RUNNING_INJECTOR_PROFILE_LEFT_ARROW, GuiStruct_RunningInjectorPage_26);   
+    tppsArray[52] = new TouchPanelPageSelector(RUNNING_DETECTOR_RIGHT_ARROW, GuiStruct_RunningGasPage_28);     
+    tppsArray[53] = new TouchPanelPageSelector(RUNNING_DETECTOR_LEFT_ARROW, GuiStruct_RunningInjectorProfilePage_Def); 
+    tppsArray[54] = new TouchPanelPageSelector(RUNNING_GAS_RIGHT_ARROW, GuiStruct_RunningPage1_7);         
+    tppsArray[55] = new TouchPanelPageSelector(RUNNING_GAS_LEFT_ARROW, GuiStruct_RunningDetectorPage_27); 
+
+    tppsArray[56] = new TouchPanelPageSelector(SETTINGS_TO_NETWORK_PARAMS_BUTTON, GuiStruct_EthernetParametersPage_50); 
+    tppsArray[57] = new TouchPanelPageSelector(NETWORK_PARAMS_RETURN_BUTTON, GuiStruct_SettingsPage_5); 
+
+    tppsArray[58] = new TouchPanelPageSelector(SETTINGS_TO_SERVICING_PAGE_BUTTON, GuiStruct_EngineersLockPage_Def); 
+    tppsArray[59] = new TouchPanelPageSelector(SERVICING_PAGE_RETURN_BUTTON, GuiStruct_SettingsPage_5); 
+
+    tppsArray[60] = new TouchPanelPageSelector(SERVICING_REQUIRED_PAGE_HOME_BUTTON, GuiStruct_HomePage_1);
+    
+    tppsArray[61] = new TouchPanelPageSelector(COLUMN_SERVICING_AREA, GuiStruct_ColumnDHAutoCalibrationPage_Def);
+    tppsArray[62] = new TouchPanelPageSelector(DETECTOR_SERVICING_AREA, GuiStruct_DetectorNudgeAndDampPage_0);
+    tppsArray[63] = new TouchPanelPageSelector(INJECTOR_SERVICING_AREA, GuiStruct_InjectorNudgeAndDampPage_0);
+    tppsArray[64] = new TouchPanelPageSelector(GAS_SERVICING_AREA, GuiStruct_GasCalibrationPage_Def);
+    tppsArray[65] = new TouchPanelPageSelector(SERVICING_HOME, GuiStruct_ServicingHomePage_Def);
+
+    tppsArray[66] = new TouchPanelPageSelector(COLUMN_DH_AUTO_CALIB_LEFT_ARROW, GuiStruct_FanPowerPage_0);
+    tppsArray[67] = new TouchPanelPageSelector(COLUMN_DH_AUTO_CALIB_RIGHT_ARROW, GuiStruct_ColumnDHManualCalibrationPage_Def);
+    tppsArray[68] = new TouchPanelPageSelector(COLUMN_DH_MANUAL_CALIB_LEFT_ARROW, GuiStruct_ColumnDHAutoCalibrationPage_Def);
+    tppsArray[69] = new TouchPanelPageSelector(COLUMN_DH_MANUAL_CALIB_RIGHT_ARROW, GuiStruct_ColumnDHSensorCalibration_Def);
+    tppsArray[70] = new TouchPanelPageSelector(COLUMN_DH_SENSOR_CALIB_LEFT_ARROW, GuiStruct_ColumnDHManualCalibrationPage_Def);
+    tppsArray[71] = new TouchPanelPageSelector(COLUMN_DH_SENSOR_CALIB_RIGHT_ARROW, GuiStruct_PSU_DAC_Page_Def);
+    tppsArray[72] = new TouchPanelPageSelector(COLUMN_DH_PSU_DAC_LEFT_ARROW, GuiStruct_ColumnDHSensorCalibration_Def);
+    tppsArray[73] = new TouchPanelPageSelector(COLUMN_DH_PSU_DAC_RIGHT_ARROW, GuiStruct_ColumnDHOvenFanPage_Def);
+    tppsArray[74] = new TouchPanelPageSelector(COLUMN_OVEN_FAN_LEFT_ARROW, GuiStruct_PSU_DAC_Page_Def);
+    tppsArray[75] = new TouchPanelPageSelector(COLUMN_OVEN_FAN_RIGHT_ARROW, GuiStruct_ColumnOvenNudgeAndDampPage_0);
+    tppsArray[76] = new TouchPanelPageSelector(COLUMN_OVEN_NUDGE_AND_DAMP_LEFT_ARROW, GuiStruct_ColumnDHOvenFanPage_Def);
+    tppsArray[77] = new TouchPanelPageSelector(COLUMN_OVEN_NUDGE_AND_DAMP_RIGHT_ARROW, GuiStruct_ColumnDHNudgeAndDampPage_0);
+    tppsArray[78] = new TouchPanelPageSelector(COLUMN_DH_NUDGE_AND_DAMP_LEFT_ARROW, GuiStruct_ColumnOvenNudgeAndDampPage_0);
+    tppsArray[79] = new TouchPanelPageSelector(COLUMN_DH_NUDGE_AND_DAMP_RIGHT_ARROW, GuiStruct_FanPowerPage_0);
+    tppsArray[80] = new TouchPanelPageSelector(FAN_POWER_LEFT_ARROW, GuiStruct_ColumnDHNudgeAndDampPage_0);
+    tppsArray[81] = new TouchPanelPageSelector(FAN_POWER_RIGHT_ARROW, GuiStruct_ColumnDHAutoCalibrationPage_Def);
+
+    tppsArray[82] = new TouchPanelPageSelector(DETECTOR_NUDGE_AND_DAMP_LEFT_ARROW, GuiStruct_AuxiliaryNudgeAndDampPage_0);
+    tppsArray[83] = new TouchPanelPageSelector(DETECTOR_NUDGE_AND_DAMP_RIGHT_ARROW, GuiStruct_AuxiliaryNudgeAndDampPage_0);
+    tppsArray[84] = new TouchPanelPageSelector(AUXILIARY_NUDGE_AND_DAMP_LEFT_ARROW, GuiStruct_DetectorNudgeAndDampPage_0);
+    tppsArray[85] = new TouchPanelPageSelector(AUXILIARY_NUDGE_AND_DAMP_RIGHT_ARROW, GuiStruct_DetectorNudgeAndDampPage_0);
+
+    tppsArray[86] = new TouchPanelPageSelector(GAS_CALIB_LEFT_ARROW, GuiStruct_GasChannelDACAndADCPage_Def);
+    tppsArray[87] = new TouchPanelPageSelector(GAS_CALIB_RIGHT_ARROW, GuiStruct_GasBackPressureDACPage_Def);
+    tppsArray[88] = new TouchPanelPageSelector(GAS_BACKPRESSURE_DAC_LEFT_ARROW, GuiStruct_GasCalibrationPage_Def);
+    tppsArray[89] = new TouchPanelPageSelector(GAS_BACKPRESSURE_DAC_RIGHT_ARROW, GuiStruct_GasChannelDACAndADCPage_Def);
+    tppsArray[90] = new TouchPanelPageSelector(GAS_CHANNEL_DAC_AND_ADC_LEFT_ARROW, GuiStruct_GasBackPressureDACPage_Def);
+    tppsArray[91] = new TouchPanelPageSelector(GAS_CHANNEL_DAC_AND_ADC_RIGHT_ARROW, GuiStruct_GasCalibrationPage_Def);
+
+    tppsArray[92] = new TouchPanelPageSelector(SERVICING_PAGE_GC_CMDS_BUTTON, GuiStruct_DebugCommandsPage_Def);
 }
-    
+   
+TouchPanelPageSelectors::~TouchPanelPageSelectors() 
+{
+    for (int i = 0; i < SELECTOR_COUNT; ++i) {
+        if(tppsArray[i] != NULL) { // We may occasionally set some to NULL while testing new changes
+            delete tppsArray[i];
+        }
+    }
+}
+
+/*
+    Given a touch area index, returns a pointer to the corresponding page selector,
+    or NULL if that index has no page selector. If the pointer is not NULL, caller 
+    can then call 'GetPageNumber' on that page selector, to find out which page to display 
+    in response to the user touching that touch area. (If the pointer is NULL, that touch area
+    does not select a new page.)
+*/
 TouchPanelPageSelector* TouchPanelPageSelectors::GetTouchPanelPageSelector(int touchAreaIndex)
 {
     for (int i = 0; i < SELECTOR_COUNT; ++i) {
-        if( tppsArray[i].GetIndex() == touchAreaIndex) {
-            return &tppsArray[i];
+        if(tppsArray[i] != NULL) { // We may occasionally set some to NULL while testing new changes
+            if( tppsArray[i]->GetIndex() == touchAreaIndex) {
+                return tppsArray[i];
+            }
         }
     }
     
     // 'else' - not found
     return NULL;        
 }
+
     
+/*
+    Tells the caller which TouchPanelPageSelector they have - i.e. returns its index
+    in our array, or -1 if we cannot find it. (This should be useful for debugging.)
+    
+    Arguments: pointer to the TouchPanelPageSelector instance in question
+    
+    Return code: its index in our array, or -1 if not found
+*/
+int TouchPanelPageSelectors::GetTouchPanelPageSelectorIndex(TouchPanelPageSelector *tppsptr)
+{
+    for (int i = 0; i < SELECTOR_COUNT; ++i) {
+        if(tppsArray[i] == tppsptr) {
+            return i;
+        }
+    }
+    
+    // 'else' - not found
+    return -1;    
+}