Repository for import to local machine

Dependencies:   DMBasicGUI DMSupport

Revision:
1:a5258871b33d
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/NetworkParameters.cpp	Thu Jul 20 08:42:29 2017 +0000
@@ -0,0 +1,1302 @@
+#include "NetworkParameters.h"
+#include "EasyGUITouchAreaIndices.h"
+#include "SettingsHandler.h"
+#include "GetGCStatusLoop.h"
+#include "NumericKeypadPageHandler.h"
+#include "EthernetKeypadPageHandler.h"
+
+#include <string.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);
+
+
+/*
+    Draws the background bitmap. It fills the screen, so you do not need to call GuiLib_Clear.
+    Defined in main.cpp
+*/
+extern void DrawBackgroundBitmap(void);
+#define USING_BACKGROUND_BITMAP
+
+/*
+    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 IP address, etc, nor will we show 
+    more than one easyGUI 'EthernetParametersPage' to the user at the same time).
+*/
+NetworkParameters * NetworkParameters::theNetworkParametersInstance = NULL;
+
+
+/*
+    We distinguish the 'active' field - i.e. the one being edited by the user - 
+    from the inactive fields, by its background colour
+*/
+#define EXPERIMENTING_WITH_COLORS
+const GuiConst_INTCOLOR NetworkParameters::inactiveFieldBackgroundColour = SixteenBitColorValue(192, 192, 192); // Grey
+#ifdef EXPERIMENTING_WITH_COLORS
+const GuiConst_INTCOLOR NetworkParameters::activeFieldBackgroundColour   = SixteenBitColorValue(255, 255, 0); // Yellow
+#else
+const GuiConst_INTCOLOR NetworkParameters::activeFieldBackgroundColour   = SixteenBitColorValue(255, 255, 255); // White
+#endif // EXPERIMENTING_WITH_COLORS
+
+//#define USE_BACKGROUND_COLOURS // Else leave them all white
+//#define TOUCH_VALUES_DIRECTLY
+
+/*
+    Convenient default values
+*/
+const unsigned int NetworkParameters::defaultPortNumber = 3456;
+const unsigned int NetworkParameters::defaultIPAddress[4] = {192, 168, 1, 200};
+const unsigned int NetworkParameters::defaultSubnetMask[4] = {255, 255, 255, 0};
+const unsigned int NetworkParameters::defaultGatewayAddress[4] = {192, 168, 1, 254};
+
+
+/*
+    Singleton class - return the one and only instance, first creating it if necessary.
+*/
+NetworkParameters * NetworkParameters::GetInstance(USBDeviceConnected* newUsbDevice, USBHostGC* newUsbHostGC)
+{
+    if (theNetworkParametersInstance == NULL) {
+        theNetworkParametersInstance = new NetworkParameters(newUsbDevice, newUsbHostGC);
+    }
+    
+    return theNetworkParametersInstance;
+}
+
+// Singleton class - private constructor
+NetworkParameters::NetworkParameters(USBDeviceConnected* newUsbDevice, USBHostGC* newUsbHostGC)
+{
+    // Note that we do not use these values here - 
+    // but we do need to pass them to the (main.cpp) function DisplayEasyGUIStructure
+    usbDevice = newUsbDevice;
+    usbHostGC = newUsbHostGC;
+
+    portNumber = defaultPortNumber;
+
+    for (int index = 0; index < 4; ++index) {
+        ipAddress[index]      = defaultIPAddress[index];
+        subnetMask[index]     = defaultSubnetMask[index];
+        gatewayAddress[index] = defaultGatewayAddress[index];
+    }
+    
+    useDHCP = false;
+    
+    ReadFromQSPISettings();
+    
+//#define WANT_ETHERNET_DEBUG
+#ifdef WANT_ETHERNET_DEBUG
+        char dbg[600];
+        int dbg1;
+        char dbg2[100];
+        char dbg3[100];
+        char dbg4[100];
+        int dbg5;
+
+        dbg1 = GetPortNumber();
+        GetIPAddressAsString(dbg2);
+        GetSubnetMaskAsString(dbg3);
+        GetGatewayAddressAsString(dbg4);
+        dbg5 = GetUseDHCP();
+        
+        sprintf(dbg, "Ethernet port: %d, IP: \"%s\", mask: \"%s\", gateway: \"%s\", useDHCP: %d", dbg1, dbg2, dbg3, dbg4, dbg5);
+        SpecialDebugPrint(dbg, 100, 70);
+#undef WANT_ETHERNET_DEBUG
+#endif // WANT_ETHERNET_DEBUG
+
+    indexOfVariablesCurrentlyBeingEdited = -1;
+
+    variablesForTouchArea[0].touchAreaIndex                    = NETWORK_PARAMS_PORT_VALUE;
+    variablesForTouchArea[0].easyGUIVariablePtr                = GuiVar_ethernetPort;
+    variablesForTouchArea[0].internalVariablePtr               = &portNumber;
+    variablesForTouchArea[0].maxValue                          = 65535;
+    variablesForTouchArea[0].easyGUIBackgroundColorVariablePtr = &GuiVar_ethernetPortBackgroundColour;
+    strcpy(variablesForTouchArea[0].variableName, "Port");
+
+
+    variablesForTouchArea[1].touchAreaIndex                    = NETWORK_PARAMS_IP1_VALUE;
+    variablesForTouchArea[1].easyGUIVariablePtr                = GuiVar_ethernetIP1;
+    variablesForTouchArea[1].internalVariablePtr               = &(ipAddress[0]);
+    variablesForTouchArea[1].maxValue                          = 255;
+    variablesForTouchArea[1].easyGUIBackgroundColorVariablePtr = &GuiVar_ethernetIP1BackgroundColour;
+    strcpy(variablesForTouchArea[1].variableName, "IP Address 1");
+    
+    variablesForTouchArea[2].touchAreaIndex                    = NETWORK_PARAMS_IP2_VALUE;
+    variablesForTouchArea[2].easyGUIVariablePtr                = GuiVar_ethernetIP2;
+    variablesForTouchArea[2].internalVariablePtr               = &(ipAddress[1]);
+    variablesForTouchArea[2].maxValue                          = 255;
+    variablesForTouchArea[2].easyGUIBackgroundColorVariablePtr = &GuiVar_ethernetIP2BackgroundColour;
+    strcpy(variablesForTouchArea[2].variableName, "IP Address 2");
+    
+    variablesForTouchArea[3].touchAreaIndex                    = NETWORK_PARAMS_IP3_VALUE;
+    variablesForTouchArea[3].easyGUIVariablePtr                = GuiVar_ethernetIP3;
+    variablesForTouchArea[3].internalVariablePtr               = &(ipAddress[2]);
+    variablesForTouchArea[3].maxValue                          = 255;
+    variablesForTouchArea[3].easyGUIBackgroundColorVariablePtr = &GuiVar_ethernetIP3BackgroundColour;
+    strcpy(variablesForTouchArea[3].variableName, "IP Address 3");
+    
+    variablesForTouchArea[4].touchAreaIndex                    = NETWORK_PARAMS_IP4_VALUE;
+    variablesForTouchArea[4].easyGUIVariablePtr                = GuiVar_ethernetIP4;
+    variablesForTouchArea[4].internalVariablePtr               = &(ipAddress[3]);
+    variablesForTouchArea[4].maxValue                          = 255;
+    variablesForTouchArea[4].easyGUIBackgroundColorVariablePtr = &GuiVar_ethernetIP4BackgroundColour;
+    strcpy(variablesForTouchArea[4].variableName, "IP Address 4");
+    
+
+    variablesForTouchArea[5].touchAreaIndex                    = NETWORK_PARAMS_MASK1_VALUE;
+    variablesForTouchArea[5].easyGUIVariablePtr                = GuiVar_ethernetMask1;
+    variablesForTouchArea[5].internalVariablePtr               = &(subnetMask[0]);
+    variablesForTouchArea[5].maxValue                          = 255;
+    variablesForTouchArea[5].easyGUIBackgroundColorVariablePtr = &GuiVar_ethernetMask1BackgroundColour;
+    strcpy(variablesForTouchArea[5].variableName, "Subnet mask 1");
+
+    variablesForTouchArea[6].touchAreaIndex                    = NETWORK_PARAMS_MASK2_VALUE;
+    variablesForTouchArea[6].easyGUIVariablePtr                = GuiVar_ethernetMask2;
+    variablesForTouchArea[6].internalVariablePtr               = &(subnetMask[1]);
+    variablesForTouchArea[6].maxValue                          = 255;
+    variablesForTouchArea[6].easyGUIBackgroundColorVariablePtr = &GuiVar_ethernetMask2BackgroundColour;
+    strcpy(variablesForTouchArea[6].variableName, "Subnet mask 2");
+
+    variablesForTouchArea[7].touchAreaIndex                    = NETWORK_PARAMS_MASK3_VALUE;
+    variablesForTouchArea[7].easyGUIVariablePtr                = GuiVar_ethernetMask3;
+    variablesForTouchArea[7].internalVariablePtr               = &(subnetMask[2]);
+    variablesForTouchArea[7].maxValue                          = 255;
+    variablesForTouchArea[7].easyGUIBackgroundColorVariablePtr = &GuiVar_ethernetMask3BackgroundColour;
+    strcpy(variablesForTouchArea[7].variableName, "Subnet mask 3");
+
+    variablesForTouchArea[8].touchAreaIndex                    = NETWORK_PARAMS_MASK4_VALUE;
+    variablesForTouchArea[8].easyGUIVariablePtr                = GuiVar_ethernetMask4;
+    variablesForTouchArea[8].internalVariablePtr               = &(subnetMask[3]);
+    variablesForTouchArea[8].maxValue                          = 255;
+    variablesForTouchArea[8].easyGUIBackgroundColorVariablePtr = &GuiVar_ethernetMask4BackgroundColour;
+    strcpy(variablesForTouchArea[8].variableName, "Subnet mask 4");
+
+
+    variablesForTouchArea[9].touchAreaIndex                     = NETWORK_PARAMS_GATEWAY1_VALUE;
+    variablesForTouchArea[9].easyGUIVariablePtr                 = GuiVar_ethernetGateway1;
+    variablesForTouchArea[9].internalVariablePtr                = &(gatewayAddress[0]);
+    variablesForTouchArea[9].maxValue                           = 255;
+    variablesForTouchArea[9].easyGUIBackgroundColorVariablePtr  = &GuiVar_ethernetGateway1BackgroundColour;
+    strcpy(variablesForTouchArea[9].variableName, "Gateway 1");
+
+    variablesForTouchArea[10].touchAreaIndex                    = NETWORK_PARAMS_GATEWAY2_VALUE;
+    variablesForTouchArea[10].easyGUIVariablePtr                = GuiVar_ethernetGateway2;
+    variablesForTouchArea[10].internalVariablePtr               = &(gatewayAddress[1]);
+    variablesForTouchArea[10].maxValue                          = 255;
+    variablesForTouchArea[10].easyGUIBackgroundColorVariablePtr = &GuiVar_ethernetGateway2BackgroundColour;
+    strcpy(variablesForTouchArea[10].variableName, "Gateway 2");
+
+    variablesForTouchArea[11].touchAreaIndex                    = NETWORK_PARAMS_GATEWAY3_VALUE;
+    variablesForTouchArea[11].easyGUIVariablePtr                = GuiVar_ethernetGateway3;
+    variablesForTouchArea[11].internalVariablePtr               = &(gatewayAddress[2]);
+    variablesForTouchArea[11].maxValue                          = 255;
+    variablesForTouchArea[11].easyGUIBackgroundColorVariablePtr = &GuiVar_ethernetGateway3BackgroundColour;
+    strcpy(variablesForTouchArea[11].variableName, "Gateway 3");
+
+    variablesForTouchArea[12].touchAreaIndex                    = NETWORK_PARAMS_GATEWAY4_VALUE;
+    variablesForTouchArea[12].easyGUIVariablePtr                = GuiVar_ethernetGateway4;
+    variablesForTouchArea[12].internalVariablePtr               = &(gatewayAddress[3]);
+    variablesForTouchArea[12].maxValue                          = 255;
+    variablesForTouchArea[12].easyGUIBackgroundColorVariablePtr = &GuiVar_ethernetGateway4BackgroundColour;
+    strcpy(variablesForTouchArea[12].variableName, "Gateway 4");
+}
+
+    
+// Private destructor also
+NetworkParameters::~NetworkParameters()
+{
+}
+
+
+/*
+    Saves the current parameter values to QSPI settings,
+    so they are maintained even when the user powers off
+    
+    No arguments, no return value
+*/
+void NetworkParameters::SaveToQSPISettings(void)
+{
+    // Put values to QSPI settings, using SettingsHandler member functions
+
+    SettingsHandler::PutIntegerValueToQSPISettings("PortNumber", portNumber);
+
+    SettingsHandler::PutIntegerValueToQSPISettings("IPAddress0", ipAddress[0]);
+    SettingsHandler::PutIntegerValueToQSPISettings("IPAddress1", ipAddress[1]);
+    SettingsHandler::PutIntegerValueToQSPISettings("IPAddress2", ipAddress[2]);
+    SettingsHandler::PutIntegerValueToQSPISettings("IPAddress3", ipAddress[3]);
+
+    SettingsHandler::PutIntegerValueToQSPISettings("SubnetMask0", subnetMask[0]);
+    SettingsHandler::PutIntegerValueToQSPISettings("SubnetMask1", subnetMask[1]);
+    SettingsHandler::PutIntegerValueToQSPISettings("SubnetMask2", subnetMask[2]);
+    SettingsHandler::PutIntegerValueToQSPISettings("SubnetMask3", subnetMask[3]);
+
+    SettingsHandler::PutIntegerValueToQSPISettings("GatewayAddress0", gatewayAddress[0]);
+    SettingsHandler::PutIntegerValueToQSPISettings("GatewayAddress1", gatewayAddress[1]);
+    SettingsHandler::PutIntegerValueToQSPISettings("GatewayAddress2", gatewayAddress[2]);
+    SettingsHandler::PutIntegerValueToQSPISettings("GatewayAddress3", gatewayAddress[3]);
+
+    SettingsHandler::PutIntegerValueToQSPISettings("UseDHCP", (useDHCP ? 1 : 0) );
+}
+
+
+/*
+    Reads the current parameter values from QSPI settings,
+    so they are maintained even when the user powers off
+    
+    No arguments, no return value
+*/
+void NetworkParameters::ReadFromQSPISettings(void)
+{
+    // Get values from QSPI settings, using SettingsHandler member functions
+    
+    portNumber = SettingsHandler::GetIntegerValueFromQSPISettings("PortNumber", defaultPortNumber);
+    
+    ipAddress[0] = SettingsHandler::GetIntegerValueFromQSPISettings("IPAddress0", defaultIPAddress[0]);
+    ipAddress[1] = SettingsHandler::GetIntegerValueFromQSPISettings("IPAddress1", defaultIPAddress[1]);
+    ipAddress[2] = SettingsHandler::GetIntegerValueFromQSPISettings("IPAddress2", defaultIPAddress[2]);
+    ipAddress[3] = SettingsHandler::GetIntegerValueFromQSPISettings("IPAddress3", defaultIPAddress[3]);
+    
+    subnetMask[0] = SettingsHandler::GetIntegerValueFromQSPISettings("SubnetMask0", defaultSubnetMask[0]);
+    subnetMask[1] = SettingsHandler::GetIntegerValueFromQSPISettings("SubnetMask1", defaultSubnetMask[1]);
+    subnetMask[2] = SettingsHandler::GetIntegerValueFromQSPISettings("SubnetMask2", defaultSubnetMask[2]);
+    subnetMask[3] = SettingsHandler::GetIntegerValueFromQSPISettings("SubnetMask3", defaultSubnetMask[3]);
+
+    gatewayAddress[0] = SettingsHandler::GetIntegerValueFromQSPISettings("GatewayAddress0", defaultGatewayAddress[0]);
+    gatewayAddress[1] = SettingsHandler::GetIntegerValueFromQSPISettings("GatewayAddress1", defaultGatewayAddress[1]);
+    gatewayAddress[2] = SettingsHandler::GetIntegerValueFromQSPISettings("GatewayAddress2", defaultGatewayAddress[2]);
+    gatewayAddress[3] = SettingsHandler::GetIntegerValueFromQSPISettings("GatewayAddress3", defaultGatewayAddress[3]);
+    
+    useDHCP = (SettingsHandler::GetIntegerValueFromQSPISettings("UseDHCP", 0) != 0); // Default to false
+}
+
+/*
+    Gets the current parameters - i.e. the values we are actually using 
+    for the Ethernet link - from the specified EthernetInterface instance, 
+    and saves them as the "real" values, so that we can restore them 
+    (a) on entering the page (called from TouchCallback in main.cpp), 
+    and (b) when the user presses Cancel.
+    
+    Args: a pointer to the EthernetInterface instance
+    
+    No return code
+*/
+void NetworkParameters::SaveRealValues(EthernetInterface *eth)
+{
+    realPortNumber = portNumber;
+
+    SetIPAddressFromString(eth->getIPAddress());
+    SetSubnetMaskFromString(eth->getNetworkMask());
+    SetGatewayAddressFromString(eth->getGateway());
+
+    for (int index = 0; index < 4; ++index) {
+        realIPAddress[index]      = ipAddress[index];
+        realSubnetMask[index]     = subnetMask[index];
+        realGatewayAddress[index] = gatewayAddress[index];
+    }
+}
+
+
+/*
+    Restores the current parameter values to the 'real' values.
+    It is up the caller to display these to the user.
+    ************************************************
+    
+    No arguments, no return code
+*/
+void NetworkParameters::RestoreRealValues(void)
+{
+    portNumber = realPortNumber;
+
+    for (int index = 0; index < 4; ++index) {
+        ipAddress[index]      = realIPAddress[index];
+        subnetMask[index]     = realSubnetMask[index];
+        gatewayAddress[index] = realGatewayAddress[index];
+    }
+}
+
+
+/*
+    Sets the background colours of all 'editable' fields to the 'inactive' colour.
+    
+    No arguments, no return code
+*/
+void NetworkParameters::SetAllFieldBackgroundColoursToInactive(void)
+{
+    GuiVar_ethernetPortBackgroundColour = inactiveFieldBackgroundColour;
+
+    GuiVar_ethernetIP1BackgroundColour = inactiveFieldBackgroundColour;
+    GuiVar_ethernetIP2BackgroundColour = inactiveFieldBackgroundColour;
+    GuiVar_ethernetIP3BackgroundColour = inactiveFieldBackgroundColour;
+    GuiVar_ethernetIP4BackgroundColour = inactiveFieldBackgroundColour;
+
+    GuiVar_ethernetMask1BackgroundColour = inactiveFieldBackgroundColour;
+    GuiVar_ethernetMask2BackgroundColour = inactiveFieldBackgroundColour;
+    GuiVar_ethernetMask3BackgroundColour = inactiveFieldBackgroundColour;
+    GuiVar_ethernetMask4BackgroundColour = inactiveFieldBackgroundColour;
+
+    GuiVar_ethernetGateway1BackgroundColour = inactiveFieldBackgroundColour;
+    GuiVar_ethernetGateway2BackgroundColour = inactiveFieldBackgroundColour;
+    GuiVar_ethernetGateway3BackgroundColour = inactiveFieldBackgroundColour;
+    GuiVar_ethernetGateway4BackgroundColour = inactiveFieldBackgroundColour;
+}
+
+/*
+    Sets the background colours of all 'editable' fields to the 'inactive' colour.
+    
+    No arguments, no return code
+*/
+void NetworkParameters::SetAllFieldBackgroundColoursToWhite(void)
+{
+    GuiVar_ethernetPortBackgroundColour = 0xFFFF;
+
+    GuiVar_ethernetIP1BackgroundColour = 0xFFFF;
+    GuiVar_ethernetIP2BackgroundColour = 0xFFFF;
+    GuiVar_ethernetIP3BackgroundColour = 0xFFFF;
+    GuiVar_ethernetIP4BackgroundColour = 0xFFFF;
+
+    GuiVar_ethernetMask1BackgroundColour = 0xFFFF;
+    GuiVar_ethernetMask2BackgroundColour = 0xFFFF;
+    GuiVar_ethernetMask3BackgroundColour = 0xFFFF;
+    GuiVar_ethernetMask4BackgroundColour = 0xFFFF;
+
+    GuiVar_ethernetGateway1BackgroundColour = 0xFFFF;
+    GuiVar_ethernetGateway2BackgroundColour = 0xFFFF;
+    GuiVar_ethernetGateway3BackgroundColour = 0xFFFF;
+    GuiVar_ethernetGateway4BackgroundColour = 0xFFFF;
+}
+
+
+/*
+    Caller is telling us it is about to display the easyGUI 'EthernetParametersPage',
+    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 NetworkParameters::DisplayingEasyGUIPage(bool updateEasyGUIVariables)
+{
+    if(updateEasyGUIVariables) {
+        UpdateEasyGUIVariablesFromInternalValues();
+    }
+
+#ifdef USE_BACKGROUND_COLOURS
+    SetAllFieldBackgroundColoursToInactive();
+#else
+    SetAllFieldBackgroundColoursToWhite();
+#endif
+
+    indexOfVariablesCurrentlyBeingEdited = -1; 
+    
+//    UpdateEasyGUIPage();
+}
+
+
+/*
+    Outputs the port number as a null-terminated string, in the form of an integer
+    with 1-5 digits. If the value is zero, it will be returned as "0", not as an empty string.
+    
+    Args: a pointer to a buffer to contain the string.
+          It is up to the caller to make sure this is long enough, i.e. at least 6 bytes long
+                                                                        **********************
+    No return code
+*/
+void NetworkParameters::GetPortNumberAsString(char *portBuffer)
+{
+    if(portNumber == 0) {
+        portBuffer[0] = '0';
+        portBuffer[1] = '\0';
+        
+        return;
+    }
+    
+    if(portNumber >= 65535) {
+        portBuffer[0] = '6';
+        portBuffer[1] = '5';
+        portBuffer[2] = '5';
+        portBuffer[3] = '3';
+        portBuffer[4] = '5';
+        portBuffer[5] = '\0';
+        
+        return;
+    }
+    
+    // 'else' - value is between 0 and 65535
+    sprintf(portBuffer, "%5u", portNumber);
+    return;
+    
+}
+
+
+/*
+    Set the port number from a null-terminated string
+    
+    Args: a pointer to a buffer that contains the string.
+
+    No return code
+*/
+void NetworkParameters::SetPortNumberFromString(char *portBuffer)
+{
+    unsigned int temp;
+    sscanf(portBuffer, "%u", &temp);
+    
+    // 'temp' is unsigned, so cannot be less than zero
+    if(temp > 65535) {
+        portNumber = 65535;
+        return;
+    }
+    
+    // 'else'
+    portNumber = temp;
+}
+
+
+/*
+    Outputs the specified field of the IP address as a null-terminated string, in the form of an integer
+    with 1-3 digits. If the value is zero, it will be returned as "0", not as an empty string.
+    
+    Args: the index to the field (value 0 through 3)
+          a pointer to a buffer to contain the string.
+          It is up to the caller to make sure this is long enough, i.e. at least 4 bytes long
+                                                                        **********************
+    No return code
+*/
+void NetworkParameters::GetIPAddressFieldAsString(int fieldIndex, char *ipAddressBuffer, bool wantLeadingSpaces)
+{
+    // By default, we pad the field with leading spaces,
+    // to try and keep it a constant width
+    if((fieldIndex >= 0) && (fieldIndex < 4)) {
+        if(ipAddress[fieldIndex] == 0) {
+            if(wantLeadingSpaces) {
+                ipAddressBuffer[0] = ' ';
+                ipAddressBuffer[1] = ' ';
+                ipAddressBuffer[2] = '0';
+                ipAddressBuffer[3] = '\0';
+            } else {
+                ipAddressBuffer[0] = '0';
+                ipAddressBuffer[1] = '\0';
+            }
+                        
+            return;
+        }
+        
+        if(ipAddress[fieldIndex] >= 255) {
+            ipAddressBuffer[0] = '2';
+            ipAddressBuffer[1] = '5';
+            ipAddressBuffer[2] = '5';
+            ipAddressBuffer[3] = '\0';
+            
+            return;
+        }
+        
+        // 'else' - value is between 0 and 255
+        if(wantLeadingSpaces) {
+            sprintf(ipAddressBuffer, "%3u", ipAddress[fieldIndex]);
+        } else {
+            sprintf(ipAddressBuffer, "%u", ipAddress[fieldIndex]);
+        }            
+        return;
+    }
+    
+    // 'else' - invalid index
+    ipAddressBuffer[0] = '\0';
+}
+
+
+/*
+    Sets the specified field of the IP address from a null-terminated string
+    
+    Args: the index to the field (value 0 through 3)
+          a pointer to a buffer that contains the string.
+
+    No return code
+*/
+void NetworkParameters::SetIPAddressFieldFromString(int fieldIndex, char *ipAddressBuffer)
+{
+    if((fieldIndex >= 0) && (fieldIndex < 4)) {
+        unsigned int temp;
+        sscanf(ipAddressBuffer, "%u", &temp);
+        
+        // 'temp' is unsigned, so cannot be less than zero
+        if(temp > 255) {
+            ipAddress[fieldIndex] = 255;
+            return;
+        }
+        
+        // 'else'
+        ipAddress[fieldIndex] = temp;
+    }
+}
+
+
+/*
+    Outputs the specified field of the subnet mask as a null-terminated string, in the form of an integer
+    with 1-3 digits. If the value is zero, it will be returned as "0", not as an empty string.
+    
+    Args: the index to the field (value 0 through 3)
+          a pointer to a buffer to contain the string.
+          It is up to the caller to make sure this is long enough, i.e. at least 4 bytes long
+                                                                        **********************
+    No return code
+*/
+void NetworkParameters::GetSubnetMaskFieldAsString(int fieldIndex, char *subnetMaskBuffer, bool wantLeadingSpaces)
+{
+    // By default, we pad the field with leading spaces,
+    // to try and keep it a constant width
+    if((fieldIndex >= 0) && (fieldIndex < 4)) {
+        if(subnetMask[fieldIndex] == 0) {
+            if(wantLeadingSpaces) {
+                subnetMaskBuffer[0] = ' ';
+                subnetMaskBuffer[1] = ' ';
+                subnetMaskBuffer[2] = '0';
+                subnetMaskBuffer[3] = '\0';
+            } else {
+                subnetMaskBuffer[0] = '0';
+                subnetMaskBuffer[1] = '\0';
+            }            
+            return;
+        }
+        
+        if(subnetMask[fieldIndex] >= 255) {
+            subnetMaskBuffer[0] = '2';
+            subnetMaskBuffer[1] = '5';
+            subnetMaskBuffer[2] = '5';
+            subnetMaskBuffer[3] = '\0';
+            
+            return;
+        }
+        
+        // 'else' - value is between 0 and 255
+        if(wantLeadingSpaces) {
+            sprintf(subnetMaskBuffer, "%3u", subnetMask[fieldIndex]);
+        } else {
+            sprintf(subnetMaskBuffer, "%u", subnetMask[fieldIndex]);
+        }
+        return;
+    }
+    
+    // 'else' - invalid index
+    subnetMaskBuffer[0] = '\0';    
+}
+
+
+/*
+    Sets the specified field of the subnet mask from a null-terminated string
+    
+    Args: the index to the field (value 0 through 3)
+          a pointer to a buffer that contains the string.
+
+    No return code
+*/
+void NetworkParameters::SetSubnetMaskFieldFromString(int fieldIndex, char *subnetMaskBuffer)
+{
+    if((fieldIndex >= 0) && (fieldIndex < 4)) {
+        unsigned int temp;
+        sscanf(subnetMaskBuffer, "%u", &temp);
+        
+        // 'temp' is unsigned, so cannot be less than zero
+        if(temp > 255) {
+            subnetMask[fieldIndex] = 255;
+            return;
+        }
+        
+        // 'else'
+        subnetMask[fieldIndex] = temp;
+    }
+}
+
+
+/*
+    Outputs the specified field of the gateway address as a null-terminated string, in the form of an integer
+    with 1-3 digits. If the value is zero, it will be returned as "0", not as an empty string.
+    
+    Args: the index to the field (value 0 through 3)
+          a pointer to a buffer to contain the string.
+          It is up to the caller to make sure this is long enough, i.e. at least 4 bytes long
+                                                                        **********************
+    No return code
+*/
+void NetworkParameters::GetGatewayAddressFieldAsString(int fieldIndex, char *gatewayAddressBuffer, bool wantLeadingSpaces)
+{
+    // By default, we pad the field with leading spaces,
+    // to try and keep it a constant width
+    if((fieldIndex >= 0) && (fieldIndex < 4)) {
+        if(gatewayAddress[fieldIndex] == 0) {
+            if(wantLeadingSpaces) {
+                gatewayAddressBuffer[0] = ' ';
+                gatewayAddressBuffer[1] = ' ';
+                gatewayAddressBuffer[2] = '0';
+                gatewayAddressBuffer[3] = '\0';
+            } else {
+                gatewayAddressBuffer[0] = '0';
+                gatewayAddressBuffer[1] = '\0';
+            }            
+            return;
+        }
+        
+        if(gatewayAddress[fieldIndex] >= 255) {
+            gatewayAddressBuffer[0] = '2';
+            gatewayAddressBuffer[1] = '5';
+            gatewayAddressBuffer[2] = '5';
+            gatewayAddressBuffer[3] = '\0';
+            
+            return;
+        }
+        
+        // 'else' - value is between 0 and 255
+        if(wantLeadingSpaces) {
+            sprintf(gatewayAddressBuffer, "%3u", gatewayAddress[fieldIndex]);
+        } else {
+            sprintf(gatewayAddressBuffer, "%u", gatewayAddress[fieldIndex]);
+        }
+        return;
+    }
+    
+    // 'else' - invalid index
+    gatewayAddressBuffer[0] = '\0';    
+}
+    
+
+/*
+    Sets the specified field of the gateway address from a null-terminated string
+    
+    Args: the index to the field (value 0 through 3)
+          a pointer to a buffer that contains the string.
+
+    No return code
+*/
+void NetworkParameters::SetGatewayAddressFieldFromString(int fieldIndex, char *gatewayAddressBuffer)
+{
+    if((fieldIndex >= 0) && (fieldIndex < 4)) {
+        unsigned int temp;
+        sscanf(gatewayAddressBuffer, "%u", &temp);
+        
+        // 'temp' is unsigned, so cannot be less than zero
+        if(temp > 255) {
+            gatewayAddress[fieldIndex] = 255;
+            return;
+        }
+        
+        // 'else'
+        gatewayAddress[fieldIndex] = temp;
+    }
+}
+
+
+/*
+    Outputs the IP address as a null-terminated string, in the conventional form,
+    i.e. as four integers, each of which can be 1-3 digits, separated by dots, e.g. "123.456.789.123".
+    If any of the values is zero, it will appear as "0", not as an empty string - but other than that,
+    there will be no leading zeroes.
+    
+    Args: a pointer to a buffer to contain the string.
+          It is up to the caller to make sure this is long enough, i.e. at least 16 bytes long
+                                                                        **********************
+    No return code
+*/
+void NetworkParameters::GetIPAddressAsString(char *ipAddressBuffer)
+{
+    char ipAddressField0[10];
+    char ipAddressField1[10];
+    char ipAddressField2[10];
+    char ipAddressField3[10];
+    
+    GetIPAddressFieldAsString(0, ipAddressField0, false);
+    GetIPAddressFieldAsString(1, ipAddressField1, false);
+    GetIPAddressFieldAsString(2, ipAddressField2, false);
+    GetIPAddressFieldAsString(3, ipAddressField3, false);
+    
+    sprintf(ipAddressBuffer, "%s.%s.%s.%s", ipAddressField0, ipAddressField1, ipAddressField2, ipAddressField3);
+}
+
+/*
+    Sets our IP address from the string passed to it, which we expect to be in the conventional form,
+    i.e. as four integers, each of which can be 1-3 digits, separated by dots, e.g. "123.456.789.123".
+
+    Args: a pointer to a buffer which contains the string.
+
+    No return code
+*/
+void NetworkParameters::SetIPAddressFromString(char *ipAddressBuffer)
+{
+    char fieldBuff[20];
+    int fieldBuffIndex;
+    int ipAddressBufferIndex;
+    
+    ipAddressBufferIndex = 0;
+    for (int ipAddressIndex = 0; ipAddressIndex < 4; ++ipAddressIndex) {
+        fieldBuffIndex = 0;
+        while((ipAddressBuffer[ipAddressBufferIndex] != '\0') && (ipAddressBuffer[ipAddressBufferIndex] != '.')){
+            fieldBuff[fieldBuffIndex++] = ipAddressBuffer[ipAddressBufferIndex++];
+        }
+        fieldBuff[fieldBuffIndex] = '\0';
+        
+        SetIPAddressFieldFromString(ipAddressIndex, fieldBuff);
+        
+        if(ipAddressBuffer[ipAddressBufferIndex] == '\0') break;
+        
+        ++ipAddressBufferIndex; // Point to next field
+    }
+}
+
+
+/*
+    Outputs the subnet mask as a null-terminated string, in the conventional form,
+    i.e. as four integers, each of which can be 1-3 digits, separated by dots, e.g. "123.456.789.123".
+    If any of the values is zero, it will appear as "0", not as an empty string - but other than that,
+    there will be no leading zeroes.
+    
+    Args: a pointer to a buffer to contain the string.
+          It is up to the caller to make sure this is long enough, i.e. at least 16 bytes long
+                                                                        **********************
+    No return code
+*/
+void NetworkParameters::GetSubnetMaskAsString(char *subnetMaskBuffer)
+{
+    char subnetMaskField0[10];
+    char subnetMaskField1[10];
+    char subnetMaskField2[10];
+    char subnetMaskField3[10];
+    
+    GetSubnetMaskFieldAsString(0, subnetMaskField0, false);
+    GetSubnetMaskFieldAsString(1, subnetMaskField1, false);
+    GetSubnetMaskFieldAsString(2, subnetMaskField2, false);
+    GetSubnetMaskFieldAsString(3, subnetMaskField3, false);
+    
+    sprintf(subnetMaskBuffer, "%s.%s.%s.%s", subnetMaskField0, subnetMaskField1, subnetMaskField2, subnetMaskField3);
+}
+
+/*
+    Sets our subnet mask from the string passed to it, which we expect to be in the conventional form,
+    i.e. as four integers, each of which can be 1-3 digits, separated by dots, e.g. "123.456.789.123".
+
+    Args: a pointer to a buffer which contains the string.
+
+    No return code
+*/
+void NetworkParameters::SetSubnetMaskFromString(char *subnetMaskBuffer)
+{
+    char fieldBuff[20];
+    int fieldBuffIndex;
+    int subnetMaskBufferIndex;
+    
+    subnetMaskBufferIndex = 0;
+    for (int subnetMaskIndex = 0; subnetMaskIndex < 4; ++subnetMaskIndex) {
+        fieldBuffIndex = 0;
+        while((subnetMaskBuffer[subnetMaskBufferIndex] != '\0') && (subnetMaskBuffer[subnetMaskBufferIndex] != '.')){
+            fieldBuff[fieldBuffIndex++] = subnetMaskBuffer[subnetMaskBufferIndex++];
+        }
+        fieldBuff[fieldBuffIndex] = '\0';
+        
+        SetSubnetMaskFieldFromString(subnetMaskIndex, fieldBuff);
+        
+        if(subnetMaskBuffer[subnetMaskBufferIndex] == '\0') break;
+        
+        ++subnetMaskBufferIndex; // Point to next field
+    }
+}
+
+
+/*
+    Outputs the gateway address as a null-terminated string, in the conventional form,
+    i.e. as four integers, each of which can be 1-3 digits, separated by dots, e.g. "123.456.789.123".
+    If any of the values is zero, it will appear as "0", not as an empty string - but other than that,
+    there will be no leading zeroes.
+    
+    Args: a pointer to a buffer to contain the string.
+          It is up to the caller to make sure this is long enough, i.e. at least 16 bytes long
+                                                                        **********************
+    No return code
+*/
+void NetworkParameters::GetGatewayAddressAsString(char *gatewayAddressBuffer)
+{
+    char gatewayAddressField0[10];
+    char gatewayAddressField1[10];
+    char gatewayAddressField2[10];
+    char gatewayAddressField3[10];
+    
+    GetGatewayAddressFieldAsString(0, gatewayAddressField0, false);
+    GetGatewayAddressFieldAsString(1, gatewayAddressField1, false);
+    GetGatewayAddressFieldAsString(2, gatewayAddressField2, false);
+    GetGatewayAddressFieldAsString(3, gatewayAddressField3, false);
+    
+    sprintf(gatewayAddressBuffer, "%s.%s.%s.%s", gatewayAddressField0, gatewayAddressField1, gatewayAddressField2, gatewayAddressField3);
+}
+
+/*
+    Sets our gateway address from the string passed to it, which we expect to be in the conventional form,
+    i.e. as four integers, each of which can be 1-3 digits, separated by dots, e.g. "123.456.789.123".
+
+    Args: a pointer to a buffer which contains the string.
+
+    No return code
+*/
+void NetworkParameters::SetGatewayAddressFromString(char *gatewayAddressBuffer)
+{
+    char fieldBuff[20];
+    int fieldBuffIndex;
+    int gatewayAddressBufferIndex;
+    
+    gatewayAddressBufferIndex = 0;
+    for (int gatewayAddressIndex = 0; gatewayAddressIndex < 4; ++gatewayAddressIndex) {
+        fieldBuffIndex = 0;
+        while((gatewayAddressBuffer[gatewayAddressBufferIndex] != '\0') && (gatewayAddressBuffer[gatewayAddressBufferIndex] != '.')){
+            fieldBuff[fieldBuffIndex++] = gatewayAddressBuffer[gatewayAddressBufferIndex++];
+        }
+        fieldBuff[fieldBuffIndex] = '\0';
+        
+        SetGatewayAddressFieldFromString(gatewayAddressIndex, fieldBuff);
+        
+        if(gatewayAddressBuffer[gatewayAddressBufferIndex] == '\0') break;
+        
+        ++gatewayAddressBufferIndex; // Point to next field
+    }
+}
+
+
+/*
+    Tells the caller whether or not the specified touch index is on the easyGUI 'EthernetParametersPage',
+    and therefore needs to be handled by this class.
+    
+    Args: the touch area index in question
+    
+    Return code: true if the touch area represents a network parameter, false if not
+*/
+bool NetworkParameters::TouchAreaIsNetworkParameter(int touchAreaIndex)
+{
+    if((touchAreaIndex >= MIN_NETWORK_PARAM) && (touchAreaIndex <= MAX_NETWORK_PARAM)) {
+        return true;
+    }
+    
+    // 'else'...
+    return false;
+}
+
+
+/*
+    Tells the caller if the specified touch area corresponds to a value the user can edit
+    on the easyGUI 'EthernetParametersPage', and if so, which one.
+    
+    Args: the touch area index in question
+    
+    Returns the index of the corresponding entry in our 'variablesForTouchArea' array,
+    or -1 if there is no such entry. It is up to the caller to check for -1
+                                     **************************************
+*/
+int NetworkParameters::GetIndexOfVariablesToEditForTouchArea(int touchAreaIndex)
+{
+    for (int index = 0; index < COUNT_OF_VARIABLES_FOR_TOUCH_AREAS; ++index) {
+        if(variablesForTouchArea[index].touchAreaIndex == touchAreaIndex) {
+            return index;
+        }
+    }
+    
+    // 'else' no Network Parameters variable corresponds to the specified touch area
+    return -1;
+}
+
+
+/*
+    If the specified touch area represents a key or field on the easyGUI 'EthernetParametersPage',
+    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 keys 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 'EthernetParametersPage', and so the caller
+    must deal with it some other way).
+*/
+bool NetworkParameters::DealWithTouch(int touchAreaIndex)
+{
+    if(TouchAreaIsNetworkParameter(touchAreaIndex)) {
+    
+#ifdef TOUCH_VALUES_DIRECTLY
+        // Has the user selected a field to edit - 
+        // if so, we will have an entry in our 'variablesForTouchArea' array that corresponds with this touch area
+        int indexOfVariablesToEdit = GetIndexOfVariablesToEditForTouchArea(touchAreaIndex);
+        if(indexOfVariablesToEdit != -1) {        
+            // User has selected a field to edit
+            indexOfVariablesCurrentlyBeingEdited = indexOfVariablesToEdit;
+            NumericKeypadPageHandler* numericKeypadPageHandler = NumericKeypadPageHandler::GetInstance(usbDevice, usbHostGC);
+            if(numericKeypadPageHandler != NULL) {
+                
+                numericKeypadPageHandler->StartEditing(variablesForTouchArea[indexOfVariablesCurrentlyBeingEdited].easyGUIVariablePtr);
+                
+                // We need the numeric keypad to update the easyGUI variable *and* our internal variable - they must always match
+                numericKeypadPageHandler->SetEasyGUIVariableToEdit(variablesForTouchArea[indexOfVariablesCurrentlyBeingEdited].easyGUIVariablePtr);
+                numericKeypadPageHandler->SetInternalVariableToEdit(variablesForTouchArea[indexOfVariablesCurrentlyBeingEdited].internalVariablePtr);
+                
+                numericKeypadPageHandler->SetEasyGUICallingPage(GuiStruct_EthernetParametersPage_50);
+                numericKeypadPageHandler->SetEditVariableRange(0, variablesForTouchArea[indexOfVariablesCurrentlyBeingEdited].maxValue);
+                numericKeypadPageHandler->SetEditVariableName(variablesForTouchArea[indexOfVariablesCurrentlyBeingEdited].variableName);
+                
+                numericKeypadPageHandler->DisplayEasyGUIPage();
+            }
+            return true;
+        } 
+#endif // TOUCH_VALUES_DIRECTLY
+
+        if(touchAreaIndex == NETWORK_PARAMS_PORT_EDIT) {
+            indexOfVariablesCurrentlyBeingEdited = 0; // Port
+            NumericKeypadPageHandler* numericKeypadPageHandler = NumericKeypadPageHandler::GetInstance(usbDevice, usbHostGC);
+            if(numericKeypadPageHandler != NULL) {
+                
+                numericKeypadPageHandler->StartEditing(variablesForTouchArea[indexOfVariablesCurrentlyBeingEdited].easyGUIVariablePtr);
+                
+                // We need the numeric keypad to update the easyGUI variable *and* our internal variable - they must always match
+                numericKeypadPageHandler->SetEasyGUIVariableToEdit(variablesForTouchArea[indexOfVariablesCurrentlyBeingEdited].easyGUIVariablePtr);                
+                numericKeypadPageHandler->SetInternalVariableToEdit(variablesForTouchArea[indexOfVariablesCurrentlyBeingEdited].internalVariablePtr);
+                
+                numericKeypadPageHandler->SetEasyGUICallingPage(GuiStruct_EthernetParametersPage_50);
+                numericKeypadPageHandler->SetEditVariableRange(0, variablesForTouchArea[indexOfVariablesCurrentlyBeingEdited].maxValue);
+                numericKeypadPageHandler->SetEditVariableName(variablesForTouchArea[indexOfVariablesCurrentlyBeingEdited].variableName);
+                
+                numericKeypadPageHandler->DisplayEasyGUIPage();
+            }
+            return true;
+        }
+        
+        // 'else'...
+        
+        if(DealWithIPEditButton(touchAreaIndex)) {
+            return true;
+        }
+        
+        // 'else'...
+        
+        if(DealWithMaskEditButton(touchAreaIndex)) {
+            return true;
+        }
+        
+        // 'else'...
+        
+        if(DealWithGatewayEditButton(touchAreaIndex)) {
+            return true;
+        }
+            
+        // 'else'...
+        
+        if(DealWithCancelButton(touchAreaIndex)) {
+            return true;
+        }
+            
+        // 'else'...
+        
+        if(DealWithApplyButton(touchAreaIndex)) {
+            return true;
+        }
+            
+        // 'else'...
+        
+        if(DealWithUseDHCPButton(touchAreaIndex)) {
+            return true;
+        }
+
+        return false; // Not dealt with touch area
+    }
+    
+    // 'else' not one of our touch areas...
+    return false;
+}
+
+
+/*
+    If the specified touch area represents the Apply button on the easyGUI 'EthernetParametersPage',
+    this function will apply the current values on that page. In theory, this should mean closing 
+    the current Ethernet connection, if any, and setting up a new one with the new values. However,
+    in practice the EthernetInterface class does not seem to be able to do this (while the first 
+    call to the EthernetInterface 'init' method succeeds, subsequent calls crash). So we write 
+    our current values to QSPI memory, and then force the entire application to restart, 
+    knowing that when it does so, GetGCStatusLoop::MainLoopWithEthernet will call us back 
+    to get the new Ethernet parameters from QSPI memory before calling the EthernetInterface 'init' method.
+
+    Args: the touch area index in question
+    
+    Returns true if the specified touch area is the Apply button, false if not
+    (we are just telling the caller whether it needs to do anything else with this value)
+*/
+bool NetworkParameters::DealWithApplyButton(int touchAreaIndex)
+{
+    if(touchAreaIndex == NETWORK_PARAMS_APPLY_BUTTON) {
+        
+        useDHCP = false;
+        
+        UpdateInternalValuesFromEasyGUIVariables();
+        
+        SaveToQSPISettings();
+        
+        GetGCStatusLoop* getGCStatusLoop = GetGCStatusLoop::GetInstance();
+        if(getGCStatusLoop != NULL) {
+            getGCStatusLoop->ForceRestart(); // This is the only way to make the new values take effect
+        }
+
+        return true;
+    }
+    
+    // 'else' not the Apply button
+    return false;
+}
+
+
+/*
+    If the specified touch area represents the Cancel button on the easyGUI 'EthernetParametersPage',
+    this function will reset the current values on that page to the 'real' values -
+    i.e. the ones we are actually using for the Ethernet link.
+
+    Args: the touch area index in question
+    
+    Returns true if the specified touch area is the Cancel button, false if not
+    (we are just telling the caller whether it needs to do anything else with this value)
+*/
+bool NetworkParameters::DealWithCancelButton(int touchAreaIndex)
+{
+    if(touchAreaIndex == NETWORK_PARAMS_CANCEL_BUTTON) {
+        
+        RestoreRealValues();
+        UpdateEasyGUIVariablesFromInternalValues();
+
+#ifdef USE_BACKGROUND_COLOURS
+        SetAllFieldBackgroundColoursToInactive();
+#else
+        SetAllFieldBackgroundColoursToWhite();
+#endif
+
+        indexOfVariablesCurrentlyBeingEdited = -1; 
+        
+        UpdateEasyGUIPage();
+
+        return true;
+    }
+    
+    // 'else' not the Cancel button
+    return false;
+}
+
+
+/*
+    If the specified touch area represents the "Use DHCP" button on the easyGUI 'EthernetParametersPage',
+    this function will restart the Ethernet connection using DHCP to obtain the IP address, etc, values, 
+    instead of using the explicit ones shown on this page. In theory, this should mean closing 
+    the current Ethernet connection, if any, and setting up a new one with the new values. However,
+    in practice the EthernetInterface class does not seem to be able to do this (while the first 
+    call to the EthernetInterface 'init' method succeeds, subsequent calls crash). So we write 
+    "UseDHCP = true" to QSPI memory, and then force the entire application to restart, 
+    knowing that when it does so, GetGCStatusLoop::MainLoopWithEthernet will call us back 
+    to get the new Ethernet parameters from QSPI memory, see that "UseDHCP" is set true,
+    and call the appropriate EthernetInterface 'init' method.
+
+    Args: the touch area index in question
+    
+    Returns true if the specified touch area is the "Use DHCP" button, false if not
+    (we are just telling the caller whether it needs to do anything else with this value)
+*/
+bool NetworkParameters::DealWithUseDHCPButton(int touchAreaIndex)
+{
+    if(touchAreaIndex == NETWORK_PARAMS_DHCP_BUTTON) {
+        
+        useDHCP = true;
+        
+        UpdateInternalValuesFromEasyGUIVariables();
+        
+        SaveToQSPISettings();
+        
+        GetGCStatusLoop* getGCStatusLoop = GetGCStatusLoop::GetInstance();
+        if(getGCStatusLoop != NULL) {
+            getGCStatusLoop->ForceRestart(); // This is the only way to make the new values take effect
+        }
+
+        return true;
+    }
+    
+    // 'else' not the Apply button
+    return false;
+}
+
+
+/*
+    If the specified touch area represents the "Edit IP address" button on the easyGUI 'EthernetParametersPage',
+    this function invokes the EthernetKeypadPageHandler to do that.
+
+    Args: the touch area index in question
+    
+    Returns true if the specified touch area is the "Edit IP address" button, false if not
+    (we are just telling the caller whether it needs to do anything else with this value)
+*/
+bool NetworkParameters::DealWithIPEditButton(int touchAreaIndex)
+{
+    if(touchAreaIndex == NETWORK_PARAMS_IP_EDIT) {
+        
+        EthernetKeypadPageHandler* ethernetKeypadPageHandler = EthernetKeypadPageHandler::GetInstance(usbDevice, usbHostGC);
+        if(ethernetKeypadPageHandler != NULL) {
+                
+            ethernetKeypadPageHandler->SetEasyGUIOctetVariablesToEdit(GuiVar_ethernetIP1, GuiVar_ethernetIP2, GuiVar_ethernetIP3, GuiVar_ethernetIP4);
+            ethernetKeypadPageHandler->SetInternalOctetVariablesToEdit(&(ipAddress[0]), &(ipAddress[1]), &(ipAddress[2]), &(ipAddress[3]));
+            
+            ethernetKeypadPageHandler->StartEditing("IP Address");
+        }
+
+        return true;
+    }
+    
+    // 'else'...
+    return false;
+}
+
+
+/*
+    If the specified touch area represents the "Edit subnet mask" button on the easyGUI 'EthernetParametersPage',
+    this function invokes the EthernetKeypadPageHandler to do that.
+
+    Args: the touch area index in question
+    
+    Returns true if the specified touch area is the "Edit subnet mask" button, false if not
+    (we are just telling the caller whether it needs to do anything else with this value)
+*/
+bool NetworkParameters::DealWithMaskEditButton(int touchAreaIndex)
+{
+    if(touchAreaIndex == NETWORK_PARAMS_MASK_EDIT) {
+        
+        EthernetKeypadPageHandler* ethernetKeypadPageHandler = EthernetKeypadPageHandler::GetInstance(usbDevice, usbHostGC);
+        if(ethernetKeypadPageHandler != NULL) {
+                
+            ethernetKeypadPageHandler->SetEasyGUIOctetVariablesToEdit(GuiVar_ethernetMask1, GuiVar_ethernetMask2, GuiVar_ethernetMask3, GuiVar_ethernetMask4);
+            ethernetKeypadPageHandler->SetInternalOctetVariablesToEdit(&(subnetMask[0]), &(subnetMask[1]), &(subnetMask[2]), &(subnetMask[3]));
+            
+            ethernetKeypadPageHandler->StartEditing("Subnet Mask");
+        }
+
+        return true;
+    }
+    
+    // 'else'...
+    return false;
+}
+
+
+/*
+    If the specified touch area represents the "Edit gateway" button on the easyGUI 'EthernetParametersPage',
+    this function invokes the EthernetKeypadPageHandler to do that.
+
+    Args: the touch area index in question
+    
+    Returns true if the specified touch area is the "Edit gateway" button, false if not
+    (we are just telling the caller whether it needs to do anything else with this value)
+*/
+bool NetworkParameters::DealWithGatewayEditButton(int touchAreaIndex)
+{
+    if(touchAreaIndex == NETWORK_PARAMS_GATEWAY_EDIT) {
+        
+        EthernetKeypadPageHandler* ethernetKeypadPageHandler = EthernetKeypadPageHandler::GetInstance(usbDevice, usbHostGC);
+        if(ethernetKeypadPageHandler != NULL) {
+
+            ethernetKeypadPageHandler->SetEasyGUIOctetVariablesToEdit(GuiVar_ethernetGateway1, GuiVar_ethernetGateway2, GuiVar_ethernetGateway3, GuiVar_ethernetGateway4);
+            ethernetKeypadPageHandler->SetInternalOctetVariablesToEdit(&(gatewayAddress[0]), &(gatewayAddress[1]), &(gatewayAddress[2]), &(gatewayAddress[3]));
+            
+            ethernetKeypadPageHandler->StartEditing("Gateway");
+        }
+
+        return true;
+    }
+    
+    return false;
+}
+
+
+/*
+    For each of our internal (private) variables, make it equal to the value
+    of the corresponding easyGUI variable (the value displayed to the user)
+    
+    No arguments, no return code
+*/
+void NetworkParameters::UpdateInternalValuesFromEasyGUIVariables(void)
+{
+    SetPortNumberFromString(GuiVar_ethernetPort);
+    
+    SetIPAddressFieldFromString(0, GuiVar_ethernetIP1);
+    SetIPAddressFieldFromString(1, GuiVar_ethernetIP2);
+    SetIPAddressFieldFromString(2, GuiVar_ethernetIP3);
+    SetIPAddressFieldFromString(3, GuiVar_ethernetIP4);
+    
+    SetSubnetMaskFieldFromString(0, GuiVar_ethernetMask1);
+    SetSubnetMaskFieldFromString(1, GuiVar_ethernetMask2);
+    SetSubnetMaskFieldFromString(2, GuiVar_ethernetMask3);
+    SetSubnetMaskFieldFromString(3, GuiVar_ethernetMask4);
+
+    SetGatewayAddressFieldFromString(0, GuiVar_ethernetGateway1);
+    SetGatewayAddressFieldFromString(1, GuiVar_ethernetGateway2);
+    SetGatewayAddressFieldFromString(2, GuiVar_ethernetGateway3);
+    SetGatewayAddressFieldFromString(3, GuiVar_ethernetGateway4);
+}
+
+
+/*
+    For each of our internal (private) variables, copy its value
+    to the corresponding easyGUI variable (the value displayed to the user)
+    
+    No arguments, no return code
+*/
+void NetworkParameters::UpdateEasyGUIVariablesFromInternalValues(void)
+{
+    GetPortNumberAsString(GuiVar_ethernetPort);
+    
+    GetIPAddressFieldAsString(0, GuiVar_ethernetIP1);
+    GetIPAddressFieldAsString(1, GuiVar_ethernetIP2);
+    GetIPAddressFieldAsString(2, GuiVar_ethernetIP3);
+    GetIPAddressFieldAsString(3, GuiVar_ethernetIP4);
+    
+    GetSubnetMaskFieldAsString(0, GuiVar_ethernetMask1);
+    GetSubnetMaskFieldAsString(1, GuiVar_ethernetMask2);
+    GetSubnetMaskFieldAsString(2, GuiVar_ethernetMask3);
+    GetSubnetMaskFieldAsString(3, GuiVar_ethernetMask4);
+
+    GetGatewayAddressFieldAsString(0, GuiVar_ethernetGateway1);
+    GetGatewayAddressFieldAsString(1, GuiVar_ethernetGateway2);
+    GetGatewayAddressFieldAsString(2, GuiVar_ethernetGateway3);
+    GetGatewayAddressFieldAsString(3, GuiVar_ethernetGateway4);
+}
+
+
+/*
+    (Re)display the easyGUI 'EthernetParametersPage' -
+    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 NetworkParameters::UpdateEasyGUIPage(void)
+{
+#define WANT_GUILIB_CLEAR
+#ifdef WANT_GUILIB_CLEAR
+#ifdef USING_BACKGROUND_BITMAP
+    DrawBackgroundBitmap();
+#else
+    GuiLib_Clear();
+#endif
+#undef WANT_GUILIB_CLEAR
+#endif
+    GuiLib_ShowScreen(GuiStruct_EthernetParametersPage_50, GuiLib_NO_CURSOR, GuiLib_RESET_AUTO_REDRAW);
+
+    GuiLib_Refresh();    
+}