Repository for import to local machine
Dependencies: DMBasicGUI DMSupport
Diff: main.cpp
- Revision:
- 1:a5258871b33d
- Parent:
- 0:47c880c1463d
- Child:
- 2:6e94a7fd1e37
--- a/main.cpp Wed Jan 13 13:17:05 2016 +0000 +++ b/main.cpp Thu Jul 20 08:42:29 2017 +0000 @@ -5,16 +5,127 @@ #include <string.h> +#include <stdio.h> +#include <stdlib.h> + #include "GuiLib.h" #include "GuiDisplay.h" #include "USBHostGC.h" -#include "TouchListener.h" #include "TouchPanelPageSelector.h" #include "GCHeatControl.h" #include "GetGCStatusLoop.h" #include "GCComponentStatusColorArea.h" -#include "EthernetTimerHandler.h" +#include "GCStateAndFaultCodes.h" +#include "ProgressBar.h" +#include "EasyGUITouchAreaIndices.h" +#include "NetworkParameters.h" +#include "ServiceInterval.h" +#include "SettingsHandler.h" +#include "GasCalibrationPageHandler.h" +#include "ColumnDHAutoCalibrationPageHandler.h" +#include "ColumnDHManualCalibrationPageHandler.h" +#include "ColumnDHSensorCalibrationPageHandler.h" +#include "ColumnDHPSUDACPageHandler.h" +#include "GasBackPressureDACPageHandler.h" +#include "GasChannelDACAndADCPageHandler.h" +#include "NudgeAndDampPageHandler.h" +#include "NumericKeypadPageHandler.h" +#include "EthernetKeypadPageHandler.h" +#include "DebugCommandsPageHandler.h" +#include "QSPIBitmap.h" +#include "DetectorIgnitionHandler.h" +#include "SwimDraw.h" +#include "USBHostGCUtilities.h" + + +#define BUILD_DATE "20 July 2017" // Copied to easyGUI variable "GuiVar_buildDate", displayed on both Settings pages (normal and Running). + // *** MUST update for each 'delivered' build, MUST correspond with date on 'delivered' binary file *** + // This should be updated first thing every morning, and immediately after every 'delivery' + // (to e.g. "dd mmm yyyy #2"), so that it is ready for the next one. + // Also - 'deliver' the ZIP file produced by the 'Export Program' command (right-click on the project + // in 'Program Workspace' at the left of this screen), as well as the binary executable and the ReadMe.txt file, + // and now the EasyGUI project file as well. + +// Defined in GuiDisplay.c - set the display frame address at runtime +extern "C" { + void GuiDisplay_SetFrameAddress(void *newFrameAddress); +} + +// Used by QSPIBitmaps class +bool qspiAlreadyFormatted = false; + +//#define MEMORY_TEST_OCT_2016 +#ifdef MEMORY_TEST_OCT_2016 +const int clogLength = 1000; +char clogUpMemory[clogLength]; +#endif // MEMORY_TEST_OCT_2016 + +/* + This application provides a draft implementation of the LPC4088 user interface to the GC. + It talks to the GC over a USB link. + + The associated easyGUI project is C:/easyGUI Projects/GC500_5inch.gui + + It is intended for use with the Embedded Artists LPC4088 board, 5 inch display. + + Note that the two most important functions in this application are: + main (obviously) or, more specifically, getGCStatusLoop->MainLoopWithEthernet(), called from main + TouchCallback, which handles the user's interaction with the LPC4088 touch screen + + Most other functions are (ultimately) called by those two. +*/ + +// Forward declarations +GuiConst_INTCOLOR SixteenBitColorValue(GuiConst_INT8U red, GuiConst_INT8U green, GuiConst_INT8U blue); +void DrawHeatOnOffButton(void); +void SetupDoorActuatorCommandUserInterface(USBDeviceConnected* usbDevice, USBHostGC* usbHostGC, bool beforePageDisplay); + + +static bool canUnlockDoorActuators = true; // Set false if there is some reason why they cannot be unlocked even when the GC is idle +/* + Function to gives the rest of the world access to the above flag +*/ +void CanUnlockDoorActuators(bool value) +{ + canUnlockDoorActuators = value; +} + + +//#define ALLOW_DEBUG_PRINTS // Without this, our 'debug print' functions contain no code, and do nothing. + // So we do not have to remove all the debug prints throughout this application - + // just comment out this #define. + // Note that we are currently *not* applying this to the code in the 'DrawErrorMessage()' function, + // which is only used here in main.cpp. + + +/* + Code received from Embedded Artists, to cause the LPC4088 to reboot + (thus allowing us to restart the Ethernet connection with a different IP address) +*/ +void reboot() +{ + /* Disable watchdog */ + LPC_WDT->MOD = 0; + LPC_WDT->TC = 0xFF; + + /* Set WDT timeout to 0.1s using the 500kHz oscillator + and the fixed pre-scaler of 4 */ + LPC_WDT->TC = ((500000 / 4) / 10); + + /* Make sure a watchdog timeout causes a reset */ + LPC_WDT->MOD |= (1<<1); + + /* Enable the watchdog */ + LPC_WDT->MOD |= (1<<0); + + /* Initial feed to start the watchdog */ + LPC_WDT->FEED = 0xAA; + LPC_WDT->FEED = 0x55; + + /* Should reboot after 100ms */ + while(true); +} // ** Start of timeout code to guard against multiple presses of the Heat On/Off button ** @@ -35,20 +146,44 @@ } // ** End of Heat On/Off timeout code ** +#define USE_HEAT_ONOFF_BUTTON_BITMAPS + +//#define TURN_HEAT_OFF_ON_ABORT // Doing this may or may not be a good idea... // These are 'global' - TouchCallback function, as well as main(), needs to access them TouchPanelPageSelectors touchPanelPageSelectors; GCHeatControl* theGCHeatControl; -TouchListener* mainTouchListener = NULL; + GetGCStatusLoop* getGCStatusLoop = NULL; HomePageGCComponentStatusColorAreas homePageGCComponentStatusColorAreas; SingleGCComponentPageStatusColorAreas singleGCComponentPageStatusColorAreas; -EthernetTimerHandler* theEthernetTimerHandler = NULL; +#define USE_QSPI_BITMAPS +#ifdef USE_QSPI_BITMAPS +QSPIBitmaps qspiBitmaps; +#endif // USE_QSPI_BITMAPS + +//#define WANT_STATUS_RECTANGLE_ON_COLUMN_AUTO_CALIB_PAGE +//#define WANT_STATUS_RECTANGLE_ON_GAS_CALIB_PAGES +/* + Bodge so GuiDisplay.c ('easyGUIFixed' file) can call Thread::wait + (giving it an accurate millisecond timer) +*/ +extern "C" { + void EasyGUIWaitMs(GuiConst_INT32U msec) + { + Thread::wait(msec); + } +} +/* + Passed three 8-bit colour components - red, green and blue. + + Returns the corresponding 16-bit colour value (5 bits for red, 6 bits for green, 5 bits for blue). +*/ GuiConst_INTCOLOR SixteenBitColorValue(GuiConst_INT8U red, GuiConst_INT8U green, GuiConst_INT8U blue) { // Make sure we don't have numeric overflow problems during the conversion @@ -56,13 +191,80 @@ GuiConst_INT32U green32 = green; GuiConst_INT32U blue32 = blue; +//#define REVERSE_RED_AND_BLUE +#ifdef REVERSE_RED_AND_BLUE + GuiConst_INT32U rgb = (red32 << 16) | (green32 << 8) | blue32; +#else GuiConst_INT32U rgb = (blue32 << 16) | (green32 << 8) | red32; - +#endif + return GuiLib_RgbToPixelColor(rgb); } +// DebugPrint without '#ifdef ALLOW_DEBUG_PRINTS' +void SpecialDebugPrint(char *stuffToPrint, GuiConst_INT16S X, GuiConst_INT16S Y) +{ + static int counter = 0; + char buff[300]; + + const GuiConst_INT16U fontNo = GuiFont_Helv1; + + GuiDisplay_Lock(); + + // (Attempt to) clear previous strings from display + sprintf(buff, " "); + GuiLib_DrawStr( + X, //GuiConst_INT16S X, + Y, //GuiConst_INT16S Y, + fontNo, //GuiConst_INT16U FontNo, + buff, //GuiConst_TEXT PrefixLocate *String, + GuiLib_ALIGN_LEFT, //GuiConst_INT8U Alignment, + GuiLib_PS_ON, //GuiConst_INT8U PsWriting, + GuiLib_TRANSPARENT_OFF, //GuiConst_INT8U Transparent, + GuiLib_UNDERLINE_OFF, //GuiConst_INT8U Underlining, + 0, //GuiConst_INT16S BackBoxSizeX, + 0, //GuiConst_INT16S BackBoxSizeY1, + 0, //GuiConst_INT16S BackBoxSizeY2, + GuiLib_BBP_NONE, //GuiConst_INT8U BackBorderPixels, + SixteenBitColorValue(0, 0, 0xFF), //GuiConst_INTCOLOR ForeColor, + SixteenBitColorValue(0, 0xFF, 0) //GuiConst_INTCOLOR BackColor + ); + + sprintf(buff, "%s [%d]", stuffToPrint, ++counter); + + GuiLib_DrawStr( + X, //GuiConst_INT16S X, + Y, //GuiConst_INT16S Y, + fontNo, //GuiConst_INT16U FontNo, + buff, //GuiConst_TEXT PrefixLocate *String, + GuiLib_ALIGN_LEFT, //GuiConst_INT8U Alignment, + GuiLib_PS_ON, //GuiConst_INT8U PsWriting, + GuiLib_TRANSPARENT_OFF, //GuiConst_INT8U Transparent, + GuiLib_UNDERLINE_OFF, //GuiConst_INT8U Underlining, + 0, //GuiConst_INT16S BackBoxSizeX, + 0, //GuiConst_INT16S BackBoxSizeY1, + 0, //GuiConst_INT16S BackBoxSizeY2, + GuiLib_BBP_NONE, //GuiConst_INT8U BackBorderPixels, + SixteenBitColorValue(0, 0, 0xFF), //GuiConst_INTCOLOR ForeColor, + SixteenBitColorValue(0, 0xFF, 0) //GuiConst_INTCOLOR BackColor + ); + + GuiLib_Refresh(); + + GuiDisplay_Unlock(); +} + +/* + Prints (i.e. displays) the specified text at the specified coordinates on the screen, + blue text on a green background, using easyGUI. + + Args are: null-terminated string to print, x coord, y coord. + + No return code. +*/ void DebugPrint(char *stuffToPrint, GuiConst_INT16S X, GuiConst_INT16S Y) { +#ifdef ALLOW_DEBUG_PRINTS char buff[200]; const GuiConst_INT16U fontNo = GuiFont_Helv1; @@ -108,32 +310,59 @@ GuiLib_Refresh(); GuiDisplay_Unlock(); +#endif //ALLOW_DEBUG_PRINTS } +/* + A 'wrapper' function for the above, so that the caller does not need access + to the easyGUI declarations + + Intended to be used as an 'extern' in other modules. +*/ void EasyGUIDebugPrint(char *stuffToPrint, short X, short Y) { -#define DEBUG_HERE -#ifdef DEBUG_HERE +#ifdef ALLOW_DEBUG_PRINTS DebugPrint(stuffToPrint, (GuiConst_INT16S) X, (GuiConst_INT16S) Y); -#undef DEBUG_HERE -#endif +#endif // ALLOW_DEBUG_PRINTS } -void DummyEasyGUIDebugPrint(char *stuffToPrint, short X, short Y) +/* + Version of the above that increments, and displays, a counter each time it is called - + so the user can see if it is being called repeatedly, or if the application has simply hung +*/ +void EasyGUIDebugPrintWithCounter(char *stuffToPrint, short X, short Y) { - //DebugPrint(stuffToPrint, (GuiConst_INT16S) X, (GuiConst_INT16S) Y); +#ifdef ALLOW_DEBUG_PRINTS + static int counter = 0; + char buff[300]; + sprintf(buff, "%s [%d]", stuffToPrint, ++counter); + + DebugPrint(buff, (GuiConst_INT16S) X, (GuiConst_INT16S) Y); +#endif // ALLOW_DEBUG_PRINTS } -int DummyDebugFunction(int i) -{ - return i^2; +extern "C" { + void EasyGUIDebugPrintWithCounterCalledFromC(char *stuffToPrint, short X, short Y) + { + EasyGUIDebugPrintWithCounter(stuffToPrint, X, Y); + } } -bool GCIsReadyToRun(USBDeviceConnected* usbDevice, USBHostGC* usbHostGC) +/* + Gets the GC status. + + Args are: a pointer to the USBHostGC instance that corresponds to the GC, + a pointer to the USBDeviceConnected instance that (also) corresponds to the GC + + Returns the GC status as an integer - see the GC_STATE enumeration in GCStateAndFaultCodes.h + for the possible values. +*/ +int GetGCStatus(USBDeviceConnected* usbDevice, USBHostGC* usbHostGC) { while(usbHostGC->ExecutingSetDeviceReport()) {} char response[50]; + int status; // Ensure we always have valid chars in the positions we are interested in, // in case we get "DNAK" or "EPKT" back @@ -141,17 +370,130 @@ response[7] = '0'; usbHostGC->SetDeviceReport(usbDevice, "QSTA", response); - // We expect a response like "QSTA00nn", where "nn" is the status. - // "33" means ready to run, anything else means "not ready" + // We expect a response like "DSTA00nn", where "nn" is the status. + sscanf(&response[6], "%d", &status); + + return status; +} + +/* + Tells the caller whether or not the GC is ready to run + + Args are: a pointer to the USBHostGC instance that corresponds to the GC, + a pointer to the USBDeviceConnected instance that (also) corresponds to the GC + + Returns true if the GC is ready to run, false if not. +*/ +bool GCIsReadyToRun(USBDeviceConnected* usbDevice, USBHostGC* usbHostGC) +{ +#ifdef USE_VERSION_102 // See GCStateAndFaultCodes.h + return (GetGCStatus(usbDevice, usbHostGC) == GC_STATE_102_METHOD_READY_TO_RUN); +#else + return (GetGCStatus(usbDevice, usbHostGC) == GC_STATE_READY_TO_RUN); +#endif +} + +/* + Tells the caller whether or not the GC is in the 'stabilising' state - return ((response[6] == '3') && (response[7]== '3')); + Args are: a pointer to the USBHostGC instance that corresponds to the GC, + a pointer to the USBDeviceConnected instance that (also) corresponds to the GC + + Returns true if the GC is stabilising, false if not. +*/ +bool GCIsStabilising(USBDeviceConnected* usbDevice, USBHostGC* usbHostGC) +{ +#ifdef USE_VERSION_102 // See GCStateAndFaultCodes.h + return (GetGCStatus(usbDevice, usbHostGC) == GC_STATE_102_METHOD_STABILISING); +#else + return false; // No "stabilising" state before version 1.02 +#endif +} + +/* + Tells the caller whether or not the GC is in the 'equilibrating' state + + Args are: a pointer to the USBHostGC instance that corresponds to the GC, + a pointer to the USBDeviceConnected instance that (also) corresponds to the GC + + Returns true if the GC is equilibrating, false if not. +*/ +bool GCIsEquilibrating(USBDeviceConnected* usbDevice, USBHostGC* usbHostGC) +{ +#ifdef USE_VERSION_102 // See GCStateAndFaultCodes.h + return (GetGCStatus(usbDevice, usbHostGC) == GC_STATE_102_METHOD_EQUILIBRATING); +#else + return (GetGCStatus(usbDevice, usbHostGC) == GC_STATE_EQUILIBRATING); +#endif } +/* + Tells the caller whether or not the GC is running + + Args are: a pointer to the USBHostGC instance that corresponds to the GC, + a pointer to the USBDeviceConnected instance that (also) corresponds to the GC + + Returns true if the GC is running, false if not. +*/ +bool GCIsRunning(USBDeviceConnected* usbDevice, USBHostGC* usbHostGC) +{ + int gcStatus = GetGCStatus(usbDevice, usbHostGC); + +#ifdef USE_VERSION_102 // See GCStateAndFaultCodes.h + return ((gcStatus >= GC_STATE_102_METHOD_RUNNING_MINIMUM) && (gcStatus <= GC_STATE_102_METHOD_RUNNING_MAXIMUM)); +#else + return ((gcStatus >= GC_STATE_RUNNING_MINIMUM) && (gcStatus <= GC_STATE_RUNNING_MAXIMUM)); +#endif +} + +/* + Pass the current value of 'GuiVar_columnMaxTemp2' to the GC as the maximum column temperature. + Intended to be called by the NumericKeypadPageHandler if the user presses the Apply button + when we are editing the maximum column temperature. We pass a pointer to this function + to the NumericKeypadPageHandler instance when we start editing. + + See the definition of 'ApplyFunctionPtr' in NumericKeypadPageHandler.h +*/ +void SetColumnMaxTempFromEasyGuiVariable(USBDeviceConnected* usbDevice, USBHostGC* usbHostGC) +{ + int maxTemp; + sscanf(GuiVar_columnMaxTemp2, "%d", &maxTemp); + + char buff[40]; + sprintf(buff, "SCMX%.4d", maxTemp); + + while(usbHostGC->ExecutingSetDeviceReport()) {} + + char response[50]; + usbHostGC->SetDeviceReport(usbDevice, buff, response); +} + + +/* + Draws the Run button in the correct place, in the correct enabled/disabled state. + + Arg is: true to display the button in an enabled state, false to display it disabled. + + No return code. +*/ void DrawRunButton(bool enabled) { +#define USE_BITMAPS +#ifdef USE_BITMAPS + GuiConst_INT8U bitmapIndex = GuiStruct_Bitmap_RunButton2; + if(enabled) { + bitmapIndex = GuiStruct_Bitmap_RunButtonGreen; + } + GuiConst_INTCOLOR transparentColor = SixteenBitColorValue(255, 255, 255); // In the 'corners' of the bitmap + + // Hard coded coordinates copied from easyGUI (I have not found + // a way of getting them from the easyGUI code at runtime) + GuiLib_ShowBitmap(bitmapIndex, 327, 170, transparentColor); + +#else // Draw a 'button' that consists of a box containing the word 'Run'. + // Black if enabled, grey if disabled GuiConst_INTCOLOR buttonColor = (enabled) ? 0 : SixteenBitColorValue(0x80, 0x80, 0x80); - GuiConst_TEXT *buttonText = "Run"; @@ -184,65 +526,609 @@ buttonColor, //GuiConst_INTCOLOR ForeColor, SixteenBitColorValue(0xFF, 0xFF, 0xFF) //GuiConst_INTCOLOR BackColor (should be ignored with GuiLib_TRANSPARENT_ON) ); +#endif // USE_BITMAPS +} + + +// Make these values available to the rest of the application +GuiConst_INTCOLOR GetFakeBackgroundBitmapMainColour(void) +{ + return SixteenBitColorValue(173, 222, 231); // From Background317 bitmap + //return SixteenBitColorValue(0, 148, 165); // From Background320 bitmap +} + +GuiConst_INTCOLOR GetFakeBackgroundBitmapButtonBandColour(void) +{ + //return SixteenBitColorValue(173, 173, 173); // Grey band at bottom + return SixteenBitColorValue(192, 192, 192); +} + + +/* + Draws the background bitmap. It fills the screen - + so you do not need to call GuiLib_Clear if you call this. + (*** BUT - maybe this causes easyGUI to lose track of which page is displayed, + and/or of its touch areas - so reinstated as a test with + '#define WANT_GUILIB_CLEAR_BEFORE_DRAWING_BITMAP' ***) + + Alternatively - if the bitmap we are using has blocks of solid colour anyway - + draw the areas directly (we could then save memory by not including + the actual bitmap in the application) +*/ +static void DrawSpecifiedBackgroundBitmap(GuiConst_INT8U bitmapIndex) +{ +// Does this solve bug #4? +//#define WANT_GUILIB_CLEAR_BEFORE_DRAWING_BITMAP +#ifdef WANT_GUILIB_CLEAR_BEFORE_DRAWING_BITMAP + GuiLib_Clear(); +#undef WANT_GUILIB_CLEAR_BEFORE_DRAWING_BITMAP +#endif //WANT_GUILIB_CLEAR_BEFORE_DRAWING_BITMAP +// Answer - no, it doesn't + +//#define FAKE_BITMAP +#ifdef FAKE_BITMAP + GuiLib_FillBox(0, 0, 800, 423, GetFakeBackgroundBitmapMainColour()); + GuiLib_FillBox(0, 424, 800, 480, GetFakeBackgroundBitmapButtonBandColour()); +#undef FAKE_BITMAP +#else + GuiLib_ShowBitmap(bitmapIndex, 0, 0, -1); // -1 means 'no transparent colour' +#endif // FAKE_BITMAP +} + +/* + Draws the default background bitmap, i.e. *without* the Ellutia logo +*/ +void DrawBackgroundBitmap(void) +{ + DrawSpecifiedBackgroundBitmap(GuiStruct_Bitmap_BlankBackground); +} + +/* + Same as the above, but draws the background bitmap *with* the Ellutia logo +*/ +void DrawBackgroundBitmapWithLogo(void) +{ + DrawSpecifiedBackgroundBitmap(GuiStruct_Bitmap_BootScreen); +} + +/* + For Display (LPC4088) Bug #11, draw a background bitmap without a grey bar at the bottom. + For now, fake this with a page full of one colour +*/ +void DrawFakeBackgroundBitmapForNumericKeypadPage(void) +{ +// GuiLib_FillBox(0, 0, 800, 480, SixteenBitColorValue(0, 90, 99)); +// Above is for the old background bitmap. For the new "BlankBackground", we need... + GuiLib_FillBox(0, 0, 800, 480, SixteenBitColorValue(255, 255, 255)); +} + + +/* + This functions erases the portions of the door Lock and Release buttons (on the Column pages) + that remain visible when they are replaced by the Close or Unlock buttons. + + I have to admit that I still do not understand why simply redrawing the whole page + (starting with the background bitmap) does not do this. + + No arguments, no return code. +*/ +void DrawBackgroundBitmapOverDoorLockAndReleaseButtons(void) +{ + // I also do not understand why the first coordinate pair in the call to GuiLib_ShowBitmapArea + // needs to be 0, 0 to display the correct part of the bitmap. I expected them to be the same + // as the second coordinate pair - but that caused the top left portion of the bitmap to be displayed, + // not the part where the buttons actually are. + GuiLib_ShowBitmapArea(GuiStruct_Bitmap_BlankBackground, 0, 0, 248, 405, 323, 480, -1); // -1 means 'no transparent colour' + GuiLib_ShowBitmapArea(GuiStruct_Bitmap_BlankBackground, 0, 0, 477, 405, 552, 480, -1); // -1 means 'no transparent colour' +// GuiLib_FillBox(248, 405, 323, 480, SixteenBitColorValue(165, 165, 173)); +// GuiLib_FillBox(477, 405, 552, 480, SixteenBitColorValue(115, 123, 132)); +} +#define USING_BACKGROUND_BITMAP + + +/* + Depending on the argument passed to it, this function either draws the specified text + on top of the Heat On button - i.e. at the bottom of the display, in the centre, + in the specified colour, or erases it. + + Args: boolean, true to display the text, false to erase it + pointer to the (null-terminated) text + the foregound (i.e. text) colour + the background colour + + No return code. +*/ +static void DrawTextOnHeatOnOffButton(bool drawIt, char* text, GuiConst_INTCOLOR foreColor, GuiConst_INTCOLOR backColor) +{ + if(drawIt) { + const GuiConst_INT16U fontNo = GuiFont_Helv20Bold; + + const GuiConst_INT16S X = 75; // Approx centre of button + const GuiConst_INT16S Y = 450; // 220 to put it on top of the Run button, 450 for the Heat On/Off button + + GuiLib_DrawStr( + X, //GuiConst_INT16S X, + Y, //GuiConst_INT16S Y, + fontNo, //GuiConst_INT16U FontNo, + text, //GuiConst_TEXT PrefixLocate *String, + GuiLib_ALIGN_CENTER, //GuiConst_INT8U Alignment, + GuiLib_PS_ON, //GuiConst_INT8U PsWriting, + GuiLib_TRANSPARENT_ON, //GuiConst_INT8U Transparent, + GuiLib_UNDERLINE_OFF, //GuiConst_INT8U Underlining, + 0, //GuiConst_INT16S BackBoxSizeX, + 0, //GuiConst_INT16S BackBoxSizeY1, + 0, //GuiConst_INT16S BackBoxSizeY2, + GuiLib_BBP_NONE, //GuiConst_INT8U BackBorderPixels, + foreColor, //GuiConst_INTCOLOR ForeColor, + backColor //GuiConst_INTCOLOR BackColor + ); + } else { + // TODO: Erase it somehow + } } -void DisplayEasyGuiStructure(int structureIndex, USBDeviceConnected* usbDevice, USBHostGC* usbHostGC) +/* + Depending on the argument passed to it,this function either draws the word "Stabilising" + at the bottom of the display, in the centre, in green, or erases it. + + Arg is: true to display the text, false to erase it + + No return code. +*/ +void DrawStabilisingMessage(bool stabilising) +{ + DrawTextOnHeatOnOffButton(stabilising, "Stabilising", SixteenBitColorValue(0, 0xFF, 0), SixteenBitColorValue(0, 0, 0)); +} + +/* + Depending on the argument passed to it,this function either draws the word "Equilibrating" + at the bottom of the display, in the centre, in amber, or erases it. + + Arg is: true to display the text, false to erase it + + No return code. +*/ +void DrawEquilibratingMessage(bool equilibrating) +{ + DrawTextOnHeatOnOffButton(equilibrating, "Equilibrating", SixteenBitColorValue(255, 255, 50), SixteenBitColorValue(0, 0, 0)); +} + +/* + Depending on the argument passed to it,this function either draws the word "Cooling" + at the bottom of the display, in the centre, in light blue, or erases it. + + Arg is: true to display the text, false to erase it + + No return code. +*/ +void DrawCoolingMessage(bool cooling) +{ + DrawTextOnHeatOnOffButton(cooling, "Cooling", SixteenBitColorValue(0, 243, 255), SixteenBitColorValue(0, 0, 0)); +} + +/* + Depending on the argument passed to it,this function either draws the word "Ready" + at the bottom of the display, in the centre, in green, or erases it. + + Arg is: true to display the text, false to erase it + + No return code. +*/ +void DrawReadyMessage(bool ready) +{ + DrawTextOnHeatOnOffButton(ready, "Ready", SixteenBitColorValue(0, 0xFF, 0), SixteenBitColorValue(0, 0, 0)); +} + + +/* + Copies the build date (#define'd as BUILD_DATE at the top of this file) + to the easyGUI variable that displays it on the Settings page +*/ +void SetupEasyGUIBuildDateVariable(void) { - // If required, query the GC to find out if it is ready to run *before* clearing the display - + strcpy(GuiVar_buildDate, BUILD_DATE); +} + + +/* + Draw a part of a profile - which will be a quadrilateral, vertical at left and right, horizontal at the bottom, but a sloping straight line at the top - + by calling the EasyGUI GuiLib_VLine function multiple times. + + Args: colour of the profile to the left of the boundary + colour of the profile to the right of the boundary + X coords of the left and right edges of the section + X coord of the colour boundary + Y coord of the bottom + Y coords of the top left and top right + + Returns true if OK, false if it failed (e.g. the coords were invalid). +*/ +bool DrawProfileSectionUsingGuiLibVLine(GuiConst_INTCOLOR colour1, GuiConst_INTCOLOR colour2, GuiConst_INT16S xLeft, GuiConst_INT16S xRight, GuiConst_INT16S xColourBoundary, + GuiConst_INT16S yBottom, GuiConst_INT16S yTopLeft, GuiConst_INT16S yTopRight) +{ + if(xRight <= xLeft) return false; // Would cause divide by zero if they were equal + + // y = mx + c + double yDiff = (double) (yTopRight - yTopLeft); + double xDiff = (double) (xRight - xLeft); + double m = yDiff / xDiff; + double c = (double) yTopLeft - (m * (double) xLeft); + + GuiConst_INT16S lineX; + double lineYTop; + + // Draw first colour up to boundary. + // Allow for the boundary being past the right-hand end + for (lineX = xLeft; (lineX <= xColourBoundary) && (lineX <= xRight); ++lineX) { + lineYTop = (((double) lineX) * m) + c; + GuiLib_VLine(lineX, yBottom, (GuiConst_INT16S) lineYTop, colour1); + } + + // Draw second colour after boundary, if we have not already reached the right-hand end + for (; lineX <= xRight; ++lineX) { + lineYTop = (((double) lineX) * m) + c; + GuiLib_VLine(lineX, yBottom, (GuiConst_INT16S) lineYTop, colour2); + } + + return true; +} + +/* + Displays the specified easyGUI 'structure' (or page, to use a more easily understood term). + + Args are: the index of the structure to be displayed, + a pointer to the USBHostGC instance that corresponds to the GC, + a pointer to the USBDeviceConnected instance that (also) corresponds to the GC + a boolean - defaulting to true - that gives the caller the option to stop the 'structure' + updating its easyGUI variables (either from the GC or from its own internal values) + when it is redisplayed. This is set false by the NumericKeypadHandler, + when the user has just pressed the Apply button on the Numeric Keypad page + and NumericKeypadHandler has updated the corresponding easyGUI variable + on the page that called it, to stop the calling page/structure + from promptly overwriting that same variable. + + No return code. + + TODO: "Refactor" this function. It has had code added to it piecemeal over a long period, + and has become too large to easily understand. +*/ +void DisplayEasyGuiStructure(int structureIndex, USBDeviceConnected* usbDevice, USBHostGC* usbHostGC, bool updateEasyGUIVariables = true) +{ + // If required, query the GC to find out if it is ready to run, etc, *before* clearing the display - // otherwise the display remains clear while we talk to the GC - causes noticeable flickering bool gcIsReadyToRun = false; + bool gcIsStabilising = false; + bool gcIsEquilibrating = false; + bool gcIsCooling = false; + bool gcIsRunning = false; if((structureIndex == GuiStruct_HomePage_1) && (usbDevice != NULL) && (usbHostGC != NULL)) { - gcIsReadyToRun = GCIsReadyToRun(usbDevice, usbHostGC); + int gcStatus = GetGCStatus(usbDevice, usbHostGC); + GCStateSimplified simplifiedGCState = GCStateOrFaultCode::GetSimplifiedGCState(gcStatus); + + gcIsReadyToRun = (simplifiedGCState == GC_READY_TO_RUN); + gcIsStabilising = (simplifiedGCState == GC_STABILISING); + gcIsEquilibrating = (simplifiedGCState == GC_EQUILIBRATING); + gcIsCooling = (simplifiedGCState == GC_COOLING); + gcIsRunning = (simplifiedGCState == GC_RUNNING); } - GuiLib_Clear(); +#define DEBUG_HERE +#ifdef DEBUG_HERE + char dbg[100]; + sprintf(dbg, "DisplayEasyGuiStructure - structure is %d", structureIndex); + EasyGUIDebugPrint(dbg, 0, 20); +#undef DEBUG_HERE +#endif +#ifdef USING_BACKGROUND_BITMAP + // We want the status rectangles to be 'on top' of this - + // if we include it in the easyGUI page itself, it gets drawn by GuiLib_ShowScreen, + // and overwrites the rectangles + if((structureIndex == GuiStruct_GCConnectionPage_Def) || (structureIndex == GuiStruct_EthernetConnectionPage_Def)) { + DrawBackgroundBitmapWithLogo(); + } else if ((structureIndex == GuiStruct_NumericKeypadPage_Def) || (structureIndex == GuiStruct_EthernetKeypadPage_Def)) { + DrawFakeBackgroundBitmapForNumericKeypadPage(); + } else { + DrawBackgroundBitmap(); + } +#else + GuiLib_Clear(); // Don't need this if we have drawn the background bitmap - it covers the entire screen +#endif + + // Now, display the status rectangles and the component bitmaps, as appropriate for the page we are displaying. // Note - we draw the status rectangles after GuiLib_Clear - otherwise we wouldn't see the rectangles at all - - // and before GuiLib_ShowScreen - so text, etc, is drawn on top of the rectangles + // and before GuiLib_ShowScreen - so text, etc, is drawn on top of the rectangles. + // We draw the component bitmaps, after - therefore, on top of - the status rectangles. switch(structureIndex) { case GuiStruct_HomePage_1: +#ifdef USE_QSPI_BITMAPS + qspiBitmaps.DisplayAllHomePageBitmaps(); +#else homePageGCComponentStatusColorAreas.DisplayAll(); +#endif // USE_QSPI_BITMAPS break; case GuiStruct_ColumnPage1_2: case GuiStruct_ColumnPage2_9: - case GuiStruct_ColumnPage3_10: + case GuiStruct_ColumnTempProfilePage_60: + case GuiStruct_ColumnDHPage1_40: + case GuiStruct_ColumnDHPage2_50: + case GuiStruct_ColumnDHTempProfilePage_61: +#ifdef WANT_STATUS_RECTANGLE_ON_COLUMN_AUTO_CALIB_PAGE + case GuiStruct_ColumnDHAutoCalibrationPage_Def: +#endif // WANT_STATUS_RECTANGLE_ON_COLUMN_AUTO_CALIB_PAGE singleGCComponentPageStatusColorAreas.DisplayGCComponentStatus(COLUMN); + qspiBitmaps.DisplayColumnComponentBitmap(); break; case GuiStruct_InjectorPage1_3: + case GuiStruct_InjectorTempProfilePage_25: + case GuiStruct_InjectorGasStatusPage_30: + case GuiStruct_InjectorConsumablesPage_20: singleGCComponentPageStatusColorAreas.DisplayGCComponentStatus(INJECTOR); + qspiBitmaps.DisplayInjectorComponentBitmap(); break; - case GuiStruct_DetectorPage1_4: + case GuiStruct_DetectorFIDPage_4: + case GuiStruct_DetectorECDPage_12: + case GuiStruct_DetectorFPDPage_14: + case GuiStruct_DetectorTCDPage_11: + case GuiStruct_DetectorNonePage_31: + case GuiStruct_DetectorNPDPage_28: + case GuiStruct_DetectorPIDPage_29: + case GuiStruct_DetectorSPDIDPage_30: + case GuiStruct_DetectorTXLPage_27: singleGCComponentPageStatusColorAreas.DisplayGCComponentStatus(DETECTOR); + qspiBitmaps.DisplayDetectorComponentBitmap(); break; - case GuiStruct_GasPage1_6: + case GuiStruct_GasProfilePage_15: + case GuiStruct_GasInformationPage_6: +#ifdef WANT_STATUS_RECTANGLE_ON_GAS_CALIB_PAGES + case GuiStruct_GasCalibrationPage_Def: + case GuiStruct_GasBackPressureDACPage_Def: + case GuiStruct_GasChannelDACAndADCPage_Def: +#endif singleGCComponentPageStatusColorAreas.DisplayGCComponentStatus(GAS); + qspiBitmaps.DisplayGasComponentBitmap(); break; default: // Don't need to display status rectangle for this page break; } - + + if(structureIndex == GuiStruct_RunningPage1_7) { + if(getGCStatusLoop != NULL) { + getGCStatusLoop->UpdateMethodRunTimeEasyGUIVariables(false); + } + } + + if((structureIndex == GuiStruct_ColumnPage1_2) || (structureIndex == GuiStruct_ColumnDHPage1_40)){ + if(getGCStatusLoop != NULL) { + getGCStatusLoop->UpdateColumnStatusEasyGUIVariable(); + } + } + + if(structureIndex == GuiStruct_InjectorPage1_3){ + if(getGCStatusLoop != NULL) { + getGCStatusLoop->UpdateInjectorStatusEasyGUIVariable(); + } + } + + if(structureIndex == GuiStruct_EthernetParametersPage_50) { + NetworkParameters *networkParameters = NetworkParameters::GetInstance(usbDevice, usbHostGC); + + if(networkParameters != NULL) { + networkParameters->DisplayingEasyGUIPage(updateEasyGUIVariables); + } + } + + if(structureIndex == GuiStruct_GasCalibrationPage_Def) { + GasCalibrationPageHandler *gasCalibrationPageHandler = GasCalibrationPageHandler::GetInstance(usbDevice, usbHostGC); + + if(gasCalibrationPageHandler != NULL) { + gasCalibrationPageHandler->DisplayingEasyGUIPage(updateEasyGUIVariables); + } + } + + if(structureIndex == GuiStruct_GasBackPressureDACPage_Def) { + GasBackPressureDACPageHandler *gasBackPressureDACPageHandler = GasBackPressureDACPageHandler::GetInstance(usbDevice, usbHostGC); + + if(gasBackPressureDACPageHandler != NULL) { + gasBackPressureDACPageHandler->DisplayingEasyGUIPage(updateEasyGUIVariables); + } + } + + if(structureIndex == GuiStruct_GasChannelDACAndADCPage_Def) { + GasChannelDACAndADCPageHandler *gasChannelDACAndADCPageHandler = GasChannelDACAndADCPageHandler::GetInstance(usbDevice, usbHostGC); + + if(gasChannelDACAndADCPageHandler != NULL) { + gasChannelDACAndADCPageHandler->DisplayingEasyGUIPage(); + } + } + + if(structureIndex == GuiStruct_ColumnDHAutoCalibrationPage_Def) { + ColumnDHAutoCalibrationPageHandler *columnDHAutoCalibrationPageHandler = ColumnDHAutoCalibrationPageHandler::GetInstance(usbDevice, usbHostGC); + + if(columnDHAutoCalibrationPageHandler != NULL) { + columnDHAutoCalibrationPageHandler->DisplayingEasyGUIPage(); + } + } + + if(structureIndex == GuiStruct_ColumnDHManualCalibrationPage_Def) { + ColumnDHManualCalibrationPageHandler *columnDHManualCalibrationPageHandler = ColumnDHManualCalibrationPageHandler::GetInstance(usbDevice, usbHostGC); + + if(columnDHManualCalibrationPageHandler != NULL) { + columnDHManualCalibrationPageHandler->DisplayingEasyGUIPage(updateEasyGUIVariables); + } + } + + if(structureIndex == GuiStruct_ColumnDHSensorCalibration_Def) { + ColumnDHSensorCalibrationPageHandler *columnDHSensorCalibrationPageHandler = ColumnDHSensorCalibrationPageHandler::GetInstance(usbDevice, usbHostGC); + + if(columnDHSensorCalibrationPageHandler != NULL) { + columnDHSensorCalibrationPageHandler->DisplayingEasyGUIPage(updateEasyGUIVariables); + } + } + + if(structureIndex == GuiStruct_PSU_DAC_Page_Def) { + ColumnDHPSUDACPageHandler *columnDHPSUDACPageHandler = ColumnDHPSUDACPageHandler::GetInstance(usbDevice, usbHostGC); + + if(columnDHPSUDACPageHandler != NULL) { + columnDHPSUDACPageHandler->DisplayingEasyGUIPage(updateEasyGUIVariables); + } + } + + if(NudgeAndDampPageHandler::PageIsANudgeAndDampPage(structureIndex)) { + NudgeAndDampPageHandler *nudgeAndDampPageHandler = NudgeAndDampPageHandler::GetInstance(usbDevice, usbHostGC); + + if(nudgeAndDampPageHandler != NULL) { + nudgeAndDampPageHandler->DisplayingEasyGUIPage(structureIndex, updateEasyGUIVariables); + } + } + + + if(structureIndex == GuiStruct_ServicingHomePage_Def) { +#ifdef USE_QSPI_BITMAPS + // Use same bitmaps on Servicing Home Page, as on the main Home Page + qspiBitmaps.DisplayAllHomePageBitmaps(); +#endif + } + GuiLib_ShowScreen(structureIndex, GuiLib_NO_CURSOR, GuiLib_RESET_AUTO_REDRAW); // But draw the run button, if required, on top of the fixed part of the home page + // Same for the Heat On/Off button, and the Stabilising or Equilibrating messages (again, if required) if(structureIndex == GuiStruct_HomePage_1) { - DrawRunButton(gcIsReadyToRun); + DrawRunButton(gcIsReadyToRun || gcIsRunning); +#ifdef USE_HEAT_ONOFF_BUTTON_BITMAPS + DrawHeatOnOffButton(); +#endif + +#define USE_IF_HERE +#ifdef USE_IF_HERE + // Pointless always calling all four DrawxxxMessage functions - + // only one can be true + + if(gcIsStabilising) { + DrawStabilisingMessage(true); + } else if (gcIsEquilibrating) { + DrawEquilibratingMessage(true); + } else if (gcIsCooling) { + DrawCoolingMessage(true); + } else if (gcIsReadyToRun) { + DrawReadyMessage(true); + } +#undef USE_IF_HERE +#else + DrawStabilisingMessage(gcIsStabilising); + DrawEquilibratingMessage(gcIsEquilibrating); + DrawCoolingMessage(gcIsCooling); + DrawReadyMessage(gcIsReadyToRun); +#endif // USE_IF_HERE } + if(structureIndex == GuiStruct_InjectorTempProfilePage_25) { + + // Make sure the injector temperature profile graph is drawn + // on entering this page (note that we must do this *after* + // drawing the injector status rectangle and *after* 'GuiLib_ShowScreen') + + if(getGCStatusLoop != NULL) { + getGCStatusLoop->DisplayInjectorTempProfilePageGraph(); + } + } + + if(structureIndex == GuiStruct_GasProfilePage_15) { + + // Make sure the gas pressure profile graph is drawn + // on entering this page (note that we must do this *after* + // drawing the gas status rectangle and *after* 'GuiLib_ShowScreen') + + if(getGCStatusLoop != NULL) { + getGCStatusLoop->DisplayGasFlowProfilePageGraph(); + } + } + + if(structureIndex == GuiStruct_ColumnTempProfilePage_60) { + + // Make sure the column temperature profile graph is drawn + // on entering this page (note that we must do this *after* + // drawing the column status rectangle and *after* 'GuiLib_ShowScreen') + + if(getGCStatusLoop != NULL) { + getGCStatusLoop->DisplayColumnTempProfilePageGraph(CONVENTIONAL_COLUMN); + } + +//Also in GetGCStatusLoop::DisplayColumnTempProfilePageData +//#define SWIM_TEST +#ifdef SWIM_TEST + SwimDraw* swimDrawInstance = SwimDraw::GetInstance(); + if(swimDrawInstance != NULL) { + // two horizontal boxes + swimDrawInstance->DrawRectangle(SixteenBitColorValue(0xFF, 0, 0), 50, 200, 650, 250); + swimDrawInstance->DrawRectangle(SixteenBitColorValue(0, 0, 0xFF), 50, 350, 650, 400); + + // two vertical boxes + swimDrawInstance->DrawRectangle(SixteenBitColorValue(0xFF, 0, 0), 100, 50, 150, 350); + swimDrawInstance->DrawRectangle(SixteenBitColorValue(0, 0, 0xFF), 500, 50, 550, 350); + } +#else // Draw the same boxes with easyGUI +// GuiLib_FillBox(50, 200, 650, 250, SixteenBitColorValue(0xFF, 0, 0)); +// GuiLib_FillBox(50, 350, 650, 400, SixteenBitColorValue(0, 0, 0xFF)); + +// GuiLib_FillBox(100, 50, 150, 350, SixteenBitColorValue(0xFF, 0, 0)); +// GuiLib_FillBox(500, 50, 550, 350, SixteenBitColorValue(0, 0, 0xFF)); + +// No - draw a dummy profile section +// DrawProfileSectionUsingGuiLibVLine(SixteenBitColorValue(0xFF, 0, 0), 300, 500, 350, 200, 125); +#endif // SWIM_TEST + } + + if(structureIndex == GuiStruct_ColumnDHTempProfilePage_61) { + + // Make sure the directly heated column temperature profile graph is drawn + // on entering this page (note that we must do this *after* + // drawing the column status rectangle and *after* 'GuiLib_ShowScreen') + + if(getGCStatusLoop != NULL) { + getGCStatusLoop->DisplayColumnTempProfilePageGraph(DIRECTLY_HEATED_COLUMN); + } + } + + // Column page - must draw Lock/Release buttons if required + if((structureIndex == GuiStruct_ColumnDHAutoCalibrationPage_Def) || + (structureIndex == GuiStruct_ColumnDHPage1_40) || + (structureIndex == GuiStruct_ColumnDHPage2_50) || + (structureIndex == GuiStruct_ColumnDHTempProfilePage_61) || + (structureIndex == GuiStruct_ColumnPage1_2) || + (structureIndex == GuiStruct_ColumnPage2_9) || + (structureIndex == GuiStruct_ColumnTempProfilePage_60)) { + SetupDoorActuatorCommandUserInterface(usbDevice, usbHostGC, false); + } + + if(structureIndex == GuiStruct_RunningPage1_7) { + if(getGCStatusLoop != NULL) { + getGCStatusLoop->UpdateAndDisplayRunningPage1ProgressBar(false); + } + } + GuiLib_Refresh(); #define DEBUG_HERE #ifdef DEBUG_HERE - char dbg[100]; - sprintf(dbg, "After GuiLib_Refresh main 1"); - EasyGUIDebugPrint(dbg, 100, 100); + char dbg2[100]; + sprintf(dbg2, "After GuiLib_Refresh main 1"); + EasyGUIDebugPrint(dbg2, 0, 40); #undef DEBUG_HERE #endif if(getGCStatusLoop != NULL) { getGCStatusLoop->SetCurrentPage(structureIndex); } -} +} // End of "DisplayEasyGUIStructure" +/* + Draws the specified error message in a standard position (X = 90, Y = 240), + blue text on a green background. + + The argument is a pointer to the (null-terminated) message text. +*/ void DrawErrorMessage(char *msg) { const GuiConst_INT16U fontNo = GuiFont_Helv1; @@ -265,6 +1151,10 @@ ); } +/* + Update the easyGUI variable that displays the command to turn the GC heat on or off, + so that it matches the GC's current state. +*/ void UpdateHeatOnOffEasyGuiVariable(void) { // Note that the easyGUI variable is not the current status of the heat on the GC, @@ -278,33 +1168,50 @@ } } -bool StartGCRun(USBDeviceConnected* usbDevice, USBHostGC* usbHostGC) +void DrawHeatOnOffButton(void) { - while(usbHostGC->ExecutingSetDeviceReport()) {} - - char response[50]; - usbHostGC->SetDeviceReport(usbDevice, "CRUN", response); - // We expect a response like this: "DACK" for success, "DNAK" for failure + // Note that the text on the button is not the current status of the heat on the GC, + // but the command to toggle its current state + GuiConst_INT8U bitmapIndex = GuiStruct_Bitmap_HeatOn; + if(theGCHeatControl != NULL) { + if(theGCHeatControl->IsHeatOn()) { + bitmapIndex = GuiStruct_Bitmap_HeatOff; + } + } #define DEBUG_HERE #ifdef DEBUG_HERE char dbg[100]; - sprintf(dbg, "CRUN returned %s", response); - EasyGUIDebugPrint(dbg, 100, 150); + sprintf(dbg, "DHOOB - bitmapIndex is %d", bitmapIndex); + EasyGUIDebugPrint(dbg, 0, 440); #endif #undef DEBUG_HERE - return (response[1] == 'A'); + // Hard coded coordinates copied from easyGUI (I have not found + // a way of getting them from the easyGUI code at runtime) + GuiLib_ShowBitmap(bitmapIndex, 0, 404, -1); // No transparent colour } -bool StopGCRun(USBDeviceConnected* usbDevice, USBHostGC* usbHostGC) + +/* + General function to pass a command to the GC, and return success or failure to the caller. + + Args are: the command (null-terminated string) + a pointer to the USBHostGC instance that corresponds to the GC, + a pointer to the USBDeviceConnected instance that (also) corresponds to the GC + + Returns true if the GC returned "DACK" in response, false if it returned "DNAK" + (or "EPKT", or anything other than "DACK"). +*/ +bool ExecuteGCCommand(char *cmd, USBDeviceConnected* usbDevice, USBHostGC* usbHostGC) { +#define USE_GC_UTILS // Testing new class +#ifdef USE_GC_UTILS + return USBHostGCUtilities::SendCommandToGCWithDACKResponse(usbDevice, usbHostGC, cmd); +#else while(usbHostGC->ExecutingSetDeviceReport()) {} char response[50]; -// TODO: Find out which is the correct command here -// char *cmd = "CSTP"; - char *cmd = "CABT"; usbHostGC->SetDeviceReport(usbDevice, cmd, response); // We expect a response like this: "DACK" for success, "DNAK" for failure @@ -312,95 +1219,709 @@ #ifdef DEBUG_HERE char dbg[100]; sprintf(dbg, "%s returned %s", cmd, response); - EasyGUIDebugPrint(dbg, 100, 150); + EasyGUIDebugPrint(dbg, 0, 20); #endif #undef DEBUG_HERE + + return (response[1] == 'A'); +#endif // USE_GC_UTILS +} + +/* + Starts the GC running, by passing it the "CRUN" command. - return (response[1] == 'A'); + Args are: a pointer to the USBHostGC instance that corresponds to the GC, + a pointer to the USBDeviceConnected instance that (also) corresponds to the GC + + Returns true if the GC returned "DACK" in response, false if it returned "DNAK". +*/ +bool StartGCRun(USBDeviceConnected* usbDevice, USBHostGC* usbHostGC) +{ + return ExecuteGCCommand("CRUN", usbDevice, usbHostGC); +} + +/* + Stops the GC running, by passing it the "CSTP" or "CABT" command. + + Args are: a pointer to the USBHostGC instance that corresponds to the GC, + a pointer to the USBDeviceConnected instance that (also) corresponds to the GC + + Returns true if the GC returned "DACK" in response, false if it returned "DNAK". +*/ +bool StopGCRun(USBDeviceConnected* usbDevice, USBHostGC* usbHostGC) +{ +// TODO: Find out which is the correct command here +// char *cmd = "CSTP"; + char *cmd = "CABT"; + return ExecuteGCCommand(cmd, usbDevice, usbHostGC); +} + +/* + Takes the GC out of standby mode, by passing it the "CDIS" command. + + Args are: a pointer to the USBHostGC instance that corresponds to the GC, + a pointer to the USBDeviceConnected instance that (also) corresponds to the GC + + Returns true if the GC returned "DACK" in response, false if it returned "DNAK". +*/ +bool ExitGCStandbyMode(USBDeviceConnected* usbDevice, USBHostGC* usbHostGC) +{ + if( ExecuteGCCommand("CDIS", usbDevice, usbHostGC)) { + if(getGCStatusLoop != NULL) { + getGCStatusLoop->ExitedGCStandbyMode(); + } + + return true; + } + + // 'else' + return false; } -bool ExitGCStandbyMode(USBDeviceConnected* usbDevice, USBHostGC* usbHostGC) +/* + Takes the GC out of its error state, by passing it the "CCLR" command. + + Args are: a pointer to the USBHostGC instance that corresponds to the GC, + a pointer to the USBDeviceConnected instance that (also) corresponds to the GC + + Returns true if the GC returned "DACK" in response, false if it returned "DNAK". +*/ +bool ClearGCErrors(USBDeviceConnected* usbDevice, USBHostGC* usbHostGC) +{ + return ExecuteGCCommand("CCLR", usbDevice, usbHostGC); +} + + +/* + Opens the (column) door on the GC, by passing it the "COPN" command. + + Args are: a pointer to the USBHostGC instance that corresponds to the GC, + a pointer to the USBDeviceConnected instance that (also) corresponds to the GC + + Returns true if the GC returned "DACK" in response, false if it returned "DNAK". +*/ +bool OpenDoor(USBDeviceConnected* usbDevice, USBHostGC* usbHostGC) +{ + return ExecuteGCCommand("COPN", usbDevice, usbHostGC); +} + + +/* + Set up the variable "GuiVar_doorActuatorCommandFGColour", to show - depending on + the current state of the GC - whether the Lock/Unlock facility is enabled or not, + by displaying the command in black (enabled) or grey (disabled). + + Args are: a pointer to the USBHostGC instance that corresponds to the GC, + a pointer to the USBDeviceConnected instance that (also) corresponds to the GC + + No return code. +*/ +void SetupDoorActuatorCommandColour(USBDeviceConnected* usbDevice, USBHostGC* usbHostGC, bool actuatorsAreMoving) +{ + // We allow the user to change the state of the actuators only if the GC is in the idle or fault states, + // and if there is no other reason why they should be disabled (e.g. we are calibrating, and the oven is hot + // even though the heat is not on. Show this to the user by setting the text colour to black (enabled) + // or grey (disabled) + bool enabled = false; + if(!actuatorsAreMoving) { + GCStateSimplified simplifiedGCState = GCStateOrFaultCode::GetSimplifiedGCState(GetGCStatus(usbDevice, usbHostGC)); + if((simplifiedGCState == GC_IDLE) || (simplifiedGCState == GC_FAULTED)) { + if(canUnlockDoorActuators) { + enabled = true; + } + } + } + // All other situations - must be disabled + + if(enabled) { + GuiVar_doorActuatorCommandFGColour = 0; // Black + } else { + GuiVar_doorActuatorCommandFGColour = SixteenBitColorValue(192, 192, 192); // Grey - but bright enough to show up against grey button colour + } +} + + +typedef enum enumDoorActuatorStatus { LOCKED, UNLOCKED, CLOSED_BUT_NOT_LOCKED, INTERMEDIATE, MOVING } DoorActuatorStatus; +static bool lockingActuators; // Do not display "Release" while we are doing this +/* + Finds out, and returns, the status of the door actuators. + + Args are: a pointer to the USBHostGC instance that corresponds to the GC, + a pointer to the USBDeviceConnected instance that (also) corresponds to the GC + + Returns the status, as a value in the 'DoorActuatorStatus' enumeration defined above. +*/ +DoorActuatorStatus GetDoorActuatorStatus(USBDeviceConnected* usbDevice, USBHostGC* usbHostGC) { while(usbHostGC->ExecutingSetDeviceReport()) {} char response[50]; - usbHostGC->SetDeviceReport(usbDevice, "CDIS", response); - // We expect a response like this: "DACK" for success, "DNAK" for failure + usbHostGC->SetDeviceReport(usbDevice, "QACT1004", response); + + + // We expect a response of the form "DACnnnnn", where "nnnnn" is the decimal value + // of two bytes, the most significant of which contains the states of each of the three actuators, + // while the least significant contains the software version (which we ignore). + + int actuatorStatus; + sscanf(&response[3], "%d", &actuatorStatus); + + if(actuatorStatus & 0x8000) { // Top bit set + return MOVING; + } + + int actuator1Status = (actuatorStatus & 0x300) >> 8; + int actuator2Status = (actuatorStatus & 0xC00) >> 10; + int actuator3Status = (actuatorStatus & 0x3000) >> 12; + + // Status 1 means locked, 2 means unlocked, 3 means closed but not locked (actuators 1 and 2 only), + // 0 means intermediate + if ((actuator1Status == 1) && (actuator2Status == 1) && (actuator3Status == 1)) { + return LOCKED; + } + // 'else' ... + if((actuator1Status == 2) && (actuator2Status == 2) && (actuator3Status == 2)) { + return UNLOCKED; + } + // 'else' ... + if((actuator1Status == 3) && (actuator2Status == 3) && (actuator3Status == 2)) { + return CLOSED_BUT_NOT_LOCKED; + } + // 'else' ... + return INTERMEDIATE; +} + +/* + We have now replaced the "Open Door" button with a button to toggle + the state of the door actuators - i.e. lock them if they are unlocked + and vice versa. We display the corresponding command in the easyGUI variable + "GuiVar_doorActuatorCommand". This function reads the current state + of the actuators, and sets up that variable appropriately. It also sets up + the variable "GuiVar_doorActuatorCommandFGColour", to show - depending on + the current state of the GC - whether the facility is enabled or not, + by displaying the command in black (enabled) or grey (disabled). + + It also now - since we have a separate state for "closed but not locked" - + displays the two "Lock" and "Release" buttons if required. + + Args are: a pointer to the USBHostGC instance that corresponds to the GC, + a pointer to the USBDeviceConnected instance that (also) corresponds to the GC + a boolean set to true before displaying the easyGUI page (GuiLib_ShowScreen), false if afterwards + + No return code. +*/ +void SetupDoorActuatorCommandUserInterface(USBDeviceConnected* usbDevice, USBHostGC* usbHostGC, bool beforePageDisplay) +{ +//#define DEBUG_PRINT_HERE +#ifdef DEBUG_PRINT_HERE + char buff[100]; + sprintf(buff, "%s", beforePageDisplay ? "Before page display" : "After page display"); + SpecialDebugPrint(buff, 150, 430); +#endif + + DoorActuatorStatus doorActuatorStatus = GetDoorActuatorStatus(usbDevice, usbHostGC); - char dbg[100]; - sprintf(dbg, "CDIS returned %s", response); - EasyGUIDebugPrint(dbg, 100, 150); +// SetupDoorActuatorCommandColour(usbDevice, usbHostGC, (doorActuatorStatus == MOVING)); + SetupDoorActuatorCommandColour(usbDevice, usbHostGC, false); + + if(beforePageDisplay) { + + // Do nothing - do not change the button text, etc - if the actuators are moving + if(doorActuatorStatus != MOVING) { + if(doorActuatorStatus == UNLOCKED) { + strcpy(GuiVar_doorActuatorCommand, "Close"); + } else if (doorActuatorStatus == LOCKED) { + strcpy(GuiVar_doorActuatorCommand, "Unlock"); + lockingActuators = false; + } else { // i.e. all other states, including INTERMEDIATE (possible emergency stop) + if(!lockingActuators) { // Do not display this while we are locking - confusing + strcpy(GuiVar_doorActuatorCommand, "Release"); + } + } + } + } else { + if(doorActuatorStatus == CLOSED_BUT_NOT_LOCKED) { + GetGCStatusLoop::DisplayColumnLockAndReleaseButtons(); +#ifdef DEBUG_PRINT_HERE + char buff2[100]; + sprintf(buff2, "%s", "Drawing lock and release buttons"); + SpecialDebugPrint(buff2, 150, 460); +#endif + } else { // Including MOVING + DrawBackgroundBitmapOverDoorLockAndReleaseButtons(); +#ifdef DEBUG_PRINT_HERE + char buff2[100]; + sprintf(buff2, "%s", "*** NOT *** drawing lock and release buttons"); + SpecialDebugPrint(buff2, 150, 460); +#undef DEBUG_PRINT_HERE +#endif + } + } +} + + +/* + Tells the caller whether or not the door actuator buttons have changed, + from the single "Close"/"Unlock" button to the two "Lock" and "Release" buttons, + or vice versa +*/ +bool DoorActuatorButtonsHaveChanged(USBDeviceConnected* usbDevice, USBHostGC* usbHostGC) +{ + bool doorActuatorButtonsHaveChanged = false; - if(getGCStatusLoop != NULL) { - getGCStatusLoop->ExitedGCStandbyMode(); + static DoorActuatorStatus previousDoorActuatorStatus = INTERMEDIATE; + + DoorActuatorStatus doorActuatorStatus = GetDoorActuatorStatus(usbDevice, usbHostGC); + + // Do not change buttons if actuators are moving + if(doorActuatorStatus != MOVING) { + if((doorActuatorStatus == LOCKED) || (doorActuatorStatus == UNLOCKED)) { + if((previousDoorActuatorStatus == CLOSED_BUT_NOT_LOCKED) || (previousDoorActuatorStatus == INTERMEDIATE)) { + doorActuatorButtonsHaveChanged = true; + } + } else if (doorActuatorStatus == CLOSED_BUT_NOT_LOCKED) { + if(previousDoorActuatorStatus != CLOSED_BUT_NOT_LOCKED) { + doorActuatorButtonsHaveChanged = true; + } + } + + // We ignore the 'moving' state + previousDoorActuatorStatus = doorActuatorStatus; + } + + return doorActuatorButtonsHaveChanged; +} + + +/* + Toggles the state of the door actuator on the GC - i.e. if it is locked, + unlocks it, and vice versa. + + Args are: the index of the touch area the user touched (note that we assume + this must be one of the 'door actuator areas' (seeEasyGUITouchAreaIndices.h) + a pointer to the USBHostGC instance that corresponds to the GC, + a pointer to the USBDeviceConnected instance that (also) corresponds to the GC + + Returns true if the GC executed the operation successfully, false if not +*/ +bool DealWithDoorActuatorButtons(int touchAreaIndex, USBDeviceConnected* usbDevice, USBHostGC* usbHostGC) +{ + // Disallow movement unless GC is in idle or faulted states + int gcStatus = GetGCStatus(usbDevice, usbHostGC); + GCStateSimplified simplifiedGCState = GCStateOrFaultCode::GetSimplifiedGCState(gcStatus); + if((simplifiedGCState != GC_IDLE) && (simplifiedGCState != GC_FAULTED)) { + return false; } - return (response[1] == 'A'); + bool bOK = false; + + DoorActuatorStatus doorActuatorStatus = GetDoorActuatorStatus(usbDevice, usbHostGC); + + if(doorActuatorStatus != MOVING) { + if(doorActuatorStatus == UNLOCKED) { + // Two touch areas, but only one button - treat both the same + // Close actuator, but do not lock it + bOK = ExecuteGCCommand("CACT1005", usbDevice, usbHostGC); + } else if (doorActuatorStatus == LOCKED) { + // Two touch areas, but only one button - treat both the same + // Unlock actuator + bOK = ExecuteGCCommand("CACT1006", usbDevice, usbHostGC); + } else if (doorActuatorStatus == CLOSED_BUT_NOT_LOCKED) { + // Unlock or Lock, depending on the touch area + if(touchAreaIndex == DOOR_ACTUATOR_AREA_1) { + // Lock + bOK = ExecuteGCCommand("CACT1007", usbDevice, usbHostGC); + if(bOK) { + lockingActuators = true; + // Get the text ready for the Close/Unlock button + strcpy(GuiVar_doorActuatorCommand, "Unlock"); + } + } else { + // Assume DOOR_ACTUATOR_AREA_2 - release, i.e. unlock + bOK = ExecuteGCCommand("CACT1006", usbDevice, usbHostGC); + if(bOK) { + // Get the text ready for the Close/Unlock button + strcpy(GuiVar_doorActuatorCommand, "Close"); + } + } + } else { // Assume INTERMEDIATE - for safety, always unlock + bOK = ExecuteGCCommand("CACT1006", usbDevice, usbHostGC); + } + } + + if(bOK) { + SetupDoorActuatorCommandUserInterface(usbDevice, usbHostGC, false); + } + + return bOK; +} + + +/* + Tells the caller whether or not a specified GC command represents the start of a method, + and that therefore a new method is now being sent to the GC. + + Params: pointer to a null-terminated string containing the command in question + + Returns true if the command is one that occurs at the start of a method (and nowhere else), + false if not. + + This code is intended to be as efficient as possible. + + Currently, called from GetGCStatusLoop class and EthernetThread class +*/ +bool IsStartOfMethodCommand(char *gcCommand) +{ + // We are looking for "CLCK" - lock local keyboard. + // Ellution only sends this at the start of a method. + + if((gcCommand[0] == 'C') && (gcCommand[1] == 'L') && (gcCommand[2] == 'C') && (gcCommand[3] == 'K')) { + return true; + } + + return false; // Not "CLCK" +} + +/* + Tells the caller whether or not a specified GC command represents the end of a method, + and that therefore a new method has just been sent to the GC. + + Params: pointer to a null-terminated string containing the command in question + + Returns true if the command is one that occurs at the end of a method (and nowhere else), + false if not. + + This code is intended to be as efficient as possible. + + Currently, called from GetGCStatusLoop class and EthernetThread class +*/ +bool IsEndOfMethodCommand(char *gcCommand) +{ + // We are looking for "CULK" - unlock local keyboard. + // Ellution only sends this at the end of a method. + + if((gcCommand[0] == 'C') && (gcCommand[1] == 'U') && (gcCommand[2] == 'L') && (gcCommand[3] == 'K')) { + return true; + } + + return false; // Not "CULK" } -bool ClearGCErrors(USBDeviceConnected* usbDevice, USBHostGC* usbHostGC) + +/* + Tells the caller whether or not a specified GC command is a control command, + which received "DACK" in acknowledgement, and is therefore likely + to have caused the GC to change its state. + + Params: pointer to a null-terminated string containing the command in question + + Returns true if the command is a control command and if it succeeded, false if not. + + This code is intended to be as efficient as possible. + + Currently, called from GetGCStatusLoop class and EthernetThread class +*/ +bool IsSuccessfulControlCommand(char* gcCommand, char* gcResponse) +{ + // Simple criteria - does the command start with 'C'? + // - was the response "DACK"? + + if(gcCommand[0] != 'C') { + return false; + } + + + if(gcResponse[0] != 'D') { + return false; + } + + if(gcResponse[1] != 'A') { + return false; + } + + if(gcResponse[2] != 'C') { + return false; + } + + if(gcResponse[3] != 'K') { + return false; + } + + // All the above were true + return true; +} + + +/* + Increment the run count recorded in the QSPI settings. + + This would be called (for example) after the Run button has been pressed. +*/ +void IncrementRunCountInQSPISettings(void) { + int runCount = SettingsHandler::GetIntegerValueFromQSPISettings("RunCount", 0); + + // Debug prints + char dbg[100]; + sprintf(dbg, "Run count read: %d", runCount); + EasyGUIDebugPrint(dbg, 500, 460); + + SettingsHandler::DisplayQSPIDirectory(600, 250); + // End of debug prints + + ++runCount; + + SettingsHandler::PutIntegerValueToQSPISettings("RunCount", runCount); +} + +/* + Update the values of all the easyGUI variables whose values are derived + from the run count. This should be called (for example) after + the Run button has been pressed. +*/ +void UpdateAllEasyGUIVariablesThatDependOnRunCount(void) +{ + int runCount = SettingsHandler::GetIntegerValueFromQSPISettings("RunCount", 0); + + int columnInstalledRunCount = SettingsHandler::GetIntegerValueFromQSPISettings("RunCountWhenColumnInstalled", 0); + sprintf(GuiVar_columnInjectionsSinceInstallation, "%d", (runCount - columnInstalledRunCount)); + + int linerChangedRunCount = SettingsHandler::GetIntegerValueFromQSPISettings("RunCountWhenLinerChanged", 0); + sprintf(GuiVar_injectionCountSinceLinerChanged, "%d", (runCount - linerChangedRunCount)); + + int septaChangedRunCount = SettingsHandler::GetIntegerValueFromQSPISettings("RunCountWhenSeptaChanged", 0); + sprintf(GuiVar_injectionCountSinceSeptaChanged, "%d", (runCount - septaChangedRunCount)); + + int oRingChangedRunCount = SettingsHandler::GetIntegerValueFromQSPISettings("RunCountWhenOringChanged", 0); + sprintf(GuiVar_injectionCountSinceOringChanged, "%d", (runCount - oRingChangedRunCount)); +} + + +/* + Sends the specified command to the GC. + + This must be a "Sxxx" command, that only expects "DACK" or "DNAK" back, + not actual data. + + Args are: a pointer to the USBHostGC instance that corresponds to the GC, + a pointer to the USBDeviceConnected instance that (also) corresponds to the GC + + Returns true if the GC returned "DACK" in response, false if it returned "DNAK". +*/ +bool SendAnyCommandToGC(char *cmd, USBDeviceConnected* usbDevice, USBHostGC* usbHostGC) +{ +#define USE_GC_UTILS // Testing new class +#ifdef USE_GC_UTILS + return USBHostGCUtilities::SendCommandToGCWithDACKResponse(usbDevice, usbHostGC, cmd); +#else while(usbHostGC->ExecutingSetDeviceReport()) {} char response[50]; - usbHostGC->SetDeviceReport(usbDevice, "CCLR", response); + usbHostGC->SetDeviceReport(usbDevice, cmd, response); // We expect a response like this: "DACK" for success, "DNAK" for failure - char dbg[100]; - sprintf(dbg, "CCLR returned %s", response); - EasyGUIDebugPrint(dbg, 100, 150); - return (response[1] == 'A'); +#endif // USE_GC_UTILS +} + + +/* + This function performs the "set up" operations required + when the GC starts running. It is intended to be called + whenever the GC starts running - note that this may happen + not only when the user presses our "Run" button, but if + he sends a "CRUN" command to the GC from the PC (e.g. using + Ellution), or if something triggers the "Run" pin + on the GC board itself (and that does not pass through + the LPC4088, so it cannot be detected directly by this software). + + Args are: a pointer to the USBHostGC instance that corresponds to the GC, + a pointer to the USBDeviceConnected instance that (also) corresponds to the GC + + No return code +*/ +void SetupForStartOfRun(USBDeviceConnected* usbDevice, USBHostGC* usbHostGC) +{ + if(getGCStatusLoop != NULL) { + getGCStatusLoop->SetGCIsRunning(); + IncrementRunCountInQSPISettings(); + UpdateAllEasyGUIVariablesThatDependOnRunCount(); + getGCStatusLoop->UpdateGCMethodRunningProfiles(); + getGCStatusLoop->SetRunningPage1ProgressBarToZero(); + getGCStatusLoop->SetupTemperatureWhileRunningEasyGUIVariables(); + DisplayEasyGuiStructure(GuiStruct_RunningPage1_7, usbDevice, usbHostGC); + } } + +static void RemoveUnitsFromEasyGUIStringIfFound(char* destination, GuiConst_TEXT* easyGUIString, char* units) +{ + strcpy(destination, easyGUIString); + + int unitsLength = strlen(units); + int stringLength = strlen(destination); + + if(strcmp(units, &destination[stringLength - unitsLength]) == 0) { + destination[stringLength - unitsLength] = '\0'; + } +} + + +/* + This is the main function dealing with user interaction via the LPC4088 touch panel. + ************************************************************************************ + + It is (currently, until we rationalise this code) called by the GetGCStatusLoop code + that deals with touch events. (Ideally, we should move it into the GetGCStatusLoop class + at some point.) + + Args are: the touch coordinates (x, y and z - we do not use the z coordinate) + a pointer to the USBHostGC instance that corresponds to the GC, + a pointer to the USBDeviceConnected instance that (also) corresponds to the GC + a count of timer ticks + a boolean set to true if the touch is 'new', false if not (a touch is 'new' + if it occurs after a period when the user appears not to have touched the screen). + + Looks to see if the user has touched a defined easyGUI touch area, and responds accordingly. + + No return code. + + See EasyGUITouchAreaIndices.h for the touch area index values. +*/ void TouchCallback(touch_coordinate_t touchCoords, USBDeviceConnected* usbDevice, USBHostGC* usbHostGC, int tickCount, bool newTouch) { + EasyGUIDebugPrintWithCounter("TouchCallback 0 ", 500, 440); + GuiConst_INT32S touchAreaIndex = GuiLib_TouchCheck((GuiConst_INT16S)touchCoords.x, (GuiConst_INT16S)touchCoords.y); + EasyGUIDebugPrintWithCounter("TouchCallback 1 ", 500, 440); + if(touchAreaIndex >= 0) { + +//#define ALLOW_DEBUG_PRINTS_HERE +#ifdef ALLOW_DEBUG_PRINTS_HERE + char buff[300]; + sprintf(buff, "tAI: %d", touchAreaIndex); + SpecialDebugPrint(buff, 150, 410); +#undef ALLOW_DEBUG_PRINTS_HERE +#endif // ALLOW_DEBUG_PRINTS_HERE + bool dealtWithTouch = false; // page selector? TouchPanelPageSelector* touchPanelPageSelector = touchPanelPageSelectors.GetTouchPanelPageSelector(touchAreaIndex); if( touchPanelPageSelector != NULL) { + + // User has touched a page selector + // ******************************** + // Do not keep switching pages if the user keeps 'touching' - // switch only if he 'lets go', then presses again if(newTouch) { - if(touchAreaIndex == 200) { - // Stop run - as well as displaying the home page, do this... - StopGCRun(usbDevice, usbHostGC); - } + + // Depending on the touch area, we may need to do extra stuff here + // before displaying the appropriate page - if(touchAreaIndex == 400) { + if(touchAreaIndex == GAS_SAVER_RETURN_TO_READY) { // Take GC out of standby mode ExitGCStandbyMode(usbDevice, usbHostGC); } - if(touchAreaIndex == 600) { + if(touchAreaIndex == CLEAR_ERRORS_BUTTON) { // Take GC out of error state ClearGCErrors(usbDevice, usbHostGC); + + // Make sure the component status rectangles change colour immediately, + // not after ~10 seconds + if(getGCStatusLoop != NULL) { + getGCStatusLoop->UpdateHomePageGCComponentStatusColorAreas(); + + getGCStatusLoop->UpdateSingleGCComponentPageStatusColorArea(COLUMN); + getGCStatusLoop->UpdateSingleGCComponentPageStatusColorArea(INJECTOR); + getGCStatusLoop->UpdateSingleGCComponentPageStatusColorArea(DETECTOR); + getGCStatusLoop->UpdateSingleGCComponentPageStatusColorArea(GAS); + } } - DisplayEasyGuiStructure(touchPanelPageSelector->GetPageNumber(), usbDevice, usbHostGC); + if(touchAreaIndex == ABORT_RUN_YES) { + + // Abort Run request confirmed + +//#define DEBUG_PRINT_ON_FAILURE +#ifdef DEBUG_PRINT_ON_FAILURE + if(!StopGCRun(usbDevice, usbHostGC)) { + SpecialDebugPrint("*** StopGCRun failed ***", 150, 430); + } +#undef DEBUG_PRINT_ON_FAILURE +#else + StopGCRun(usbDevice, usbHostGC); +#endif // DEBUG_PRINT_ON_FAILURE + + getGCStatusLoop->ClearGCIsRunning(); + +#ifdef SERVICE_INTERVALS_ACTIVE + ServiceInterval::TellAllServiceIntervalsInstrumentHasCycled(); +#endif // SERVICE_INTERVALS_ACTIVE + +#ifdef TURN_HEAT_OFF_ON_ABORT + // Turn heat off + if(heatOnOffAvailable) { + if(theGCHeatControl != NULL) { + if(theGCHeatControl->IsHeatOn()) { + theGCHeatControl->TurnHeatOff(); +#ifdef USE_HEAT_ONOFF_BUTTON_BITMAPS + DrawHeatOnOffButton(); +#else + UpdateHeatOnOffEasyGuiVariable(); +#endif // USE_HEAT_ONOFF_BUTTON_BITMAPS + } + + StartHeatOnOffTimeout(); + } + } +#endif // TURN_HEAT_OFF_ON_ABORT + } + + if(touchAreaIndex == SETTINGS_TO_NETWORK_PARAMS_BUTTON) { + // We are about to display the Network Parameters page - so tell the class + // to display the real IP address, etc - i.e. the values we are actually using + NetworkParameters *networkParameters = NetworkParameters::GetInstance(usbDevice, usbHostGC); + if(networkParameters != NULL) { + networkParameters->RestoreRealValues(); + } + } + + if(touchAreaIndex == SETTINGS_TO_SERVICING_PAGE_BUTTON) { + strcpy(GuiVar_engineersLockCodeMessage, "No lock code entered"); + } + + if(touchAreaIndex == SERVICING_PAGE_GC_CMDS_BUTTON ) { + // Clear the easyGUI variables that display the command and the response + GuiVar_debugCommandTx[0] = '\0'; + GuiVar_debugCommandRx[0] = '\0'; + } + + if(touchPanelPageSelector->CanChangePage()) { + DisplayEasyGuiStructure(touchPanelPageSelector->GetPageNumber(usbDevice, usbHostGC), usbDevice, usbHostGC); + } } - + dealtWithTouch = true; // The user touched a page selector, so we have still 'dealt' with this, // whether we had a 'new touch' or not - - if(touchAreaIndex == 200) { - // Is in same place as Heat On/Off button - StartHeatOnOffTimeout(); - } - } + } // TouchPanelPageSelector if(!dealtWithTouch) { - if(touchAreaIndex == 100) { // Run button + + if(touchAreaIndex == RUN_BUTTON) { if(newTouch) { // As above - do not do this repeatedly - GC does not like it... + + EasyGUIDebugPrintWithCounter("TouchCallback 4.1 ", 500, 440); + if(GCIsReadyToRun(usbDevice, usbHostGC)) { - // Start run - if this works, display the 'Run' page, else do nothing + // Start run - if this works, display the 'Run' page, etc, else do nothing if(StartGCRun(usbDevice, usbHostGC)) { - DisplayEasyGuiStructure(GuiStruct_RunningPage_7, usbDevice, usbHostGC); + SetupForStartOfRun(usbDevice, usbHostGC); } else { DrawErrorMessage("*** Run failed to start ***"); @@ -409,16 +1930,21 @@ DisplayEasyGuiStructure(GuiStruct_HomePage_1, usbDevice, usbHostGC); } + } else { + // GC is not ready to run - tell the user why + getGCStatusLoop->SetupGCNotReadyStateEasyGUIVariable(); + + DisplayEasyGuiStructure(GuiStruct_GCNotReadyToRunPage_Def, usbDevice, usbHostGC); } - // else GC is not ready to run (button should be greyed out) - ignore } dealtWithTouch = true; } - } + } // Run button if(!dealtWithTouch) { - if(touchAreaIndex == 300) { // Heat on/off button + + if(touchAreaIndex == HEAT_ON_BUTTON) { // Heat on/off button if(newTouch) { // As above - do not do this repeatedly - GC does not like it... if(heatOnOffAvailable) { if(theGCHeatControl != NULL) { @@ -427,12 +1953,22 @@ } else { theGCHeatControl->TurnHeatOn(); } +#ifdef USE_HEAT_ONOFF_BUTTON_BITMAPS + // If we do not do this first, we do not see the bitmap change on the button + // (I don't understand why...) + DisplayEasyGuiStructure(GuiStruct_HomePage_1, usbDevice, usbHostGC); + DrawHeatOnOffButton(); +#else UpdateHeatOnOffEasyGuiVariable(); - // Make GuiVar_heatOnOffCommand update visible on screen DisplayEasyGuiStructure(GuiStruct_HomePage_1, usbDevice, usbHostGC); +#endif // USE_HEAT_ONOFF_BUTTON_BITMAPS StartHeatOnOffTimeout(); + + // Update the door lock/unlock command colour + // *before* we display the column page(s) + SetupDoorActuatorCommandColour(usbDevice, usbHostGC, false); } } } @@ -441,111 +1977,425 @@ // so no-one else should try and deal with this touch dealtWithTouch = true; } + } // Heat ON/Off button + + if(!dealtWithTouch) { + + if((touchAreaIndex == COLUMN_PAGE1_EDIT_COLUMN_MAX_TEMP) || + (touchAreaIndex == COLUMN_DH_PAGE1_EDIT_COLUMN_MAX_TEMP)) { + + NumericKeypadPageHandler* numericKeypadPageHandler = NumericKeypadPageHandler::GetInstance(usbDevice, usbHostGC); + if(numericKeypadPageHandler != NULL) { + + // Remove units ("deg C")from the initial value to be displayed in the keypad + char temp[50]; + RemoveUnitsFromEasyGUIStringIfFound(temp, GuiVar_columnMaxTemp2, " deg C"); // Remove space before units as well as the units themselves + + numericKeypadPageHandler->StartEditing(temp); + numericKeypadPageHandler->SetEasyGUIVariableToEdit(GuiVar_columnMaxTemp2); + numericKeypadPageHandler->SetEasyGUICallingPage((touchAreaIndex == COLUMN_DH_PAGE1_EDIT_COLUMN_MAX_TEMP) ? GuiStruct_ColumnDHPage1_40 : GuiStruct_ColumnPage1_2); + numericKeypadPageHandler->SetEditVariableRange(0, 500); + numericKeypadPageHandler->SetEditVariableName("Col. Max Temp"); + numericKeypadPageHandler->SetEditVariableUnits("deg C"); + numericKeypadPageHandler->SetApplyFunctionPtr(&SetColumnMaxTempFromEasyGuiVariable); + numericKeypadPageHandler->DisplayEasyGUIPage(); + } + + dealtWithTouch = true; + } } + + if(!dealtWithTouch) { + + if(touchAreaIndex == ENTER_ENGINEERS_LOCK_CODE) { + + NumericKeypadPageHandler* numericKeypadPageHandler = NumericKeypadPageHandler::GetInstance(usbDevice, usbHostGC); + if(numericKeypadPageHandler != NULL) { + numericKeypadPageHandler->StartEditingInLockMode(842, GuiStruct_ServicingHomePage_Def, GuiVar_engineersLockCodeMessage, "Invalid lock code"); + numericKeypadPageHandler->SetEasyGUICallingPage(GuiStruct_EngineersLockPage_Def); + numericKeypadPageHandler->SetEditVariableRange(0, 32767); + numericKeypadPageHandler->SetEditVariableName("Lock Code"); + numericKeypadPageHandler->DisplayEasyGUIPage(); + } + + dealtWithTouch = true; + } + } + + if(!dealtWithTouch) { + + if((touchAreaIndex == DOOR_ACTUATOR_AREA_1) || (touchAreaIndex == DOOR_ACTUATOR_AREA_2)) { + DealWithDoorActuatorButtons(touchAreaIndex, usbDevice, usbHostGC); + + dealtWithTouch = true; + } + } // Open door + + if(!dealtWithTouch) { + NetworkParameters *networkParameters = NetworkParameters::GetInstance(usbDevice, usbHostGC); + + if(networkParameters != NULL) { + + if(networkParameters->TouchAreaIsNetworkParameter(touchAreaIndex)) { + + networkParameters->DealWithTouch(touchAreaIndex); + + dealtWithTouch = true; + } + } + } // Network parameter + +#define USE_GAS_CALIBRATION_PAGE_HANDLER +#ifdef USE_GAS_CALIBRATION_PAGE_HANDLER + if(!dealtWithTouch) { + GasCalibrationPageHandler *gasCalibrationPageHandler = GasCalibrationPageHandler::GetInstance(usbDevice, usbHostGC); + + if(gasCalibrationPageHandler != NULL) { + + if(gasCalibrationPageHandler->TouchAreaIsOnCalibrationPage(touchAreaIndex)) { + + dealtWithTouch = gasCalibrationPageHandler->DealWithTouch(touchAreaIndex); + } + } + } // Touch area on Gas Calibration page +#undef USE_GAS_CALIBRATION_PAGE_HANDLER +#endif // USE_GAS_CALIBRATION_PAGE_HANDLER + + if(!dealtWithTouch) { + ColumnDHAutoCalibrationPageHandler *columnDHAutoCalibrationPageHandler = ColumnDHAutoCalibrationPageHandler::GetInstance(usbDevice, usbHostGC); + + if(columnDHAutoCalibrationPageHandler != NULL) { + + if(columnDHAutoCalibrationPageHandler->TouchAreaIsOnCalibrationPage(touchAreaIndex)) { + + dealtWithTouch = columnDHAutoCalibrationPageHandler->DealWithTouch(touchAreaIndex); + } + } + } // Touch area on DH Column Auto Calibration page + + if(!dealtWithTouch) { + ColumnDHManualCalibrationPageHandler *columnDHManualCalibrationPageHandler = ColumnDHManualCalibrationPageHandler::GetInstance(usbDevice, usbHostGC); + + if(columnDHManualCalibrationPageHandler != NULL) { + + if(columnDHManualCalibrationPageHandler->TouchAreaIsOnCalibrationPage(touchAreaIndex)) { + + dealtWithTouch = columnDHManualCalibrationPageHandler->DealWithTouch(touchAreaIndex); + } + } + } // Touch area on DH Column Manual Calibration page + + if(!dealtWithTouch) { + ColumnDHSensorCalibrationPageHandler *columnDHSensorCalibrationPageHandler = ColumnDHSensorCalibrationPageHandler::GetInstance(usbDevice, usbHostGC); + + if(columnDHSensorCalibrationPageHandler != NULL) { + + if(columnDHSensorCalibrationPageHandler->TouchAreaIsOnCalibrationPage(touchAreaIndex)) { + + dealtWithTouch = columnDHSensorCalibrationPageHandler->DealWithTouch(touchAreaIndex); + } + } + } // Touch area on DH Column Sensor Calibration page + + if(!dealtWithTouch) { + ColumnDHPSUDACPageHandler *columnDHPSUDACPageHandler = ColumnDHPSUDACPageHandler::GetInstance(usbDevice, usbHostGC); + + if(columnDHPSUDACPageHandler != NULL) { + + if(columnDHPSUDACPageHandler->TouchAreaIsOnPSUDACPage(touchAreaIndex)) { + + dealtWithTouch = columnDHPSUDACPageHandler->DealWithTouch(touchAreaIndex); + } + } + } // Touch area on DH PSU DAC page + + if(!dealtWithTouch) { + NudgeAndDampPageHandler *nudgeAndDampPageHandler = NudgeAndDampPageHandler::GetInstance(usbDevice, usbHostGC); + + if(nudgeAndDampPageHandler != NULL) { + + if(nudgeAndDampPageHandler->TouchAreaIsOnNudgeAndDampPage(touchAreaIndex)) { + + dealtWithTouch = nudgeAndDampPageHandler->DealWithTouch(touchAreaIndex); + } + } + } // Touch area on one of the Nudge and Damp pages + + if(!dealtWithTouch) { + DebugCommandsPageHandler *debugCommandsPageHandler = DebugCommandsPageHandler::GetInstance(usbDevice, usbHostGC); + + if(debugCommandsPageHandler != NULL) { + + if(debugCommandsPageHandler->TouchAreaIsOnDebugCommandsPage(touchAreaIndex)) { + + dealtWithTouch = debugCommandsPageHandler->DealWithTouch(touchAreaIndex); + } + } + } // Touch area on the GC (Debug) Commands page + + if(!dealtWithTouch) { // Try Column Oven Fan page - no 'PageHandler' class for this - + // trivial - only two touch areas/buttons, each of which simply sends + // a command (without arguments) to the GC - no values displayed + if(touchAreaIndex == COLUMN_OVEN_FAN_NORMAL) { + ExecuteGCCommand("CFNO",usbDevice, usbHostGC); + dealtWithTouch = true; + } else if(touchAreaIndex == COLUMN_OVEN_FAN_COOLING) { + ExecuteGCCommand("CFCO",usbDevice, usbHostGC); + dealtWithTouch = true; + } + } + + if(!dealtWithTouch) { + GasBackPressureDACPageHandler *gasBackPressureDACPageHandler = GasBackPressureDACPageHandler::GetInstance(usbDevice, usbHostGC); + + if(gasBackPressureDACPageHandler != NULL) { + + if(gasBackPressureDACPageHandler->TouchAreaIsOnGasBackPressureDACPage(touchAreaIndex)) { + + dealtWithTouch = gasBackPressureDACPageHandler->DealWithTouch(touchAreaIndex); + } + } + } // Touch area on Gas Backpressure DAC page + + if(!dealtWithTouch) { + GasChannelDACAndADCPageHandler *gasChannelDACAndADCPageHandler = GasChannelDACAndADCPageHandler::GetInstance(usbDevice, usbHostGC); + + if(gasChannelDACAndADCPageHandler != NULL) { + + if(gasChannelDACAndADCPageHandler->TouchAreaIsOnGasChannelDACAndADCPage(touchAreaIndex)) { + + dealtWithTouch = gasChannelDACAndADCPageHandler->DealWithTouch(touchAreaIndex); + } + } + } // Touch area on Gas channel DAC and ADC page + + if(!dealtWithTouch) { + NumericKeypadPageHandler *numericKeypadPageHandler = NumericKeypadPageHandler::GetInstance(usbDevice, usbHostGC); + + if(numericKeypadPageHandler != NULL) { + + if(numericKeypadPageHandler->TouchAreaIsOnNumericKeypadPage(touchAreaIndex)) { + + dealtWithTouch = numericKeypadPageHandler->DealWithTouch(touchAreaIndex); + } + } + } // Touch area on numeric keypad page + + if(!dealtWithTouch) { + EthernetKeypadPageHandler *ethernetKeypadPageHandler = EthernetKeypadPageHandler::GetInstance(usbDevice, usbHostGC); + + if(ethernetKeypadPageHandler != NULL) { + + if(ethernetKeypadPageHandler->TouchAreaIsOnEthernetKeypadPage(touchAreaIndex)) { + + dealtWithTouch = ethernetKeypadPageHandler->DealWithTouch(touchAreaIndex); + } + } + } // Touch area on numeric keypad page + + if(!dealtWithTouch) { + + DetectorIgnitionHandler *detectorIgnitionHandler = DetectorIgnitionHandler::GetInstance(usbDevice, usbHostGC); + + if(detectorIgnitionHandler != NULL) { + + if(detectorIgnitionHandler->TouchAreaIsDetectorIgniteButton(touchAreaIndex)) { + + dealtWithTouch = detectorIgnitionHandler->DealWithTouch(touchAreaIndex); + } + } + } // Handling detector ignition + + if(!dealtWithTouch) { +#ifdef SERVICE_INTERVALS_ACTIVE + if(ServiceInterval::IsServicedTouchArea(touchAreaIndex)) { + + ServiceInterval::DealWithServicedTouchArea(touchAreaIndex); + + // This is a ServiceInterval touch area - + // nothing else can deal with it, + // whether we actually did anything or not + dealtWithTouch = true; + } +#endif // SERVICE_INTERVALS_ACTIVE + } // Service interval } } -void SetupUSBGCTouchListener(DMBoard* board, USBDeviceConnected* usbDevice, USBHostGC* usbHostGC) -{ - // Note that TouchListener is a singleton - we do not need or want there to be more than one instance of it - // (there is only one board, and only one touch panel) - mainTouchListener = TouchListener::GetInstance(board->touchPanel(), usbDevice, usbHostGC); + +/* + Waits (indefinitely) for a USB device to be connected - + note that, if there is no USB device, we will hang at this point - + there is no timeout. - if(mainTouchListener != NULL) { - mainTouchListener->SetTouchCallbackFunction(&TouchCallback); + Args are: a pointer to the USBHost instance on which we are to look for the USB device + + Returns a pointer to the USB device +*/ +USBDeviceConnected* GetUSBDevice(USBHost* usbHost) +{ + USBDeviceConnected* usbDevice = NULL; -// Not yet... -// mainTouchListener->SetTouchReleasedCallbackFunction(&TouchReleasedCallback); -// -// mainTouchListener->SetTimerOneSecondCallbackFunction(&TimerOneSecondCallback); + while(usbDevice == NULL) { + for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; ++i) { + usbDevice = usbHost->getDevice(i); + + if (usbDevice) { + return usbDevice; + } + } } + + return NULL; } - -int main() +/* + Function that executes the easyGUI code in VarInit.c, to initialise all the easyGUI variables + to the values we have specified in the easyGUI application. +*/ +static void InitialiseAllEasyGUIVariables(void) { - DMBoard::BoardError err; - DMBoard* board = &DMBoard::instance(); - RtosLog* log = board->logger(); - Display* disp = board->display(); - - do { - err = board->init(); - if (err != DMBoard::Ok) { - log->printf("Failed to initialize the board, got error %d\r\n", err); - break; - } - - log->printf("\n\nHello World!\n\n"); +#include "VarInit.h" // Renamed from the easyGUI file "VarInit.c", so as not to confuse the mbed compiler +} - void* fb = disp->allocateFramebuffer(); - if (fb == NULL) { - log->printf("Failed to allocate memory for a frame buffer\r\n"); - err = DMBoard::MemoryError; - break; - } - - -// Display::DisplayError disperr = disp->powerUp(fb, Display::Resolution_24bit_rgb888); - // Start display in default mode (16-bit) (24-bit uses too much memory) - Display::DisplayError disperr = disp->powerUp(fb); - if (disperr != Display::DisplayError_Ok) { - log->printf("Failed to initialize the display, got error %d\r\n", disperr); - break; - } - - } while(false); + +/* + Sets up the easyGUI user interface in an acceptable initial state. - if (err != DMBoard::Ok) { - log->printf("\nTERMINATING\n"); - wait_ms(2000); // allow RtosLog to flush messages - mbed_die(); - } - - - // easyGUI stuff - note function calls require 'extern "C"' in relevant header + No return code. +*/ +void InitEasyGUIDisplay(int initialEasyGUIPage) +{ + // easyGUI stuff - note function calls require 'extern "C"' in relevant header // Need to set up heat on/off command easyGUI variable // before we display the home page for the first time - // but we do not have a heat control object at this point - // default to 'Heat On' strcpy(GuiVar_heatOnOffCommand, "Heat On"); +#ifdef USE_HEAT_ONOFF_BUTTON_BITMAPS + DrawHeatOnOffButton(); +#endif GuiDisplay_Lock(); GuiLib_Init(); - GuiLib_Refresh(); - - DisplayEasyGuiStructure(GuiStruct_HomePage_1, NULL, NULL); - - GuiLib_Refresh(); + DisplayEasyGuiStructure(initialEasyGUIPage, NULL, NULL); GuiDisplay_Unlock(); + +#ifdef USE_QSPI_BITMAPS + qspiBitmaps.SetupArray(); +#endif +} + +void InitialiseLPC4088(DMBoard* board, void **frameBufferAddress1, void **frameBufferAddress2) +{ + RtosLog* log = board->logger(); + Display* disp = board->display(); + DMBoard::BoardError err; + + do { + err = board->init(); + if (err != DMBoard::Ok) { + log->printf("Failed to initialize the board, got error %d\r\n", err); + break; + } + +#ifdef MEMORY_TEST_OCT_2016 + for (int ind = 0; ind < clogLength; ++ind) { + clogUpMemory[ind] = 'A'; + } +#endif // MEMORY_TEST_OCT_2016 + + +#define COLOR_FLICKERING_FIX_1 +#ifdef COLOR_FLICKERING_FIX_1 + // Possible fix for display flickering on LPC4088 + uint32_t* reg = ((uint32_t*)0x400fc188); + *reg |= (3<<10); +#undef COLOR_FLICKERING_FIX_1 +#endif + log->printf("\n\nHello World!\n\n"); + + void* fb = disp->allocateFramebuffer(); + if (fb == NULL) { + log->printf("Failed to allocate memory for a frame buffer\r\n"); + err = DMBoard::MemoryError; + break; + } + + *frameBufferAddress1 = fb; + + // Allocate a second frame buffer - what will its address be? + void* fb2 = disp->allocateFramebuffer(); + *frameBufferAddress2 = fb2; + + Display::DisplayError disperr; +// disperr = disp->powerUp(fb, Display::Resolution_24bit_rgb888); + // Start display in default mode (16-bit) (24-bit uses too much memory) +#define COLOR_FLICKERING_FIX_2 +#ifdef COLOR_FLICKERING_FIX_2 + // Second possible fix for colour flickering problem, + // suggested by Embedded Artists - specify low frame rate + disp->powerDown(); + disperr = disp->powerUp(fb, Display::Resolution_16bit_rgb565, FrameRate_Low); +#undef COLOR_FLICKERING_FIX_2 +#else + disperr = disp->powerUp(fb); +#endif + if (disperr != Display::DisplayError_Ok) { + log->printf("Failed to initialize the display, got error %d\r\n", disperr); + break; + } + + } while(false); + + if (err != DMBoard::Ok) { + log->printf("\nTERMINATING\n"); + wait_ms(2000); // allow RtosLog to flush messages + mbed_die(); + } +} + +int main() +{ + DMBoard* board = &DMBoard::instance(); + void *frameBuffer1; + void *frameBuffer2; + InitialiseLPC4088(board, &frameBuffer1, &frameBuffer2); + GuiDisplay_SetFrameAddress(frameBuffer1); + + SwimDraw* swimDrawInstance = SwimDraw::GetInstance(); + if(swimDrawInstance != NULL) { + swimDrawInstance->Initialise(board, frameBuffer1); + } + + InitialiseAllEasyGUIVariables(); + + // The first thing we do is try to connect to the GC - + // so tell the user this first of all... + InitEasyGUIDisplay(GuiStruct_GCConnectionPage_Def); + + + SetupEasyGUIBuildDateVariable(); + + + char dbgBuff[100]; + sprintf(dbgBuff, "FrameBuffers are: %X, %X", frameBuffer1, frameBuffer2); + EasyGUIDebugPrint(dbgBuff, 100, 100); // Now the USB 'stuff' USBHost* usbHost = USBHost::getHostInst(); - USBDeviceConnected* usbDevice; USBHostGC usbHostGC; - usbDevice = NULL; - DrawErrorMessage("Waiting for USB device..."); - - // Wait (indefinitely) for a USB device to be connected - - // note that, if there is no USB device, we will hang at this point - - // there is no timeout - while(usbDevice == NULL) { - for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; ++i) { - usbDevice = usbHost->getDevice(i); - - if (usbDevice) { - break; - } - } - } + // Note that 'GetUSBDevice' will not return until it finds a USB device - + // it does *not* timeout + USBDeviceConnected* usbDevice = GetUSBDevice(usbHost); DrawErrorMessage(" "); @@ -558,10 +2408,11 @@ DrawErrorMessage("Found GC device "); +#ifdef OLD_TOUCH_LISTENER SetupUSBGCTouchListener(board, usbDevice, &usbHostGC); DrawErrorMessage("After call to SetupUSBGCTouchListener "); - +#endif getGCStatusLoop = GetGCStatusLoop::GetInstance(usbDevice, &usbHostGC); @@ -570,32 +2421,49 @@ theGCHeatControl = new GCHeatControl(usbDevice, &usbHostGC); +#ifdef USE_HEAT_ONOFF_BUTTON_BITMAPS + DrawHeatOnOffButton(); +#else UpdateHeatOnOffEasyGuiVariable(); - +#endif // USE_HEAT_ONOFF_BUTTON_BITMAPS + DrawErrorMessage("After UpdateHeatOnOffEasyGuiVariable "); - - //theEthernetTimerHandler = EthernetTimerHandler::GetInstance(usbDevice, &usbHostGC); - - + getGCStatusLoop->SetHomePageGCComponentStatusColorAreas(&homePageGCComponentStatusColorAreas); getGCStatusLoop->SetSingleGCComponentPageStatusColorAreas(&singleGCComponentPageStatusColorAreas); DrawErrorMessage("Point 1 "); +#ifdef SERVICE_INTERVALS_ACTIVE + ServiceInterval::SetupAllServiceIntervals(); + // Note these two functions *** have different names *** + ServiceInterval::StartAllServiceIntervals(); +#endif // SERVICE_INTERVALS_ACTIVE + + DrawErrorMessage("Point 2 "); + getGCStatusLoop->SetupAllEasyGUIVariables(); - - DrawErrorMessage("Point 2 "); + SetupDoorActuatorCommandUserInterface(usbDevice, &usbHostGC, true); + + DrawErrorMessage("Point 3 "); +#ifdef USE_QSPI_BITMAPS + getGCStatusLoop->SetQSPIBitmaps(&qspiBitmaps); +// Test - what does it do if it cannot find the bitmaps?? +#endif + DrawErrorMessage("Point 4 "); getGCStatusLoop->SetCurrentPage(GuiStruct_HomePage_1); - DrawErrorMessage("Point 3 "); + DrawErrorMessage("Point 5 "); - DisplayEasyGuiStructure(GuiStruct_HomePage_1, usbDevice, &usbHostGC); - - // Currently, this never returns - but it allows time for the TouchCallback function to be invoked - //getGCStatusLoop->MainLoop(); - getGCStatusLoop->MainLoopWithEthernet(); + //DisplayEasyGuiStructure(GuiStruct_HomePage_1, usbDevice, &usbHostGC); + + DebugPrint("Before MainLoopWithEthernet", 100, 450); + + // Currently, this never returns - but it allows time for the TouchCallback function to be invoked + //getGCStatusLoop->MainLoop(board); + getGCStatusLoop->MainLoopWithEthernet(board); // Should never reach this code - but just in case... delete theGCHeatControl;