Repository for import to local machine
Dependencies: DMBasicGUI DMSupport
GetGCStatusLoop.cpp
- Committer:
- jmitc91516
- Date:
- 2016-01-13
- Revision:
- 0:47c880c1463d
- Child:
- 1:a5258871b33d
File content as of revision 0:47c880c1463d:
#include "mbed.h" #include "DMBoard.h" #include <string.h> #include "EthernetInterface.h" #include "GetGCStatusLoop.h" #include "GCStateAndFaultCodes.h" #include "GuiLib.h" extern void EasyGUIDebugPrint(char *stuffToPrint, short X, short Y); extern GuiConst_INTCOLOR SixteenBitColorValue(GuiConst_INT8U red, GuiConst_INT8U green, GuiConst_INT8U blue); extern void DrawRunButton(bool enabled); // Note that GetGCStatusLoop is a singleton - we do not need or want there to be more than one instance of it // (there is only one GC, and only one LPC4088) GetGCStatusLoop * GetGCStatusLoop::theGetGCStatusLoop = NULL; const int GetGCStatusLoop::waitTimeMs = 1000; #define USE_THREAD_WAIT // TODO: Make these values dynamic somehow - currently will work on only one system (obviously) const int GetGCStatusLoop::ethernetPort = 3456; const char* GetGCStatusLoop::ethernetIP = "192.168.2.2"; const char* GetGCStatusLoop::ethernetMask = "255.255.255.0"; const char* GetGCStatusLoop::ethernetGateway = "0.0.0.0"; GCStateAndFaultCodes gcStateAndFaultCodes; // Singleton class - return the one and only instance, first creating it if necessary GetGCStatusLoop *GetGCStatusLoop::GetInstance(USBDeviceConnected* newUsbDevice, USBHostGC* newUsbHostGC) { if (theGetGCStatusLoop == NULL) { theGetGCStatusLoop = new GetGCStatusLoop(newUsbDevice, newUsbHostGC); } return theGetGCStatusLoop; } // Singleton class - private constructor GetGCStatusLoop::GetGCStatusLoop(USBDeviceConnected* newUsbDevice, USBHostGC* newUsbHostGC) { usbDevice = newUsbDevice; usbHostGC = newUsbHostGC; currentPage = 9999; // Impossible value pageJustChanged = false; displayingData = false; gcInStandbyMode = false; homePageGCComponentStatusColorAreas = NULL; singleGCComponentPageStatusColorAreas = NULL; } GetGCStatusLoop::~GetGCStatusLoop() { } GuiConst_INT16U GetGCStatusLoop::GetCurrentPage(void) { return currentPage; } void GetGCStatusLoop::SetCurrentPage(GuiConst_INT16U newCurrentPage) { if(currentPage != newCurrentPage) { currentPage = newCurrentPage; pageJustChanged = true; // Try this - can it prevent crashes on updating? // Stop the status rectangles flashing when we display these pages/structures if((currentPage != GuiStruct_HomePage_1) && (currentPage != GuiStruct_ColumnPage1_2) && (currentPage != GuiStruct_InjectorPage1_3) && (currentPage != GuiStruct_DetectorPage1_4) && (currentPage != GuiStruct_GasPage1_6)) { DisplayCurrentPageData(true); } } } void GetGCStatusLoop::SetHomePageGCComponentStatusColorAreas(HomePageGCComponentStatusColorAreas* newColorAreas) { homePageGCComponentStatusColorAreas = newColorAreas; UpdateHomePageGCComponentStatusColorAreas(); } void GetGCStatusLoop::SetSingleGCComponentPageStatusColorAreas(SingleGCComponentPageStatusColorAreas* newColorAreas) { singleGCComponentPageStatusColorAreas = newColorAreas; UpdateSingleGCComponentPageStatusColorArea(COLUMN); UpdateSingleGCComponentPageStatusColorArea(INJECTOR); UpdateSingleGCComponentPageStatusColorArea(DETECTOR); UpdateSingleGCComponentPageStatusColorArea(GAS); } void GetGCStatusLoop::DisplayText(char *text, short X, short Y) { const GuiConst_INT16U fontNo = GuiFont_Helv1; GuiLib_DrawStr( X, //GuiConst_INT16S X, Y, //GuiConst_INT16S Y, fontNo, //GuiConst_INT16U FontNo, text, //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, 0, //GuiConst_INTCOLOR ForeColor, 0xFFFF //GuiConst_INTCOLOR BackColor ); } void GetGCStatusLoop::SetGCDeviceReport(char *cmd, char *response) { // Guard against simultaneous calls to usbHostGC->SetDeviceReport - // it is not re-entrant (and nor is the GC) while(usbHostGC->ExecutingSetDeviceReport()) {} usbHostGC->SetDeviceReport(usbDevice, cmd, response); } int GetGCStatusLoop::GetGCStatusOrFaultCode(char *cmd) { char response[GC_MESSAGE_LENGTH+2]; SetGCDeviceReport(cmd, response); int gcStatusCode; // We expect a response of the form "Dxxx00nn", where the two digits 'nn' are the status code // But check for "EPKT" first... if(response[0] == 'E') { gcStatusCode = -1; // *** Caller must check for this *** } else { sscanf(&response[6], "%d", &gcStatusCode); } return gcStatusCode; } int GetGCStatusLoop::GetGCStatus(void) { return GetGCStatusOrFaultCode("QSTA"); } int GetGCStatusLoop::GetGCFaultCode(void) { return GetGCStatusOrFaultCode("QFLT"); } void GetGCStatusLoop::GetGCStateAsInfoString(int gcStateCode, int gcFaultCode, char *statusString) { char buff[100]; if(gcStateCode == 99) { // GC is in fault state if(gcStateAndFaultCodes.GetFaultCodeString(gcFaultCode, buff)) { sprintf(statusString, "GC faulted: %s", buff); } else { sprintf(statusString, "GC faulted: unknown fault code %d", gcFaultCode); } } else { if(gcStateAndFaultCodes.GetStateCodeString(gcStateCode, buff)) { sprintf(statusString, "GC state: %s", buff); } else { sprintf(statusString, "GC state: unknown state code %d", gcStateCode); } } } bool GetGCStatusLoop::GCHasFaulted(char* statusString) { bool gcHasFaulted = false; statusString[0] = '\0'; int gcStatus = GetGCStatus(); if(gcStatus == -1) { // Got "EPKT" as response from GC strcpy(statusString, "Failed to get status"); gcHasFaulted = true; } else { int gcFaultCode = 0; if(gcStatus == 99) { gcFaultCode = GetGCFaultCode(); if(gcFaultCode != 0) { gcHasFaulted = true; } } GetGCStateAsInfoString(gcStatus, gcFaultCode, statusString); } return gcHasFaulted; } void GetGCStatusLoop::GetComponentTemperature(char *cmd, char *temp) { char response[50]; SetGCDeviceReport(cmd, response); // We expect a response like this: "Dxxx1234" - temp in units of 0.1 deg temp[0] = 'T'; temp[1] = 'e'; temp[2] = 'm'; temp[3] = 'p'; temp[4] = ':'; temp[5] = ' '; // But check for "EPKT" first if(response[0] == 'E') { temp[6] = '*'; temp[7] = '*'; temp[8] = ' '; temp[9] = 'E'; temp[10] = 'r'; temp[11] = 'r'; temp[12] = 'o'; temp[13] = 'r'; temp[14] = ' '; temp[15] = '*'; temp[16] = '*'; temp[17] = '\0'; } else { temp[6] = response[4]; temp[7] = response[5]; temp[8] = response[6]; temp[9] = '.'; temp[10] = response[7]; temp[11] = '\0'; } } void GetGCStatusLoop::GetComponentTemperature(char *cmd, float *temp) { char buff[100]; GetComponentTemperature(cmd, buff); // Allow for "EPKT" being returned from GC - see above if(buff[9] == 'E') { *temp = -1.0f; // ** Caller must check for this ** } else { sscanf(&buff[6], "%f", temp); } //#define DEBUG_HERE #ifdef DEBUG_HERE char dbg[100]; sprintf(dbg, "GGCSL::GCT - returning : %f", *temp); EasyGUIDebugPrint(dbg, 100, 100); #endif //#undef DEBUG_HERE } void GetGCStatusLoop::GetColumnTemperature(char *temp) { GetComponentTemperature("QCOL", temp); } void GetGCStatusLoop::GetColumnTemperature(float *temp) { GetComponentTemperature("QCOL", temp); } void GetGCStatusLoop::GetDetectorTemperature(char *temp) { GetComponentTemperature("QDET", temp); } void GetGCStatusLoop::GetDetectorTemperature(float *temp) { GetComponentTemperature("QDET", temp); } void GetGCStatusLoop::GetInjectorTemperature(char *temp) { GetComponentTemperature("QINJ", temp); } void GetGCStatusLoop::GetInjectorTemperature(float *temp) { GetComponentTemperature("QINJ", temp); } void GetGCStatusLoop::GetGasPressure(char *press) { char response[50]; SetGCDeviceReport("QPRS", response); // We expect a response like this: "DPRS1234" - pressure in units of 0.1 psi press[0] = 'P'; press[1] = 'r'; press[2] = 'e'; press[3] = 's'; press[4] = 's'; press[5] = 'u'; press[6] = 'r'; press[7] = 'e'; press[8] = ':'; press[9] = ' '; // But check for "EPKT" first if(response[0] == 'E') { press[10] = '*'; press[11] = '*'; press[12] = ' '; press[13] = 'E'; press[14] = 'r'; press[15] = 'r'; press[16] = 'o'; press[17] = 'r'; press[18] = ' '; press[19] = '*'; press[20] = '*'; press[21] = '\0'; } else { press[10] = response[4]; press[11] = response[5]; press[12] = response[6]; press[13] = '.'; press[14] = response[7]; press[15] = '\0'; } } void GetGCStatusLoop::GetGasPressure(float *press) { char buff[100]; GetGasPressure(buff); // Allow for "EPKT" being returned from GC - see above if(buff[13] == 'E') { *press = -1.0f; // ** Caller must check for this ** } else { sscanf(&buff[10], "%f", press); } //#define DEBUG_HERE #ifdef DEBUG_HERE char dbg[100]; sprintf(dbg, "GGCSL::GGP - returning : %f", *press); EasyGUIDebugPrint(dbg, 100, 100); #endif //#undef DEBUG_HERE } void GetGCStatusLoop::DisplayHomePageData(bool mustUpdateDisplay) { // EasyGUIDebugPrint("Home Page", 100, 100); char buff[40]; GetColumnTemperature(buff); if(strcmp(buff, GuiVar_columnTemperature2) != 0) { mustUpdateDisplay = true; strcpy(GuiVar_columnTemperature2, buff); } GetDetectorTemperature(buff); if(strcmp(buff, GuiVar_detectorTemperature2) != 0) { mustUpdateDisplay = true; strcpy(GuiVar_detectorTemperature2, buff); } GetInjectorTemperature(buff); if(strcmp(buff, GuiVar_injectorTemperature2) != 0) { mustUpdateDisplay = true; strcpy(GuiVar_injectorTemperature2, buff); } GetGasPressure(buff); if(strcmp(buff, GuiVar_gasPressure2) != 0) { mustUpdateDisplay = true; strcpy(GuiVar_gasPressure2, buff); } if(mustUpdateDisplay) { // Updating the color areas involves getting the component statuses from the GC - // do this before GuiLib_Clear, otherwise the display stays blank for an annoyingly long time if(homePageGCComponentStatusColorAreas != NULL) { UpdateHomePageGCComponentStatusColorAreas(); } // Also get the run ready state before GuiLib_Clear, for the same reason bool gcIsReadyToRun = (GetGCStatus() == 33); // Makes the display flicker - but omitting it means old text is not cleared from the display //#define WANT_GUILIB_CLEAR #ifdef WANT_GUILIB_CLEAR GuiLib_Clear(); #undef WANT_GUILIB_CLEAR #endif //...except that redrawing the status rectangles effectively clears the text on top of the rectangles - // so we do not need GuiLib_Clear - so only the text flickers, not the rectangles // 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. // (But note that we get the component statuses before GuiLib_Clear above.) if(homePageGCComponentStatusColorAreas != NULL) { homePageGCComponentStatusColorAreas->DisplayAll(); } GuiLib_ShowScreen(GuiStruct_HomePage_1, GuiLib_NO_CURSOR, GuiLib_RESET_AUTO_REDRAW); // ...but we draw the run button on top of the structure DrawRunButton(gcIsReadyToRun); GuiLib_Refresh(); #define DEBUG_HERE #ifdef DEBUG_HERE static int counter = 0; char dbg[100]; sprintf(dbg, "After GuiLib_Clear 1 [%d]", ++counter); EasyGUIDebugPrint(dbg, 100, 100); #undef DEBUG_HERE #endif } } void GetGCStatusLoop::GetColumnMaxTemperature(char *maxTemp, bool wantFullPrefix) { char response[50]; SetGCDeviceReport("QCMX", response); // We expect a response like this: "DCMX1234" - max temp in units of 0.1 deg int index = 0; if(wantFullPrefix) { maxTemp[index++] = 'C'; maxTemp[index++] = 'o'; maxTemp[index++] = 'l'; maxTemp[index++] = 'u'; maxTemp[index++] = 'm'; maxTemp[index++] = 'n'; maxTemp[index++] = ' '; maxTemp[index++] = 'm'; } else { maxTemp[index++] = 'M'; } maxTemp[index++] = 'a'; maxTemp[index++] = 'x'; maxTemp[index++] = ' '; maxTemp[index++] = 't'; maxTemp[index++] = 'e'; maxTemp[index++] = 'm'; maxTemp[index++] = 'p'; maxTemp[index++] = ':'; maxTemp[index++] = ' '; // But check for "EPKT" first if(response[0] == 'E') { maxTemp[index++] = '*'; maxTemp[index++] = '*'; maxTemp[index++] = ' '; maxTemp[index++] = 'E'; maxTemp[index++] = 'r'; maxTemp[index++] = 'r'; maxTemp[index++] = 'o'; maxTemp[index++] = 'r'; maxTemp[index++] = ' '; maxTemp[index++] = '*'; maxTemp[index++] = '*'; maxTemp[index++] = '\0'; } else { maxTemp[index++] = response[4]; maxTemp[index++] = response[5]; maxTemp[index++] = response[6]; maxTemp[index++] = '.'; maxTemp[index++] = response[7]; maxTemp[index++] = '\0'; } } void GetGCStatusLoop::GetColumnMaxTemperature(float *maxTemp) { char response[50]; SetGCDeviceReport("QCMX", response); // Check for "EPKT" first if(response[0] == 'E') { *maxTemp = 0.0; } else { char buff[100]; buff[0] = response[4]; buff[1] = response[5]; buff[2] = response[6]; buff[3] = '.'; buff[4] = response[7]; buff[5] = '\0'; sscanf(buff, "%f", maxTemp); } //#define DEBUG_HERE #ifdef DEBUG_HERE char dbg[100]; sprintf(dbg, "GGCSL::GCMTT - returning : %f", *maxTemp); EasyGUIDebugPrint(dbg, 100, 100); #endif //#undef DEBUG_HERE } void GetGCStatusLoop::DisplayColumnPageData(bool mustUpdateDisplay) { // EasyGUIDebugPrint("Column Page", 100, 100); // Column temperature and maximum temperature char buff[40]; GetColumnTemperature(buff); if(strcmp(buff, GuiVar_columnTemperature) != 0) { mustUpdateDisplay = true; strcpy(GuiVar_columnTemperature, buff); } GetColumnMaxTemperature(buff, false); if(strcmp(buff, GuiVar_columnMaxTemp2) != 0) { mustUpdateDisplay = true; strcpy(GuiVar_columnMaxTemp2, buff); } if(mustUpdateDisplay) { // Reduce display flickering - get the component status from the GC // *before* we call GuiLib_Clear() if(singleGCComponentPageStatusColorAreas != NULL) { UpdateSingleGCComponentPageStatusColorArea(COLUMN); } GuiLib_Clear(); // Makes the display flicker - but omitting it means old text is not cleared from the display // Note - we draw the status rectangle 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 if(singleGCComponentPageStatusColorAreas != NULL) { singleGCComponentPageStatusColorAreas->DisplayGCComponentStatus(COLUMN); } GuiLib_ShowScreen(GuiStruct_ColumnPage1_2, GuiLib_NO_CURSOR, GuiLib_RESET_AUTO_REDRAW); GuiLib_Refresh(); #define DEBUG_HERE #ifdef DEBUG_HERE char dbg[100]; sprintf(dbg, "After GuiLib_Clear 2"); EasyGUIDebugPrint(dbg, 100, 100); #undef DEBUG_HERE #endif } } void GetGCStatusLoop::GetInjectionMode(char *mode, bool wantFullPrefix) { char response[50]; SetGCDeviceReport("QIMD", response); // We expect a response like this: "DIMD0000" for split, "DIMD0001" for splitless int index = 0; if(wantFullPrefix) { mode[index++] = 'I'; mode[index++] = 'n'; mode[index++] = 'j'; mode[index++] = 'e'; mode[index++] = 'c'; mode[index++] = 't'; mode[index++] = 'i'; mode[index++] = 'o'; mode[index++] = 'n'; mode[index++] = ' '; mode[index++] = 'm'; } else { mode[index++] = 'M'; } mode[index++] = 'o'; mode[index++] = 'd'; mode[index++] = 'e'; mode[index++] = ':'; mode[index++] = ' '; // Check for "EPKT" first if(response[0] == 'E') { mode[index++] = '*'; mode[index++] = '*'; mode[index++] = ' '; mode[index++] = 'E'; mode[index++] = 'r'; mode[index++] = 'r'; mode[index++] = 'o'; mode[index++] = 'r'; mode[index++] = ' '; mode[index++] = '*'; mode[index++] = '*'; mode[index++] = '\0'; } else { mode[index++] = 'S'; mode[index++] = 'p'; mode[index++] = 'l'; mode[index++] = 'i'; mode[index++] = 't'; if(response[7] == '0') { mode[index++] = '\0'; } else { mode[index++] = 'l'; mode[index++] = 'e'; mode[index++] = 's'; mode[index++] = 's'; mode[index++] = '\0'; } } } void GetGCStatusLoop::DisplayInjectorPageData(bool mustUpdateDisplay) { // EasyGUIDebugPrint("Injector Page", 100, 100); // Injector temperature and mode char buff[40]; GetInjectorTemperature(buff); if(strcmp(buff, GuiVar_injectorTemperature) != 0) { mustUpdateDisplay = true; strcpy(GuiVar_injectorTemperature, buff); } GetInjectionMode(buff, false); if(strcmp(buff, GuiVar_injectionMode2) != 0) { mustUpdateDisplay = true; strcpy(GuiVar_injectionMode2, buff); } if(mustUpdateDisplay) { // Reduce display flickering - get the component status from the GC // *before* we call GuiLib_Clear() if(singleGCComponentPageStatusColorAreas != NULL) { UpdateSingleGCComponentPageStatusColorArea(INJECTOR); } // Makes the display flicker - but omitting it means old text is not cleared from the display GuiLib_Clear(); // Note - we draw the status rectangle 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 if(singleGCComponentPageStatusColorAreas != NULL) { singleGCComponentPageStatusColorAreas->DisplayGCComponentStatus(INJECTOR); } GuiLib_ShowScreen(GuiStruct_InjectorPage1_3, GuiLib_NO_CURSOR, GuiLib_RESET_AUTO_REDRAW); GuiLib_Refresh(); #define DEBUG_HERE #ifdef DEBUG_HERE char dbg[100]; sprintf(dbg, "After GuiLib_Clear 3"); EasyGUIDebugPrint(dbg, 100, 100); #undef DEBUG_HERE #endif } } void GetGCStatusLoop::GetDetectorType(char *type, bool wantFullPrefix) { char response[50]; SetGCDeviceReport("QDTY", response); // We expect a response like this: "DDTY0000" for FID, "DIMD0001" for TCD, // "DIMD0002" for ECD, "DIMD0003" for PID, "DIMD0004" for PDID, "DIMD0099" for None int index = 0; if(wantFullPrefix) { type[index++] = 'D'; type[index++] = 'e'; type[index++] = 't'; type[index++] = 'e'; type[index++] = 'c'; type[index++] = 't'; type[index++] = 'o'; type[index++] = 'r'; type[index++] = ' '; type[index++] = 't'; } else { type[index++] = 'T'; } type[index++] = 'y'; type[index++] = 'p'; type[index++] = 'e'; type[index++] = ':'; type[index++] = ' '; // Check for "EPKT" first if(response[0] == 'E') { type[index++] = '*'; type[index++] = '*'; type[index++] = ' '; type[index++] = 'E'; type[index++] = 'r'; type[index++] = 'r'; type[index++] = 'o'; type[index++] = 'r'; type[index++] = ' '; type[index++] = '*'; type[index++] = '*'; type[index++] = '\0'; } else { switch(response[7] ) { case '0': type[index++] = 'F'; type[index++] = 'I'; type[index++] = 'D'; type[index++] = '\0'; break; case '1': type[index++] = 'T'; type[index++] = 'C'; type[index++] = 'D'; type[index++] = '\0'; break; case '2': type[index++] = 'E'; type[index++] = 'C'; type[index++] = 'D'; type[index++] = '\0'; break; case '3': type[index++] = 'P'; type[index++] = 'I'; type[index++] = 'D'; type[index++] = '\0'; break; case '4': type[index++] = 'P'; type[index++] = 'D'; type[index++] = 'I'; type[index++] = 'D'; type[index++] = '\0'; break; default: type[index++] = 'N'; type[index++] = 'o'; type[index++] = 'n'; type[index++] = 'e'; type[index++] = '\0'; break; } } } void GetGCStatusLoop::DisplayDetectorPageData(bool mustUpdateDisplay) { // EasyGUIDebugPrint("Detector Page", 100, 100); // Detector temperature and type char buff[40]; GetDetectorTemperature(buff); if(strcmp(buff, GuiVar_detectorTemperature) != 0) { mustUpdateDisplay = true; strcpy(GuiVar_detectorTemperature, buff); } GetDetectorType(buff, false); if(strcmp(buff, GuiVar_detectorType2) != 0) { mustUpdateDisplay = true; strcpy(GuiVar_detectorType2, buff); } if(mustUpdateDisplay) { // Reduce display flickering - get the component status from the GC // *before* we call GuiLib_Clear() if(singleGCComponentPageStatusColorAreas != NULL) { UpdateSingleGCComponentPageStatusColorArea(DETECTOR); } // Makes the display flicker - but omitting it means old text is not cleared from the display GuiLib_Clear(); // Note - we draw the status rectangle 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 if(singleGCComponentPageStatusColorAreas != NULL) { singleGCComponentPageStatusColorAreas->DisplayGCComponentStatus(DETECTOR); } GuiLib_ShowScreen(GuiStruct_DetectorPage1_4, GuiLib_NO_CURSOR, GuiLib_RESET_AUTO_REDRAW); GuiLib_Refresh(); #define DEBUG_HERE #ifdef DEBUG_HERE char dbg[100]; sprintf(dbg, "After GuiLib_Clear 4"); EasyGUIDebugPrint(dbg, 100, 100); #undef DEBUG_HERE #endif } } bool GetGCStatusLoop::GetGasControlMode(char *mode, bool wantFullPrefix) { bool retval = true; // Return false only if we get "EPKT" from the GC char response[50]; SetGCDeviceReport("QGAS", response); // We expect a response like this: "DGAS0000" for Manual, "DGAS0001" for EPPC, or "EPKT" for error int index = 0; if(wantFullPrefix) { mode[index++] = 'G'; mode[index++] = 'a'; mode[index++] = 's'; mode[index++] = ' '; mode[index++] = 'c'; } else { mode[index++] = 'C'; } mode[index++] = 'o'; mode[index++] = 'n'; mode[index++] = 't'; mode[index++] = 'r'; mode[index++] = 'o'; mode[index++] = 'l'; mode[index++] = ' '; mode[index++] = 'm'; mode[index++] = 'o'; mode[index++] = 'd'; mode[index++] = 'e'; mode[index++] = ':'; mode[index++] = ' '; if(response[0] == 'E') { mode[index++] = '*'; mode[index++] = '*'; mode[index++] = ' '; mode[index++] = 'E'; mode[index++] = 'r'; mode[index++] = 'r'; mode[index++] = 'o'; mode[index++] = 'r'; mode[index++] = ' '; mode[index++] = '*'; mode[index++] = '*'; mode[index++] = '\0'; retval = false; } else { if(response[7] == '0') { mode[index++] = 'M'; mode[index++] = 'a'; mode[index++] = 'n'; mode[index++] = 'u'; mode[index++] = 'a'; mode[index++] = 'l'; mode[index++] = '\0'; } else { mode[index++] = 'E'; mode[index++] = 'P'; mode[index++] = 'P'; mode[index++] = 'C'; mode[index++] = '\0'; } } return retval; } void GetGCStatusLoop::DisplayGasPageData(bool mustUpdateDisplay) { //EasyGUIDebugPrint("Gas Page", 100, 100); // Gas pressure and control mode char buff[60]; GetGasPressure(buff); if(strcmp(buff, GuiVar_gasPressure) != 0) { mustUpdateDisplay = true; strcpy(GuiVar_gasPressure, buff); } GetGasControlMode(buff, true); if(strcmp(buff, GuiVar_gasControlMode2) != 0) { mustUpdateDisplay = true; strcpy(GuiVar_gasControlMode2, buff); } if(mustUpdateDisplay) { // Reduce display flickering - get the component status from the GC // *before* we call GuiLib_Clear() if(singleGCComponentPageStatusColorAreas != NULL) { UpdateSingleGCComponentPageStatusColorArea(GAS); } // Makes the display flicker - but omitting it means old text is not cleared from the display GuiLib_Clear(); // Note - we draw the status rectangle 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 if(singleGCComponentPageStatusColorAreas != NULL) { singleGCComponentPageStatusColorAreas->DisplayGCComponentStatus(GAS); } GuiLib_ShowScreen(GuiStruct_GasPage1_6, GuiLib_NO_CURSOR, GuiLib_RESET_AUTO_REDRAW); GuiLib_Refresh(); #define DEBUG_HERE #ifdef DEBUG_HERE char dbg[100]; sprintf(dbg, "After GuiLib_Clear 5"); EasyGUIDebugPrint(dbg, 100, 100); #undef DEBUG_HERE #endif } } void GetGCStatusLoop::DisplayRunningPageData(bool mustUpdateDisplay) { EasyGUIDebugPrint("Running Page", 100, 100); } void GetGCStatusLoop::DisplayRunningSettingsPageData(bool mustUpdateDisplay) { EasyGUIDebugPrint("Running Settings Page", 100, 100); } void GetGCStatusLoop::GetSoftwareVersion(char *version) { char response[50]; SetGCDeviceReport("QWHO", response); // We expect a response like this: "DWHO0320" -> version 3.20 version[0] = 'V'; version[1] = 'e'; version[2] = 'r'; version[3] = 's'; version[4] = 'i'; version[5] = 'o'; version[6] = 'n'; version[7] = ':'; version[8] = ' '; version[9] = response[4]; version[10] = response[5]; version[11] = '.'; version[12] = response[6]; version[13] = response[7]; version[14] = '\0'; } void GetGCStatusLoop::GetRunTime(char *time) { char response[50]; SetGCDeviceReport("QTIM", response); // We expect a response like this: "DTIM1234", with run time in units of 0.1 min time[0] = 'R'; time[1] = 'u'; time[2] = 'n'; time[3] = ' '; time[4] = 't'; time[5] = 'i'; time[6] = 'm'; time[7] = 'e'; time[8] = ':'; time[9] = ' '; time[10] = response[4]; time[11] = response[5]; time[12] = response[6]; time[13] = '.'; time[14] = response[7]; time[15] = '\0'; } void GetGCStatusLoop::DisplaySettingsPageData(bool mustUpdateDisplay) { //EasyGUIDebugPrint("Settings Page", 100, 100); // Various settings char buff[60]; GetSoftwareVersion(GuiVar_gcSoftwareVersion); // Assume software version cannot change while we are running GetGasControlMode(buff, true); if(strcmp(buff, GuiVar_gasControlMode) != 0) { mustUpdateDisplay = true; strcpy(GuiVar_gasControlMode, buff); } GetDetectorType(buff, true); if(strcmp(buff, GuiVar_detectorType) != 0) { mustUpdateDisplay = true; strcpy(GuiVar_detectorType, buff); } GetColumnMaxTemperature(buff, true); if(strcmp(buff, GuiVar_columnMaxTemp) != 0) { mustUpdateDisplay = true; strcpy(GuiVar_columnMaxTemp, buff); } GetInjectionMode(buff, true); if(strcmp(buff, GuiVar_injectionMode) != 0) { mustUpdateDisplay = true; strcpy(GuiVar_injectionMode, buff); } GetRunTime(buff); if(strcmp(buff, GuiVar_runTime) != 0) { mustUpdateDisplay = true; strcpy(GuiVar_runTime, buff); } if(mustUpdateDisplay) { // Makes the display flicker - but omitting it means old text is not cleared from the display GuiLib_Clear(); GuiLib_ShowScreen(GuiStruct_SettingsPage_5, GuiLib_NO_CURSOR, GuiLib_RESET_AUTO_REDRAW); GuiLib_Refresh(); #define DEBUG_HERE #ifdef DEBUG_HERE char dbg[100]; sprintf(dbg, "After GuiLib_Clear 6"); EasyGUIDebugPrint(dbg, 100, 100); #undef DEBUG_HERE #endif } } void GetGCStatusLoop::DisplayCurrentPageData(bool mustUpdateDisplay) { // We don't do re-entrancy here - can get random crashes // if the user switches between pages too quickly if(displayingData) { return; } displayingData = true; switch(currentPage) { case GuiStruct_HomePage_1: DisplayHomePageData(mustUpdateDisplay); break; case GuiStruct_ColumnPage1_2: DisplayColumnPageData(mustUpdateDisplay); break; case GuiStruct_InjectorPage1_3: DisplayInjectorPageData(mustUpdateDisplay); break; case GuiStruct_DetectorPage1_4: DisplayDetectorPageData(mustUpdateDisplay); break; case GuiStruct_GasPage1_6: DisplayGasPageData(mustUpdateDisplay); break; case GuiStruct_RunningPage_7: DisplayRunningPageData(mustUpdateDisplay); break; case GuiStruct_RunningSettings_8: DisplayRunningSettingsPageData(mustUpdateDisplay); break; case GuiStruct_SettingsPage_5: DisplaySettingsPageData(mustUpdateDisplay); break; default: // Page with no data (e.g. Gas Saver/Standby) - ignore break; } displayingData = false; } // This effectively duplicates the function of the same name in GCHeatControl - // it seems less complicated than calling GCHeatControl::IsHeatOn from here - // would need an instance of GCHeatControl in this class, etc - // why bother, since both would just call the same GC? bool GetGCStatusLoop::IsHeatOn(void) { char response[50]; SetGCDeviceReport("QHTS", response); // Check for "EPKT" first if(response[0] == 'E') return false; return (response[7] != '0'); } int GetGCStatusLoop::GetInstrumentStatus(void) { char response[50]; SetGCDeviceReport("QSTA", response); // We expect a response of the form "DSTA00nn", where 'nn' is a two-digit code representing the status. // We convert those two digits to an integer, and return the result to the user // But check for "EPKT" first if(response[0] == 'E') return 99; // Faulted int retval; sscanf(&response[6], "%d", &retval); //#define DEBUG_HERE #ifdef DEBUG_HERE char dbg[100]; sprintf(dbg, "GGCSL::GIS - returning : %d", retval); EasyGUIDebugPrint(dbg, 100, 100); #endif //#undef DEBUG_HERE return retval; } GCComponentStatus GetGCStatusLoop::GetComponentStatus(GCComponent component) { // Certain values for the overall instrument status override the status(es) of the individual components switch (GetInstrumentStatus()) { case 33: // Instrument is ready return READY; case 99: // Instrument has faulted somehow return FAULTED; default: break; // Fall through to code below... } char buff[100]; float temperature, maxTemperature; float pressure; switch (component) { case COLUMN: GetColumnTemperature(&temperature); if(temperature < 0.0f) {// Got "EPKT" response return FAULTED; } if(temperature < 0.1f) { // Allow for floating-point rounding errors return COLD; } GetColumnMaxTemperature(&maxTemperature); if(temperature < maxTemperature) { return HEATING_UP; } else { return READY; } case INJECTOR: GetInjectorTemperature(&temperature); if(temperature < 0.0f) {// Got "EPKT" response return FAULTED; } if(temperature < 0.1f) { // Allow for floating-point rounding errors return COLD; } //TODO: Fill in... return HEATING_UP; case DETECTOR: GetDetectorTemperature(&temperature); if(temperature < 0.0f) {// Got "EPKT" response return FAULTED; } if(temperature < 0.1f) { // Allow for floating-point rounding errors return COLD; } //TODO: Fill in... return HEATING_UP; case GAS: GetGasPressure(&pressure); if(pressure < 0.0f) {// Got "EPKT" response return FAULTED; } if(GetGasControlMode(buff, false) == false) { // Got "EPKT" return FAULTED; } if(pressure < 0.1f) { // Allow for floating-point rounding errors return COLD; } //TODO: Fill in... return HEATING_UP; default: sprintf(buff, "Unknown component: %d", component); EasyGUIDebugPrint(buff, 100, 100); break; } return FAULTED; } bool GetGCStatusLoop::GCIsInStandbyMode(void) { char response[50]; SetGCDeviceReport("QDIS", response); // We expect a response of the form "DHTS000n", where 'n' == '0' means the GC is in standby mode, // while 'n' == '1' means that it is not in standby mode bool retval = (response[7] == '0'); // Also check for "EPKT" if(response[0] == 'E') retval = false; //#define DEBUG_HERE #ifdef DEBUG_HERE if(retval) { EasyGUIDebugPrint("GGCSL::GCIISM - returning true", 100, 100); } else { EasyGUIDebugPrint("GGCSL::GCIISM - returning false", 100, 100); } #endif //#undef DEBUG_HERE return retval; } void GetGCStatusLoop::ExitedGCStandbyMode(void) { gcInStandbyMode = false; } void GetGCStatusLoop::DisplayStandbyModePage(void) { GuiLib_Clear(); GuiLib_ShowScreen(GuiStruct_GasSaver_9, GuiLib_NO_CURSOR, GuiLib_RESET_AUTO_REDRAW); GuiLib_Refresh(); #define DEBUG_HERE #ifdef DEBUG_HERE char dbg[100]; sprintf(dbg, "After GuiLib_Clear 7"); EasyGUIDebugPrint(dbg, 100, 100); #undef DEBUG_HERE #endif SetCurrentPage(GuiStruct_GasSaver_9); } void GetGCStatusLoop::DisplayGCInFaultStatePage(void) { GuiLib_Clear(); // Display red background to the error message GuiLib_FillBox(10, 10, 790, 420, SixteenBitColorValue(0xFF, 0, 0)); // red GuiLib_ShowScreen(GuiStruct_GCInFaultStatePage_11, GuiLib_NO_CURSOR, GuiLib_RESET_AUTO_REDRAW); GuiLib_Refresh(); #define DEBUG_HERE #ifdef DEBUG_HERE char dbg[100]; sprintf(dbg, "After GuiLib_Clear 8"); EasyGUIDebugPrint(dbg, 100, 100); #undef DEBUG_HERE #endif SetCurrentPage(GuiStruct_GCInFaultStatePage_11); } void GetGCStatusLoop::UpdateHomePageGCComponentStatusColorAreas(void) { if(homePageGCComponentStatusColorAreas != NULL) { homePageGCComponentStatusColorAreas->SetGCComponentStatus(COLUMN, GetComponentStatus(COLUMN)); homePageGCComponentStatusColorAreas->SetGCComponentStatus(INJECTOR, GetComponentStatus(INJECTOR)); homePageGCComponentStatusColorAreas->SetGCComponentStatus(DETECTOR, GetComponentStatus(DETECTOR)); homePageGCComponentStatusColorAreas->SetGCComponentStatus(GAS, GetComponentStatus(GAS)); } } void GetGCStatusLoop::UpdateSingleGCComponentPageStatusColorArea(GCComponent component) { if(singleGCComponentPageStatusColorAreas != NULL) { singleGCComponentPageStatusColorAreas->SetGCComponentStatus(component, GetComponentStatus(component)); } } void GetGCStatusLoop::SetupAllEasyGUIVariables(void) { // Set up (i.e. get from the GC) the values for all the EasyGUI variables used by the various pages/structures we display. // Caller should do this before entering our main loop - this ensures these variables are set up and ready // before each of the pages is displayed // Home page #define SETUP_HOME_PAGE #ifdef SETUP_HOME_PAGE GetColumnTemperature(GuiVar_columnTemperature2); GetDetectorTemperature(GuiVar_detectorTemperature2); GetInjectorTemperature(GuiVar_injectorTemperature2); GetGasPressure(GuiVar_gasPressure2); #undef SETUP_HOME_PAGE #endif // We were omitting the home page variables here, on the theory that the home page is the first one displayed, // so its variables will get updated anyway, and if we set them here, the page does not get updated when first displayed. // However, this no longer appears to be true (and I cannot now remember why I thought it was). // If we do *not* update these variables here, then we see the component status rectangles in their correct colours at startup, // but the text does not appear for several seconds. If we *do* update these variables, the text is displayed at startup // at the same time as the rectangles, i.e. we get the behaviour we expect. // Column page GetColumnTemperature(GuiVar_columnTemperature); GetColumnMaxTemperature(GuiVar_columnMaxTemp2, false); // Injector page GetInjectorTemperature(GuiVar_injectorTemperature); GetInjectionMode(GuiVar_injectionMode2, false); // Detector page GetDetectorTemperature(GuiVar_detectorTemperature); GetDetectorType(GuiVar_detectorType2, false); // Gas page GetGasPressure(GuiVar_gasPressure); GetGasControlMode(GuiVar_gasControlMode2, true); // Settings page GetSoftwareVersion(GuiVar_gcSoftwareVersion); GetRunTime(GuiVar_runTime); GetInjectionMode(GuiVar_injectionMode, true); GetColumnMaxTemperature(GuiVar_columnMaxTemp, true); GetDetectorType(GuiVar_detectorType, true); GetGasControlMode(GuiVar_gasControlMode, true); } void GetGCStatusLoop::MainLoop(void) { #ifdef PAGE_DEBUG char dbg[100]; char response[50]; #endif char statusString[100]; // We will now sit in this loop until the end of time, or the user powers off, whichever happens sooner... while(true) { #ifdef PAGE_DEBUG sprintf(dbg, "Current page is: %d ", GetCurrentPage()); EasyGUIDebugPrint(dbg, 20, 80); usbHostGC->SetDeviceReport(usbDevice, "QCOL", response); sprintf(dbg, "QCOL response was: %s ", response); EasyGUIDebugPrint(dbg, 20, 100); #endif if(GCIsInStandbyMode()) { if(!gcInStandbyMode) { gcInStandbyMode = true; DisplayStandbyModePage(); } } if(GCHasFaulted(statusString)) { if((currentPage != GuiStruct_GCInFaultStatePage_11) || (strcmp(GuiVar_gcState, statusString) != 0)) { strcpy(GuiVar_gcState, statusString); DisplayGCInFaultStatePage(); } } if(pageJustChanged) { // Don't display page data if it has just been done - leave till next time - // (a) it's unnecessary, (b) it appears to cause random crashes pageJustChanged = false; } else { DisplayCurrentPageData(false); } #ifdef USE_THREAD_WAIT Thread::wait(waitTimeMs); // Let other things happen #else wait_ms(waitTimeMs); // Let other things happen #endif } } void GetGCStatusLoop::MainLoopWithEthernet(void) { #define WANT_ETHERNET #ifdef WANT_ETHERNET EthernetInterface eth; eth.init(ethernetIP, ethernetMask, ethernetGateway); eth.connect(); // EasyGUIDebugPrint("Ethernet 0", 20, 80); TCPSocketServer server; server.bind(ethernetPort); server.listen(); char buffer[256]; // EasyGUIDebugPrint("Ethernet 1", 20, 80); #endif //WANT_ETHERNET char statusString[100]; // We will now sit in this loop until the end of time, or the user powers off, whichever happens sooner... while(true) { #ifdef WANT_ETHERNET TCPSocketConnection client; // EasyGUIDebugPrint("Ethernet 2", 20, 80); // Look for a client, but do not hang if there isn't one server.set_blocking(false); // Timeout after (1.5)s bool clientFound = (server.accept(client) == 0); // EasyGUIDebugPrint("Ethernet 3", 20, 80); if(clientFound) { // EasyGUIDebugPrint("Found Ethernet client ", 20, 100); client.set_blocking(false, 1500); // Timeout after (1.5)s // Now look for messages from the Ethernet client - as long as they keep coming, // pass them to the GC, and pass its responses back to the client while (true) { char response[GC_MESSAGE_LENGTH + 2]; // Note that since this is non-blocking, it is effectively 'polling' the Ethernet connection int n = client.receive(buffer, sizeof(buffer)); if (n <= 0) break; buffer[n] = '\0'; SetGCDeviceReport(buffer, response); // Echo received message back to client client.send_all(response, strlen(response)); if (n <= 0) break; } client.close(); } else { // EasyGUIDebugPrint("Not found Ethernet client", 20, 100); } #endif // WANT_ETHERNET if(GCIsInStandbyMode()) { if(!gcInStandbyMode) { gcInStandbyMode = true; DisplayStandbyModePage(); } } if(GCHasFaulted(statusString)) { if((currentPage != GuiStruct_GCInFaultStatePage_11) || (strcmp(GuiVar_gcState, statusString) != 0)) { strcpy(GuiVar_gcState, statusString); DisplayGCInFaultStatePage(); } } if(pageJustChanged) { // Don't display page data if it has just been done - leave till next time - // (a) it's unnecessary, (b) it appears to cause random crashes pageJustChanged = false; } else { DisplayCurrentPageData(false); } #ifdef USE_THREAD_WAIT Thread::wait(waitTimeMs); // Let other things happen #else wait_ms(waitTimeMs); // Let other things happen #endif } }