Repository for import to local machine

Dependencies:   DMBasicGUI DMSupport

GasBackPressureDACPageHandler.cpp

Committer:
jmitc91516
Date:
2017-07-31
Revision:
8:26e49e6955bd
Parent:
1:a5258871b33d

File content as of revision 8:26e49e6955bd:

#include "GasBackPressureDACPageHandler.h"
#include "EasyGUITouchAreaIndices.h"
#include "SettingsHandler.h"
#include "GetGCStatusLoop.h"
#include "NumericKeypadPageHandler.h"

#include <stdio.h>
#include <stdlib.h>



/*
    Displays the specified easyGUI 'structure' (or page, to use a more easily understood term).
    Defined in main.cpp
*/
extern void DisplayEasyGuiStructure(int structureIndex, USBDeviceConnected* usbDevice, USBHostGC* usbHostGC, bool updateEasyGUIVariables = true);


/*
    Converts three eight-bit colour values to the corresponding 16-bit RGB565 value.
    Defined in main.cpp
*/
extern GuiConst_INTCOLOR SixteenBitColorValue(GuiConst_INT8U red, GuiConst_INT8U green, GuiConst_INT8U blue); 


/*                      
    Note that this class is a singleton - we do not need or want there to be more than one instance of it
    (we do not want multiple values for the gain and offset, etc, and nor will we show 
    more than one easyGUI 'GasBackPressureDACPage' to the user at the same time).
*/
GasBackPressureDACPageHandler * GasBackPressureDACPageHandler::theGasBackPressureDACPageHandlerInstance = NULL;


/*
    The minimum and maximum values for the gain and offset (both the same)
*/
const int GasBackPressureDACPageHandler::minimumGainAndOffsetValue = 0;
const int GasBackPressureDACPageHandler::maximumGainAndOffsetValue = 9999;
    
/*
    We distinguish the 'active' field - i.e. the one being edited by the user - 
    from the inactive fields, by its background colour
*/
const GuiConst_INTCOLOR GasBackPressureDACPageHandler::inactiveFieldBackgroundColour = SixteenBitColorValue(192, 192, 192); // Grey
const GuiConst_INTCOLOR GasBackPressureDACPageHandler::activeFieldBackgroundColour   = SixteenBitColorValue(255, 255, 0); // Yellow


/*
    Singleton class - return the one and only instance, first creating it if necessary.
*/
GasBackPressureDACPageHandler * GasBackPressureDACPageHandler::GetInstance(USBDeviceConnected* newUsbDevice, USBHostGC* newUsbHostGC)
{
    if (theGasBackPressureDACPageHandlerInstance == NULL) {
        theGasBackPressureDACPageHandlerInstance = new GasBackPressureDACPageHandler(newUsbDevice, newUsbHostGC);
    }
    
    return theGasBackPressureDACPageHandlerInstance;
}

// Singleton class - private constructor
GasBackPressureDACPageHandler::GasBackPressureDACPageHandler(USBDeviceConnected* newUsbDevice, USBHostGC* newUsbHostGC)
{
    usbDevice = newUsbDevice;
    usbHostGC = newUsbHostGC;
}

// Private destructor also
GasBackPressureDACPageHandler::~GasBackPressureDACPageHandler()
{
    //SaveCarrierGasSelectionToQSPISettings();
}


/*
    Tells the caller whether or not the specified touch index is on the easyGUI 'GasCalibrationPage',
    and therefore needs to be handled by this class.
    
    Args: the touch area index in question
    
    Return code: true if the touch area is 'one of ours', false if not
*/
bool GasBackPressureDACPageHandler::TouchAreaIsOnGasBackPressureDACPage(int touchAreaIndex)
{
    if((touchAreaIndex >= MIN_GAS_BACKPRESSURE_DAC_TOUCHINDEX) && (touchAreaIndex <= MAX_GAS_BACKPRESSURE_DAC_TOUCHINDEX)) {
        return true;
    }
    
    // 'else'
    return false;
}

/*
    If the specified touch area represents a key or field on the easyGUI 'GasBackPressureDACPage',
    this function performs whatever action is appropriate for it. Provided so that the caller
    can (in effect) say "if this is one of yours, deal with it", without needing to know 
    anything about what this class does, or how it handles the touch areas on that easyGUI page.

    Args: the touch area index in question
    
    Returns true if it dealt with the touch area (so the caller need not do anything else 
    with the value), or false if it did not deal with the touch area (implying that it 
    was not a touch area on the easyGUI 'GasBackPressureDACPage', and so the caller
    must deal with it some other way).
*/
bool GasBackPressureDACPageHandler::DealWithTouch(int touchAreaIndex)
{
    // Note that we have only two editable fields

    if(touchAreaIndex == GAS_BACKPRESSURE_DAC_GAIN_EDIT) {
        NumericKeypadPageHandler* numericKeypadPageHandler = NumericKeypadPageHandler::GetInstance(usbDevice, usbHostGC);
        if(numericKeypadPageHandler != NULL) {
            numericKeypadPageHandler->StartEditing(GuiVar_gasBackPressureDACGain);
            numericKeypadPageHandler->SetEasyGUIVariableToEdit(GuiVar_gasBackPressureDACGain);
            numericKeypadPageHandler->SetEasyGUICallingPage(GuiStruct_GasBackPressureDACPage_Def);
            numericKeypadPageHandler->SetEditVariableRange(minimumGainAndOffsetValue, maximumGainAndOffsetValue);
            numericKeypadPageHandler->SetEditVariableName("0 PSI");
            numericKeypadPageHandler->DisplayEasyGUIPage();
        }

        return true;
    }

    if(touchAreaIndex == GAS_BACKPRESSURE_DAC_OFFSET_EDIT) {
        NumericKeypadPageHandler* numericKeypadPageHandler = NumericKeypadPageHandler::GetInstance(usbDevice, usbHostGC);
        if(numericKeypadPageHandler != NULL) {
            numericKeypadPageHandler->StartEditing(GuiVar_gasBackPressureDACOffset);
            numericKeypadPageHandler->SetEasyGUIVariableToEdit(GuiVar_gasBackPressureDACOffset);
            numericKeypadPageHandler->SetEasyGUICallingPage(GuiStruct_GasBackPressureDACPage_Def);
            numericKeypadPageHandler->SetEditVariableRange(minimumGainAndOffsetValue, maximumGainAndOffsetValue);
            numericKeypadPageHandler->SetEditVariableName("50 PSI");
            numericKeypadPageHandler->DisplayEasyGUIPage();
        }
        
        return true;
    }
    
    if(touchAreaIndex == GAS_BACKPRESSURE_DAC_GET) {
        
        GetCurrentGasBackPressureDACValuesFromGC();
        SetAllEditableFieldsToInactive();
        
        UpdateEasyGUIPage();
        
        return true;
    }
    
    if(touchAreaIndex == GAS_BACKPRESSURE_DAC_SET) {
        
        SetCurrentGasBackPressureDACValuesInGC();
        SetAllEditableFieldsToInactive();
        
        return true;
    }
    
    // 'else' - none of the above
    return false;
}


/*
    Gets the current gas backpressure gain and offset values from the GC,
    and copies them to the relevant easyGUI variables so that they can be displayed.
    Note that it is up to the caller to redisplay the page.
    
    No arguments, no return code
*/
bool GasBackPressureDACPageHandler::GetCurrentGasBackPressureDACValuesFromGC(void)
{
    char response[50];

    // Gain first
    while(usbHostGC->ExecutingSetDeviceReport()) {}
    usbHostGC->SetDeviceReport(usbDevice, "GBPG", response);
    // We expect a response like this: "DBPGnnnn", when nnnn is the DAC value,
    // or "EPKT" if something went wrong
    if(response[0] == 'E') {
        // Assume "EPKT"
        return false;
    }
    
    //Ensure null terminator
    response[8] = '\0';
    
    // Ignore leading zeroes - but make sure we leave the final digit, whether zero or not
    int startIndex;
    for(startIndex = 4; startIndex < 7; ++startIndex) {
        if(response[startIndex] != '0') {
            break;
        }
    }
    
    strcpy(GuiVar_gasBackPressureDACGain, &response[startIndex]);
    
    
    // Now the offset
    while(usbHostGC->ExecutingSetDeviceReport()) {}
    usbHostGC->SetDeviceReport(usbDevice, "GBPO", response);
    // We expect a response like this: "DBPOnnnn", when nnnn is the DAC value,
    // or "EPKT" if something went wrong
    if(response[0] == 'E') {
        // Assume "EPKT"
        return false;
    }
    
    //Ensure null terminator
    response[8] = '\0';
    
    // Ignore leading zeroes - but make sure we leave the final digit, whether zero or not
    for(startIndex = 4; startIndex < 7; ++startIndex) {
        if(response[startIndex] != '0') {
            break;
        }
    }
    
    strcpy(GuiVar_gasBackPressureDACOffset, &response[startIndex]);
    
    return true;
}


/*
    To set the gas backpressure gain or offset, the GC expects a command of the form:
    
        "SBPcnnnn"
    
    where 'c' is the single character 'G' for gain or 'O' for offset, and "nnnn" is the value in question.
    This must be four digits, and must therefore be padded with leading zeroes if the actual value is shorter than this. 
    
    This function constructs the required command.
    
    Arguments: a buffer to contain the command
               a single character for gain or offset (we leave it up to the caller to make sure this is 'G' or 'O')
               a pointer to the easyGUI variable containing the value (we expect this to be a null-terminated character string)
               
    No return code
*/
void GasBackPressureDACPageHandler::ConstructSetBackPressureCommand(char *command, char gainOrOffsetCharacter, GuiConst_TEXT* easyGUIVariable)
{
    command[0] = 'S';
    command[1] = 'B';
    command[2] = 'P';
    command[3] = gainOrOffsetCharacter;
    
    int startIndex = 8 - strlen(easyGUIVariable);
    
    int index = 4;
    while(index < startIndex) {
        command[index++] = '0';
    }
    int easyGUIVariableIndex = 0;
    while(index < 8) {
        command[index++] = easyGUIVariable[easyGUIVariableIndex++];
    }
    
    command[8] = '\0';
}

/*
    Sets the Gas Backpressure DAC gain and offset values in the GC,
    from our easyGUIvariables.
    
    No arguments
    
    Returns true on success, false on failure
*/
bool GasBackPressureDACPageHandler::SetCurrentGasBackPressureDACValuesInGC(void)
{
    char command[10];
    char response[50];
    
    // Gain first
    ConstructSetBackPressureCommand(command, 'G', GuiVar_gasBackPressureDACGain);
    while(usbHostGC->ExecutingSetDeviceReport()) {}
    usbHostGC->SetDeviceReport(usbDevice, command, response);
    if(response[0] == 'E') {
        // Assume "EPKT"
        return false;
    }
    
    // Now offset     
    ConstructSetBackPressureCommand(command, 'O', GuiVar_gasBackPressureDACOffset);
    while(usbHostGC->ExecutingSetDeviceReport()) {}
    usbHostGC->SetDeviceReport(usbDevice, command, response);
    if(response[0] == 'E') {
        // Assume "EPKT"
        return false;
    }
    
    return true;
}
    

/*
    (Re)display the easyGUI 'GasBackPressureDACPage' -
    e.g. after the caller has updated one or more of the easyGUI variables
    included in the page, and wants to display the new value to the user.
    
    No arguments, no return code
*/
void GasBackPressureDACPageHandler::UpdateEasyGUIPage(void)
{
    GetGCStatusLoop *getGCStatusLoop = GetGCStatusLoop::GetInstance();
    
    if(getGCStatusLoop != NULL) {
        // The Gas Back Pressure DAC page has a status rectangle for the gas - 
        // GetGCStatusLoop can display this, we cannot
        getGCStatusLoop->ForceUpdateOfGasBackPressureDACPage();
    }
}

/*
    Inactivates all editable fields, i.e. sets all the background colours to the 'inactive' colour,
    and sets the currently active field selection to 'none'.
    
    No arguments, no return code
*/
void GasBackPressureDACPageHandler::SetAllEditableFieldsToInactive(void)
{
    GuiVar_gasBackPressureDACGainBackgroundColour = inactiveFieldBackgroundColour;
    GuiVar_gasBackPressureDACOffsetBackgroundColour = inactiveFieldBackgroundColour;
    
    currentlyActiveField = NONE;
}


/*
    Caller is telling us it is about to display the easyGUI 'GasBackPressureDACPage',
    and that we should do whatever we have to do to get it ready,
    before the caller displays it.
    
    Args: a boolean set true if the easyGUI variables displayed in the page are to be updated
          from the GC, false if not. The expectation is that this will be true 
          except when the user has just updated one of variables using the numeric keypad.
          
    No return code
*/
void GasBackPressureDACPageHandler::DisplayingEasyGUIPage(bool updateEasyGUIVariables)
{
    if(updateEasyGUIVariables) {
        GetCurrentGasBackPressureDACValuesFromGC();
    }
    
    SetAllEditableFieldsToInactive();
}


/*
    Selects one field (gain or offset) as the active field, and if the other field is currently active, inactivates it
    
    Arguments: 'this' field - i.e. the field to be activated 
               the other field
               pointer to the background colour easyGUI variable for 'this' field
               pointer to the background colour easyGUI variable for the other field
               
    no return code
*/
void GasBackPressureDACPageHandler::SelectActiveField(ActiveField thisField, ActiveField otherField, GuiConst_INTCOLOR *thisFieldBGColour, GuiConst_INTCOLOR* otherFieldBGColour)
{
    if(currentlyActiveField == otherField) {
        *otherFieldBGColour = inactiveFieldBackgroundColour;
    }
    
    *thisFieldBGColour = activeFieldBackgroundColour;
    
    currentlyActiveField = thisField;

    UpdateEasyGUIPage();
}