/// <summary>
        /// Return the GasConcentrations of the cylinder's part number.
        /// </summary>
        /// <param name="factoryCylinder"></param>
        /// <param name="trx"></param>
        /// <returns>Returned list is empty if part number can't be found.</returns>
        internal IList <GasConcentration> FindByFactoryCylinder(FactoryCylinder factoryCylinder, DataAccessTransaction trx)
        {
            List <GasConcentration> list = new List <GasConcentration>();

            using (IDbCommand cmd = GetCommand("SELECT * FROM FACTORYCYLINDERGAS WHERE PARTNUMBER = @PARTNUMBER", trx))
            {
                cmd.Parameters.Add(GetDataParameter("@PARTNUMBER", factoryCylinder.PartNumber));

                using (IDataReader reader = cmd.ExecuteReader())
                {
                    DataAccessOrdinals ordinals = new DataAccessOrdinals(reader);

                    while (reader.Read())
                    {
                        string gasCode = SqlSafeGetString(reader, ordinals["GASCODE"]);

                        double concentration = SqlSafeGetDouble(reader, ordinals["CONCENTRATION"], 0.0f);

                        GasConcentration gasConcentration = new GasConcentration(gasCode, concentration);

                        list.Add(gasConcentration);
                    }
                }
            }
            return(list);
        }
        // INS-8630 RHP v7.5 - Updated method signature to include errorCodes and explanationCodes to display ISC Cylinder Part Number on LCD and to send the same as Alert
        private void FindInstalledCylinderGases(string eventCode, List <GasEndPoint> gasEndPoints,
                                                DockingStation dockingStation, InstalledComponent installedComponent,
                                                StringBuilder explanation,
                                                List <string> explanationCodes,
                                                List <string> errorCodes)
        {
            Sensor sensor = installedComponent.Component as Sensor;

            // INS-8630 RHP v7.5 - Initialize outside the loop since if no gas is found on entire loop, then we still need to pass expired/empty if either are true.
            _expired = _empty = false;

            // SGF  21-May-2012  INS-3078
            _gasNeeded = IsGasOperationSupported(eventCode, sensor);

            foreach (GasEndPoint gasEndPoint in dockingStation.GasEndPoints)
            {
                Cylinder cyl = gasEndPoint.Cylinder;

                // If we are examining the fresh air/zero air port to possibly add a gas to the gas end points list,
                // make sure that the type of fresh air/zero air is allowed based on port 1 descriptions.  For example,
                // if the installed cylinder is fresh air, make sure the port 1 restrictions allow for fresh
                // air to be specified on this port.
                //
                if (gasEndPoint.Position == Controller.FRESH_AIR_GAS_PORT)
                {
                    if (cyl.IsFreshAir && ((dockingStation.Port1Restrictions & PortRestrictions.FreshAir) != PortRestrictions.FreshAir))
                    {
                        Log.Debug(Name + ": FRESH AIR attached to Port 1; defined Port 1 Restrictions prohibit the use of FRESH AIR");
                        continue;
                    }

                    if (cyl.IsZeroAir && ((dockingStation.Port1Restrictions & PortRestrictions.ZeroAir) != PortRestrictions.ZeroAir))
                    {
                        Log.Debug(Name + ": ZERO AIR attached to Port 1; defined Port 1 Restrictions prohibit the use of ZERO AIR");
                        continue;
                    }
                }

                // Reset each time through loop. At end of loop, they'll be
                // set for the last cylinder matching desired gas that was looked at.
                //_expired = _empty = false; - INS-8630 RHP v7.5 Commented since if no gas is found on entire loop, then we still need to pass expired/empty if either are true.
                bool alreadyAdded = false;

                string msg = string.Format("{0} Examining port {1} ({2}), fid={3},pn={4},Fresh={5},ZeroAir={6},Exp={7},Pressure={8}",
                                           Name, gasEndPoint.Position, gasEndPoint.InstallationType.ToString(), cyl.FactoryId, cyl.PartNumber, cyl.IsFreshAir, cyl.IsZeroAir,
                                           cyl.ExpirationDate.ToShortDateString(), cyl.Pressure.ToString());
                Log.Debug(msg);

                msg = "......";
                foreach (GasConcentration gasCon in gasEndPoint.Cylinder.GasConcentrations)
                {
                    msg += "[" + gasCon.Type.Code + " ";
                    msg += (gasCon.Concentration == double.MinValue) ? "fresh" : gasCon.Concentration.ToString();
                    msg += "]";
                }
                Log.Debug(msg);

                string sensorGasCode = sensor.CalibrationGas.Code;

                // If we're doing a bump test, we use Chlorine for the calibration gas.
                if (sensor.Type.Code == SensorCode.ClO2 && eventCode == EventCode.BumpTest)
                {
                    sensorGasCode = GasCode.Cl2;
                    Log.Debug("...Sensor is CLO2. Looking for cylinders containing Chlorine instead of cal gas.");
                }

                bool containsGas = gasEndPoint.Cylinder.ContainsGas(sensorGasCode);

                if (Configuration.DockingStation.UseExpiredCylinders && (eventCode == EventCode.BumpTest))
                {
                    Log.Debug("...UseExpiredCylinders=true; Ignoring expiration date");
                }
                else if (Configuration.ToLocalTime(gasEndPoint.Cylinder.ExpirationDate) <= Configuration.GetLocalTime())
                {
                    //Log.Debug( "...Skipping expired cylinder" );
                    explanation.Append("Cylinder has expired." + '\n');
                    explanation.Append("Cylinder id =" + gasEndPoint.Cylinder.FactoryId + '\n');
                    explanation.Append("Port number: " + gasEndPoint.Position + '\n');

                    // INS-8630 RHP v7.5 - IDS is expected to display expired cylinder details on LCD
                    if (containsGas)
                    {
                        // INS-8630 RHP v7.5 - Multiple cylinder with the same gas code may be expired, in such scenarios IDS message
                        // should display the first cylinder it identifies.
                        if (!(_expired || _empty))
                        {
                            // For ISC cylinder IDS should display the cylinder part NUmber, so add the part number to explanation codes
                            if (!explanationCodes.Contains(gasEndPoint.Cylinder.PartNumber) && !string.IsNullOrEmpty(gasEndPoint.Cylinder.PartNumber))
                            {
                                explanationCodes.Add(gasEndPoint.Cylinder.PartNumber);
                                errorCodes.Add(string.Format("{0} ({1})", gasEndPoint.Cylinder.PartNumber, gasEndPoint.Position)); // see INS-3821
                            }
                            else
                            {
                                // For Non ISC Pass the gas code. But I believe that both ISC and Non-ISC cylinders have their own PArt numbers.
                                // So this condition may not be required ?
                                GasType gs = GasType.Cache[GasCode.FreshAir];
                                if (!explanationCodes.Contains(gasEndPoint.Cylinder.PartNumber) && gs != null)
                                {
                                    explanationCodes.Add(gs.Symbol);
                                    errorCodes.Add(string.Format("{0} ({1})", gs.Symbol, gs.Code));
                                }
                            }
                            _expired = true;
                        }
                        continue;
                    }
                }

                if (gasEndPoint.Cylinder.Pressure == PressureLevel.Empty)
                {
                    //Log.Debug( "...Skipping cylinder; Pressure is " + gasEndPoint.Cylinder.Pressure );
                    explanation.Append("Cylinder is empty." + '\n');
                    explanation.Append("Cylinder id =" + gasEndPoint.Cylinder.FactoryId + '\n');
                    explanation.Append("Port number: " + gasEndPoint.Position + '\n');

                    // INS-8630 RHP v7.5 - IDS is expected to display empty cylinder details on LCD
                    if (containsGas)
                    {
                        // INS-8630 RHP v7.5 - Multiple cylinder with the same gas code may be expired, in such scenarios IDS message
                        // should display the first cylinder it identifies.
                        if (!(_expired || _empty))
                        {
                            // For ISC cylinder IDS should display the cylinder part NUmber, so add the part number to explanation codes
                            if (!explanationCodes.Contains(gasEndPoint.Cylinder.PartNumber) && !string.IsNullOrEmpty(gasEndPoint.Cylinder.PartNumber))
                            {
                                explanationCodes.Add(gasEndPoint.Cylinder.PartNumber);
                                errorCodes.Add(string.Format("{0} ({1})", gasEndPoint.Cylinder.PartNumber, gasEndPoint.Position));  // see INS-3821
                            }
                            else
                            {
                                // For Non ISC Pass the gas code. But I believe that both ISC and Non-ISC cylinders have their own PArt numbers.
                                // So this condition may not be required ?
                                GasType gs = GasType.Cache[GasCode.FreshAir];
                                if (!explanationCodes.Contains(gasEndPoint.Cylinder.PartNumber) && gs != null)
                                {
                                    explanationCodes.Add(gs.Symbol);
                                    errorCodes.Add(string.Format("{0} ({1})", gs.Symbol, gs.Code));
                                }
                            }
                            _empty = true;
                        }
                        continue;
                    }
                }

                //string sensorGasCode = sensor.CalibrationGas.Code;

                if (eventCode == EventCode.BumpTest)
                {
                    // If we're doing a bump test, and this is a combustible sensor either in LEL or PPM mode,
                    // and docking station has a CombustibleBumpTestGas setting, then ignore the sensor's cal
                    // gas code and instead only look for cylinders that match the CombustibleBumpTestGas setting.
                    if ((sensor.Type.Code == SensorCode.CombustibleLEL || sensor.Type.Code == SensorCode.CombustiblePPM) &&
                        (Configuration.DockingStation.CombustibleBumpTestGas.Length > 0))
                    {
                        sensorGasCode = Configuration.DockingStation.CombustibleBumpTestGas;
                        Log.Debug(string.Format("...Sensor is combustible and CombustibleBumpTestGas setting is {0}.", sensorGasCode));
                        Log.Debug(string.Format("...Overriding sensor cal gas. Looking for cylinders containing {0}.", sensorGasCode));
                    }
                    // If we're doing a bump test, we use Chlorine for the calibration gas.
                    else if (sensor.Type.Code == SensorCode.ClO2)
                    {
                        sensorGasCode = GasCode.Cl2;
                        Log.Debug("...Sensor is CLO2. Looking for cylinders containing Chlorine instead of cal gas.");
                    }
                }

                containsGas = gasEndPoint.Cylinder.ContainsGas(sensorGasCode);

                // Ensure bump tests for O2 sensors use concentrations of 19% O2 or less.
                // Zero air cylinders should not be selected for gasFound, but should be selected for zeroFound.
                if (containsGas && (eventCode == EventCode.BumpTest && sensor.CalibrationGas.Code == GasCode.O2))
                {
                    // The following Find should always succeed because containsGas is true.
                    GasConcentration gasConcentration = cyl.GasConcentrations.Find(gc => gc.Type.Code == sensorGasCode);
                    // Parts per million (ppm) of X divided by 10,000 = percentage concentration of X
                    if ((gasConcentration.Concentration / 10000.0) > 19.0)
                    {
                        Log.Debug("...Not allowed to use O2 concentration higher than 19%.");

                        containsGas = false;
                    }
                }

                // Ensure cylinder concentration is not higher than 60% for potentially explosive cal gases
                double lelMultiplier = GasType.Cache[sensorGasCode].LELMultiplier;
                if (containsGas && lelMultiplier > 0.0)
                {
                    double cylinderPPM = -1.0;
                    foreach (GasConcentration gasConcentration in cyl.GasConcentrations)
                    {
                        if (gasConcentration.Type.Code == sensorGasCode)
                        {
                            cylinderPPM = gasConcentration.Concentration;
                            break;
                        }
                    }

                    if (cylinderPPM < 0)   // this should never happen.  Which means we better check anyways.
                    {
                        Log.Debug("...Skipping cylinder. Does not contain " + sensorGasCode);
                        continue;
                    }

                    double cylinderLEL = cylinderPPM * lelMultiplier;
                    if (cylinderLEL > 60.0)                        // cylinder is higher than 60%?  Don't use it.
                    {
                        Log.Debug(string.Format("...Skipping cylinder. Contains {0} with too high LEL concentration ({1}%)",
                                                sensorGasCode, Math.Round(cylinderLEL, 1)));
                        Log.Debug("...Not allowed to use LEL concentration higher than 60%.");
                        continue;
                    }
                }

                // The gas is found if the cylinder contains a gas with a matching code, or
                // if the cylinder is fresh air and the sensor is an O2 sensor.
                // Fresh air is not acceptable as O2 if doing a bump test.
                // Zero air is not acceptable for an O2 bump test.
                if (containsGas || ((sensor.CalibrationGas.Code == GasCode.O2) && !(eventCode == EventCode.BumpTest) && gasEndPoint.Cylinder.IsFreshAir))
                {
                    Log.Debug("...Gas found.");
                    if (HasCylinder(gasEndPoint, gasEndPoints) == false)
                    {
                        gasEndPoints.Add(gasEndPoint);
                    }
                    _gasFound    = true;
                    alreadyAdded = true;
                }

                // Nitrogen is acceptable for doing O2 bump tests.
                if (sensor.CalibrationGas.Code == GasCode.O2 &&
                    (eventCode == EventCode.BumpTest) &&
                    gasEndPoint.Cylinder.ContainsOnlyGas(GasCode.N2) == true)
                {
                    Log.Debug("...Gas found.");
                    if (HasCylinder(gasEndPoint, gasEndPoints) == false)
                    {
                        gasEndPoints.Add(gasEndPoint);
                    }
                    _gasFound = true;
                }

                if (gasEndPoint.Cylinder.IsFreshAir)
                {
                    Log.Debug("...Fresh air found.");
                    if (!alreadyAdded)
                    {
                        if (HasCylinder(gasEndPoint, gasEndPoints) == false)
                        {
                            gasEndPoints.Add(gasEndPoint);
                        }
                    }
                    _freshFound  = true;
                    alreadyAdded = true;
                }

                if (gasEndPoint.Cylinder.IsZeroAir)
                {
                    Log.Debug("...Zero Air found.");
                    if (!alreadyAdded)
                    {
                        if (HasCylinder(gasEndPoint, gasEndPoints) == false)
                        {
                            gasEndPoints.Add(gasEndPoint);
                        }
                    }
                    _zeroFound   = true;
                    alreadyAdded = true;
                }
            }   // end-foreach  Gasendpoints

            // BEGIN INS-8630 RHP v7.5 - Loop through the entire list of installed cylinders.
            // if _gasFound is set to true, then the desired gas is found and hence we can reset _expired and _empty.
            // There may be cases where a docking station may have more than one gas code of the same kind assigned to it as a part of installed cylinders and
            // put of which one of the cylinders may be expired/empty and other may be full.
            if (_empty && _gasFound)
            {
                _empty = false;
            }
            else if (_expired && _gasFound)
            {
                _expired = false;
            }
            // END INS-8630 RHP v7.5
        }
        /// <summary>
        /// Private helper method for GetSensorGasEndPoint(Sensor).
        /// </summary>
        /// <param name="sensor"></param>
        /// <param name="gasEndPoints"></param>
        /// <returns></returns>
        private GasEndPoint GetSensorGasEndPoint(Sensor sensor, List <GasEndPoint> gasEndPoints)
        {
            MeasurementType sensorMeasurementType = ((SensorType)sensor.Type).MeasurementType;

            string sensorGasCode = sensor.CalibrationGas.Code;

            double sensorConcentration = sensor.CalibrationGasConcentration;

            double lelMultiplier = GasType.Cache[sensorGasCode].LELMultiplier;

            int pointNumber = 0;

            Log.Debug("SCAN 1 (find appropriate gas with desired concentration)...");
            foreach (GasEndPoint gasEndPoint in gasEndPoints)
            {
                Cylinder cyl = gasEndPoint.Cylinder;

                LogGasEndPoint(gasEndPoint, ++pointNumber);

                // Ignore already tried cylinders.
                if (_triedGasEndPoints.ContainsKey(gasEndPoint))
                {
                    Log.Debug("...Rejected. Already tried cylinder.");
                    continue;
                }

                // Ignore empty cylinders.
                if (cyl.Pressure == PressureLevel.Empty)
                {
                    _triedGasEndPoints[gasEndPoint] = gasEndPoint;
                    Log.Debug("...Rejected. Cylinder empty.");
                    continue;
                }

                // Check the measurement type for how to multiply the concentration.

                // Make sure we convert sensor's LEL
                // concentration to PPM for matching against cylinders concentrations
                if (sensorMeasurementType == MeasurementType.LEL)
                {
                    // Convert sensor's cal gas concentration from %LEL to PPM
                    sensorConcentration = sensor.CalibrationGasConcentration / lelMultiplier;
                    // We want to round the concentration to the nearest hundred.
                    // e.g., if concentration is 3928, we want to round it to 3900.
                    //
                    // DO NOT DO THE FOLLOWING COMMENTED OUT LINE!  IT NEEDS TO BE KEPT
                    // SEPARATED AS THREE SEPARATE LINES, OTHERWISE IT MIGHT CRASHES WINCE.
                    // SOME BUG IN COMPACT FRAMEWORK?
                    // sensorConcentration = Math.Round( sensorConcentration / 100.0, 0 ) * 100.0;
                    sensorConcentration /= 100.0;
                    sensorConcentration  = Math.Round(sensorConcentration, 0);
                    sensorConcentration *= 100.0;
                    Log.Debug(string.Format("...Sensor concentration of {0}%% LEL equals {1} PPM ({2} multiplier).",
                                            sensor.CalibrationGasConcentration, sensorConcentration, lelMultiplier));
                }

                else if (sensorMeasurementType == MeasurementType.VOL)
                {
                    sensorConcentration = sensor.CalibrationGasConcentration * 10000;
                    Log.Debug(string.Format("...Sensor concentration of {0}%% VOL equals {1} PPM.",
                                            sensor.CalibrationGasConcentration, sensorConcentration));
                }

                // For oxygen sensors, ignore 20.9 concentration end points.
                if ((sensorGasCode == GasCode.O2) && cyl.IsZeroAir)
                {
                    Log.Debug("...Rejected. Can't use ZeroAir for O2.");
                    continue;
                }

                // For oxygen sensors, ignore 20.9 concentration end points.
                if ((sensorGasCode == GasCode.O2) && cyl.IsFreshAir)
                {
                    Log.Debug("...Rejected. Can't use FreshAir for O2.");
                    continue;
                }

                // Ignore cylinders lacking the right gases.
                if (!cyl.ContainsGas(sensorGasCode, sensorConcentration, sensorMeasurementType))
                {
                    Log.Debug("...Rejected. Does not contain " + sensorGasCode + " with concentration " + sensorConcentration);
                    continue;
                }

                // Ensure bump tests for O2 sensors use concentrations of 19% O2 or less.
                if (sensorGasCode == GasCode.O2)
                {
                    // The following Find should always succeed assuming we already did a Cylinder.ContainsGas call earlier.
                    GasConcentration gasConcentration = cyl.GasConcentrations.Find(gc => gc.Type.Code == sensorGasCode);
                    // Parts per million (ppm) of X divided by 10,000 = percentage concentration of X
                    if ((gasConcentration.Concentration / 10000.0) > 19.0)
                    {
                        Log.Debug("...Rejected. Can't use concentrations above 19% for O2.");
                        continue;
                    }
                }

                // Ensure cylinder concentration is not higher than 60% for potentially explosive cal gases
                if (lelMultiplier > 0.0)
                {
                    // We now know this cylinder contains the desired gas concentration. But we don't allow
                    // calibration of combustible sensor using any cylinder that is higher than 60% LEL.
                    // So, find the gas in the cylinder and check it's LEL level.

                    double cylinderPPM = -1.0;
                    foreach (GasConcentration gasConcentration in cyl.GasConcentrations)
                    {
                        if (gasConcentration.Type.Code == sensorGasCode)
                        {
                            cylinderPPM = gasConcentration.Concentration;
                            break;
                        }
                    }

                    if (cylinderPPM < 0) // this should never happen.  Which means we better check.
                    {
                        Log.Debug("...Rejected. Does not contain " + sensorGasCode);
                        continue;
                    }

                    double cylinderLEL = cylinderPPM * lelMultiplier;
                    if (cylinderLEL > 60.0)  // cylinder is higher than 60%?  Don't use it.
                    {
                        Log.Debug(string.Format("...Rejected. Contains {0} with too high LEL concentration ({1}%%).",
                                                sensorGasCode, Math.Round(cylinderLEL, 1)));
                        Log.Debug("...Will not use concentration higher than 60%% LEL.");
                        continue;
                    }
                }

                // Found a cylinder with the correct gas and concentration.
                _triedGasEndPoints[gasEndPoint] = gasEndPoint;

                Log.Debug("...SELECTED. Contains " + sensorGasCode + " with desired concentration " + sensorConcentration);

                return(gasEndPoint);
            }

            Log.Debug("SCAN 2 (find appropriate gas with any concentration)...");

            pointNumber = 0;
            foreach (GasEndPoint gasEndPoint in gasEndPoints)
            {
                LogGasEndPoint(gasEndPoint, ++pointNumber);

                // Ignore already tried cylinders.
                if (_triedGasEndPoints.ContainsKey(gasEndPoint))
                {
                    Log.Debug("...Rejected. Already tried cylinder.");
                    continue;
                }

                // Ignore empty cylinders.
                if (gasEndPoint.Cylinder.Pressure == PressureLevel.Empty)
                {
                    _triedGasEndPoints[gasEndPoint] = gasEndPoint;
                    Log.Debug("...Rejected. Cylinder empty.");
                    continue;
                }

                // For oxygen sensors, ignore 20.9 concentration end points.
                if ((sensorGasCode == GasCode.O2) &&
                    gasEndPoint.Cylinder.IsZeroAir)
                {
                    Log.Debug("...Rejected. Can't use Zero Air for O2.");
                    continue;
                }

                // For oxygen sensors, ignore 20.9 concentration end points.
                if ((sensorGasCode == GasCode.O2) &&
                    gasEndPoint.Cylinder.IsFreshAir)
                {
                    Log.Debug("...Rejected. Can't use FreshAir for O2.");
                    continue;
                }

                // Ignore cylinders lack the right gases.
                if (!gasEndPoint.Cylinder.ContainsGas(sensorGasCode))
                {
                    Log.Debug("...Rejected. Does not contain " + sensorGasCode);
                    continue;
                }

                // Ensure bump tests for O2 sensors use concentrations of 19% O2 or less.
                if (sensorGasCode == GasCode.O2)
                {
                    // The following Find should always succeed assuming we already did a Cylinder.ContainsGas call earlier.
                    GasConcentration gasConcentration = gasEndPoint.Cylinder.GasConcentrations.Find(gc => gc.Type.Code == sensorGasCode);
                    // Parts per million (ppm) of X divided by 10,000 = percentage concentration of X
                    if ((gasConcentration.Concentration / 10000.0) > 19.0)
                    {
                        Log.Debug("...Rejected. Can't use concentrations above 19% for O2.");
                        continue;
                    }
                }

                // SGF  Feb-10-2009  DSW-72
                // Ensure cylinder concentration is not higher than 60% for potentially explosive cal gases

                if (lelMultiplier > 0.0)
                {
                    // We now know this cylinder contains the desired gas concentration. But we don't allow
                    // calibration of combustible sensor using any cylinder that is higher than 60% LEL.
                    // So, find the gas in the cylinder and check it's LEL level.

                    double cylinderPPM = -1.0;
                    foreach (GasConcentration gasConcentration in gasEndPoint.Cylinder.GasConcentrations)
                    {
                        if (gasConcentration.Type.Code == sensorGasCode)
                        {
                            cylinderPPM = gasConcentration.Concentration;
                            break;
                        }
                    }

                    if (cylinderPPM < 0) // this should never happen.  Which means we better check.
                    {
                        Log.Debug("...Rejected. Does not contain " + sensorGasCode);
                        continue;
                    }

                    double cylinderLEL = cylinderPPM * lelMultiplier;
                    if (cylinderLEL > 60.0)  // cylinder is higher than 60%?  Don't use it.
                    {
                        Log.Debug(string.Format("...Rejected. Contains {0} with too high LEL concentration ({1}%%).",
                                                sensorGasCode, Math.Round(cylinderLEL, 1)));
                        Log.Debug("...Will not use concentration higher than 60%% LEL.");
                        continue;
                    }
                }

                // Found a cylinder with the correct gas.
                _triedGasEndPoints[gasEndPoint] = gasEndPoint;

                Log.Debug("...SELECTED. Contains " + sensorGasCode);

                return(gasEndPoint);
            }

            return(null);
        }
Exemple #4
0
        internal static Mock <InstrumentController> GetInstrumentControllerMockForCal(Instrument instrument = null)
        {
            Mock <InstrumentController> instrumentController = new Mock <InstrumentController>();

            SensorPosition[] sensorPositions = null;

            if (instrument != null)
            {
                sensorPositions = instrument.InstalledComponents
                                  .Where(installedComponent => installedComponent.Component is Sensor)
                                  .Select(sensor => new SensorPosition(sensor.Position, SensorMode.Installed, false))
                                  .ToArray();

                instrumentController.Setup(x => x.AccessoryPump).Returns(instrument.AccessoryPump);
            }

            instrumentController.Setup(x => x.Initialize(It.IsAny <InstrumentController.Mode>()));
            instrumentController.Setup(x => x.TestForInstrumentReset(It.IsAny <SensorGasResponse>(), It.IsAny <string>())).Returns(false);
            instrumentController.Setup(x => x.GetSensorBiasStatus()).Returns(true);
            instrumentController.Setup(x => x.EnablePump(It.IsAny <bool>()));
            instrumentController.Setup(x => x.GetSensorPositions()).Returns(sensorPositions);
            instrumentController.Setup(x => x.OpenGasEndPoint(It.IsAny <GasEndPoint>(), It.IsAny <int>()));
            instrumentController.Setup(x => x.CloseGasEndPoint(It.IsAny <GasEndPoint>()));
            instrumentController.Setup(x => x.GetSensorReading(It.IsAny <int>(), It.IsAny <double>())).Returns(0);
            instrumentController.Setup(x => x.GetSensorBumpStatus(It.IsAny <int>())).Returns(true);
            instrumentController.Setup(x => x.PauseGasFlow(It.IsAny <GasEndPoint>(), It.IsAny <long>()));
            instrumentController.Setup(x => x.GetSensorMaximumReading(It.IsAny <int>(), It.IsAny <double>())).Returns(30);

            instrumentController.Setup(x => x.IsSensorEnabled(It.IsAny <int>())).Returns <int>(pos =>
            {
                InstalledComponent installedComponent = instrument.InstalledComponents.Find(component => component.Position == pos);
                if (installedComponent != null)
                {
                    return(installedComponent.Component.Enabled);
                }
                return(false);
            });
            instrumentController.Setup(x => x.GetSensorLowAlarm(It.IsAny <int>(), It.IsAny <double>())).Returns <int, double>((pos, resolution) =>
            {
                InstalledComponent installedComponent = instrument.InstalledComponents.Find(component => component.Position == pos);
                if (installedComponent != null)
                {
                    Sensor sensor = (Sensor)installedComponent.Component;
                    return(sensor.Alarm.Low);
                }
                return(0);
            });

            #region [ Calibration Methods ]

            instrumentController.Setup(x => x.PreconditionSensor(It.IsAny <InstalledComponent>(), It.IsAny <GasEndPoint>(), It.IsAny <SensorGasResponse>())).Returns(new TimeSpan(0));
            instrumentController.Setup(x => x.GetSensorZeroingStatus(It.IsAny <int>())).Returns(true);
            instrumentController.Setup(x => x.IsSensorCalibrationEnabled(It.IsAny <InstalledComponent>())).Returns(true);
            instrumentController.Setup(x => x.GetSensorLastCalibrationTime(It.IsAny <int>())).Returns(DateTime.Now);
            instrumentController.Setup(x => x.ZeroSensors(It.IsAny <GasEndPoint>())).Returns(true);
            instrumentController.Setup(x => x.SetSensorCalGasConcentration(It.IsAny <int>(), It.IsAny <double>(), It.IsAny <double>()));
            instrumentController.Setup(x => x.SetCalibrationGasConcentration(It.IsAny <InstalledComponent>(), It.IsAny <double>(), It.IsAny <bool>()));
            instrumentController.Setup(x => x.GetSensorCalibrationTimeout(It.IsAny <int>())).Returns(new TimeSpan(0, 0, 10));
            instrumentController.Setup(x => x.GetSensorBaseline(It.IsAny <int>())).Returns(0);
            instrumentController.Setup(x => x.GetSensorZeroOffset(It.IsAny <int>(), It.IsAny <double>())).Returns(0);
            instrumentController.Setup(x => x.GetSensorSpanCoeff(It.IsAny <int>())).Returns(49485);
            instrumentController.Setup(x => x.BeginSensorCalibration(It.IsAny <IEnumerable <int> >()));
            instrumentController.Setup(x => x.GetSensorCalibrationFlowRate(It.IsAny <InstalledComponent>())).Returns(500);
            instrumentController.Setup(x => x.GetSensorPreconditionFlowRate(It.IsAny <InstalledComponent>())).Returns(500);
            instrumentController.Setup(x => x.GetSensorPreconditionTimeout(It.IsAny <InstalledComponent>())).Returns(new TimeSpan(0, 0, 10));

            instrumentController.Setup(x => x.SetCalibrationGasConcentration(It.IsAny <InstalledComponent>(), It.IsAny <GasEndPoint>())).Returns <InstalledComponent, GasEndPoint>((installedComponent, gasEndPoint) =>
            {
                Sensor sensor = (Sensor)installedComponent.Component;
                GasConcentration gasConcentration = null;

                gasConcentration = gasEndPoint.Cylinder.GasConcentrations.Find(gas => gas.Type.Code == sensor.CalibrationGas.Code);
                if (gasConcentration != null)
                {
                    sensor.CalibrationGasConcentration = gasConcentration.Concentration;
                    return(gasConcentration.Concentration);
                }

                gasConcentration = gasEndPoint.Cylinder.GasConcentrations.Find(gas => gas.Type.Code == GasCode.FreshAir && sensor.CalibrationGas.Code == GasCode.O2);
                if (gasConcentration != null)
                {
                    sensor.CalibrationGasConcentration = 209000;
                    return(209000);
                }

                return(0);
            });
            if (instrument != null && instrument.InstalledComponents.Where(installedComponent => installedComponent.Component is Sensor).Count() > 0)
            {
                int noOfReadingsNeeded = 3;
                Func <string, int, string>  sensorID = (sn, position) => string.Join("_", sn, position);
                Func <Sensor, double>       sensorCalibrationGasConcentration = s => ((SensorType)s.Type).MeasurementType != MeasurementType.VOL ? s.CalibrationGasConcentration : s.CalibrationGasConcentration * 10000;
                Dictionary <string, double> sensorReadings      = createSensorReadingDictionary(instrument.InstalledComponents.Where(installedComponent => installedComponent.Component is Sensor));
                Dictionary <int, double>    sensorReadingCounts = createSensorReadingCount(instrument.InstalledComponents.Where(installedComponent => installedComponent.Component is Sensor));
                Func <int, double>          sensorSpanReserve   = position =>
                {
                    double             spanReserve        = 0;
                    InstalledComponent installedComponent = instrument.InstalledComponents.Find(installComp => installComp.Position == position);
                    if (installedComponent != null)
                    {
                        Sensor sensor        = (Sensor)installedComponent.Component;
                        double calGasConc    = sensorCalibrationGasConcentration(sensor);
                        double sensorReading = sensorReadings[sensorID(sensor.SerialNumber, position)];
                        spanReserve = (sensorReading / calGasConc) * 100;
                    }
                    return(spanReserve);
                };

                instrumentController.Setup(x => x.GetSensorCalibrationReading(It.IsAny <int>(), It.IsAny <double>()))
                .Returns <int, double>((position, resolution) =>
                {
                    double reading = 0;
                    InstalledComponent installedComponent = instrument.InstalledComponents.Find(installComp => installComp.Position == position);
                    if (installedComponent != null)
                    {
                        reading = sensorReadings[sensorID(installedComponent.Component.SerialNumber, position)];
                    }
                    return(reading);
                })
                .Callback <int, double>((position, resolution) =>
                {
                    InstalledComponent installedComponent = instrument.InstalledComponents.Find(installComp => installComp.Position == position);
                    if (installedComponent != null)
                    {
                        Sensor sensor        = (Sensor)installedComponent.Component;
                        double calGasConc    = sensorCalibrationGasConcentration(sensor);
                        double increment     = calGasConc / noOfReadingsNeeded;
                        double sensorReading = sensorReadings[sensorID(sensor.SerialNumber, position)];
                        if (sensorReading < (calGasConc + increment))
                        {
                            sensorReadings[sensorID(sensor.SerialNumber, position)] += increment;
                        }
                    }
                });

                instrumentController.Setup(x => x.GetSensorCalibrationStatus(It.IsAny <int>()))
                .Returns <int>(position => sensorSpanReserve(position) > 80);

                instrumentController.Setup(x => x.IsSensorCalibrating(It.IsAny <int>()))
                .Returns <int>(position => sensorReadingCounts[position] <= noOfReadingsNeeded)
                .Callback <int>(position => sensorReadingCounts[position] += 1);

                instrumentController.Setup(x => x.GetSensorSpanReserve(It.IsAny <int>())).Returns <int>(pos => sensorSpanReserve(pos));
                instrumentController.Setup(x => x.GetSensorSpanCoeff(It.IsAny <int>())).Returns(1);

                instrumentController.Setup(x => x.GetSensorLastCalibrationTime(It.IsAny <int>()))
                .Returns <int>(position => sensorReadingCounts[position] > 0 ? DateTime.Now : DateTime.Now.AddMinutes(-5))
                .Callback <int>(position =>
                {
                    if (sensorReadingCounts[position] > 1)
                    {
                        sensorReadingCounts[position] = 0;
                    }
                });
            }

            #endregion

            return(instrumentController);
        }