Repository for import to local machine
Dependencies: DMBasicGUI DMSupport
Diff: main.cpp
- Revision:
- 0:47c880c1463d
- Child:
- 1:a5258871b33d
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.cpp Wed Jan 13 13:17:05 2016 +0000 @@ -0,0 +1,616 @@ +#include "mbed.h" +#include "DMBoard.h" +#include "lpc_swim.h" +#include "lpc_swim_font.h" + +#include <string.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" + + +// ** Start of timeout code to guard against multiple presses of the Heat On/Off button ** +// (which is in the same position as the Abort Run button) +Timeout heatOnOffTimeout; + +bool heatOnOffAvailable = true; + +void MakeHeatOnOffAvailableAgain(void) +{ + heatOnOffAvailable = true; +} + +void StartHeatOnOffTimeout(void) +{ + heatOnOffAvailable = false; + heatOnOffTimeout.attach(&MakeHeatOnOffAvailableAgain, 1.0); // Wait 1.0 sec before accepting touches again on Heat On/Off button +} +// ** End of Heat On/Off timeout code ** + + +// 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; + + +GuiConst_INTCOLOR SixteenBitColorValue(GuiConst_INT8U red, GuiConst_INT8U green, GuiConst_INT8U blue) +{ + // Make sure we don't have numeric overflow problems during the conversion + GuiConst_INT32U red32 = red; + GuiConst_INT32U green32 = green; + GuiConst_INT32U blue32 = blue; + + GuiConst_INT32U rgb = (blue32 << 16) | (green32 << 8) | red32; + + return GuiLib_RgbToPixelColor(rgb); +} + +void DebugPrint(char *stuffToPrint, GuiConst_INT16S X, GuiConst_INT16S Y) +{ + char buff[200]; + + 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 + ); + + GuiLib_DrawStr( + X, //GuiConst_INT16S X, + Y, //GuiConst_INT16S Y, + fontNo, //GuiConst_INT16U FontNo, + stuffToPrint, //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(); +} + +void EasyGUIDebugPrint(char *stuffToPrint, short X, short Y) +{ +#define DEBUG_HERE +#ifdef DEBUG_HERE + DebugPrint(stuffToPrint, (GuiConst_INT16S) X, (GuiConst_INT16S) Y); +#undef DEBUG_HERE +#endif +} + +void DummyEasyGUIDebugPrint(char *stuffToPrint, short X, short Y) +{ + //DebugPrint(stuffToPrint, (GuiConst_INT16S) X, (GuiConst_INT16S) Y); +} + +int DummyDebugFunction(int i) +{ + return i^2; +} + +bool GCIsReadyToRun(USBDeviceConnected* usbDevice, USBHostGC* usbHostGC) +{ + while(usbHostGC->ExecutingSetDeviceReport()) {} + + char response[50]; + + // Ensure we always have valid chars in the positions we are interested in, + // in case we get "DNAK" or "EPKT" back + response[6] = '0'; + 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" + + return ((response[6] == '3') && (response[7]== '3')); +} + +void DrawRunButton(bool enabled) +{ + // Black if enabled, grey if disabled + GuiConst_INTCOLOR buttonColor = (enabled) ? 0 : SixteenBitColorValue(0x80, 0x80, 0x80); + + + GuiConst_TEXT *buttonText = "Run"; + + // These are hard-coded to match the corresponding definitions in easyGUI + // (I have not found a way of getting these values from easyGUI at run time) + const GuiConst_INT16S textX1 = 400; + const GuiConst_INT16S textY1 = 220; + const GuiConst_INT16U textFont = GuiFont_Helv1; + + const GuiConst_INT16S boxX1 = 338; + const GuiConst_INT16S boxY1 = 195; + const GuiConst_INT16S boxX2 = 462; + const GuiConst_INT16S boxY2 = 235; + + GuiLib_Box(boxX1, boxY1, boxX2, boxY2, buttonColor); + + GuiLib_DrawStr( + textX1, //GuiConst_INT16S X, + textY1, //GuiConst_INT16S Y, + textFont, //GuiConst_INT16U FontNo, + buttonText, //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, + buttonColor, //GuiConst_INTCOLOR ForeColor, + SixteenBitColorValue(0xFF, 0xFF, 0xFF) //GuiConst_INTCOLOR BackColor (should be ignored with GuiLib_TRANSPARENT_ON) + ); +} + + +void DisplayEasyGuiStructure(int structureIndex, USBDeviceConnected* usbDevice, USBHostGC* usbHostGC) +{ + // If required, query the GC to find out if it is ready to run *before* clearing the display - + // otherwise the display remains clear while we talk to the GC - causes noticeable flickering + bool gcIsReadyToRun = false; + if((structureIndex == GuiStruct_HomePage_1) && (usbDevice != NULL) && (usbHostGC != NULL)) { + gcIsReadyToRun = GCIsReadyToRun(usbDevice, usbHostGC); + } + + GuiLib_Clear(); + + // 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 + switch(structureIndex) { + case GuiStruct_HomePage_1: + homePageGCComponentStatusColorAreas.DisplayAll(); + break; + case GuiStruct_ColumnPage1_2: + case GuiStruct_ColumnPage2_9: + case GuiStruct_ColumnPage3_10: + singleGCComponentPageStatusColorAreas.DisplayGCComponentStatus(COLUMN); + break; + case GuiStruct_InjectorPage1_3: + singleGCComponentPageStatusColorAreas.DisplayGCComponentStatus(INJECTOR); + break; + case GuiStruct_DetectorPage1_4: + singleGCComponentPageStatusColorAreas.DisplayGCComponentStatus(DETECTOR); + break; + case GuiStruct_GasPage1_6: + singleGCComponentPageStatusColorAreas.DisplayGCComponentStatus(GAS); + break; + default: // Don't need to display status rectangle for this page + break; + } + + 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 + if(structureIndex == GuiStruct_HomePage_1) { + DrawRunButton(gcIsReadyToRun); + } + + GuiLib_Refresh(); +#define DEBUG_HERE +#ifdef DEBUG_HERE + char dbg[100]; + sprintf(dbg, "After GuiLib_Refresh main 1"); + EasyGUIDebugPrint(dbg, 100, 100); +#undef DEBUG_HERE +#endif + + if(getGCStatusLoop != NULL) { + getGCStatusLoop->SetCurrentPage(structureIndex); + } +} + +void DrawErrorMessage(char *msg) +{ + const GuiConst_INT16U fontNo = GuiFont_Helv1; + + GuiLib_DrawStr( + 90, //GuiConst_INT16S X, + 240, //GuiConst_INT16S Y, + fontNo, //GuiConst_INT16U FontNo, + msg, //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 + ); +} + +void UpdateHeatOnOffEasyGuiVariable(void) +{ + // Note that the easyGUI variable is not the current status of the heat on the GC, + // but the command to toggle its current state + if(theGCHeatControl != NULL) { + if(theGCHeatControl->IsHeatOn()) { + strcpy(GuiVar_heatOnOffCommand, "Heat Off"); + } else { + strcpy(GuiVar_heatOnOffCommand, "Heat On"); + } + } +} + +bool StartGCRun(USBDeviceConnected* usbDevice, USBHostGC* usbHostGC) +{ + while(usbHostGC->ExecutingSetDeviceReport()) {} + + char response[50]; + usbHostGC->SetDeviceReport(usbDevice, "CRUN", response); + // We expect a response like this: "DACK" for success, "DNAK" for failure + +#define DEBUG_HERE +#ifdef DEBUG_HERE + char dbg[100]; + sprintf(dbg, "CRUN returned %s", response); + EasyGUIDebugPrint(dbg, 100, 150); +#endif +#undef DEBUG_HERE + + return (response[1] == 'A'); +} + +bool StopGCRun(USBDeviceConnected* usbDevice, USBHostGC* usbHostGC) +{ + 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 + +#define DEBUG_HERE +#ifdef DEBUG_HERE + char dbg[100]; + sprintf(dbg, "%s returned %s", cmd, response); + EasyGUIDebugPrint(dbg, 100, 150); +#endif +#undef DEBUG_HERE + + return (response[1] == 'A'); +} + +bool ExitGCStandbyMode(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 + + char dbg[100]; + sprintf(dbg, "CDIS returned %s", response); + EasyGUIDebugPrint(dbg, 100, 150); + + if(getGCStatusLoop != NULL) { + getGCStatusLoop->ExitedGCStandbyMode(); + } + + return (response[1] == 'A'); +} + +bool ClearGCErrors(USBDeviceConnected* usbDevice, USBHostGC* usbHostGC) +{ + while(usbHostGC->ExecutingSetDeviceReport()) {} + + char response[50]; + usbHostGC->SetDeviceReport(usbDevice, "CCLR", 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'); +} + +void TouchCallback(touch_coordinate_t touchCoords, USBDeviceConnected* usbDevice, USBHostGC* usbHostGC, int tickCount, bool newTouch) +{ + GuiConst_INT32S touchAreaIndex = GuiLib_TouchCheck((GuiConst_INT16S)touchCoords.x, (GuiConst_INT16S)touchCoords.y); + + if(touchAreaIndex >= 0) { + bool dealtWithTouch = false; + + // page selector? + TouchPanelPageSelector* touchPanelPageSelector = touchPanelPageSelectors.GetTouchPanelPageSelector(touchAreaIndex); + + if( touchPanelPageSelector != NULL) { + // 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); + } + + if(touchAreaIndex == 400) { + // Take GC out of standby mode + ExitGCStandbyMode(usbDevice, usbHostGC); + } + + if(touchAreaIndex == 600) { + // Take GC out of error state + ClearGCErrors(usbDevice, usbHostGC); + } + + DisplayEasyGuiStructure(touchPanelPageSelector->GetPageNumber(), 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(); + } + } + + if(!dealtWithTouch) { + if(touchAreaIndex == 100) { // Run button + if(newTouch) { // As above - do not do this repeatedly - GC does not like it... + if(GCIsReadyToRun(usbDevice, usbHostGC)) { + // Start run - if this works, display the 'Run' page, else do nothing + if(StartGCRun(usbDevice, usbHostGC)) { + DisplayEasyGuiStructure(GuiStruct_RunningPage_7, usbDevice, usbHostGC); + } else { + DrawErrorMessage("*** Run failed to start ***"); + + // Give user time to read error, then erase it + Thread::wait(2000); + + DisplayEasyGuiStructure(GuiStruct_HomePage_1, usbDevice, usbHostGC); + } + } + // else GC is not ready to run (button should be greyed out) - ignore + } + + dealtWithTouch = true; + } + } + + if(!dealtWithTouch) { + if(touchAreaIndex == 300) { // Heat on/off button + if(newTouch) { // As above - do not do this repeatedly - GC does not like it... + if(heatOnOffAvailable) { + if(theGCHeatControl != NULL) { + if(theGCHeatControl->IsHeatOn()) { + theGCHeatControl->TurnHeatOff(); + } else { + theGCHeatControl->TurnHeatOn(); + } + UpdateHeatOnOffEasyGuiVariable(); + + // Make GuiVar_heatOnOffCommand update visible on screen + DisplayEasyGuiStructure(GuiStruct_HomePage_1, usbDevice, usbHostGC); + + StartHeatOnOffTimeout(); + } + } + } + + // Whether we changed the heat or not, the user still 'touched' our area, + // so no-one else should try and deal with this touch + dealtWithTouch = true; + } + } + } +} + +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); + + if(mainTouchListener != NULL) { + mainTouchListener->SetTouchCallbackFunction(&TouchCallback); + +// Not yet... +// mainTouchListener->SetTouchReleasedCallbackFunction(&TouchReleasedCallback); +// +// mainTouchListener->SetTimerOneSecondCallbackFunction(&TimerOneSecondCallback); + } +} + + +int main() +{ + 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"); + + 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); + + 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 + + // 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"); + + GuiDisplay_Lock(); + + GuiLib_Init(); + + GuiLib_Refresh(); + + DisplayEasyGuiStructure(GuiStruct_HomePage_1, NULL, NULL); + + GuiLib_Refresh(); + + GuiDisplay_Unlock(); + + + // 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; + } + } + } + + DrawErrorMessage(" "); + + if(usbDevice != NULL) { + USB_TYPE enumerateRetVal = usbHost->enumerate(usbDevice, &usbHostGC); + + if (usbHostGC.DeviceIsGC()) { + if (usbHostGC.AttachGCDevice(usbDevice)) { + + DrawErrorMessage("Found GC device "); + + + SetupUSBGCTouchListener(board, usbDevice, &usbHostGC); + + DrawErrorMessage("After call to SetupUSBGCTouchListener "); + + + getGCStatusLoop = GetGCStatusLoop::GetInstance(usbDevice, &usbHostGC); + + DrawErrorMessage("After creation of GetGCStatusLoop instance "); + + + theGCHeatControl = new GCHeatControl(usbDevice, &usbHostGC); + + UpdateHeatOnOffEasyGuiVariable(); + + DrawErrorMessage("After UpdateHeatOnOffEasyGuiVariable "); + + + //theEthernetTimerHandler = EthernetTimerHandler::GetInstance(usbDevice, &usbHostGC); + + + getGCStatusLoop->SetHomePageGCComponentStatusColorAreas(&homePageGCComponentStatusColorAreas); + getGCStatusLoop->SetSingleGCComponentPageStatusColorAreas(&singleGCComponentPageStatusColorAreas); + + DrawErrorMessage("Point 1 "); + + getGCStatusLoop->SetupAllEasyGUIVariables(); + + DrawErrorMessage("Point 2 "); + + getGCStatusLoop->SetCurrentPage(GuiStruct_HomePage_1); + + DrawErrorMessage("Point 3 "); + + 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(); + + // Should never reach this code - but just in case... + delete theGCHeatControl; + + } else { + DrawErrorMessage("Failed to attach GC device to host "); + } + } else { + DrawErrorMessage(" *** USB device found, is *not* a GC *** "); + } + } else { + DrawErrorMessage(" *** No USB device found *** "); + } + + while(true) {} +} + +