Repository for import to local machine

Dependencies:   DMBasicGUI DMSupport

GasChannelDACAndADCPageHandler.cpp

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

File content as of revision 8:26e49e6955bd:

#include "GasChannelDACAndADCPageHandler.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
*/
GuiConst_INTCOLOR SixteenBitColorValue(GuiConst_INT8U red, GuiConst_INT8U green, GuiConst_INT8U blue); 


/*
    Displays the specified text string at the specified location in the currently-displayed easyGUI page.
    
    Defined in main.cpp - and omits the 'ALLOW_DEBUG_PRINTS' #define
*/
extern void SpecialDebugPrint(char *stuffToPrint, GuiConst_INT16S X, GuiConst_INT16S Y);


/*                      
    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 carrier gas selection, etc, and nor will we show 
    more than one easyGUI 'GasCalibrationPage' to the user at the same time).
*/
GasChannelDACAndADCPageHandler * GasChannelDACAndADCPageHandler::theGasChannelDACAndADCPageHandlerInstance = NULL;


/*
    The minimum and maximum values for the DAC value 
*/
const int GasChannelDACAndADCPageHandler::minimumDACValue = 0;
const int GasChannelDACAndADCPageHandler::maximumDACValue = 4095;
    
/*
    We distinguish the 'active' field - i.e. the one being edited by the user - 
    from the inactive field(s), by its background colour
*/
const GuiConst_INTCOLOR GasChannelDACAndADCPageHandler::inactiveFieldBackgroundColour = SixteenBitColorValue(192, 192, 192); // Grey
const GuiConst_INTCOLOR GasChannelDACAndADCPageHandler::activeFieldBackgroundColour   = SixteenBitColorValue(255, 255, 0); // Yellow


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

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

// Private destructor also
GasChannelDACAndADCPageHandler::~GasChannelDACAndADCPageHandler()
{
    
}

/*
    Saves the current parameter values to QSPI settings,
    so they are maintained even when the user powers off
    
    No arguments, no return value
*/
void GasChannelDACAndADCPageHandler::SaveGasChannelSelectionToQSPISettings(void)
{
    // Put values to QSPI settings, using SettingsHandler member functions

    SettingsHandler::PutIntegerValueToQSPISettings("GasDACChannelSelection", channelSelection);
}


/*
    Reads the current parameter values from QSPI settings,
    so they are maintained even when the user powers off
    
    No arguments, no return value
*/
void GasChannelDACAndADCPageHandler::ReadGasChannelSelectionFromQSPISettings(void)
{
    // Get values from QSPI settings, using SettingsHandler member functions
    
    // Get round C++ casting rules from integer to enumeration - assign to integer first
    int intChannelSelection = SettingsHandler::GetIntegerValueFromQSPISettings("GasDACChannelSelection", TOTAL_FLOW);
    
    // Correct for possible error (e.g. off by one)
    if(intChannelSelection < TOTAL_FLOW) intChannelSelection = TOTAL_FLOW;
    if(intChannelSelection > AIR) intChannelSelection = AIR;
    
    channelSelection = (ChannelSelection) intChannelSelection;
    
    // Channel index starts at 1 (GC code requires this), but easyGUI radio button indices start at zero
    GuiVar_gasChannelDACSelection = channelSelection - 1;
}


/*
    Tells the caller whether or not the specified touch index is on the easyGUI 'GasChannelDACAndADCPage',
    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 GasChannelDACAndADCPageHandler::TouchAreaIsOnGasChannelDACAndADCPage(int touchAreaIndex)
{
    if((touchAreaIndex >= MIN_GAS_CHANNEL_DAC_AND_ADC_TOUCHINDEX) && (touchAreaIndex <= MAX_GAS_CHANNEL_DAC_AND_ADC_TOUCHINDEX)) {
        return true;
    }
    
    // 'else'
    return false;
}


/*
    If the specified touch area represents a key or field on the easyGUI 'GasChannelDACAndADCPage',
    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 'GasChannelDACAndADCPage', and so the caller
    must deal with it some other way).
*/
bool GasChannelDACAndADCPageHandler::DealWithTouch(int touchAreaIndex)
{
    if(touchAreaIndex == GAS_CHANNEL_DAC_AND_ADC_TOTALFLOW) {
        if(channelSelection != TOTAL_FLOW) {
            channelSelection = TOTAL_FLOW;
            // Channel index starts at 1 (GC code requires this), but easyGUI radio button indices start at zero
            GuiVar_gasChannelDACSelection = channelSelection - 1;
//            UpdateEasyGUIPage();
            SaveGasChannelSelectionToQSPISettings();
            GetGasChannelADCValue(channelSelection, GuiVar_gasChannelDAC_ADCValue);
            UpdateEasyGUIPage(); // Surely this makes more sense here?
        }
        return true;
    }    
    
    if(touchAreaIndex == GAS_CHANNEL_DAC_AND_ADC_BACKPRESSURE) {
        if(channelSelection != BACK_PRESSURE) {
            channelSelection = BACK_PRESSURE;
            // Channel index starts at 1 (GC code requires this), but easyGUI radio button indices start at zero
            GuiVar_gasChannelDACSelection = channelSelection - 1;
//            UpdateEasyGUIPage();
            SaveGasChannelSelectionToQSPISettings();
            GetGasChannelADCValue(channelSelection, GuiVar_gasChannelDAC_ADCValue);
            UpdateEasyGUIPage(); // Surely this makes more sense here?
        }
        return true;
    }    
    
    if(touchAreaIndex == GAS_CHANNEL_DAC_AND_ADC_FUEL) {
        if(channelSelection != FUEL) {
            channelSelection = FUEL;
            // Channel index starts at 1 (GC code requires this), but easyGUI radio button indices start at zero
            GuiVar_gasChannelDACSelection = channelSelection - 1;
//            UpdateEasyGUIPage();
            SaveGasChannelSelectionToQSPISettings();
            GetGasChannelADCValue(channelSelection, GuiVar_gasChannelDAC_ADCValue);
            UpdateEasyGUIPage(); // Surely this makes more sense here?
        }
        return true;
    }    
    
    if(touchAreaIndex == GAS_CHANNEL_DAC_AND_ADC_AIR) {
        if(channelSelection != AIR) {
            channelSelection = AIR;
            // Channel index starts at 1 (GC code requires this), but easyGUI radio button indices start at zero
            GuiVar_gasChannelDACSelection = channelSelection - 1;
//            UpdateEasyGUIPage();
            SaveGasChannelSelectionToQSPISettings();
            GetGasChannelADCValue(channelSelection, GuiVar_gasChannelDAC_ADCValue);
            UpdateEasyGUIPage(); // Surely this makes more sense here?
        }
        return true;
    }    
    
    if(touchAreaIndex == GAS_CHANNEL_DAC_AND_ADC_GET_ADC_VALUE_BUTTON) {
        GetGasChannelADCValue(channelSelection, GuiVar_gasChannelDAC_ADCValue);
        UpdateEasyGUIPage();
        return true;
    }    
    
    if(touchAreaIndex == GAS_CHANNEL_DAC_AND_ADC_SET_DAC_VALUE_BUTTON) {
        SetGasChannelDACValue(channelSelection, GuiVar_gasChannelDAC_DACValue);
        return true;
    }    
    
    if(touchAreaIndex == GAS_CHANNEL_DAC_AND_ADC_DAC_VALUE_EDIT) {
        NumericKeypadPageHandler* numericKeypadPageHandler = NumericKeypadPageHandler::GetInstance(usbDevice, usbHostGC);
        if(numericKeypadPageHandler != NULL) {
            numericKeypadPageHandler->StartEditing(GuiVar_gasChannelDAC_DACValue);
            numericKeypadPageHandler->SetEasyGUIVariableToEdit(GuiVar_gasChannelDAC_DACValue);
            numericKeypadPageHandler->SetEasyGUICallingPage(GuiStruct_GasChannelDACAndADCPage_Def);
            numericKeypadPageHandler->SetEditVariableRange(minimumDACValue, maximumDACValue);
            numericKeypadPageHandler->SetEditVariableName("DAC");
            numericKeypadPageHandler->DisplayEasyGUIPage();
        }
    }

    // 'else' - none of the above
    return false;
}


/*
    (Re)display the easyGUI 'GasChannelDACAndADCPage' -
    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 GasChannelDACAndADCPageHandler::UpdateEasyGUIPage(void)
{
    GetGCStatusLoop *getGCStatusLoop = GetGCStatusLoop::GetInstance();
    
    if(getGCStatusLoop != NULL) {
        // The GasChannelDACAndADC page has a status rectangle for the gas - 
        // GetGCStatusLoop can display this, we cannot
        getGCStatusLoop->ForceUpdateOfGasChannelDACAndADCPage();
    }
}


/*
    Caller is telling us it is about to display the easyGUI 'GasChannelDACAndADCPage',
    and that we should do whatever we have to do to get it ready,
    before the caller displays it.
    
    No arguments, no return code
*/
void GasChannelDACAndADCPageHandler::DisplayingEasyGUIPage(void)
{
    ReadGasChannelSelectionFromQSPISettings();
    
    // Make both fields grey - text on page tells user what to do, no need to show them which one is active
    GuiVar_gasChannelDAC_DACValueBackgroundColour = inactiveFieldBackgroundColour; // = activeFieldBackgroundColour;    
    GuiVar_gasChannelDAC_ADCValueBackgroundColour = inactiveFieldBackgroundColour;
    
    GetGasChannelADCValue(channelSelection, GuiVar_gasChannelDAC_ADCValue);
}


/*
    Gets the ADC value for the specified gas channel, as a null-terminated string
    
    Arguments: the channel number
               pointer to a buffer to contain the ADC value
               
    Returns true on success, false on error
*/
bool GasChannelDACAndADCPageHandler::GetGasChannelADCValue(int channel, char* buffer)
{
    char cmd[20];
    sprintf(cmd, "QGA%1d", channel);
    
    char response[50];
    while(usbHostGC->ExecutingSetDeviceReport()) {}
    usbHostGC->SetDeviceReport(usbDevice, cmd, response);
//#define DEBUG_PRINTS_HERE
#ifdef DEBUG_PRINTS_HERE
char dbg[100];
sprintf(dbg, "GetGasChannADC %s %s", cmd, response);
SpecialDebugPrint(dbg, 6, 300);
#undef DEBUG_PRINTS_HERE
#endif
    // We expect a response like this: "DGAnnnnn", where nnnnn (5 digits) is the ADC 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 = 3; startIndex < 7; ++startIndex) {
        if(response[startIndex] != '0') {
            break;
        }
    }
    
    strcpy(buffer, &response[startIndex]);

    return true;
}


/*
    Sets the DAC value for the specified gas channel, as a null-terminated string
    
    Arguments: the channel number
               pointer to a buffer that contains the new DAC value, as a null-terminated string
               
    Returns true on success, false on error
*/
bool GasChannelDACAndADCPageHandler::SetGasChannelDACValue(int channel, char* buffer)
{
    char command[20];
    sprintf(command, "SGD%1d", channel);
    
    int startIndex = 8 - strlen(buffer);
    int index = 4;
    while(index < startIndex) {
        command[index++] = '0';
    }
    int bufferIndex = 0;
    while(index < 8) {
        command[index++] = buffer[bufferIndex++];
    }
    command[8] = '\0';

    char response[50];
    while(usbHostGC->ExecutingSetDeviceReport()) {}
    usbHostGC->SetDeviceReport(usbDevice, command, response);
//#define DEBUG_PRINTS_HERE
#ifdef DEBUG_PRINTS_HERE
char dbg[100];
sprintf(dbg, "SetGasChannDAC %s %s", command, response);
SpecialDebugPrint(dbg, 6, 300);
#undef DEBUG_PRINTS_HERE
#endif
    // We expect a "DACK" response, or "DNAK" or "EPKT" if something went wrong
    if((response[0] == 'E') || (response [1] == 'N')) { // "EPKT" or "DNAK"
        return false;
    }
    
    return true;
}