//-------------------------------------------------------------------------------------------------//

        public virtual ValidationReport Validate(string xmlSpecification)
        {
            const string STRLOG_MethodName = "Validate";

            Logfile.WriteCalled(STRLOG_ClassName, STRLOG_MethodName);

            ValidationReport validationReport = new ValidationReport(false);

            //
            // Parse the XML specification string to generate a validation report
            //
            try
            {
                ExperimentSpecification experimentSpecification = new ExperimentSpecification(this.labConfiguration, this.equipmentServiceProxy);
                validationReport = experimentSpecification.Parse(xmlSpecification);
            }
            catch (Exception ex)
            {
                validationReport.errorMessage = ex.Message;
            }

            Logfile.WriteCompleted(STRLOG_ClassName, STRLOG_MethodName);

            return(validationReport);
        }
        //-------------------------------------------------------------------------------------------------//
        public override int GetExecutionTime(ExperimentSpecification experimentSpecification)
        {
            const string STRLOG_MethodName = "GetExecutionTime";

            Logfile.WriteCalled(STRLOG_ClassName, STRLOG_MethodName);

            // Typecast the specification so that it can be used here
            Specification specification = (Specification)experimentSpecification;

            //
            // Initialise variables
            //
            double executionTime = EXECUTION_TIME;

            string logMessage = STRLOG_ExecutionTime + executionTime.ToString();

            Logfile.WriteCompleted(STRLOG_ClassName, STRLOG_MethodName, logMessage);

            return (int)executionTime;
        }
Exemplo n.º 3
0
        //-------------------------------------------------------------------------------------------------//

        public virtual void Create()
        {
            const string STRLOG_MethodName = "Create";

            Logfile.WriteCalled(STRLOG_ClassName, STRLOG_MethodName);

            //
            // Create local class instances just to check that all is in order
            //
            ExperimentSpecification experimentSpecification = new ExperimentSpecification(this.appData.labConfiguration, null);
            LabExperimentResult     labExperimentResult     = new LabExperimentResult(this.appData.labConfiguration);

            //
            // Create instances of lab experiment engines
            //
            this.appData.labExperimentEngines = new LabExperimentEngine[this.appData.farmSize];
            for (int i = 0; i < this.appData.farmSize; i++)
            {
                this.appData.labExperimentEngines[i] = new LabExperimentEngine(i, this.appData);
            }

            Logfile.WriteCompleted(STRLOG_ClassName, STRLOG_MethodName);
        }
        //-------------------------------------------------------------------------------------------------//
        public virtual ValidationReport Validate(string xmlSpecification)
        {
            const string STRLOG_MethodName = "Validate";

            Logfile.WriteCalled(STRLOG_ClassName, STRLOG_MethodName);

            ValidationReport validationReport = new ValidationReport(false);

            //
            // Parse the XML specification string to generate a validation report
            //
            try
            {
                ExperimentSpecification experimentSpecification = new ExperimentSpecification(this.labConfiguration, this.equipmentServiceProxy);
                validationReport = experimentSpecification.Parse(xmlSpecification);
            }
            catch (Exception ex)
            {
                validationReport.errorMessage = ex.Message;
            }

            Logfile.WriteCompleted(STRLOG_ClassName, STRLOG_MethodName);

            return validationReport;
        }
        //-------------------------------------------------------------------------------------------------//
        /// <summary>
        /// Run the experiment and fill in the result report. Override in a derived class.
        /// </summary>
        /// <param name="experimentInfo"></param>
        /// <returns></returns>
        public virtual ExperimentInfo RunExperiment(ExperimentInfo experimentInfo)
        {
            const string STRLOG_MethodName = "RunExperiment";

            Logfile.WriteCalled(STRLOG_ClassName, STRLOG_MethodName);

            // Create a result report ready to fill in
            experimentInfo.resultReport = new ResultReport();

            try
            {
                //
                // Parse the XML specification string to generate a validation report (should be accepted!)
                //
                ExperimentSpecification experimentSpecification = new ExperimentSpecification(this.labConfiguration, this.equipmentServiceProxy);
                ValidationReport validationReport = experimentSpecification.Parse(experimentInfo.xmlSpecification);
                if (validationReport.accepted == false)
                {
                    throw new ArgumentException(validationReport.errorMessage);
                }
                experimentInfo.setupId = experimentSpecification.SetupId;

                //
                // Create an instance of the driver for the specified setup and then
                // execute the experiment and return the result information
                //
                ExperimentResultInfo experimentResultInfo = null;
                if (experimentSpecification.SetupId.Equals(Consts.STRXML_SetupId_EquipmentGeneric))
                {
                    DriverEquipmentGeneric driver = new DriverEquipmentGeneric(this.equipmentServiceProxy, this.labConfiguration, this.labExperimentInfo.cancelExperiment);
                    experimentResultInfo = driver.Execute(experimentSpecification);
                }
                else if (experimentSpecification.SetupId.Equals(Consts.STRXML_SetupId_ModuleGeneric))
                {
                    DriverModuleGeneric driver = new DriverModuleGeneric(this.labConfiguration, this.labExperimentInfo.cancelExperiment);
                    experimentResultInfo = driver.Execute(experimentSpecification);
                }

                //
                // Create an instance of LabExperimentResult to convert the experiment results to an XML string
                //
                LabExperimentResult labExperimentResult = new LabExperimentResult(
                    experimentInfo.experimentId, experimentInfo.sbName, DateTime.Now,
                    experimentSpecification.SetupId, this.unitId, this.labConfiguration);

                //
                // Fill in the result report
                //
                experimentInfo.resultReport.experimentResults = labExperimentResult.ToString();
                experimentInfo.resultReport.statusCode = (int)experimentResultInfo.statusCode;
                experimentInfo.resultReport.errorMessage = experimentResultInfo.errorMessage;
            }
            catch (Exception ex)
            {
                experimentInfo.resultReport.statusCode = (int)StatusCodes.Failed;
                experimentInfo.resultReport.errorMessage = ex.Message;
                Logfile.WriteError(ex.Message);
            }

            Logfile.WriteCompleted(STRLOG_ClassName, STRLOG_MethodName);

            return experimentInfo;
        }
        //---------------------------------------------------------------------------------------//
        public override ExperimentResultInfo Execute(ExperimentSpecification experimentSpecification)
        {
            const string STRLOG_MethodName = "Execute";

            Logfile.WriteCalled(STRLOG_ClassName, STRLOG_MethodName);

            //
            // Determine how long it actually take to execute
            //
            DateTime startDateTime = DateTime.Now;

            // Typecast the specification so that it can be used here
            Specification specification = (Specification)experimentSpecification;

            //
            // Log the specification
            //
            string strDistanceList = null;
            for (int i = 0; i < specification.DistanceList.Length; i++)
            {
                if (i > 0)
                {
                    strDistanceList += Consts.CHR_CsvSplitter.ToString();
                }
                strDistanceList += specification.DistanceList[i].ToString();
            }
            string logMessage = STRLOG_Distance + strDistanceList;
            logMessage += Logfile.STRLOG_Spacer + STRLOG_Duration + specification.Duration.ToString();
            logMessage += Logfile.STRLOG_Spacer + STRLOG_Repeat + specification.Repeat.ToString();
            Logfile.Write(logMessage);

            //
            // Create an instance of the result info ready to fill in
            //
            ResultInfo resultInfo = new ResultInfo();
            resultInfo.statusCode = StatusCodes.Running;
            resultInfo.dataType = DataTypes.Real;

            //
            // Create data structures to hold the results
            //
            resultInfo.dataVectors = new int[specification.DistanceList.Length, specification.Repeat];

            //
            // Initialise variables used in the state machine
            //
            int distanceIndex = 0;
            int repeatIndex = 0;
            int tubeHomeDistance = 0;
            char sourceHomeLocation = (char)0;
            char absorberHomeLocation = (char)0;

            try
            {
                //
                // First, check to see if the LabEquipment is online
                //
                LabEquipmentStatus labEquipmentStatus = this.equipmentServiceProxy.GetLabEquipmentStatus();
                if (labEquipmentStatus.online == false)
                {
                    throw new Exception(labEquipmentStatus.statusMessage);
                }

                //
                // Run the state machine to execute the experiment specification
                //
                States_Execute state = States_Execute.sCompleted;
                if (smTable_Execute.Length > 0)
                {
                    state = smTable_Execute[0].currentState;
                }
                while (state != States_Execute.sCompleted)
                {
                    //
                    // Find table entry
                    //
                    int index = -1;
                    for (int i = 0; i < smTable_Execute.Length; i++)
                    {
                        if (smTable_Execute[i].currentState == state)
                        {
                            // Entry found
                            index = i;
                            break;
                        }
                    }
                    if (index == -1)
                    {
                        throw new ArgumentOutOfRangeException(state.ToString(), STRERR_StateNotFound);
                    }

                    //
                    // Get table entry and save next state
                    //
                    SMTableEntry_Execute entry = smTable_Execute[index];
                    States_Execute nextState = entry.nextState;

                    logMessage = " [ " + STRLOG_MethodName + ": " + entry.currentState.ToString() + " ]";
                    Logfile.Write(logMessage);

                    Trace.WriteLine(logMessage);

                    //
                    // Check if experiment was cancelled
                    //
                    if (this.cancelExperiment != null && this.cancelExperiment.IsCancelled == true &&
                        resultInfo.statusCode == StatusCodes.Running)
                    {
                        //
                        // Experiment was cancelled
                        //
                        resultInfo.statusCode = StatusCodes.Cancelled;
                        state = entry.exitState;
                        continue;
                    }

                    //
                    // Process non-XML commands
                    //
                    switch (entry.currentState)
                    {
                        case States_Execute.sSuspendPowerdown:
                            if (this.equipmentServiceProxy.SuspendPowerdown() == false)
                            {
                                //
                                // Command execution failed
                                //
                                resultInfo.statusCode = StatusCodes.Failed;
                                resultInfo.errorMessage = STRERR_SuspendPowerdown;
                                state = entry.exitState;
                            }
                            else
                            {
                                state = nextState;
                            }
                            continue;

                        case States_Execute.sResumePowerdown:
                            if (this.equipmentServiceProxy.ResumePowerdown() == false)
                            {
                                //
                                // Command execution failed
                                //
                                resultInfo.statusCode = StatusCodes.Failed;
                                resultInfo.errorMessage = STRERR_ResumePowerdown;
                                state = entry.exitState;
                            }
                            else
                            {
                                state = nextState;
                            }
                            continue;

                        default:
                            break;
                    }

                    //
                    // Add command arguments where required
                    //
                    switch (entry.currentState)
                    {
                        case States_Execute.sSelectAbsorberMessageLine2:
                            entry.commandArguments[1, 1] = HttpUtility.UrlEncode(specification.AbsorberList[0].name);
                            break;

                        case States_Execute.sSelectAbsorber:
                            entry.commandArguments[0, 1] = specification.AbsorberList[0].location.ToString();
                            break;

                        case States_Execute.sSelectSourceMessageLine2:
                            entry.commandArguments[1, 1] = HttpUtility.UrlEncode(specification.SourceName);
                            break;

                        case States_Execute.sSelectSource:
                            entry.commandArguments[0, 1] = specification.SourceLocation.ToString();
                            break;

                        case States_Execute.sSetTubeDistanceMessageLine2:
                            entry.commandArguments[1, 1] = HttpUtility.UrlEncode(specification.DistanceList[distanceIndex].ToString() + STRLCD_Millimetres);
                            break;

                        case States_Execute.sSetTubeDistance:
                            entry.commandArguments[0, 1] = specification.DistanceList[distanceIndex].ToString();
                            break;

                        case States_Execute.sCaptureDataMessageLine2:
                            string lcdMessage = specification.DistanceList[distanceIndex].ToString() + STRLCD_Millimetres;
                            lcdMessage += STRLCD_Break + specification.Duration.ToString() + STRLCD_Seconds;
                            lcdMessage += STRLCD_Break + (repeatIndex + 1).ToString() + STRLCD_Of + specification.Repeat.ToString();
                            entry.commandArguments[1, 1] = HttpUtility.UrlEncode(lcdMessage);
                            break;

                        case States_Execute.sCaptureData:
                            entry.commandArguments[0, 1] = specification.Duration.ToString();
                            break;

                        case States_Execute.sReturnSource:
                            entry.commandArguments[0, 1] = sourceHomeLocation.ToString();
                            break;

                        case States_Execute.sReturnAbsorber:
                            entry.commandArguments[0, 1] = absorberHomeLocation.ToString();
                            break;

                        case States_Execute.sReturnTube:
                            entry.commandArguments[0, 1] = tubeHomeDistance.ToString();
                            break;

                        default:
                            break;
                    }

                    //
                    // Execute command and check response success
                    //
                    XmlDocument xmlRequestDocument = CreateXmlRequestDocument(entry.equipmentCommand, entry.commandArguments);
                    string xmlResponse = this.equipmentServiceProxy.ExecuteRequest(xmlRequestDocument.InnerXml);
                    XmlNode xmlResponseNode = CreateXmlResponseNode(xmlResponse);
                    if (XmlUtilities.GetBoolValue(xmlResponseNode, LabServerEngine.Consts.STRXML_RspSuccess, false) == false)
                    {
                        //
                        // Command execution failed
                        //
                        resultInfo.statusCode = StatusCodes.Failed;
                        resultInfo.errorMessage = XmlUtilities.GetXmlValue(xmlResponseNode, LabServerEngine.Consts.STRXML_RspErrorMessage, true);
                        state = entry.exitState;
                        continue;
                    }

                    //
                    // Extract response values where required
                    //
                    switch (entry.currentState)
                    {
                        case States_Execute.sCaptureData:
                            resultInfo.dataVectors[distanceIndex, repeatIndex] = XmlUtilities.GetIntValue(xmlResponseNode, Consts.STRXML_RspCount, 0);
                            if (++repeatIndex == specification.Repeat)
                            {
                                if (++distanceIndex == specification.DistanceList.Length)
                                {
                                    // All distances completed
                                    break;
                                }

                                // Next distance
                                repeatIndex = 0;
                                nextState = States_Execute.sSetTubeDistanceMessageLine1;
                                break;
                            }

                            // Next repeat
                            nextState = States_Execute.sCaptureDataMessageLine1;
                            break;

                        case States_Execute.sGetSourceHomeLocation:
                            sourceHomeLocation = XmlUtilities.GetCharValue(xmlResponseNode, Consts.STRXML_RspSourceHomeLocation, (char)0);
                            break;

                        case States_Execute.sGetAbsorberHomeLocation:
                            absorberHomeLocation = XmlUtilities.GetCharValue(xmlResponseNode, Consts.STRXML_RspAbsorberHomeLocation, (char)0);
                            break;

                        case States_Execute.sGetTubeHomeDistance:
                            tubeHomeDistance = XmlUtilities.GetIntValue(xmlResponseNode, Consts.STRXML_RspTubeHomeDistance, 0);
                            break;

                        default:
                            break;
                    }

                    Trace.WriteLine("nextState: " + entry.nextState.ToString());

                    //
                    // Next state
                    //
                    state = nextState;
                }

                //
                // Update status code
                //
                if (resultInfo.statusCode == StatusCodes.Running)
                {
                    resultInfo.statusCode = StatusCodes.Completed;
                }
            }
            catch (Exception ex)
            {
                resultInfo.statusCode = StatusCodes.Failed;
                resultInfo.errorMessage = ex.Message;
                Logfile.WriteError(ex.Message);
            }

            //
            // Calculate actual execution time and round to the nearest integer
            //
            TimeSpan timeSpan = DateTime.Now - startDateTime;
            int execTime = (int)(timeSpan.TotalSeconds + 0.5);

            logMessage = STRLOG_StatusCode + resultInfo.statusCode
                + Logfile.STRLOG_Spacer + STRLOG_ExecutionTime + execTime.ToString();

            Logfile.WriteCompleted(STRLOG_ClassName, STRLOG_MethodName, logMessage);

            return resultInfo;
        }
        //-------------------------------------------------------------------------------------------------//
        public override int GetExecutionTime(ExperimentSpecification experimentSpecification)
        {
            const string STRLOG_MethodName = "GetExecutionTime";

            Logfile.WriteCalled(STRLOG_ClassName, STRLOG_MethodName);

            // Typecast the specification so that it can be used here
            Specification specification = (Specification)experimentSpecification;

            //
            // Log the specification
            //
            string logMessage = string.Empty;

            //
            // Initialise variables used in the state machine
            //
            double executionTime = 0.0;

            try
            {
                //
                // First, check to see if the LabEquipment is online
                //
                LabEquipmentStatus labEquipmentStatus = this.equipmentServiceProxy.GetLabEquipmentStatus();
                if (labEquipmentStatus.online == false)
                {
                    throw new Exception(labEquipmentStatus.statusMessage);
                }

                //
                // Get the time until the LabEquipment is ready to use
                //
                executionTime = this.equipmentServiceProxy.GetTimeUntilReady();

                //
                // Run the state machine to determine the execution time for the experiment specification
                //
                States_GetExecutionTime state = States_GetExecutionTime.sCompleted;
                if (smTable_GetExecutionTime.Length > 0)
                {
                    state = smTable_GetExecutionTime[0].currentState;
                }
                while (state != States_GetExecutionTime.sCompleted)
                {
                    //
                    // Find table entry
                    //
                    int index = -1;
                    for (int i = 0; i < smTable_GetExecutionTime.Length; i++)
                    {
                        if (smTable_GetExecutionTime[i].currentState == state)
                        {
                            // Entry found
                            index = i;
                            break;
                        }
                    }
                    if (index == -1)
                    {
                        throw new ArgumentOutOfRangeException(state.ToString(), "State not found!");
                    }

                    //
                    // Get table entry and save next state
                    //
                    SMTableEntry_GetExecutionTime entry = smTable_GetExecutionTime[index];
                    States_GetExecutionTime nextState = entry.nextState;

                    logMessage = " [ " + STRLOG_MethodName + ": " + entry.currentState.ToString() + " ]";
                    Logfile.Write(logMessage);
                    Trace.WriteLine(logMessage);

                    //
                    // Add command arguments where required
                    //
                    switch (entry.currentState)
                    {
                        default:
                            break;
                    }

                    //
                    // Execute command and check response success
                    //
                    XmlDocument xmlRequestDocument = CreateXmlRequestDocument(entry.equipmentCommand, entry.commandArguments);
                    string xmlResponse = this.equipmentServiceProxy.ExecuteRequest(xmlRequestDocument.InnerXml);
                    XmlNode xmlResponseNode = CreateXmlResponseNode(xmlResponse);
                    if (XmlUtilities.GetBoolValue(xmlResponseNode, LabServerEngine.Consts.STRXML_RspSuccess, false) == false)
                    {
                        //
                        // Command execution failed
                        //
                        string errorMessage = XmlUtilities.GetXmlValue(xmlResponseNode, LabServerEngine.Consts.STRXML_RspErrorMessage, true);
                        throw new ArgumentException(errorMessage);
                    }

                    //
                    // Extract response values where required
                    //
                    double stateExecutionTime = 0.0;
                    switch (entry.currentState)
                    {
                        case States_GetExecutionTime.sGetTimeOfDayTime:
                            stateExecutionTime = XmlUtilities.GetRealValue(xmlResponseNode, Consts.STRXML_RspTimeOfDayTime, 0);
                            break;

                        default:
                            break;
                    }

                    //
                    // Update the execution time so far
                    //
                    executionTime += stateExecutionTime;

                    //
                    // Next state
                    //
                    state = nextState;
                }
            }
            catch (Exception ex)
            {
                Logfile.WriteError(ex.Message);
                throw;
            }

            logMessage = STRLOG_ExecutionTime + executionTime.ToString();

            Logfile.WriteCompleted(STRLOG_ClassName, STRLOG_MethodName, logMessage);

            return (int)executionTime;
        }
        //---------------------------------------------------------------------------------------//
        public override ExperimentResultInfo Execute(ExperimentSpecification experimentSpecification)
        {
            const string STRLOG_MethodName = "Execute";

            Logfile.WriteCalled(STRLOG_ClassName, STRLOG_MethodName);

            // Typecast the specification so that it can be used here
            Specification specification = (Specification)experimentSpecification;

            //
            // Log the specification
            //
            string logMessage = string.Empty;
            //Logfile.Write(logMessage);

            //
            // Create an instance of the result info ready to fill in
            //
            ResultInfo resultInfo = new ResultInfo();
            resultInfo.statusCode = StatusCodes.Running;

            //
            // Initialise variables used in the state machine
            //
            int repeatCount = 0;

            try
            {
                //
                // First, check to see if the LabEquipment is online
                //
                LabEquipmentStatus labEquipmentStatus = this.equipmentServiceProxy.GetLabEquipmentStatus();
                if (labEquipmentStatus.online == false)
                {
                    throw new Exception(labEquipmentStatus.statusMessage);
                }

                //
                // Run the state machine to execute the experiment specification
                //
                States_Execute state = States_Execute.sCompleted;
                if (smTable_Execute.Length > 0)
                {
                    state = smTable_Execute[0].currentState;
                }
                while (state != States_Execute.sCompleted)
                {
                    //
                    // Find table entry
                    //
                    int index = -1;
                    for (int i = 0; i < smTable_Execute.Length; i++)
                    {
                        if (smTable_Execute[i].currentState == state)
                        {
                            // Entry found
                            index = i;
                            break;
                        }
                    }
                    if (index == -1)
                    {
                        throw new ArgumentOutOfRangeException(state.ToString(), STRERR_StateNotFound);
                    }

                    //
                    // Get table entry and save next state
                    //
                    SMTableEntry_Execute entry = smTable_Execute[index];
                    States_Execute nextState = entry.nextState;

                    logMessage = " [ " + STRLOG_MethodName + ": " + entry.currentState.ToString() + " ]";
                    Logfile.Write(logMessage);

                    Trace.WriteLine(logMessage);

                    //
                    // Check if experiment was cancelled
                    //
                    if (this.cancelExperiment != null && this.cancelExperiment.IsCancelled == true &&
                        resultInfo.statusCode == StatusCodes.Running)
                    {
                        //
                        // Experiment was cancelled
                        //
                        resultInfo.statusCode = StatusCodes.Cancelled;
                        state = entry.exitState;
                        continue;
                    }

                    //
                    // Process non-XML commands
                    //
                    switch (entry.currentState)
                    {
                        case States_Execute.sSuspendPowerdown:
                            if (this.equipmentServiceProxy.SuspendPowerdown() == false)
                            {
                                //
                                // Command execution failed
                                //
                                resultInfo.statusCode = StatusCodes.Failed;
                                resultInfo.errorMessage = STRERR_SuspendPowerdown;
                                state = entry.exitState;
                            }
                            else
                            {
                                state = nextState;
                            }
                            continue;

                        case States_Execute.sResumePowerdown:
                            if (this.equipmentServiceProxy.ResumePowerdown() == false)
                            {
                                //
                                // Command execution failed
                                //
                                resultInfo.statusCode = StatusCodes.Failed;
                                resultInfo.errorMessage = STRERR_ResumePowerdown;
                                state = entry.exitState;
                            }
                            else
                            {
                                state = nextState;
                            }
                            continue;

                        default:
                            break;
                    }

                    //
                    // Add command arguments where required
                    //
                    switch (entry.currentState)
                    {
                        //
                        // Nothing to do here
                        //

                        default:
                            break;
                    }

                    //
                    // Execute command and check response success
                    //
                    XmlDocument xmlRequestDocument = CreateXmlRequestDocument(entry.equipmentCommand, entry.commandArguments);
                    string xmlResponse = this.equipmentServiceProxy.ExecuteRequest(xmlRequestDocument.InnerXml);
                    XmlNode xmlResponseNode = CreateXmlResponseNode(xmlResponse);
                    if (XmlUtilities.GetBoolValue(xmlResponseNode, LabServerEngine.Consts.STRXML_RspSuccess, false) == false)
                    {
                        //
                        // Command execution failed
                        //
                        resultInfo.statusCode = StatusCodes.Failed;
                        resultInfo.errorMessage = XmlUtilities.GetXmlValue(xmlResponseNode, LabServerEngine.Consts.STRXML_RspErrorMessage, true);
                        state = entry.exitState;
                        continue;
                    }

                    //
                    // Extract response values where required
                    //
                    switch (entry.currentState)
                    {
                        case States_Execute.sTakeMeasurement:

                            //
                            // Add in the values
                            //
                            resultInfo.voltage += (float)XmlUtilities.GetRealValue(xmlResponseNode, Consts.STRXML_RspVoltageMut, 0.0);
                            resultInfo.current += (float)XmlUtilities.GetRealValue(xmlResponseNode, Consts.STRXML_RspCurrentMut, 0.0);
                            resultInfo.powerFactor += (float)XmlUtilities.GetRealValue(xmlResponseNode, Consts.STRXML_RspPowerFactorMut, 0.0);
                            resultInfo.speed += XmlUtilities.GetIntValue(xmlResponseNode, Consts.STRXML_RspSpeed, 0);
                            resultInfo.torque += XmlUtilities.GetIntValue(xmlResponseNode, Consts.STRXML_RspTorque, 0);

                            //
                            // Check if all measurements have been taken
                            //
                            if (++repeatCount == this.measurementCount)
                            {
                                //
                                // All measurements taken, average the values
                                //
                                resultInfo.voltage /= this.measurementCount;
                                resultInfo.current /= this.measurementCount;
                                resultInfo.powerFactor /= this.measurementCount;
                                resultInfo.speed /= this.measurementCount;
                                resultInfo.torque /= this.measurementCount;
                                break;
                            }

                            // Next measurement
                            nextState = States_Execute.sTakeMeasurement;
                            break;

                        default:
                            break;
                    }

                    //
                    // Next state
                    //
                    state = nextState;
                }

                //
                // Update status code
                //
                if (resultInfo.statusCode == StatusCodes.Running)
                {
                    resultInfo.statusCode = StatusCodes.Completed;
                }
            }
            catch (Exception ex)
            {
                resultInfo.statusCode = StatusCodes.Failed;
                resultInfo.errorMessage = ex.Message;
                Logfile.WriteError(ex.Message);
            }

            logMessage = STRLOG_StatusCode + resultInfo.statusCode;

            Logfile.WriteCompleted(STRLOG_ClassName, STRLOG_MethodName, logMessage);

            return resultInfo;
        }
        //---------------------------------------------------------------------------------------//
        public override ExperimentResultInfo Execute(ExperimentSpecification experimentSpecification)
        {
            const string STRLOG_MethodName = "Execute";

            Logfile.WriteCalled(STRLOG_ClassName, STRLOG_MethodName);

            //
            // Determine how long it actually take to execute
            //
            DateTime startDateTime = DateTime.Now;

            // Typecast the specification so that it can be used here
            Specification specification = (Specification)experimentSpecification;

            //
            // Log the specification
            //
            string strDistanceList = null;
            for (int i = 0; i < specification.DistanceList.Length; i++)
            {
                if (i > 0)
                {
                    strDistanceList += Consts.CHR_CsvSplitter.ToString();
                }
                strDistanceList += specification.DistanceList[i].ToString();
            }
            string logMessage = STRLOG_Distance + strDistanceList;
            logMessage += Logfile.STRLOG_Spacer + STRLOG_Duration + specification.Duration.ToString();
            logMessage += Logfile.STRLOG_Spacer + STRLOG_Repeat + specification.Repeat.ToString();
            Logfile.Write(logMessage);

            //
            // Create an instance of the result info ready to fill in
            //
            ResultInfo resultInfo = new ResultInfo();
            resultInfo.statusCode = StatusCodes.Running;
            if (this.simActivity.SimulateDelays == true)
            {
                resultInfo.dataType = DataTypes.Simulated;
            }
            else
            {
                resultInfo.dataType = DataTypes.Calculated;
            }

            //
            // Create data structures to hold the results
            //
            resultInfo.dataVectors = new int[specification.DistanceList.Length, specification.Repeat];

            //
            // Initialise variables used in the state machine
            //
            int distanceIndex = 0;
            int repeatIndex = 0;
            int[] generatedData = null;

            try
            {
                //
                // Run the state machine to execute the experiment specification
                //
                States_Execute state = States_Execute.sCompleted;
                if (smTable_Execute.Length > 0)
                {
                    state = smTable_Execute[0].currentState;
                }
                while (state != States_Execute.sCompleted)
                {
                    //
                    // Find table entry
                    //
                    int index = -1;
                    for (int i = 0; i < smTable_Execute.Length; i++)
                    {
                        if (smTable_Execute[i].currentState == state)
                        {
                            // Entry found
                            index = i;
                            break;
                        }
                    }
                    if (index == -1)
                    {
                        throw new ArgumentOutOfRangeException(state.ToString(), STRERR_StateNotFound);
                    }

                    //
                    // Get table entry and save next state
                    //
                    SMTableEntry_Execute entry = smTable_Execute[index];
                    States_Execute nextState = entry.nextState;

                    logMessage = " [ " + STRLOG_MethodName + ": " + entry.currentState.ToString() + " ]";
                    Logfile.Write(logMessage);

                    Trace.WriteLine(logMessage);

                    //
                    // Check if experiment was cancelled
                    //
                    if (this.cancelExperiment != null && this.cancelExperiment.IsCancelled == true &&
                        resultInfo.statusCode == StatusCodes.Running)
                    {
                        //
                        // Experiment was cancelled
                        //
                        resultInfo.statusCode = StatusCodes.Cancelled;
                        state = entry.exitState;
                        continue;
                    }

                    //
                    // Process commands
                    //
                    switch (entry.currentState)
                    {
                        case States_Execute.sSelectAbsorber:

                            //
                            // Get absorber location from specification
                            //
                            char absorberLocation = specification.AbsorberList[0].location;
                            Logfile.Write(STRLOG_AbsorberLocation + absorberLocation.ToString());

                            //
                            // Set absorber location
                            //
                            this.simActivity.SetAbsorberLocation(absorberLocation);
                            break;

                        case States_Execute.sSelectSource:

                            //
                            // Get source location from specification
                            //
                            char sourceLocation = specification.SourceLocation;
                            Logfile.Write(STRLOG_SourceLocation + sourceLocation.ToString());

                            //
                            // Set source location
                            //
                            this.simActivity.SetSourceLocation(sourceLocation);
                            break;

                        case States_Execute.sSetTubeDistance:

                            //
                            // Get tube distance from specification
                            //
                            int tubeDistance = specification.DistanceList[distanceIndex];
                            Logfile.Write(STRLOG_TubeDistance + tubeDistance.ToString());

                            //
                            // Set tube distance
                            //
                            this.simActivity.SetTubeDistance(tubeDistance);
                            break;

                        case States_Execute.sCaptureData:

                            if (repeatIndex == 0)
                            {
                                //
                                // Generate data for repeat counts at this distance
                                //
                                generatedData = this.simActivity.GenerateData(
                                    specification.DistanceList[distanceIndex], specification.Duration, specification.Repeat);
                            }

                            //
                            // Get capture data for this repeat count
                            //
                            int[] counts = new int[1];
                            this.simActivity.CaptureData(specification.Duration, counts, generatedData, repeatIndex);
                            resultInfo.dataVectors[distanceIndex, repeatIndex] = counts[0];
                            Logfile.Write(STRLOG_Duration + specification.Duration.ToString() +
                                Logfile.STRLOG_Spacer + STRLOG_Count + counts[0].ToString());

                            //
                            // Determine next state
                            //
                            if (++repeatIndex == specification.Repeat)
                            {
                                if (++distanceIndex == specification.DistanceList.Length)
                                {
                                    // All distances completed
                                    break;
                                }

                                // Next distance
                                repeatIndex = 0;
                                nextState = States_Execute.sSetTubeDistance;
                                break;
                            }

                            // Next repeat
                            nextState = States_Execute.sCaptureData;
                            break;

                        case States_Execute.sReturnSource:

                            //
                            // Get source home location
                            //
                            sourceLocation = this.simActivity.SourceHomeLocation;
                            Logfile.Write(STRLOG_SourceLocation + sourceLocation.ToString());

                            //
                            // Set source location
                            //
                            this.simActivity.SetSourceLocation(sourceLocation);
                            break;

                        case States_Execute.sReturnAbsorber:

                            //
                            // Get absorber home location
                            //
                            absorberLocation = this.simActivity.AbsorberHomeLocation;
                            Logfile.Write(STRLOG_AbsorberLocation + absorberLocation.ToString());

                            //
                            // Set absorber location
                            //
                            this.simActivity.SetAbsorberLocation(absorberLocation);
                            break;

                        case States_Execute.sReturnTube:

                            //
                            // Get tube home distance
                            //
                            tubeDistance = this.simActivity.TubeHomeDistance;
                            Logfile.Write(STRLOG_TubeDistance + tubeDistance.ToString());

                            //
                            // Set tube distance
                            //
                            this.simActivity.SetTubeDistance(tubeDistance);
                            break;

                        default:
                            break;
                    }

                    Trace.WriteLine("nextState: " + entry.nextState.ToString());

                    //
                    // Next state
                    //
                    state = nextState;
                }

                //
                // Update status code
                //
                if (resultInfo.statusCode == StatusCodes.Running)
                {
                    resultInfo.statusCode = StatusCodes.Completed;
                }
            }
            catch (Exception ex)
            {
                resultInfo.statusCode = StatusCodes.Failed;
                resultInfo.errorMessage = ex.Message;
                Logfile.WriteError(ex.Message);
            }

            TimeSpan timeSpan = DateTime.Now - startDateTime;
            logMessage = STRLOG_ExecutionTime + timeSpan.TotalSeconds.ToString();

            Logfile.WriteCompleted(STRLOG_ClassName, STRLOG_MethodName, logMessage);

            return resultInfo;
        }
        //---------------------------------------------------------------------------------------//
        public override ExperimentResultInfo Execute(ExperimentSpecification experimentSpecification)
        {
            const string STRLOG_MethodName = "Execute";

            Logfile.WriteCalled(STRLOG_ClassName, STRLOG_MethodName);

            //
            // Determine how long it actually take to execute
            //
            DateTime startDateTime = DateTime.Now;

            // Typecast the specification so that it can be used here
            Specification specification = (Specification)experimentSpecification;

            //
            // Log the specification
            //
            string logMessage = string.Empty;

            //
            // Create an instance of the result info ready to fill in
            //
            ResultInfo resultInfo = new ResultInfo();
            resultInfo.statusCode = StatusCodes.Running;

            //
            // Create data structures to hold the results
            //

            //
            // Initialise variables used in the state machine
            //

            try
            {
                //
                // First, check to see if the LabEquipment is online
                //
                LabEquipmentStatus labEquipmentStatus = this.equipmentServiceProxy.GetLabEquipmentStatus();
                if (labEquipmentStatus.online == false)
                {
                    throw new Exception(labEquipmentStatus.statusMessage);
                }

                //
                // Run the state machine to execute the experiment specification
                //
                States_Execute state = States_Execute.sCompleted;
                if (smTable_Execute.Length > 0)
                {
                    state = smTable_Execute[0].currentState;
                }
                while (state != States_Execute.sCompleted)
                {
                    //
                    // Find table entry
                    //
                    int index = -1;
                    for (int i = 0; i < smTable_Execute.Length; i++)
                    {
                        if (smTable_Execute[i].currentState == state)
                        {
                            // Entry found
                            index = i;
                            break;
                        }
                    }
                    if (index == -1)
                    {
                        throw new ArgumentOutOfRangeException(state.ToString(), STRERR_StateNotFound);
                    }

                    //
                    // Get table entry and save next state
                    //
                    SMTableEntry_Execute entry = smTable_Execute[index];
                    States_Execute nextState = entry.nextState;

                    logMessage = " [ " + STRLOG_MethodName + ": " + entry.currentState.ToString() + " ]";
                    Logfile.Write(logMessage);

                    Trace.WriteLine(logMessage);

                    //
                    // Check if experiment was cancelled
                    //
                    if (this.cancelExperiment != null && this.cancelExperiment.IsCancelled == true &&
                        resultInfo.statusCode == StatusCodes.Running)
                    {
                        //
                        // Experiment was cancelled
                        //
                        resultInfo.statusCode = StatusCodes.Cancelled;
                        state = entry.exitState;
                        continue;
                    }

                    //
                    // Process non-XML commands
                    //
                    switch (entry.currentState)
                    {
                        case States_Execute.sSuspendPowerdown:
                            if (this.equipmentServiceProxy.SuspendPowerdown() == false)
                            {
                                //
                                // Command execution failed
                                //
                                resultInfo.statusCode = StatusCodes.Failed;
                                resultInfo.errorMessage = STRERR_SuspendPowerdown;
                                state = entry.exitState;
                            }
                            else
                            {
                                state = nextState;
                            }
                            continue;

                        case States_Execute.sResumePowerdown:
                            if (this.equipmentServiceProxy.ResumePowerdown() == false)
                            {
                                //
                                // Command execution failed
                                //
                                resultInfo.statusCode = StatusCodes.Failed;
                                resultInfo.errorMessage = STRERR_ResumePowerdown;
                                state = entry.exitState;
                            }
                            else
                            {
                                state = nextState;
                            }
                            continue;

                        default:
                            break;
                    }

                    //
                    // Add command arguments where required
                    //
                    switch (entry.currentState)
                    {
                        case States_Execute.sGetTimeOfDay:

                            entry.commandArguments[0, 1] = specification.ServerUrl;
                            break;

                        default:
                            break;
                    }

                    //
                    // Execute command and check response success
                    //
                    XmlDocument xmlRequestDocument = CreateXmlRequestDocument(entry.equipmentCommand, entry.commandArguments);
                    string xmlResponse = this.equipmentServiceProxy.ExecuteRequest(xmlRequestDocument.InnerXml);
                    XmlNode xmlResponseNode = CreateXmlResponseNode(xmlResponse);
                    if (XmlUtilities.GetBoolValue(xmlResponseNode, LabServerEngine.Consts.STRXML_RspSuccess, false) == false)
                    {
                        //
                        // Command execution failed
                        //
                        resultInfo.statusCode = StatusCodes.Failed;
                        resultInfo.errorMessage = XmlUtilities.GetXmlValue(xmlResponseNode, LabServerEngine.Consts.STRXML_RspErrorMessage, true);
                        state = entry.exitState;
                        continue;
                    }

                    //
                    // Extract response values where required
                    //
                    switch (entry.currentState)
                    {
                        case States_Execute.sGetTimeOfDay:

                            string strTimeOfDayBinary = XmlUtilities.GetXmlValue(xmlResponseNode, Consts.STRXML_RspTimeOfDay, false);
                            long timeOfDay = Convert.ToInt64(strTimeOfDayBinary);
                            resultInfo.dateTime = DateTime.FromBinary(timeOfDay);

                            //
                            // Save the timestamp string in the specified format
                            //
                            if (specification.FormatName.Equals(Consts.STRXML_Format_12Hour))
                            {
                                resultInfo.timeofday = resultInfo.dateTime.ToString(Consts.STR_DateTimeFormat_12Hour);
                            }
                            else if (specification.FormatName.Equals(Consts.STRXML_Format_24Hour))
                            {
                                resultInfo.timeofday = resultInfo.dateTime.ToString(Consts.STR_DateTimeFormat_24Hour);
                            }
                            break;

                        default:
                            break;
                    }

                    //
                    // Next state
                    //
                    state = nextState;
                }

                //
                // Update status code
                //
                if (resultInfo.statusCode == StatusCodes.Running)
                {
                    resultInfo.statusCode = StatusCodes.Completed;
                }
            }
            catch (Exception ex)
            {
                resultInfo.statusCode = StatusCodes.Failed;
                resultInfo.errorMessage = ex.Message;
                Logfile.WriteError(ex.Message);
            }

            //
            // Calculate actual execution time
            //
            TimeSpan timeSpan = DateTime.Now - startDateTime;

            logMessage = STRLOG_StatusCode + resultInfo.statusCode
                + Logfile.STRLOG_Spacer + STRLOG_ExecutionTime + timeSpan.TotalSeconds.ToString();

            Logfile.WriteCompleted(STRLOG_ClassName, STRLOG_MethodName, logMessage);

            return resultInfo;
        }
        //-------------------------------------------------------------------------------------------------//
        public override int GetExecutionTime(ExperimentSpecification experimentSpecification)
        {
            const string STRLOG_MethodName = "GetExecutionTime";

            Logfile.WriteCalled(STRLOG_ClassName, STRLOG_MethodName);

            // Typecast the specification so that it can be used here
            Specification specification = (Specification)experimentSpecification;

            //
            // Log the specification
            //
            string strAbsorberList = null;
            for (int i = 0; i < specification.AbsorberList.Length; i++)
            {
                if (i > 0)
                {
                    strAbsorberList += Consts.CHR_CsvSplitter.ToString();
                }
                strAbsorberList += specification.AbsorberList[i].name;
            }
            string logMessage = STRLOG_Absorber + strAbsorberList;
            logMessage += Logfile.STRLOG_Spacer + STRLOG_Duration + specification.Duration.ToString();
            logMessage += Logfile.STRLOG_Spacer + STRLOG_Repeat + specification.Repeat.ToString();
            Logfile.Write(logMessage);

            //
            // Initialise variables used in the state machine
            //
            double executionTime = 0.0;
            double lcdWriteLineTime = 0.0;
            int tubeHomeDistance = 0;
            int absorberIndex = 0;
            char absorberHomeLocation = (char)0;
            double lastAbsorberSelectTime = 0.0;
            double absorberSelectHomeTime = 0.0;

            try
            {
                //
                // First, check to see if the LabEquipment is online
                //
                LabEquipmentStatus labEquipmentStatus = this.equipmentServiceProxy.GetLabEquipmentStatus();
                if (labEquipmentStatus.online == false)
                {
                    throw new Exception(labEquipmentStatus.statusMessage);
                }

                //
                // Get the time until the LabEquipment is ready to use
                //
                executionTime = this.equipmentServiceProxy.GetTimeUntilReady();

                //
                // Run the state machine to determine the execution time for the experiment specification
                //
                States_GetExecutionTime state = States_GetExecutionTime.sCompleted;
                if (smTable_GetExecutionTime.Length > 0)
                {
                    state = smTable_GetExecutionTime[0].currentState;
                }
                while (state != States_GetExecutionTime.sCompleted)
                {
                    //
                    // Find table entry
                    //
                    int index = -1;
                    for (int i = 0; i < smTable_GetExecutionTime.Length; i++)
                    {
                        if (smTable_GetExecutionTime[i].currentState == state)
                        {
                            // Entry found
                            index = i;
                            break;
                        }
                    }
                    if (index == -1)
                    {
                        throw new ArgumentOutOfRangeException(state.ToString(), STRERR_StateNotFound);
                    }

                    //
                    // Get table entry and save next state
                    //
                    SMTableEntry_GetExecutionTime entry = smTable_GetExecutionTime[index];
                    States_GetExecutionTime nextState = entry.nextState;

                    Trace.Write(" [ " + entry.currentState.ToString() + ": " + entry.currentState.ToString());

                    //
                    // Add command arguments where required
                    //
                    switch (entry.currentState)
                    {
                        case States_GetExecutionTime.sGetTubeMoveTime:
                            entry.commandArguments[0, 1] = tubeHomeDistance.ToString();
                            entry.commandArguments[1, 1] = specification.DistanceList[0].ToString();
                            break;

                        case States_GetExecutionTime.sGetSourceSelectTime:
                            entry.commandArguments[0, 1] = specification.SourceLocation.ToString();
                            break;

                        case States_GetExecutionTime.sGetAbsorberSelectHomeTime:
                            entry.commandArguments[0, 1] = absorberHomeLocation.ToString();
                            break;

                        case States_GetExecutionTime.sGetAbsorberSelectTime:
                            entry.commandArguments[0, 1] = specification.AbsorberList[absorberIndex].location.ToString();
                            break;

                        case States_GetExecutionTime.sGetCaptureDataTime:
                            entry.commandArguments[0, 1] = specification.Duration.ToString();
                            break;

                        case States_GetExecutionTime.sGetAbsorberReturnTime:
                            entry.commandArguments[0, 1] = specification.AbsorberList[absorberIndex].location.ToString();
                            break;

                        case States_GetExecutionTime.sGetSourceReturnTime:
                            entry.commandArguments[0, 1] = specification.SourceLocation.ToString();
                            break;

                        case States_GetExecutionTime.sGetTubeReturnTime:
                            entry.commandArguments[0, 1] = specification.DistanceList[0].ToString();
                            entry.commandArguments[1, 1] = tubeHomeDistance.ToString();
                            break;

                        default:
                            break;
                    }

                    //
                    // Execute command and check response success
                    //
                    XmlDocument xmlRequestDocument = CreateXmlRequestDocument(entry.equipmentCommand, entry.commandArguments);
                    string xmlResponse = this.equipmentServiceProxy.ExecuteRequest(xmlRequestDocument.InnerXml);
                    XmlNode xmlResponseNode = CreateXmlResponseNode(xmlResponse);
                    if (XmlUtilities.GetBoolValue(xmlResponseNode, LabServerEngine.Consts.STRXML_RspSuccess, false) == false)
                    {
                        //
                        // Command execution failed
                        //
                        string errorMessage = XmlUtilities.GetXmlValue(xmlResponseNode, LabServerEngine.Consts.STRXML_RspErrorMessage, true);
                        throw new ArgumentException(errorMessage);
                    }

                    //
                    // Extract response values where required
                    //
                    double stateExecutionTime = 0.0;
                    switch (entry.currentState)
                    {
                        case States_GetExecutionTime.sGetLcdWriteLineTime:
                            lcdWriteLineTime = XmlUtilities.GetRealValue(xmlResponseNode, Consts.STRXML_RspLcdWriteLineTime, 0);

                            // Time to ready LCD when completed
                            stateExecutionTime = lcdWriteLineTime * 2;
                            break;

                        case States_GetExecutionTime.sGetTubeHomeDistance:
                            tubeHomeDistance = XmlUtilities.GetIntValue(xmlResponseNode, Consts.STRXML_RspTubeHomeDistance, 0);
                            break;

                        case States_GetExecutionTime.sGetTubeMoveTime:
                            stateExecutionTime = XmlUtilities.GetRealValue(xmlResponseNode, Consts.STRXML_RspTubeMoveTime, 0.0);
                            stateExecutionTime += lcdWriteLineTime * 2;
                            break;

                        case States_GetExecutionTime.sGetSourceSelectTime:
                            stateExecutionTime = XmlUtilities.GetRealValue(xmlResponseNode, Consts.STRXML_RspSourceSelectTime, 0.0);
                            stateExecutionTime += lcdWriteLineTime * 2;
                            break;

                        case States_GetExecutionTime.sGetAbsorberHomeLocation:
                            absorberHomeLocation = XmlUtilities.GetCharValue(xmlResponseNode, Consts.STRXML_RspAbsorberHomeLocation);
                            break;

                        case States_GetExecutionTime.sGetAbsorberSelectHomeTime:
                            absorberSelectHomeTime = XmlUtilities.GetRealValue(xmlResponseNode, Consts.STRXML_RspAbsorberSelectTime, 0.0);
                            break;

                        case States_GetExecutionTime.sGetAbsorberSelectTime:
                            double absorberSelectTime = XmlUtilities.GetRealValue(xmlResponseNode, Consts.STRXML_RspAbsorberSelectTime, 0.0);
                            if (absorberIndex == 0)
                            {
                                // Time to select the first absorber
                                stateExecutionTime = absorberSelectTime;
                            }
                            else
                            {
                                // Calulate time to move to the next absorber
                                stateExecutionTime = absorberSelectTime - lastAbsorberSelectTime + absorberSelectHomeTime;
                            }
                            stateExecutionTime += lcdWriteLineTime * 2;

                            // Save absorber select time for next iteration
                            lastAbsorberSelectTime = absorberSelectTime;
                            break;

                        case States_GetExecutionTime.sGetCaptureDataTime:
                            stateExecutionTime = XmlUtilities.GetRealValue(xmlResponseNode, Consts.STRXML_RspCaptureDataTime, 0.0);
                            stateExecutionTime += lcdWriteLineTime * 2;
                            stateExecutionTime *= specification.Repeat;
                            break;

                        case States_GetExecutionTime.sGetAbsorberReturnTime:
                            if (++absorberIndex < specification.AbsorberList.Length)
                            {
                                // Next absorber
                                nextState = States_GetExecutionTime.sGetAbsorberSelectTime;
                            }
                            else
                            {
                                // Only want return time for last absorber
                                stateExecutionTime = XmlUtilities.GetRealValue(xmlResponseNode, Consts.STRXML_RspAbsorberReturnTime, 0.0);
                                stateExecutionTime += lcdWriteLineTime * 2;
                            }
                            break;

                        case States_GetExecutionTime.sGetSourceReturnTime:
                            stateExecutionTime = XmlUtilities.GetRealValue(xmlResponseNode, Consts.STRXML_RspSourceReturnTime, 0.0);
                            stateExecutionTime += lcdWriteLineTime * 2;
                            break;

                        case States_GetExecutionTime.sGetTubeReturnTime:
                            stateExecutionTime = XmlUtilities.GetRealValue(xmlResponseNode, Consts.STRXML_RspTubeMoveTime, 0.0);
                            stateExecutionTime += lcdWriteLineTime * 2;
                            break;

                        default:
                            break;
                    }

                    Trace.WriteLine("  nextState: " + entry.nextState.ToString() + " ]");
                    Trace.WriteLine(" stateExecutionTime: " + stateExecutionTime.ToString());

                    //
                    // Update the execution time so far
                    //
                    executionTime += stateExecutionTime;

                    //
                    // Next state
                    //
                    state = nextState;
                }
            }
            catch (Exception ex)
            {
                Logfile.WriteError(ex.Message);
                throw;
            }

            //
            // Round execution time to the nearest integer
            //
            int execTime = (int)(executionTime + 0.5);

            logMessage = STRLOG_ExecutionTime + execTime.ToString();

            Logfile.WriteCompleted(STRLOG_ClassName, STRLOG_MethodName, logMessage);

            return execTime;
        }
        //-------------------------------------------------------------------------------------------------//
        public virtual void Create()
        {
            const string STRLOG_MethodName = "Create";

            Logfile.WriteCalled(STRLOG_ClassName, STRLOG_MethodName);

            //
            // Create local class instances just to check that all is in order
            //
            ExperimentSpecification experimentSpecification = new ExperimentSpecification(this.appData.labConfiguration, null);
            LabExperimentResult labExperimentResult = new LabExperimentResult(this.appData.labConfiguration);

            //
            // Create instances of lab experiment engines
            //
            this.appData.labExperimentEngines = new LabExperimentEngine[this.appData.farmSize];
            for (int i = 0; i < this.appData.farmSize; i++)
            {
                this.appData.labExperimentEngines[i] = new LabExperimentEngine(i, this.appData);
            }

            Logfile.WriteCompleted(STRLOG_ClassName, STRLOG_MethodName);
        }
        //-------------------------------------------------------------------------------------------------//

        /// <summary>
        /// Run the experiment and fill in the result report. Override in a derived class.
        /// </summary>
        /// <param name="experimentInfo"></param>
        /// <returns></returns>
        public virtual ExperimentInfo RunExperiment(ExperimentInfo experimentInfo)
        {
            const string STRLOG_MethodName = "RunExperiment";

            Logfile.WriteCalled(STRLOG_ClassName, STRLOG_MethodName);

            // Create a result report ready to fill in
            experimentInfo.resultReport = new ResultReport();

            try
            {
                //
                // Parse the XML specification string to generate a validation report (should be accepted!)
                //
                ExperimentSpecification experimentSpecification = new ExperimentSpecification(this.labConfiguration, this.equipmentServiceProxy);
                ValidationReport        validationReport        = experimentSpecification.Parse(experimentInfo.xmlSpecification);
                if (validationReport.accepted == false)
                {
                    throw new ArgumentException(validationReport.errorMessage);
                }
                experimentInfo.setupId = experimentSpecification.SetupId;

                //
                // Create an instance of the driver for the specified setup and then
                // execute the experiment and return the result information
                //
                ExperimentResultInfo experimentResultInfo = null;
                if (experimentSpecification.SetupId.Equals(Consts.STRXML_SetupId_EquipmentGeneric))
                {
                    DriverEquipmentGeneric driver = new DriverEquipmentGeneric(this.equipmentServiceProxy, this.labConfiguration, this.labExperimentInfo.cancelExperiment);
                    experimentResultInfo = driver.Execute(experimentSpecification);
                }
                else if (experimentSpecification.SetupId.Equals(Consts.STRXML_SetupId_ModuleGeneric))
                {
                    DriverModuleGeneric driver = new DriverModuleGeneric(this.labConfiguration, this.labExperimentInfo.cancelExperiment);
                    experimentResultInfo = driver.Execute(experimentSpecification);
                }

                //
                // Create an instance of LabExperimentResult to convert the experiment results to an XML string
                //
                LabExperimentResult labExperimentResult = new LabExperimentResult(
                    experimentInfo.experimentId, experimentInfo.sbName, DateTime.Now,
                    experimentSpecification.SetupId, this.unitId, this.labConfiguration);

                //
                // Fill in the result report
                //
                experimentInfo.resultReport.experimentResults = labExperimentResult.ToString();
                experimentInfo.resultReport.statusCode        = (int)experimentResultInfo.statusCode;
                experimentInfo.resultReport.errorMessage      = experimentResultInfo.errorMessage;
            }
            catch (Exception ex)
            {
                experimentInfo.resultReport.statusCode   = (int)StatusCodes.Failed;
                experimentInfo.resultReport.errorMessage = ex.Message;
                Logfile.WriteError(ex.Message);
            }

            Logfile.WriteCompleted(STRLOG_ClassName, STRLOG_MethodName);

            return(experimentInfo);
        }
        //-------------------------------------------------------------------------------------------------//
        public override int GetExecutionTime(ExperimentSpecification experimentSpecification)
        {
            const string STRLOG_MethodName = "GetExecutionTime";

            Logfile.WriteCalled(STRLOG_ClassName, STRLOG_MethodName);

            // Typecast the specification so that it can be used here
            Specification specification = (Specification)experimentSpecification;

            //
            // Initialise variables
            //
            double executionTime = 1.0;
            int tubeHomeDistance = this.simActivity.GetTubeHomeDistance();
            int distanceIndex = 0;
            int fromDistance = 0;
            int toDistance = 0;

            //
            // Get source and absorber select times
            //
            executionTime += this.simActivity.GetAbsorberSelectTime(specification.AbsorberList[0].location);
            executionTime += this.simActivity.GetSourceSelectTime(specification.SourceLocation);

            //
            // Get tube move times
            //
            while (true)
            {
                //
                // Determine the 'from' and 'to' distances
                //
                if (distanceIndex == 0)
                {
                    // From home to first distance
                    fromDistance = tubeHomeDistance;
                    toDistance = specification.DistanceList[distanceIndex];
                }
                else if (distanceIndex < specification.DistanceList.Length)
                {
                    // Everything in between
                    fromDistance = specification.DistanceList[distanceIndex - 1];
                    toDistance = specification.DistanceList[distanceIndex];
                }

                //
                // Get tube move time
                //
                executionTime += this.simActivity.GetTubeMoveTime(fromDistance, toDistance);

                //
                // Get capture data time
                //
                executionTime += this.simActivity.GetCaptureDataTime(specification.Duration) * specification.Repeat;
                if (++distanceIndex == specification.DistanceList.Length)
                {
                    // All distances are done
                    break;
                }
            }

            //
            // Get source and absorber return times
            //
            executionTime += this.simActivity.GetSourceReturnTime(specification.SourceLocation);
            executionTime += this.simActivity.GetAbsorberReturnTime(specification.AbsorberList[0].location);

            //
            // Get tube return to home time
            //
            fromDistance = specification.DistanceList[specification.DistanceList.Length - 1];
            toDistance = tubeHomeDistance;
            executionTime += this.simActivity.GetTubeMoveTime(fromDistance, toDistance);

            string logMessage = STRLOG_ExecutionTime + executionTime.ToString();

            Logfile.WriteCompleted(STRLOG_ClassName, STRLOG_MethodName, logMessage);

            return (int)executionTime;
        }
        //---------------------------------------------------------------------------------------//
        public override ExperimentResultInfo Execute(ExperimentSpecification experimentSpecification)
        {
            const string STRLOG_MethodName = "Execute";

            Logfile.WriteCalled(STRLOG_ClassName, STRLOG_MethodName);

            //
            // Determine how long it actually take to execute
            //
            DateTime startDateTime = DateTime.Now;

            // Typecast the specification so that it can be used here
            Specification specification = (Specification)experimentSpecification;

            //
            // Log the specification
            //
            string logMessage = STRLOG_SetupId + specification.SetupId;
            Logfile.Write(logMessage);

            //
            // Create an instance of the result info ready to fill in
            //
            ResultInfo resultInfo = new ResultInfo();
            resultInfo.statusCode = StatusCodes.Running;

            //
            // Initialise variables used in the state machine
            //

            try
            {
                //
                // First, check to see if the LabEquipment is online
                //
                LabEquipmentStatus labEquipmentStatus = this.equipmentServiceProxy.GetLabEquipmentStatus();
                if (labEquipmentStatus.online == false)
                {
                    throw new Exception(labEquipmentStatus.statusMessage);
                }

                //
                // Run the state machine to execute the experiment specification
                //
                States_Execute state = States_Execute.sCompleted;
                if (smTable_Execute.Length > 0)
                {
                    state = smTable_Execute[0].currentState;
                }
                while (state != States_Execute.sCompleted)
                {
                    //
                    // Find table entry
                    //
                    int index = -1;
                    for (int i = 0; i < smTable_Execute.Length; i++)
                    {
                        if (smTable_Execute[i].currentState == state)
                        {
                            // Entry found
                            index = i;
                            break;
                        }
                    }
                    if (index == -1)
                    {
                        throw new ArgumentOutOfRangeException(state.ToString(), STRERR_StateNotFound);
                    }

                    //
                    // Get table entry and save next state
                    //
                    SMTableEntry_Execute entry = smTable_Execute[index];
                    States_Execute nextState = entry.nextState;

                    logMessage = " [ " + STRLOG_MethodName + ": " + entry.currentState.ToString() + " ]";
                    Logfile.Write(logMessage);

                    Trace.WriteLine(logMessage);

                    //
                    // Check if experiment was cancelled
                    //
                    if (this.cancelExperiment != null && this.cancelExperiment.IsCancelled == true &&
                        resultInfo.statusCode == StatusCodes.Running)
                    {
                        //
                        // Experiment was cancelled
                        //
                        resultInfo.statusCode = StatusCodes.Cancelled;
                        state = entry.exitState;
                        continue;
                    }

                    //
                    // Process non-XML commands
                    //
                    switch (entry.currentState)
                    {
                        case States_Execute.sSuspendPowerdown:
                            if (this.equipmentServiceProxy.SuspendPowerdown() == false)
                            {
                                //
                                // Command execution failed
                                //
                                resultInfo.statusCode = StatusCodes.Failed;
                                resultInfo.errorMessage = STRERR_SuspendPowerdown;
                                state = entry.exitState;
                            }
                            else
                            {
                                state = nextState;
                            }
                            continue;

                        case States_Execute.sResumePowerdown:
                            if (this.equipmentServiceProxy.ResumePowerdown() == false)
                            {
                                //
                                // Command execution failed
                                //
                                resultInfo.statusCode = StatusCodes.Failed;
                                resultInfo.errorMessage = STRERR_ResumePowerdown;
                                state = entry.exitState;
                            }
                            else
                            {
                                state = nextState;
                            }
                            continue;

                        default:
                            break;
                    }

                    //
                    // Add command arguments where required
                    //
                    switch (entry.currentState)
                    {
                        case States_Execute.sStartExecution:
                            entry.commandArguments[0, 1] = specification.ToString();
                            break;

                        default:
                            break;
                    }

                    //
                    // Execute command and check response success
                    //
                    XmlDocument xmlRequestDocument = CreateXmlRequestDocument(entry.equipmentCommand, entry.commandArguments);
                    string xmlResponse = this.equipmentServiceProxy.ExecuteRequest(xmlRequestDocument.InnerXml);
                    XmlNode xmlResponseNode = CreateXmlResponseNode(xmlResponse);
                    if (XmlUtilities.GetBoolValue(xmlResponseNode, LabServerEngine.Consts.STRXML_RspSuccess, false) == false)
                    {
                        //
                        // Command execution failed
                        //
                        resultInfo.statusCode = StatusCodes.Failed;
                        resultInfo.errorMessage = XmlUtilities.GetXmlValue(xmlResponseNode, LabServerEngine.Consts.STRXML_RspErrorMessage, true);
                        state = entry.exitState;
                        continue;
                    }

                    //
                    // Extract response values where required
                    //
                    switch (entry.currentState)
                    {
                        case States_Execute.sGetExecutionStatus:
                            //
                            // Get the execution status
                            //
                            string strExecutionStatus = XmlUtilities.GetXmlValue(xmlResponseNode, Consts.STRXML_RspExecutionStatus, false);
                            Trace.WriteLine("ExecutionStatus: " + strExecutionStatus);

                            //
                            // Get the execution time remaining
                            //
                            int executionTimeRemaining = XmlUtilities.GetIntValue(xmlResponseNode, Consts.STRXML_RspExecutionTimeRemaining, -1);
                            Trace.WriteLine("ExecutionTimeRemaining: " + executionTimeRemaining.ToString());

                            //
                            // Convert to an ExecutionStatus enum type
                            //
                            ExecutionStatus executionStatus = (ExecutionStatus)Enum.Parse(typeof(ExecutionStatus), strExecutionStatus);

                            //
                            // Check if execution has completed
                            //
                            if (executionStatus != ExecutionStatus.Completed)
                            {
                                //
                                // Not yet, wait a bit and then check again
                                //
                                int secondsToWait = 1;
                                if (executionTimeRemaining > 40)
                                {
                                    secondsToWait = 20;
                                }
                                else if (executionTimeRemaining > 5)
                                {
                                    secondsToWait = executionTimeRemaining / 2;
                                }
                                else
                                {
                                    secondsToWait = 2;
                                }

                                for (int i = 0; i < secondsToWait; i++)
                                {
                                    Trace.Write(".");
                                    Thread.Sleep(1000);
                                }

                                nextState = States_Execute.sGetExecutionStatus;
                            }
                            break;

                        case States_Execute.sGetExecutionResultStatus:
                            //
                            // Get the execution result status
                            //
                            string strExecutionResultStatus = XmlUtilities.GetXmlValue(xmlResponseNode, Consts.STRXML_RspExecutionResultStatus, false);
                            Trace.WriteLine("ExecutionResultStatus: " + strExecutionResultStatus);

                            //
                            // Convert to an ExecutionStatus enum type
                            //
                            ExecutionStatus executionResultStatus = (ExecutionStatus)Enum.Parse(typeof(ExecutionStatus), strExecutionResultStatus);

                            //
                            // Check if results are available
                            //
                            if (executionResultStatus != ExecutionStatus.Completed)
                            {
                                resultInfo.statusCode = StatusCodes.Failed;
                                //resultInfo.errorMessage = ;
                            }
                            break;

                        case States_Execute.sGetExecutionResults:
                            //
                            // Get the execution results
                            //
                            resultInfo.xmlMeasurements = XmlUtilities.GetXmlValue(xmlResponseNode, Consts.STRXML_RspExecutionResults, false);
                            Trace.WriteLine("ExecutionResults: " + resultInfo.xmlMeasurements);
                            break;

                        default:
                            break;
                    }

                    //
                    // Next state
                    //
                    state = nextState;
                }

                //
                // Update status code
                //
                if (resultInfo.statusCode == StatusCodes.Running)
                {
                    resultInfo.statusCode = StatusCodes.Completed;
                }
            }
            catch (Exception ex)
            {
                resultInfo.statusCode = StatusCodes.Failed;
                resultInfo.errorMessage = ex.Message;
                Logfile.WriteError(ex.Message);
            }

            //
            // Calculate actual execution time
            //
            TimeSpan timeSpan = DateTime.Now - startDateTime;

            logMessage = STRLOG_StatusCode + resultInfo.statusCode
                + Logfile.STRLOG_Spacer + STRLOG_ExecutionTime + timeSpan.TotalSeconds.ToString();

            Logfile.WriteCompleted(STRLOG_ClassName, STRLOG_MethodName, logMessage);

            return resultInfo;
        }
        //---------------------------------------------------------------------------------------//
        public override ExperimentResultInfo Execute(ExperimentSpecification experimentSpecification)
        {
            const string STRLOG_MethodName = "Execute";

            Logfile.WriteCalled(STRLOG_ClassName, STRLOG_MethodName);

            //
            // Determine how long it actually take to execute
            //
            DateTime startDateTime = DateTime.Now;

            // Typecast the specification so that it can be used here
            Specification specification = (Specification)experimentSpecification;

            //
            // Log the specification
            //
            string logMessage = STRLOG_SpeedMin + specification.Speed.min.ToString() +
                Logfile.STRLOG_Spacer + STRLOG_SpeedMax + specification.Speed.max.ToString() +
                Logfile.STRLOG_Spacer + STRLOG_SpeedStep + specification.Speed.step.ToString();
            Logfile.Write(logMessage);

            //
            // Create an instance of the result info ready to fill in
            //
            ResultInfo resultInfo = new ResultInfo();
            resultInfo.statusCode = StatusCodes.Running;

            //
            // Create data structures to hold the results
            //
            int vectorLength = ((specification.Speed.max - specification.Speed.min) / specification.Speed.step) + 1;
            resultInfo.speedVector = new int[vectorLength];
            resultInfo.voltageVector = new int[vectorLength];
            resultInfo.loadVector = new int[vectorLength];
            resultInfo.fieldVector = new float[vectorLength];

            //
            // Initialise variables used in the state machine
            //
            int vectorIndex = 0;
            int repeatCount = 0;

            try
            {
                //
                // First, check to see if the LabEquipment is online
                //
                LabEquipmentStatus labEquipmentStatus = this.equipmentServiceProxy.GetLabEquipmentStatus();
                if (labEquipmentStatus.online == false)
                {
                    throw new Exception(labEquipmentStatus.statusMessage);
                }

                //
                // Run the state machine to execute the experiment specification
                //
                States_Execute state = States_Execute.sCompleted;
                if (smTable_Execute.Length > 0)
                {
                    state = smTable_Execute[0].currentState;
                }
                while (state != States_Execute.sCompleted)
                {
                    //
                    // Find table entry
                    //
                    int index = -1;
                    for (int i = 0; i < smTable_Execute.Length; i++)
                    {
                        if (smTable_Execute[i].currentState == state)
                        {
                            // Entry found
                            index = i;
                            break;
                        }
                    }
                    if (index == -1)
                    {
                        throw new ArgumentOutOfRangeException(state.ToString(), STRERR_StateNotFound);
                    }

                    //
                    // Get table entry and save next state
                    //
                    SMTableEntry_Execute entry = smTable_Execute[index];
                    States_Execute nextState = entry.nextState;

                    logMessage = " [ " + STRLOG_MethodName + ": " + entry.currentState.ToString() + " ]";
                    Logfile.Write(logMessage);

                    Trace.WriteLine(logMessage);

                    //
                    // Check if experiment was cancelled
                    //
                    if (this.cancelExperiment != null && this.cancelExperiment.IsCancelled == true &&
                        resultInfo.statusCode == StatusCodes.Running)
                    {
                        //
                        // Experiment was cancelled
                        //
                        resultInfo.statusCode = StatusCodes.Cancelled;
                        state = entry.exitState;
                        continue;
                    }

                    //
                    // Process non-XML commands
                    //
                    switch (entry.currentState)
                    {
                        case States_Execute.sSuspendPowerdown:
                            if (this.equipmentServiceProxy.SuspendPowerdown() == false)
                            {
                                //
                                // Command execution failed
                                //
                                resultInfo.statusCode = StatusCodes.Failed;
                                resultInfo.errorMessage = STRERR_SuspendPowerdown;
                                state = entry.exitState;
                            }
                            else
                            {
                                state = nextState;
                            }
                            continue;

                        case States_Execute.sResumePowerdown:
                            if (this.equipmentServiceProxy.ResumePowerdown() == false)
                            {
                                //
                                // Command execution failed
                                //
                                resultInfo.statusCode = StatusCodes.Failed;
                                resultInfo.errorMessage = STRERR_ResumePowerdown;
                                state = entry.exitState;
                            }
                            else
                            {
                                state = nextState;
                            }
                            continue;

                        default:
                            break;
                    }

                    //
                    // Add command arguments where required
                    //
                    switch (entry.currentState)
                    {
                        case States_Execute.sSetSpeedACDrive:
                            int speedACDrive = specification.Speed.min + (vectorIndex * specification.Speed.step);
                            entry.commandArguments[0, 1] = speedACDrive.ToString();
                            break;

                        case States_Execute.sResetSpeedACDrive:
                            speedACDrive = 0;
                            entry.commandArguments[0, 1] = speedACDrive.ToString();
                            break;

                        default:
                            break;
                    }

                    //
                    // Execute command and check response success
                    //
                    XmlDocument xmlRequestDocument = CreateXmlRequestDocument(entry.equipmentCommand, entry.commandArguments);
                    string xmlResponse = this.equipmentServiceProxy.ExecuteRequest(xmlRequestDocument.InnerXml);
                    XmlNode xmlResponseNode = CreateXmlResponseNode(xmlResponse);
                    if (XmlUtilities.GetBoolValue(xmlResponseNode, LabServerEngine.Consts.STRXML_RspSuccess, false) == false)
                    {
                        //
                        // Command execution failed
                        //
                        resultInfo.statusCode = StatusCodes.Failed;
                        resultInfo.errorMessage = XmlUtilities.GetXmlValue(xmlResponseNode, LabServerEngine.Consts.STRXML_RspErrorMessage, true);
                        state = entry.exitState;
                        continue;
                    }

                    //
                    // Extract response values where required
                    //
                    switch (entry.currentState)
                    {
                        case States_Execute.sTakeMeasurement:

                            //
                            // Add in the values
                            //
                            resultInfo.speedVector[vectorIndex] += XmlUtilities.GetIntValue(xmlResponseNode, Consts.STRXML_RspSpeed, 0);
                            resultInfo.voltageVector[vectorIndex] += XmlUtilities.GetIntValue(xmlResponseNode, Consts.STRXML_RspVoltage, 0);
                            resultInfo.loadVector[vectorIndex] += XmlUtilities.GetIntValue(xmlResponseNode, Consts.STRXML_RspLoad, 0);
                            resultInfo.fieldVector[vectorIndex] += (float)XmlUtilities.GetRealValue(xmlResponseNode, Consts.STRXML_RspFieldCurrent, 0.0);

                            //
                            // Check if all measurements have been taken for this field value
                            //
                            if (++repeatCount == this.measurementCount)
                            {
                                //
                                // All measurements have been taken for this field value, average the values
                                //
                                resultInfo.speedVector[vectorIndex] /= measurementCount;
                                resultInfo.voltageVector[vectorIndex] /= measurementCount;
                                resultInfo.fieldVector[vectorIndex] /= measurementCount;
                                resultInfo.loadVector[vectorIndex] /= measurementCount;

                                //
                                // Check if field values have been completed
                                //
                                if (++vectorIndex == vectorLength)
                                {
                                    //
                                    // All measurements have been taken
                                    //
                                    break;
                                }

                                //
                                // Next field value
                                //
                                repeatCount = 0;
                                nextState = States_Execute.sSetSpeedACDrive;
                                break;
                            }

                            // Next measurement at the same field value
                            nextState = States_Execute.sTakeMeasurement;
                            break;

                        default:
                            break;
                    }

                    //
                    // Next state
                    //
                    state = nextState;
                }

                //
                // Update status code
                //
                if (resultInfo.statusCode == StatusCodes.Running)
                {
                    resultInfo.statusCode = StatusCodes.Completed;
                }
            }
            catch (Exception ex)
            {
                resultInfo.statusCode = StatusCodes.Failed;
                resultInfo.errorMessage = ex.Message;
                Logfile.WriteError(ex.Message);
            }

            //
            // Calculate actual execution time
            //
            TimeSpan timeSpan = DateTime.Now - startDateTime;

            logMessage = STRLOG_StatusCode + resultInfo.statusCode
                + Logfile.STRLOG_Spacer + STRLOG_ExecutionTime + timeSpan.TotalSeconds.ToString();

            Logfile.WriteCompleted(STRLOG_ClassName, STRLOG_MethodName, logMessage);

            return resultInfo;
        }
        //---------------------------------------------------------------------------------------//
        public override ExperimentResultInfo Execute(ExperimentSpecification experimentSpecification)
        {
            const string STRLOG_MethodName = "Execute";

            Logfile.WriteCalled(STRLOG_ClassName, STRLOG_MethodName);

            //
            // Determine how long it actually take to execute
            //
            DateTime startDateTime = DateTime.Now;

            // Typecast the specification so that it can be used here
            Specification specification = (Specification)experimentSpecification;

            //
            // Log the specification
            //
            string logMessage = string.Empty;
            //
            // YOUR CODE HERE
            //
            Logfile.Write(logMessage);

            //
            // Create an instance of the result info ready to fill in
            //
            ResultInfo resultInfo = new ResultInfo();
            resultInfo.statusCode = StatusCodes.Running;

            //
            // Initialise variables used in the state machine
            //

            try
            {
                //
                // Run the state machine to execute the experiment specification
                //
                States_Execute state = States_Execute.sCompleted;
                if (smTable_Execute.Length > 0)
                {
                    state = smTable_Execute[0].currentState;
                }
                while (state != States_Execute.sCompleted)
                {
                    //
                    // Find table entry
                    //
                    int index = -1;
                    for (int i = 0; i < smTable_Execute.Length; i++)
                    {
                        if (smTable_Execute[i].currentState == state)
                        {
                            // Entry found
                            index = i;
                            break;
                        }
                    }
                    if (index == -1)
                    {
                        throw new ArgumentOutOfRangeException(state.ToString(), STRERR_StateNotFound);
                    }

                    //
                    // Get table entry and save next state
                    //
                    SMTableEntry_Execute entry = smTable_Execute[index];
                    States_Execute nextState = entry.nextState;

                    logMessage = " [ " + STRLOG_MethodName + ": " + entry.currentState.ToString() + " ]";
                    Logfile.Write(logMessage);

                    Trace.WriteLine(logMessage);

                    //
                    // Check if experiment was cancelled
                    //
                    if (this.cancelExperiment != null && this.cancelExperiment.IsCancelled == true &&
                        resultInfo.statusCode == StatusCodes.Running)
                    {
                        //
                        // Experiment was cancelled
                        //
                        resultInfo.statusCode = StatusCodes.Cancelled;
                        state = entry.exitState;
                        continue;
                    }

                    //
                    // Process commands
                    //
                    switch (entry.currentState)
                    {
                        //
                        // YOUR CODE HERE
                        //

                        default:
                            break;
                    }

                    Trace.WriteLine("nextState: " + entry.nextState.ToString());

                    //
                    // Next state
                    //
                    state = nextState;
                }

                //
                // Update status code
                //
                if (resultInfo.statusCode == StatusCodes.Running)
                {
                    resultInfo.statusCode = StatusCodes.Completed;
                }
            }
            catch (Exception ex)
            {
                resultInfo.statusCode = StatusCodes.Failed;
                resultInfo.errorMessage = ex.Message;
                Logfile.WriteError(ex.Message);
            }

            TimeSpan timeSpan = DateTime.Now - startDateTime;
            logMessage = STRLOG_ExecutionTime + timeSpan.TotalSeconds.ToString();

            Logfile.WriteCompleted(STRLOG_ClassName, STRLOG_MethodName, logMessage);

            return resultInfo;
        }