/// <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); }
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); }