/// <summary> /// Create gas endpoints for testing, port 1 contains fresh air and port 2 contains default 4-gas cylinder /// Change gas endpoints as needed for your testing if default configuration is not what you wanted. /// </summary> /// <param name="components"></param> /// <returns></returns> internal static List <GasEndPoint> GetGasEndPointsForTest(List <InstalledComponent> components) { List <GasEndPoint> gasEndPoints = new List <GasEndPoint>(); //Port 1 is fresh air gasEndPoints.Add(GasEndPoint.CreateFreshAir(1)); //Port 2, add 4-gas cylinder Cylinder cyl = new Cylinder("1810-9155", "ISC") { ExpirationDate = DateTime.Today.AddDays(30), Pressure = PressureLevel.Full }; cyl.GasConcentrations.AddRange(new List <GasConcentration>() { new GasConcentration(GasType.Cache[GasCode.CO.ToString()], 100.00), new GasConcentration(GasType.Cache[GasCode.H2S.ToString()], 25.00), new GasConcentration(GasType.Cache[GasCode.Pentane.ToString()], 3521.10), new GasConcentration(GasType.Cache[GasCode.O2.ToString()], 180000.00) }); gasEndPoints.Add(new GasEndPoint(cyl, 2, GasEndPoint.Type.Manual)); return(gasEndPoints); }
/// <summary> /// Determines if passed-in GasEndPoints list already contains the passed-in cylinder. /// <para> /// (Matches on cylinder position and part number.) /// </para> /// </summary> /// <param name="candidateCylinder"></param> /// <param name="gasEndPoints"></param> /// <returns></returns> private bool HasCylinder(GasEndPoint candidateCylinder, List <GasEndPoint> gasEndPoints) { GasEndPoint foundEndPoint = gasEndPoints.Find(g => g.Position == candidateCylinder.Position && g.Cylinder.PartNumber == candidateCylinder.Cylinder.PartNumber); return(foundEndPoint != null); }
/// <summary> /// Logs the gas end point. This is a helper method for GetGasEndPoint. /// </summary> /// <param name="gasEndPoint"></param> /// <param name="pointCount"></param> private void LogGasEndPoint(GasEndPoint gasEndPoint, int pointCount) { string msg = "GasEndPoint #" + pointCount; Log.Debug(msg); Cylinder cyl = gasEndPoint.Cylinder; msg = "...Pos=" + gasEndPoint.Position //+ ", ID=" + cyl.ID + ", FactID=" + cyl.FactoryId + ", Part=" + cyl.PartNumber + ", Fresh=" + cyl.IsFreshAir + ", ZeroAir=" + cyl.IsZeroAir + ", Pressure=" + cyl.Pressure.ToString() + ", ExpDate=" + cyl.ExpirationDate; if (cyl.Volume != DomainModelConstant.NullInt) { msg += ", Vol=" + cyl.Volume; } Log.Debug(msg); msg = "......"; foreach (GasConcentration gasCon in cyl.GasConcentrations) { msg += "[" + gasCon.Type.Code; msg += " "; msg += (gasCon.Concentration == DomainModelConstant.NullDouble) ? "fresh" : gasCon.Concentration.ToString(); msg += "]"; } Log.Debug(msg); }
/// <summary> /// /// </summary> /// <param name="gep"></param> /// <param name="trx"></param> /// <returns></returns> public bool Save(GasEndPoint gep, DataAccessTransaction trx) { string sql = string.Empty; try { Delete(gep, trx); // delete any old cylinder at this position. sql = "INSERT INTO GASENDPOINT ( POSITION, RECUPDATETIMEUTC, FACTORYID, PARTNUMBER, PRESSURE, REFILLDATE, EXPIRATIONDATE, INSTALLATIONTYPE ) VALUES ( @POSITION, @RECUPDATETIMEUTC, @FACTORYID, @PARTNUMBER, @PRESSURE, @REFILLDATE, @EXPIRATIONDATE, @INSTALLATIONTYPE )"; using (IDbCommand cmd = GetCommand(sql, trx)) { cmd.Parameters.Add(GetDataParameter("@POSITION", gep.Position)); cmd.Parameters.Add(GetDataParameter("@RECUPDATETIMEUTC", trx.TimestampUtc)); cmd.Parameters.Add(GetDataParameter("@INSTALLATIONTYPE", gep.InstallationType.ToString())); cmd.Parameters.Add(GetDataParameter("@FACTORYID", gep.Cylinder.FactoryId)); cmd.Parameters.Add(GetDataParameter("@PARTNUMBER", gep.Cylinder.PartNumber)); cmd.Parameters.Add(GetDataParameter("@PRESSURE", gep.Cylinder.Pressure.ToString())); cmd.Parameters.Add(GetDataParameter("@REFILLDATE", gep.Cylinder.RefillDate)); cmd.Parameters.Add(GetDataParameter("@EXPIRATIONDATE", gep.Cylinder.ExpirationDate)); return(cmd.ExecuteNonQuery() > 0); } } catch (DataAccessException) { throw; } catch (Exception ex) { throw new DataAccessException(sql, ex); } }
/// <summary> /// Throws a FlowFailedException if cylinder is detected as going empty /// during the purge. /// </summary> /// <param name="airEndPoint"></param> private void CheckAir(GasEndPoint airEndPoint) { if (Pump.GetOpenValvePosition() > 0) { return; } // For now, we don't bother checking fresh air to be 'empty'. // If we did check fresh air, then the port would get marked as 'empty' // in the database, and there's currently no way to reset it back to // Full except to reboot the docking station. // // If/when we have mechanism to allow an 'Empty' fresh air port to // be 'reset' back to Full, then we should remove this check for IsFreshAir. // // SEE ALSO: The IsFreshAir check in Pump.CheckFlow's loop. // // - JMP, 6/30/2011 if (airEndPoint.Cylinder.IsFreshAir) { return; } throw new FlowFailedException(airEndPoint); // empty }
private UnsupportedCylinderAction CreateUnsupportedCylinderAction(GasEndPoint gasEndPoint) { UnsupportedCylinderAction action = new UnsupportedCylinderAction(gasEndPoint); action.Messages.Add(gasEndPoint.Cylinder.PartNumber); return(action); }
public DockingStationEvent Execute() { string funcMsg = Name + ".Execute"; Log.Debug(funcMsg); // We copy the PostUpdate and SettingsRefId from the action to the event so they can // be passed on to the followup SettingsRead. See the EventProcessor.GetFollowupAction method. CylinderPressureResetEvent dsEvent = new CylinderPressureResetEvent(this); dsEvent.PostUpdate = this.PostUpdate; dsEvent.SettingsRefId = this.SettingsRefId; List <GasEndPoint> emptyManGasEndPoints = new List <GasEndPoint>(); List <GasEndPoint> manGasEndPoints = new GasEndPointDataAccess().FindAll().FindAll(m => m.InstallationType == GasEndPoint.Type.Manifold || m.InstallationType == GasEndPoint.Type.Manual); // We want to reset low/empty non-iGas cylinders to full. for (int position = 1; position <= Configuration.DockingStation.NumGasPorts; position++) { // We don't want to process (manual) fresh air cylinders on port 1. GasEndPoint man = manGasEndPoints.Find(m => m.Position == position && !(m.Position == 1 && m.Cylinder.IsFreshAir)); if (man != null) { Log.Debug(string.Format("{0}Position {1} {2} found (\"{3}\", \"{4}\") with {5} pressure.", LOG_LABEL, position, man.InstallationType == GasEndPoint.Type.Manifold ? "Manifold" : "Manual Cylinder", man.Cylinder.FactoryId, man.Cylinder.PartNumber, man.Cylinder.Pressure)); if (man.Cylinder.Pressure != PressureLevel.Full) { man.GasChangeType = GasEndPoint.ChangeType.PressureChanged; man.Cylinder.Pressure = PressureLevel.Full; emptyManGasEndPoints.Add(man); } } } if (emptyManGasEndPoints.Count > 0) { // Save the modified cylinders in the local database. The followup SettingsRead with // ChangedSmartCards set to null will take care of updating the cylinders in memory. using (DataAccessTransaction trx = new DataAccessTransaction()) { new GasEndPointDataAccess().SaveChangedCylinders(emptyManGasEndPoints, trx); trx.Commit(); Log.Debug(string.Format("{0}{1} non-iGas cylinders were reset to full.", LOG_LABEL, emptyManGasEndPoints.Count)); } } else { Log.Debug(string.Format("{0}No manifold or manual cylinders were found that needed reset to full.", LOG_LABEL)); } return(dsEvent); }
public DockingStationAction ReportFlowFailedError(GasEndPoint gasEndPoint) { Log.Debug(string.Format("Empty Cylinder was reported on position {0} during gas operation.", gasEndPoint.Position)); using (InetUploader inetUploader = new InetUploader()) { DockingStationAction dsAction = ProcessEmptyGasEndPoint(gasEndPoint, inetUploader); return(dsAction); } }
/// <summary> /// Get the bump test gas end point for a sensor. /// </summary> /// <param name="sensor">The sensor to get the gas for.</param> /// <returns>The correct gas end point.</returns> /// <exception cref="CorrectBumpTestGasUnavailable"> /// Thrown when no cylinder is provided for the sensor. /// </exception> protected GasEndPoint GetSensorGasEndPoint(Sensor sensor) { #region LogDebug if (sensor != null) { Log.Debug("BumpTest.GetSensorGasEndPoint"); Log.Debug("Finding appropriate Bump gas for Sensor: " + sensor.Type + ", S/N: " + sensor.Uid + ", CalGas Code: " + sensor.CalibrationGas.Code + ", Conc: " + sensor.CalibrationGasConcentration + ", Measurement: " + ((SensorType)sensor.Type).MeasurementType); } #endregion GasEndPoint endPoint = null; Log.Debug("UseExpiredCylinders=" + Configuration.DockingStation.UseExpiredCylinders); // If UseExpiredCylinders is true, then we should try and use expired cylinders // if there are any. i.e., expired cylinders are "preferred" over non-expired cylinders. if (Configuration.DockingStation.UseExpiredCylinders) { // Get sub-list of available end points that are only the expired cylinders. DateTime localTime = Configuration.GetLocalTime(); List <GasEndPoint> gasEndPoints = GasEndPoints.FindAll(gep => gep.Cylinder.ExpirationDate <= localTime); Log.Debug(string.Format("Looking for an expired cylinder to use ({0} expired candidates)....", gasEndPoints.Count)); // See if we can find an appropriate gas to use that's in this expired end points list. endPoint = GetSensorGasEndPoint(sensor, gasEndPoints); // If we didn't find an expired cylinder to use, we need to see if there's an un-expired cylinder to use. if (endPoint == null) { gasEndPoints = GasEndPoints.FindAll(gep => gep.Cylinder.ExpirationDate > localTime); Log.Debug(string.Format("No expired cylinder found. Looking for an unexpired cylinder ({0} unexpired candidates)....", gasEndPoints.Count)); endPoint = GetSensorGasEndPoint(sensor, gasEndPoints); } } else { endPoint = GetSensorGasEndPoint(sensor, GasEndPoints); } if (endPoint == null) { Log.Debug("NO APPROPRIATE BUMP GAS FOUND!"); } return(endPoint); }
private void ConstructorInit(PurgeType purgeType, InstrumentController instrumentController, List <GasEndPoint> gasEndPoints, InstrumentGasResponseEvent gasResponseEvent) { Log.Assert(instrumentController != null, "instrumentController cannot be null"); _instrumentController = instrumentController; _purgeType = purgeType; _returnGasResponseEvent = gasResponseEvent; // clone the supplied GasEndPoints foreach (GasEndPoint currentGasEndPoint in gasEndPoints) { GasEndPoint purgeGasEndPoint = (GasEndPoint)currentGasEndPoint.Clone(); GasEndPoints.Add(purgeGasEndPoint); } }
private GasEndPoint MakeInstalledCylinder(IDataReader reader, DataAccessOrdinals ordinals, DataAccessTransaction trx) { short position = SqlSafeGetShort(reader, ordinals["POSITION"]); string partNumber = SqlSafeGetString(reader, ordinals["PARTNUMBER"]); // Try and get the Factory Cylinder information for the part number. // Note that there may not be any factory cylinder info available if the // part number is for a new cylinder type that's unknown to to iNet. FactoryCylinder factoryCylinder = null; if (partNumber != string.Empty) { factoryCylinder = new FactoryCylinderDataAccess().FindByPartNumber(partNumber, trx); } Cylinder cylinder; if (factoryCylinder != null) { cylinder = new Cylinder(factoryCylinder); } else { cylinder = new Cylinder(); cylinder.PartNumber = partNumber; } string installationTypeString = SqlSafeGetString(reader, ordinals["INSTALLATIONTYPE"]); GasEndPoint.Type installationType = (GasEndPoint.Type)Enum.Parse(typeof(GasEndPoint.Type), installationTypeString, true); GasEndPoint gep = new GasEndPoint(cylinder, position, installationType); gep.Cylinder.FactoryId = SqlSafeGetString(reader, ordinals["FACTORYID"]); gep.Cylinder.ExpirationDate = SqlSafeGetDate(reader, ordinals["EXPIRATIONDATE"]); gep.Cylinder.RefillDate = SqlSafeGetDate(reader, ordinals["REFILLDATE"]); string pressure = SqlSafeGetString(reader, ordinals["PRESSURE"]); gep.Cylinder.Pressure = (PressureLevel)Enum.Parse(typeof(PressureLevel), pressure, true); return(gep); }
/// <summary> /// Returns all of the currently known installed cylinders. /// </summary> /// <param name="trx"></param> /// <returns>The list of InstalledCylinders will be sorted by Position</returns> public List <GasEndPoint> FindAll(DataAccessTransaction trx) { List <GasEndPoint> list = new List <GasEndPoint>(); string sql = "SELECT * FROM GASENDPOINT ORDER BY POSITION"; using (IDbCommand cmd = GetCommand(sql, trx)) { using (IDataReader reader = cmd.ExecuteReader()) { DataAccessOrdinals ordinals = new DataAccessOrdinals(reader); while (reader.Read()) { GasEndPoint gep = MakeInstalledCylinder(reader, ordinals, trx); list.Add(gep); } } } return(list); }
/// <summary> /// Deletes the InstalledCylinder from its specified Position. /// </summary> /// <param name="gep"></param> /// <param name="trx"></param> /// <returns></returns> public bool Delete(GasEndPoint gep, DataAccessTransaction trx) { string sql = "DELETE FROM GASENDPOINT WHERE POSITION = @POSITION"; try { using (IDbCommand cmd = GetCommand(sql, trx)) { cmd.Parameters.Add(GetDataParameter("@POSITION", gep.Position)); return(cmd.ExecuteNonQuery() > 0); } } catch (DataAccessException) { throw; } catch (Exception ex) { throw new DataAccessException(sql, ex); } }
public bool UpdatePressureLevel(GasEndPoint gep, DataAccessTransaction trx) { string sql = "UPDATE GASENDPOINT SET PRESSURE = @PRESSURE, RECUPDATETIMEUTC = @RECUPDATETIMEUTC WHERE POSITION = @POSITION"; try { using (IDbCommand cmd = GetCommand(sql, trx)) { cmd.Parameters.Add(GetDataParameter("@POSITION", gep.Position)); cmd.Parameters.Add(GetDataParameter("@RECUPDATETIMEUTC", trx.TimestampUtc)); cmd.Parameters.Add(GetDataParameter("@PRESSURE", gep.Cylinder.Pressure.ToString())); return(cmd.ExecuteNonQuery() > 0); } } catch (DataAccessException) { throw; } catch (Exception ex) { throw new DataAccessException(sql, ex); } }
/// <summary> /// </summary> /// <remarks> /// 1) Updates the cylinder's pressure in the database (change it from Full to Low, or Low to Empty). /// 2) Update cached cylinder (in Configuration.DockingStation.InstalledCylinders) with the pressure /// change. /// 3) Also forces an upload of a SettingsReadEvent in order to notify iNet of the pressure change. /// </remarks> /// <param name="emptyCylinderError"></param> /// <param name="inetUploader"></param> /// <returns></returns> private DockingStationAction ProcessEmptyGasEndPoint(GasEndPoint emptyEndPoint, InetUploader inetUploader) { Log.Debug(string.Format("Empty Cylinder was reported on position {0}", emptyEndPoint.Position)); GasEndPoint gasEndPoint = null; using (DataAccessTransaction trx = new DataAccessTransaction()) { GasEndPointDataAccess gepDataAccess = new GasEndPointDataAccess(); gasEndPoint = gepDataAccess.FindByPosition(emptyEndPoint.Position, trx); if (gasEndPoint == null) { return(null); // should we display an error? } if (gasEndPoint.Cylinder.Pressure == PressureLevel.Full) { gasEndPoint.Cylinder.Pressure = PressureLevel.Low; Log.Warning("Low pressure warning, position " + emptyEndPoint.Position); } else { gasEndPoint.Cylinder.Pressure = PressureLevel.Empty; Log.Warning("Empty pressure warning, position " + emptyEndPoint.Position); } Log.Debug(string.Format("Changing pressure to \"{0}\" for cylinder on position {1}", gasEndPoint.Cylinder.Pressure.ToString(), gasEndPoint.Position)); Log.Debug(string.Format("...PartNumber={0}, FactoryId={1}", gasEndPoint.Cylinder.PartNumber, gasEndPoint.Cylinder.FactoryId)); gepDataAccess.UpdatePressureLevel(gasEndPoint, trx); trx.Commit(); } // After updating the database, we need to update the cached copy of the // installed cylinder, too, which is kept in the global DockingStation. GasEndPoint cachedGasEndPoint = Configuration.DockingStation.GasEndPoints.Find(g => g.Position == gasEndPoint.Position); if (cachedGasEndPoint != null) { cachedGasEndPoint.Cylinder.Pressure = gasEndPoint.Cylinder.Pressure; } // We need to inform iNet whenever a cylinder's pressure changes. We can only do this // by uploading a full docking station with the cylinder information. Which means we // need to immediately do a SettingsRead to get the full docking station info, and then // upload that info along with the currently installed cylinder info. SettingsReadOperation settingsReadOperation = new SettingsReadOperation(); // Explicitly set the ChangedSmartCards to all falses so that no smart cards are read. settingsReadOperation.ChangedSmartCards = new bool[Configuration.DockingStation.NumGasPorts]; SettingsReadEvent settingsReadEvent = (SettingsReadEvent)settingsReadOperation.Execute(); // Copy currently installed cylinder info to the docking station object we're going to upload. settingsReadEvent.DockingStation.GasEndPoints.Clear(); settingsReadEvent.DockingStation.ChangedGasEndPoints.Clear(); foreach (GasEndPoint gep in Configuration.DockingStation.GasEndPoints) { settingsReadEvent.DockingStation.GasEndPoints.Add((GasEndPoint)gep.Clone()); } inetUploader.UploadEvent(settingsReadEvent, Configuration.DockingStation.TimeZoneInfo); // BEGIN INS-8630 RHP v7.5 List <string> consoleMessages = new List <string>(); consoleMessages.Add(gasEndPoint.Cylinder.Pressure.ToString()); if (!string.IsNullOrEmpty(gasEndPoint.Cylinder.PartNumber)) // For ISC Pass the Cylinder Part Number { consoleMessages.Add(gasEndPoint.Cylinder.PartNumber); } // For Non ISC Pass the gas code. But I believe that both ISC and Non-ISC cylinders have their own PArt numbers. // So below condition may not be required ? else if (gasEndPoint.Cylinder.GasConcentrations.Count > 0) { consoleMessages.Add(gasEndPoint.Cylinder.GasConcentrations[0].Type.Symbol); } Log.Info("Sending IDS ReplaceCylinderAction"); DockingStationAction dsAction = new ResourceUnavailableAction(new List <string>() { gasEndPoint.Cylinder.Pressure.ToString() }, consoleMessages); // END INS-8630 return(dsAction); }
private bool Prepare() { const string funcMsg = "PreparePurge: "; Log.Debug(string.Format("{0}Starting ({1})", funcMsg, _purgeType)); // SGF 06-Jun-2011 INS-1735 // Do not perform a purge if the type is Unknown or Invalid if (_purgeType == PurgeType.Unknown) { return(false); } if (Master.Instance.ControllerWrapper.IsDocked() == false) { Log.Debug(string.Format("{0}No instrument is docked -- NO PURGE NECESSARY", funcMsg)); return(false); } bool instHasAccessoryPump = false; bool isPumpAdapterAttached = false; if (_instrumentController != null) { instHasAccessoryPump = (_instrumentController.AccessoryPump == AccessoryPumpSetting.Installed); isPumpAdapterAttached = Master.Instance.ControllerWrapper.IsPumpAdapterAttached(); Log.Debug(string.Format("{0}PurgeType={1}", funcMsg, _purgeType)); Log.Debug(string.Format("{0}AccessoryPump={1}, PumpAdapter={2}", funcMsg, instHasAccessoryPump, isPumpAdapterAttached)); // Normal flow rate for purging is the docking station's maximum flow rate. // Except if instrument has a pump and there is no pump adapter, then we purge // using a lower flow rate to avoid damaging the instrument pump. if (instHasAccessoryPump && !isPumpAdapterAttached) { _desiredFlow = Pump.StandardFlowRate; } } else { _desiredFlow = Pump.MaxFlowRate; } bool purgeRequired = true; // helper variable for multiple case blocks bool isDSX = !Configuration.DockingStation.Reservoir; Log.Debug(string.Format("{0}Reservoir={1}", funcMsg, Configuration.DockingStation.Reservoir)); int PUMP_PURGE_20SECONDS = (instHasAccessoryPump) ? 20 : 0; // Determine if we really have to purge or not (based on instrument's sensor // configuration) and, if so, how long we should purge. switch (_purgeType) { case PurgeType.PreCalibration: // INS-6723: DSX - 10 seconds (30 if aspirated) // iNet DS - 40 seconds (60 if aspirated) #if TEST _purge1Seconds = 0; // TODO: not a fix. Will have to be revisited #else _purge1Seconds = isDSX ? 10 + PUMP_PURGE_20SECONDS : 40 + PUMP_PURGE_20SECONDS; #endif break; case PurgeType.PostCalibration: // INS-6723: DSX / iNet DS - 30 seconds for enabled exotic sensor (50 if aspirated), followed by // DSX / iNet DS - 60 seconds smart purge regardless foreach (InstalledComponent ic in _returnGasResponseEvent.DockedInstrument.InstalledComponents) { if ((ic.Component is Sensor) && ((Sensor)ic.Component).RequiresExtendedPostCalibrationPurge) { Log.Debug(string.Format("{0}Purge required for {1} sensor.", funcMsg, ic.Component.Type.Code)); _purge1Seconds = 30 + PUMP_PURGE_20SECONDS; break; } } #if !TEST _purge2Seconds = 60; // follow-up smart purge #else _purge2Seconds = 0; #endif break; case PurgeType.PreBump: // INS-6723: DSX / iNet DS - 30 seconds smart purge if aspirated or for enabled exotic sensor purgeRequired = instHasAccessoryPump; if (purgeRequired) { Log.Debug(string.Format("{0}Purge required for aspirated instrument.", funcMsg)); } else { // if instrument does not have a pump, see if there are enabled exotic sensors foreach (InstalledComponent ic in _returnGasResponseEvent.DockedInstrument.InstalledComponents) { if ((ic.Component is Sensor) && ((Sensor)ic.Component).RequiresBumpTestPurge(GasEndPoints) == true) { Log.Debug(string.Format("{0}Purge required for {1} sensor.", funcMsg, ic.Component.Type.Code)); purgeRequired = true; break; } } } if (purgeRequired) { #if TEST _purge1Seconds = 0; // TODO: not a fix. Will have to be revisited #else _purge1Seconds = 30; #endif } else { Log.Debug(string.Format("{0}PurgeType={1} -- NO PURGE NECESSARY.", funcMsg, _purgeType)); return(false); } break; case PurgeType.PostBump: // INS-6723: DSX / iNet DS - 30 seconds for enabled exotic sensor (50 if aspirated), followed by // DSX / iNet DS - 60 seconds smart purge when "Purge After Bump" setting enabled purgeRequired = false; foreach (InstalledComponent ic in _returnGasResponseEvent.DockedInstrument.InstalledComponents.FindAll(c => c.Component is Sensor)) { if (((Sensor)ic.Component).RequiresBumpTestPurge(GasEndPoints) == true) { Log.Debug(string.Format("{0}Purge required for {1} sensor.", funcMsg, ic.Component.Type.Code)); purgeRequired = true; #if TEST _purge1Seconds = 0; // TODO: not a fix. Will have to be revisited #else _purge1Seconds = 30 + PUMP_PURGE_20SECONDS; #endif break; } } if (Configuration.DockingStation.PurgeAfterBump) { purgeRequired = true; _purge2Seconds = 60; Log.Debug(string.Format("{0}Purge required as PurgeAfterBump={1}.", funcMsg, Configuration.DockingStation.PurgeAfterBump)); } if (!purgeRequired) { Log.Debug(string.Format("{0}PurgeType={1} -- NO PURGE NECESSARY", funcMsg, _purgeType)); return(false); } break; case PurgeType.O2Recovery: // INS-6684: DSX / iNet DS - until 20% vol seen with 120 seconds maximum purgeRequired = false; bool isSecondHighBump = false; foreach (InstalledComponent ic in _returnGasResponseEvent.DockedInstrument.InstalledComponents) { if (!(ic.Component is Sensor)) { continue; } if (!((Sensor)ic.Component).Enabled) { continue; } if (ic.Component.Type.Code == SensorCode.O2) { Log.Debug(string.Format("{0}Purge required for {1} sensor.", funcMsg, ic.Component.Type.Code)); purgeRequired = true; // INS-7625 SSAM v7.6 // Second high bump test should flow gas and have a much shorter timeout of 30 seconds. // If the purge is done as a part of second high bump test, set the purge timeout to 30 seconds. // Else, set it to 120 seconds. SensorGasResponse sgr = _returnGasResponseEvent.GetSensorGasResponseByUid(ic.Component.Uid); if (sgr != null && sgr.IsSecondO2HighBump) { isSecondHighBump = true; } #if !TEST _purge1Seconds = isSecondHighBump ? 30 : 120; // See INS-6684 (and INS-2314) #else _purge1Seconds = 0; #endif } } if (!purgeRequired) { Log.Debug(string.Format("{0}PurgeType={1} -- NO PURGE NECESSARY", funcMsg, _purgeType)); return(false); } break; case PurgeType.CylinderSwitch: #if !TEST // 40 seconds (60 if aspirated) _purge1Seconds = 40 + PUMP_PURGE_20SECONDS; // For Calibration, 30 seconds (45 if aspirated) if (_returnGasResponseEvent is InstrumentCalibrationEvent) { _purge1Seconds = instHasAccessoryPump ? 45 : 30; } #else _purge1Seconds = 0; #endif break; } Log.Debug(string.Format("{0}Purge seconds={1}, Desired flow={2}", funcMsg, _purge1Seconds, _desiredFlow)); if (_purge2Seconds > 0) { Log.Debug(string.Format("{0}Secondary purge seconds={1}", funcMsg, _purge2Seconds)); } // First try to find fresh air. If found, then use it. try { _airEndPoint = GetFreshAir(); // Find the fresh air valve Log.Debug(string.Format("{0}Found fresh air for purging.", funcMsg)); } catch (CorrectCalibrationGasUnavailable) { Log.Debug(string.Format("{0}No fresh air found for purging. Looking for zero air instead.", funcMsg)); } // If no fresh air found, then look for zero air. Note that we pass a true // to GetSensorZeroAir causing it to NOT look for a fresh air alternative. // We just looked for fresh air above. if (_airEndPoint == null) { _airEndPoint = GetZeroAir(true); Log.Debug(string.Format("{0}Found zero air for purging.", funcMsg)); } if (_airEndPoint == null) { Log.Debug(string.Format("{0}FOUND NO AIR FOR PURGING.", funcMsg)); return(false); } return(true); } // end-Prepare
/// <summary> /// /// </summary> /// <param name="gasEndPoints"></param> /// <param name="changesOnly"> /// If changesOnly is set, then the passed-in list only contains /// changes. e.g.., if there's been no iGas card insertion/removal on, say, /// position 2, then there will be no cylinder in the list at that position. /// </param> public void SaveInstalledCylinders(List <GasEndPoint> gasEndPoints, DataAccessTransaction trx) { List <GasEndPoint> persistedListed = FindAll(trx); List <GasEndPoint> saveList = new List <GasEndPoint>(); for (int position = 1; position <= Configuration.DockingStation.NumGasPorts; position++) { GasEndPoint installed = gasEndPoints.Find(g => g.Position == position); GasEndPoint persisted = persistedListed.Find(g => g.Position == position); // Is no cylinder on the port, but database thinks there is one? // Then assume user has uninstalled the cylinder. We need to remove it from the database if (installed == null && persisted != null) // Not installed? make sure it's marked as uninstalled in the DB, too. { Log.Debug(string.Format("Port {0} (fid=\"{1}\",pn=\"{2}\",{3}) has been uninstalled.", position, persisted.Cylinder.FactoryId, persisted.Cylinder.PartNumber, persisted.InstallationType)); persisted.GasChangeType = GasEndPoint.ChangeType.Uninstalled; // mark it for deletion. saveList.Add(persisted); } // Was this cylinder not known to be installed but is now installed? else if (persisted == null && installed != null) { installed.GasChangeType = GasEndPoint.ChangeType.Installed; // mark it for saving. saveList.Add(installed); } // Was this cylinder already known to be installed? Then update // any data that's changed. else if (installed != null && persisted != null) { // If anything has changed, then we need to update the cylinder. if (installed.Cylinder.FactoryId != persisted.Cylinder.FactoryId || installed.Cylinder.ExpirationDate != persisted.Cylinder.ExpirationDate || installed.Cylinder.Pressure != persisted.Cylinder.Pressure || installed.Cylinder.PartNumber != persisted.Cylinder.PartNumber) { Log.Debug(string.Format("Port {0} has changed...", position)); Log.Debug(string.Format("......fid=\"{0}\", pn=\"{1}\", {2}, {3}, {4}", installed.Cylinder.FactoryId, installed.Cylinder.PartNumber, installed.InstallationType, Log.DateTimeToString(installed.Cylinder.ExpirationDate), installed.Cylinder.Pressure)); installed.GasChangeType = GasEndPoint.ChangeType.Installed; // mark it for saving. saveList.Add(installed); } else { Log.Debug(string.Format("Port {0} has not changed. (fid=\"{1}\",pn=\"{2}\",{3})", position, persisted.Cylinder.FactoryId, persisted.Cylinder.PartNumber, persisted.InstallationType)); } } else if (installed == null && persisted == null) { Log.Debug(string.Format("Port {0}: Nothing installed.", position)); } } SaveGasEndPoints(saveList, trx); return; }
/// <summary> /// Return the information from all smart cards that are present. /// </summary> /// <returns>All of the installed cylinders.</returns> static private void ReadChangedCylinders(bool[] changedSmartCards, IList <GasEndPoint> changedGasEndPoints, PortRestrictions port1Restrictions) { const string funcName = "ReadChangedCylinders: "; Log.Assert(changedSmartCards != null, funcName + "changedSmartCards should not be null."); DockingStation dockingStation = Controller.GetDockingStation(); // SGF 8-Nov-2012 INS-2686 changedGasEndPoints.Clear(); for (int i = 0; i < changedSmartCards.Length; i++) { int position = i + 1; Log.Debug(funcName + "POSITION " + position); if (changedSmartCards[position - 1] == false) // No detection of a card insertion, nor a removal? { Log.Debug(string.Format("{0}Position {1} Smart card SKIPPED; No insertion change detected.", funcName, position)); if (position == Controller.FRESH_AIR_GAS_PORT) { GasEndPoint persistedPort1GasEndPoint = new GasEndPointDataAccess().FindByPosition(Controller.FRESH_AIR_GAS_PORT); // If there's nothing known to be installed on port 1, then create a fresh air // cylinder for the port. // This could happen if, while nothing was installed on the port, a SettingsUpdate // just occurred previously where the port setting was changed to allow fresh air. // In that situation, we have to then make the fresh air cylinder. if (persistedPort1GasEndPoint == null) { Log.Debug(string.Format("{0}Position {1}, No persisted cylinder; assuming Fresh Air.", funcName, position)); GasEndPoint freshAirCylinder = GasEndPoint.CreateFreshAir(position); freshAirCylinder.GasChangeType = GasEndPoint.ChangeType.Installed; changedGasEndPoints.Add(freshAirCylinder); } } // SGF 8-Nov-2012 INS-2686 -- begin // Soon, we will check to see if a pressure switch is present, and if so, read the pressure level. // Before we do that, we must check for two scenarios in which it is not necessary or appropriate // to read a pressure switch. // 1. If there is no cylinder attached to the port, there is no reason to check for a pressure switch. // 2. If this is the first port, and we know that the port is drawing fresh air, there is no reason // to check for a pressure switch. This case cannot be handled by case #1, as we define a "logical" // cylinder to represent fresh air. // If we find either scenario for the current port, we skip further processing on this port, and proceed to // the next one. GasEndPoint currentInstalledCylinder = dockingStation.GasEndPoints.Find(ic => ic.Position == position); if (currentInstalledCylinder == null) { Log.Debug(string.Format("{0}Position {1} No cylinder present; do not check for pressure switch.", funcName, position)); continue; } else { bool isFreshAir = currentInstalledCylinder.Cylinder.IsFreshAir; if (isFreshAir) { Log.Debug(string.Format("{0}Position {1} Fresh air; do not check for pressure switch.", funcName, position)); continue; } } // SGF 8-Nov-2012 INS-2686 -- end // SMARTCARD NOT CHANGED (NO INSERT OR REMOVAL DETECTED). // WE NEED TO AT LEAST ALWAYS READ THE PRESSURE SWITCH THEN. if (SmartCardManager.IsPressureSwitchPresent(position)) { GasEndPoint pressureCylinder = new GasEndPoint(); pressureCylinder.Position = position; pressureCylinder.Cylinder.Pressure = ReadPressureLevel(position); pressureCylinder.GasChangeType = GasEndPoint.ChangeType.PressureChanged; Log.Debug(string.Format("{0}Position {1} Pressure Switch reports {2}.", funcName, position, pressureCylinder.Cylinder.Pressure)); changedGasEndPoints.Add(pressureCylinder); } else { Log.Debug(string.Format("{0}Position {1} Pressure Switch not present.", funcName, position)); } continue; } // IF WE MAKE IT TO HERE, THE CARD HAS BEEN EITHER INSERTED OR REMOVED. if (!SmartCardManager.IsCardPresent(position)) // CARD REMOVED? { Log.Debug(string.Format("{0}Position {1} SmartCard not present, Returning CardRemoved", funcName, position)); // Server needs to know specifically that cylinder is missing. // Indicate this with an InstalledCylinder containing an empty Cylinder object. GasEndPoint missingCylinder = new GasEndPoint(); missingCylinder.Position = position; missingCylinder.GasChangeType = GasEndPoint.ChangeType.Uninstalled; changedGasEndPoints.Add(missingCylinder); // If a cylinder is not installed on the fresh air port, then assume fresh air // for the port if (position == Controller.FRESH_AIR_GAS_PORT) { Log.Debug(string.Format("{0}Position {1} is assumed to be Fresh Air.", funcName, position)); GasEndPoint freshAirCylinder = GasEndPoint.CreateFreshAir(position); freshAirCylinder.GasChangeType = GasEndPoint.ChangeType.Installed; changedGasEndPoints.Add(freshAirCylinder); } continue; } // IF WE MAKE IT TO HERE, THE CARD HAS BEEN INSERTED. Cylinder cylinder = SmartCardManager.ReadCard(position); if (cylinder == null) // Couldn't read valid cylinder? Driver error or corrupt card. { Log.Debug(string.Format("{0}Position {1}, ReadCard returned null. SKIPPING cylinder.", funcName, position)); continue; } // Dates read from card will be in 'local' time, but everything we deal with is in UTC. cylinder.ExpirationDate = Configuration.ToUniversalTime(cylinder.ExpirationDate); cylinder.RefillDate = Configuration.ToUniversalTime(cylinder.RefillDate); Thread.Sleep(1000); cylinder.Pressure = ReadPressureLevel(position); GasEndPoint gasEndPoint = new GasEndPoint(cylinder, position, GasEndPoint.Type.iGas); gasEndPoint.GasChangeType = GasEndPoint.ChangeType.Installed; Log.Debug(string.Format("{0}Position {1}, Returning CardInserted. Pressure={2}", funcName, position, cylinder.Pressure)); changedGasEndPoints.Add((GasEndPoint)gasEndPoint.Clone()); } // end-for return; }
internal List <GasEndPoint> GetGasEndPoints(string eventCode, DockingStationAction dsAction, StringBuilder explanation, List <string> explanationCodes, List <string> errorCodes) { Log.Debug(string.Format("{0}.GetGasEndPoints, {1}", Name, eventCode)); //explanationCodes.Clear(); //errorCodes.Clear(); // SGF 20-Feb-2013 INS-3821 ISC.iNet.DS.DomainModel.Instrument dockedInstrument = Master.Instance.SwitchService.Instrument; DockingStation dockingStation = Configuration.DockingStation; List <GasEndPoint> gasEndPoints = new List <GasEndPoint>(); foreach (InstalledComponent installedComponent in dockedInstrument.InstalledComponents) { if (!(installedComponent.Component is Sensor)) { continue; } Sensor sensor = (Sensor)installedComponent.Component; if (!sensor.Enabled) { Log.Info(string.Format("{0}: Ignoring disabled sensor {1}", Name, sensor.Uid)); continue; } // SGF 21-May-2012 INS-3078 -- Comment out the following if statement //if (!GasOperationsSupported(sensor)) //{ // Log.Debug( string.Format( "{0}.GasOperationsSupported returned False for sensor {1}. Ignoring sensor.", Name, sensor.SerialNumber ) ); // continue; //} if (sensor.CalibrationGas.Code.Length == 0) { throw new ApplicationException("Sensor " + sensor.Uid + " has null calibration gas code."); } // SGF 03-Nov-2010 Single Sensor Cal and Bump if (dsAction is InstrumentGasAction) { InstrumentGasAction gasAction = (InstrumentGasAction)dsAction; if (gasAction.ComponentCodes.Count != 0 && !gasAction.ComponentCodes.Contains(sensor.Type.Code)) { Log.Debug(string.Format("{0}: Component type {1} is not included in the defined list of components to test. Ignoring sensor.", Name, sensor.Type.Code)); continue; } } Log.Debug(string.Format("{0}: Looking for sensor {1}'s cal gas ({2})", Name, sensor.Uid, sensor.CalibrationGas.Code)); _empty = _expired = _gasFound = _freshFound = _zeroFound = false; _gasNeeded = true; // SGF 21-May-2012 INS-3078 // INS-8630 RHP v7.5 clear the messages for every installed component to avoid confusion explanationCodes.Clear(); errorCodes.Clear(); // SGF 20-Feb-2013 INS-3821 // Loop thru the cylinders for the docking station and if the cylinder contains the gas that // the sensor needs, add that cylinder as a gas end point in the docking station action. FindInstalledCylinderGases(eventCode, gasEndPoints, dockingStation, installedComponent, explanation, explanationCodes, errorCodes); if (!_freshFound && !_zeroFound) { // Present which type of air should be, but is not, available. If the port1 restrictions // only allow for zero air, present 'ZERO AIR'; otherwise, present 'FRESH AIR'. if (Configuration.DockingStation.Port1Restrictions == PortRestrictions.ZeroAir) { explanationCodes.Add("ZEROAIR"); errorCodes.Add(string.Format("{0} ({1})", "ZEROAIR", GasCode.O2)); // SGF 20-Feb-2013 INS-3821 } else if (Configuration.DockingStation.Port1Restrictions == PortRestrictions.FreshAir) { GasType gasType = GasType.Cache[GasCode.FreshAir]; if (gasType != null) { explanationCodes.Add(gasType.Symbol); errorCodes.Add(string.Format("{0} ({1})", gasType.Symbol, gasType.Code)); // SGF 20-Feb-2013 INS-3821 } } else // SGF 19-Jan-2012 INS-1913 & INS-1914 { // either fresh air or zero air is allowed; present which type is connected, if something is connected. GasEndPoint gasEndPoint = dockingStation.GasEndPoints[0]; Cylinder cyl = gasEndPoint.Cylinder; if (cyl.IsZeroAir) { explanationCodes.Add("ZEROAIR"); errorCodes.Add(string.Format("{0} ({1})", "ZEROAIR", GasCode.O2)); // SGF 20-Feb-2013 INS-3821 } else //suresh 14-Mar-2012 INS-4427 (DEV) { // If port 1 cylinder is not Zero Air then we report that 'Fresh air' is unavailable GasType gasType = GasType.Cache[GasCode.FreshAir]; if (gasType != null) { explanationCodes.Add(gasType.Symbol); errorCodes.Add(string.Format("{0} ({1})", gasType.Symbol, gasType.Code)); // SGF 20-Feb-2013 INS-3821 } } } if (_expired) { explanationCodes.Add("Expired"); errorCodes.Add("Expired"); // INS-8630 RHP v7.5 - Notify iNet on the expired state } else if (_empty) { explanationCodes.Add(PressureLevel.Empty.ToString()); errorCodes.Add(PressureLevel.Empty.ToString()); // INS-8630 RHP v7.5 - Notify iNet on the empty state } explanation.Append("Fresh air not found for sensor " + sensor.Uid + '\n'); Log.Debug(string.Format("{0}: Returning nothing: gasFound={1}, freshFound={2}, expired={3}, empty={4}", Name, _gasFound, _freshFound, _expired, _empty)); return(new List <GasEndPoint>()); } if (_gasNeeded && !_gasFound) // SGF 21-May-2012 INS-3078 -- add the '_gasNeeded' clause to the if-condition { // If gas not found, IDS needs the symbol for that gas for display on its LCD. // Look it up in our cache. For Fresh Air, we just return the gas code; // The IDS knows to look for that as a special case. if (sensor.CalibrationGas.Code == GasCode.FreshAir) { GasType gasType = GasType.Cache[GasCode.FreshAir]; if (gasType != null) { explanationCodes.Add(gasType.Symbol); errorCodes.Add(string.Format("{0} ({1})", gasType.Symbol, gasType.Code)); // SGF 20-Feb-2013 INS-3821 } } // DSW-1758 RHP v9.6.1 - Added (! (_expired || _empty) ) since gas symbol has already been added to explanationCodes for Empty/Expired states. else if (!(_expired || _empty)) { // 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 make sure we report that the // gas type not found is the CombustibleBumpTestGas and not the sensor cal gas. string sensorGasCode = sensor.CalibrationGas.Code; if ((eventCode == EventCode.BumpTest) && (sensor.Type.Code == SensorCode.CombustibleLEL || sensor.Type.Code == SensorCode.CombustiblePPM) && (Configuration.DockingStation.CombustibleBumpTestGas.Length > 0)) { sensorGasCode = Configuration.DockingStation.CombustibleBumpTestGas; } GasType gasType = GasType.Cache[sensorGasCode]; if (gasType != null) { explanationCodes.Add(gasType.Symbol); errorCodes.Add(string.Format("{0} ({1})", gasType.Symbol, gasType.Code)); // SGF 20-Feb-2013 INS-3821 } } if (_expired) { explanationCodes.Add("Expired"); errorCodes.Add("Expired"); // INS-8630 RHP v7.5 - Notify iNet on the expired state } else if (_empty) { explanationCodes.Add(PressureLevel.Empty.ToString()); errorCodes.Add(PressureLevel.Empty.ToString()); // INS-8630 RHP v7.5 - Notify iNet on the empty state } explanation.Append("Could not find cylinder needed for sensor " + sensor.Uid + ", CalGasCode=\"" + sensor.CalibrationGas.Code + "\" ("); for (int i = 0; i < explanationCodes.Count; i++) { if (i > 0) { explanation.Append(" "); } explanation.Append(explanationCodes[i]); } explanation.Append(")\n"); Log.Debug(string.Format("{0}: Returning nothing: gasFound={1}, freshFound={2}, expired={3}, empty={4}", Name, _gasFound, _freshFound, _expired, _empty)); return(new List <GasEndPoint>()); } // Zero air is required for CO2 sensors; Only zero air is used to zero CO2, never fresh air. if ((sensor.CalibrationGas.Code == GasCode.CO2) && !_zeroFound) { GasType gasType = GasType.Cache[GasCode.O2]; if (gasType != null) { explanationCodes.Add("ZEROAIR"); // SGF 5-Feb-2013 INS-3837 errorCodes.Add(string.Format("{0} ({1})", "ZEROAIR", GasCode.O2)); // SGF 20-Feb-2013 INS-3821 } if (_expired) { explanationCodes.Add("Expired"); } else if (_empty) { explanationCodes.Add(PressureLevel.Empty.ToString()); } explanation.Append("Zero air not found for CO2 sensor " + sensor.Uid + '\n'); Log.Debug(string.Format("{0}: Returning nothing: gasFound={1}, freshFound={2}, expired={3}, empty={4}", Name, _gasFound, _freshFound, _expired, _empty)); return(new List <GasEndPoint>());; } } Log.Debug(string.Format("{0}.GetGasEndPoints returned {1} gas end points", Name, gasEndPoints.Count)); return(gasEndPoints); }
public virtual void OpenGasEndPoint(GasEndPoint endPoint) { Pump.OpenGasEndPoint(endPoint); }
/// <summary> /// Check if pump works properly. /// </summary> /// <remarks> /// Engineering Notes: This step is to check if pump works properly. /// Run pump at two different control voltages, check the flow rate difference between these two cases. /// </remarks> /// <param name="details">The string to hold details.</param> private void TestPump(DetailsBuilder details) { // Find a port without a gas cylinder connected. // If all ports are connected, skip this test. DockingStation ds = Controller.GetDockingStation(); // First, see if port one is unconnected or is providing FRESH AIR // Note: we are trying ports in the order of 3-2-1 so as to avoid pulling air through the filter, if possible. int testPort = -1; GasEndPoint gasEndPoint = null; for ( int solenoid = Configuration.DockingStation.NumGasPorts; solenoid >= 1 && testPort <= 0; solenoid-- ) { gasEndPoint = ds.GasEndPoints.Find(m => m.Position == solenoid); if (gasEndPoint == null || gasEndPoint.Cylinder.IsFreshAir) testPort = solenoid; } if (testPort <= 0) { Log.Debug("TestPump: could not find open solenoid; this test will be skipped."); return; } // Open solenoid valve determined to be unconnected Pump.CloseAllValves( true ); Thread.Sleep(500); // Give the valves a chance to finish closing Pump.OpenValve(testPort, false); // Start pump with pump voltage of 80 Pump.Start(80); // Wait 3 seconds Thread.Sleep(3000); // Read flow 1 ushort flowCount1 = Pump.GetRawFlow(); ushort flowVolts1 = Pump.ConvertRawFlowToVolts( flowCount1 ); ushort vacuumCounts1 = Pump.GetRawVacuum(); int flowRate1 = Pump.CalculateFlowRate( flowVolts1, vacuumCounts1 ); string flowString1 = BuildFlowString(flowCount1, flowRate1, flowVolts1); // Increase pump voltage to 240 Pump.SetNewPumpVoltage(240); // Wait 3 seconds Thread.Sleep(3000); // Check Pump Error status int pumpErrorState = Pump.GetPumpErrorState(); // Fail if state is 1 _gdpList.Add(new GeneralDiagnosticProperty("DIAGNOSTIC_PUMP_ERROR_STATUS", pumpErrorState.ToString())); ReportDiagnostic(details, DiagnosticResources.PUMP_ERROR_STATUS, pumpErrorState.ToString(), (pumpErrorState == 1)); // Read flow 2 ushort flowCount2 = Pump.GetRawFlow(); ushort flowVolts2 = Pump.ConvertRawFlowToVolts( flowCount2 ); ushort vacuumCounts2 = Pump.GetRawVacuum(); int flowRate2 = Pump.CalculateFlowRate( flowVolts2, vacuumCounts2 ); string flowString2 = BuildFlowString(flowCount2, flowRate2, flowVolts2); // Fail if f2 - f1 < 100 OR f2 - f1 > 450 _gdpList.Add(new GeneralDiagnosticProperty("DIAGNOSTIC_PUMP_F1", flowCount1.ToString())); _gdpList.Add(new GeneralDiagnosticProperty("DIAGNOSTIC_PUMP_F2", flowCount2.ToString())); ReportDiagnostic(details, DiagnosticResources.PUMP, flowString1, flowString2, ( flowCount2 - flowCount1 < 100 ) || ( flowCount2 - flowCount1 > 450 ) ); // Stop the pump and close the port used for this test Pump.CloseValve(testPort); Thread.Sleep(500); }
/// <summary> /// Test the specified solenoid /// </summary> /// <param name="details">The string to hold details.</param> private void TestFlow( DetailsBuilder details, int solenoid ) { // Validate the solenoid number if ( solenoid < 1 || solenoid > Configuration.DockingStation.NumGasPorts ) { Log.Debug( "TestFlow: Invalid solenoid value = " + solenoid.ToString() ); return; } Log.Debug( "TestFlow: port=" + solenoid.ToString() ); // Determine whether a cylinder is attached to this port. // If there is one attached, skip this test. DockingStation ds = Controller.GetDockingStation(); GasEndPoint gasEndPoint = ds.GasEndPoints.Find(m => m.Position == solenoid); if (gasEndPoint != null && gasEndPoint.Cylinder.IsFreshAir == false) { Log.Debug( "TestFlow: Cylinder attached to port " + solenoid.ToString() + "; SKIPPING THIS TEST." ); return; } Pump.DoCheckFlow = true; // Ensure that only the specified solenoid is open. Pump.CloseAllValves( true ); Thread.Sleep(500); // Give the valves a chance to finish closing Pump.OpenValve(solenoid, false); // Open the specified solenoid Thread.Sleep(500); // Pause at least 500ms. Pump.SetDesiredFlow( Pump.StandardFlowRate); Pump.Start( Pump.StandardStartVoltage ); // Turn on the pump. Thread.Sleep( 3000 ); // Wait for it to stabilize the flow before letting CheckFlow take its first reading. // CheckFlow could enter an infinite loop if it's unable to // establish the desired flow rate and we don't tell it to time out. // We therefore give it a time out of a minute which should be more than sufficient. ushort rawFlowCounts; ushort rawVacuumCounts; Pump.FlowStatus flowStatus = Pump.CheckFlow( new TimeSpan( 0, 1, 0 ), out rawFlowCounts, out rawVacuumCounts ); byte pumpVoltage = Pump.GetPumpVoltage(); // obtain and hold onto final voltage of the pump, to report it to inet. // Get the flow rate. ushort flowVolts = Pump.ConvertRawFlowToVolts( rawFlowCounts ); int flowRate = Pump.CalculateFlowRate( flowVolts, rawVacuumCounts ); // Convert that value to mL/min // Report the results. string flowString = BuildFlowString(flowRate, flowVolts); // We create a property for every value used to compute the flow rate, and also the flow rate itself. _gdpList.Add( new GeneralDiagnosticProperty( "DIAGNOSTIC_CHECK_FLOW_" + solenoid + "_VACUUM", rawVacuumCounts.ToString() ) ); _gdpList.Add( new GeneralDiagnosticProperty( "DIAGNOSTIC_CHECK_FLOW_" + solenoid + "_VACUUM_INCHES", Pump.ConvertRawVacuumToInches( rawVacuumCounts ).ToString() ) ); _gdpList.Add( new GeneralDiagnosticProperty( "DIAGNOSTIC_CHECK_FLOW_" + solenoid, rawFlowCounts.ToString() ) ); _gdpList.Add( new GeneralDiagnosticProperty( "DIAGNOSTIC_CHECK_FLOW_" + solenoid + "_VOLTS", flowVolts.ToString() ) ); _gdpList.Add( new GeneralDiagnosticProperty( "DIAGNOSTIC_CHECK_FLOW_" + solenoid + "_RATE", flowRate.ToString() ) ); _gdpList.Add( new GeneralDiagnosticProperty( "DIAGNOSTIC_CHECK_FLOW_" + solenoid + "_PUMP_VOLTS", pumpVoltage.ToString() ) ); // The flow is considered a failure if it's not equal to the StandardFlowRate plus/minus the standardtolerance bool flowFailed = flowRate < ( Pump.StandardFlowRate - Pump.FLOWRATE_TOLERANCE ) || flowRate > ( Pump.StandardFlowRate + Pump.FLOWRATE_TOLERANCE ); // TODO - we should rename the translation string so that it's prefixed with "CHECK_FLOW" instead of "SOLENOID_FLOW" ReportDiagnostic( details, details.GetText( "SOLENOID_FLOW_" + solenoid ), flowString, flowFailed ); // Check Pump Error Status -- FAIL IF STATE IS 1 int pumpErrorState = Pump.GetPumpErrorState(); // Report the results. _gdpList.Add( new GeneralDiagnosticProperty( "DIAGNOSTIC_CHECK_FLOW_" + solenoid + "_PUMP_ERROR", pumpErrorState.ToString() ) ); // TODO - we should rename the translation string so that it's prefixed with "CHECK_FLOW" instead of "SOLENOID_FLOW" ReportDiagnostic(details, details.GetText("SOLENOID_PUMP_ERROR_" + solenoid), pumpErrorState.ToString(), (pumpErrorState == 1)); // Stop the pump and close the solenoid Pump.CloseValve(solenoid); Pump.DoCheckFlow = false; }
private DockingStationAction ExamineGasEndPoints() { // First, for each attached cylinder, make sure it's a valid part number. // We try to not hit the database over and over to do this check // The GasEndPoints.Supported property helps us do that. If it's null, // then we've not checked the cylinder, so we query the database to do so. // We then set it to true or false appropiately. Once all GasEndPoints' Supported // properties are non-null, we don't have to hit the database anymore. // Note that there's no need to check the 'part number' for fresh air. List <GasEndPoint> unverifiedGasEndPoints = Configuration.DockingStation.GasEndPoints.FindAll(g => g.Supported == null && g.Cylinder.PartNumber != FactoryCylinder.FRESH_AIR_PART_NUMBER); if (unverifiedGasEndPoints.Count > 0) { // Next, for every currently installed cylinder, verify that we recognize // the part number. We check because the user may attach a cylinder // that has a new part number not yet known to iNet. FactoryCylinderDataAccess fcDataAccess = new FactoryCylinderDataAccess(); using (DataAccessTransaction trx = new DataAccessTransaction(true)) { foreach (GasEndPoint g in unverifiedGasEndPoints) { g.Supported = fcDataAccess.FindByPartNumber(g.Cylinder.PartNumber, trx) != null; Log.Debug(string.Format("Verified GasEndPoint {0} on port {1}. Supported={2}", g.Cylinder.PartNumber, g.Position, g.Supported)); if (g.Supported == false) // no match found? Must be an unknown part number. { return(CreateUnsupportedCylinderAction(g)); } } } } // At this point, we expect that cylinders have been verified. // We now check to see that each cylinder is supported by checking the // InstalledCylinder.Supported property. List <GasEndPoint> unsupportedGasEndPoints = Configuration.DockingStation.GasEndPoints.FindAll(g => g.Supported != null && g.Supported == false); if (unsupportedGasEndPoints.Count > 0) { GasEndPoint gep = unsupportedGasEndPoints[0]; Log.Debug(string.Format("GasEndPoint {0} on port {1}. Supported={2}", gep.Cylinder.PartNumber, gep.Position, gep.Supported)); return(CreateUnsupportedCylinderAction(gep)); } // Next, verify that the cylinder on port 1 is legal for whatever the // current Fresh/Zero air restriction for that port. GasEndPoint gasEndPoint = Configuration.DockingStation.GasEndPoints.Find(g => g.Position == 1); // Either zero air OR fresh air is allowed? if (Configuration.DockingStation.Port1Restrictions == (PortRestrictions.FreshAir | PortRestrictions.ZeroAir)) { if (gasEndPoint != null && !gasEndPoint.Cylinder.IsFreshAir && !gasEndPoint.Cylinder.IsZeroAir) { Log.Debug(string.Format("Port1Restriction={0}, but cylinder is {1}", Configuration.DockingStation.Port1Restrictions.ToString(), gasEndPoint.Cylinder.PartNumber)); return(CreateUnsupportedCylinderAction(gasEndPoint)); } } // Only fresh air is allowed? It's illegal to have a non-freshAir cylinder is installed. if (Configuration.DockingStation.Port1Restrictions == PortRestrictions.FreshAir) { if (gasEndPoint != null && !gasEndPoint.Cylinder.IsFreshAir) { Log.Debug(string.Format("Port1Restriction is FreshAir, but cylinder is {0}", gasEndPoint.Cylinder.PartNumber)); return(CreateUnsupportedCylinderAction(gasEndPoint)); } } // Only zero air is allowed? It's illegal to have either fresh air or a non-zeroAir // cylinder installed. else if (Configuration.DockingStation.Port1Restrictions == PortRestrictions.ZeroAir) { // It's required that we have a zero-air cylinder on port1. So return // Unsupported gas if there is no cylinder, or if the cylinder is not zero-air. if (gasEndPoint == null) { Log.Debug("Port1Restriction is ZeroAir, but no cylinder is installed"); return(CreateUnsupportedCylinderAction(GasEndPoint.CreateFreshAir(Controller.FRESH_AIR_GAS_PORT))); } if (!gasEndPoint.Cylinder.IsZeroAir) { Log.Debug(string.Format("Port1Restriction is ZeroAir, but cylinder is {0}", gasEndPoint.Cylinder.PartNumber)); return(CreateUnsupportedCylinderAction(gasEndPoint)); } } return(null); }
} // end-CalibrateInstrumentSequential /// <summary> /// Calibrate the sensor. Operates on "_component" member variable (an InstalledComponent) /// Note that this routine assumes that the parent class has already zeroed sensor. /// </summary> /// <param name="instComp">Component to be calibrated</param> /// <param name="gasEndPoints">Gas End Points to be used</param> /// <param name="isO2HighBumpFailed">Whether the CalibrateSensor is called as a part of O2 High Bump Failure</param> /// <returns></returns> internal SensorGasResponse CalibrateSensor(InstalledComponent instComp, List <GasEndPoint> gasEndPoints, bool isO2HighBumpFailed) { _component = instComp; GasEndPoints = gasEndPoints; Log.Assert(this._component != null); bool alreadyFailed = false; GasEndPoint gasEndPoint; Sensor sensor = (Sensor)_component.Component; double currentConcentration = sensor.CalibrationGasConcentration; // SGF 11-Oct-2010 INS-1189 DateTime durationStart = DateTime.UtcNow; List <SensorCalibrationLimits> sensorCalibrationLimits = _testOnlySensorCalibrationLimits == null ? new SensorCalibrationLimitsDataAccess().FindAll() : _testOnlySensorCalibrationLimits; // SGF 14-Jun-2011 INS-1732 SensorGasResponse response = _returnEvent.GetSensorGasResponseByUid(sensor.Uid); // If CalibrateSensor was called as a part of O2 High Bump Failure, the reponse // object will be null and has to be initialized for calibration operation. if (isO2HighBumpFailed) { response = new SensorGasResponse(sensor.Uid, DateTime.UtcNow); response.GasConcentration = new GasConcentration(sensor.CalibrationGas, currentConcentration); response.GasDetected = sensor.GasDetected; response.Type = GasResponseType.Calibrate; } if (response == null) { Log.Debug("CALIBRATION: Skipping sensor " + _component.Position + " due to missing sensor gas response object!"); return(null); } response.Position = _component.Position; // Add in whatever cylinder was used for zeroing. zeroGasEndPoint // will have been set by zerosensor(). Should never be null, but check just in case. if (_zeroingUsedGasEndPoint != null) { response.UsedGasEndPoints.Add(_zeroingUsedGasEndPoint); } try { // See if Zeroing was successful. If not, set up response to indicate // the failure and then we can leave. (The finally block below will handle // the response as we leave this method) if (!_instrumentController.GetSensorZeroingStatus(_component.Position)) { Log.Debug(string.Format("CALIBRATION: SKIPPING SENSOR {0} ({1}) DUE TO FAILED ZEROING!", _component.Position, _component.Component.Uid)); // Setup status with our failed zeroing and last cal status. response.Status = Status.ZeroFailed; response.Time = DateTime.UtcNow; response.Reading = 0.0; return(response); } //Suresh 16-JAN-2012 INS-2480 - Begin if (!_instrumentController.IsSensorCalibrationEnabled(_component)) { Log.Debug("CALIBRATION: Calibration is disabled for sensor " + _component.Position + " (" + sensor.Type.Code + ")"); //In the above if condition we have already checked for zeroing status, therefore we verywell know //when execution comes here then zeroing is passed for current calibration disabled sensor. response.Status = Status.ZeroPassed; response.Time = DateTime.UtcNow; response.Reading = 0.0; Log.Debug("CALIBRATION: SKIPPING SENSOR " + _component.Position + " (" + sensor.Type.Code + ")"); return(response); } //Suresh 16-JAN-2012 INS-2480 - End // SGF 03-Nov-2010 Single Sensor Cal and Bump if (ComponentCodes.Count != 0 && !ComponentCodes.Contains(sensor.Type.Code)) { Log.Debug(string.Format("CALIBRATION: Skipping sensor {0} ({1}) not included in schedule's specified component list.", _component.Position, sensor.Type.Code)); // This sensor will not be calibrated. Indicate that zeroing passed. response.Status = Status.ZeroPassed; response.Time = DateTime.UtcNow; response.Reading = 0.0; return(response); } //INS-7282 - To determine if the sensor is expired based on the configured sensor age and setup date. Applicable only to Service Account if (IsSensorExpiredForServiceAccount(sensor, response, sensorCalibrationLimits)) { Log.Debug(string.Format("CALIBRATION: IsSensorExpiredForServiceAccount returned TRUE for {0} at position {1}.", sensor.Type.Code, _component.Position)); Log.Debug(string.Format("CALIBRATION: Marking {0} sensor at position {1} as {2}.", sensor.Type.Code, _component.Position, Status.Failed)); response.Status = Status.Failed; response.Time = DateTime.UtcNow; response.Reading = 0.0; return(response); } if (_instrumentController.TestForInstrumentReset(response, "calibrating sensor, checked zeroing status") == true) { Log.Warning("CALIBRATION: ABORTED DUE TO INSTRUMENT RESET"); return(response); } Log.Debug("CALIBRATION: Zeroing of sensor " + _component.Position + " determined as successful."); // Continue to calibrate, until there is known success, failure, or timeout while (true) { // We'll fail to get a gas end point when we've tried and failed on // every available bottle of appropriate gas. try { gasEndPoint = GetSensorGasEndPoint(_component); // Get gas end point for calibrating this sensor. } catch { if (alreadyFailed) { return(response); } throw; } try { if (gasEndPoint == null) // There is no gas available.? { throw new CorrectCalibrationGasUnavailable(_returnEvent.DockedInstrument.SerialNumber); } // Purge between each passes when switching between attached cylinders during CAL to clear gases in line. // INETQA-4189 RHP v7.6. Also make sure that this CYLINDER SWITCH PURGE does not happen for O2 Calibration initiated as part of Bump Test(02 sensor) if (_usedGasEndPoint == null) { _usedGasEndPoint = (sensor.Type.Code == SensorCode.O2) ? null : gasEndPoint; } else if (_usedGasEndPoint != gasEndPoint && !isO2HighBumpFailed) { Log.Debug("CYLINDER SWITCH DETECTED : CLEAR GASES IN LINES BEFORE CALIBRATING NEXT SENSOR"); Stopwatch cylinderSwitchPurgeStopwatch = Log.TimingBegin("CALIBRATING - PURGE(CYLINDER-SWITCH)"); new InstrumentPurgeOperation(PurgeType.CylinderSwitch, _instrumentController, GasEndPoints, _returnEvent, new List <SensorGasResponse> { response }).Execute(); Log.TimingEnd("CALIBRATING - PURGE(CYLINDER-SWITCH)", cylinderSwitchPurgeStopwatch); _usedGasEndPoint = gasEndPoint; } //Suresh 18-OCT-2011 INS-2293 // Indicate on the console which sensor is being calibrated Master.Instance.ConsoleService.UpdateState(ConsoleState.CalibratingInstrument, Master.Instance.ConsoleService.GetSensorLabel(sensor.Type.Code)); // Guarantee that the correct calibration gas concentration is available. double availableConcentration = _instrumentController.SetCalibrationGasConcentration(_component, gasEndPoint); // If we didn't find anything with the gas. if (availableConcentration == 0.0) { throw new CorrectCalibrationGasUnavailable(sensor.CalibrationGas.Code); } // Set the gas concentration. response.GasConcentration.Concentration = sensor.CalibrationGasConcentration; Log.Debug("Calibrating gas: " + sensor.CalibrationGas.Code + " conc: " + sensor.CalibrationGasConcentration); // Determine the length of time to calibrate before timing out. We add a an extra // timeout cushion so we don't want the DS to timeout before the instrument. TimeSpan calTimeOut = _instrumentController.GetSensorCalibrationTimeout(_component.Position) + _timeOutCushion; if (_instrumentController.TestForInstrumentReset(response, "calibrating sensor, getting calibration timeout") == true) { Log.Warning("CALIBRATION: ABORTED DUE TO INSTRUMENT RESET"); return(response); } // Do any preconditioning necessary. Stopwatch stopwatch = Log.TimingBegin("CAL - PRECONDITION SENSOR"); TimeSpan preTime = _instrumentController.PreconditionSensor(_component, gasEndPoint, response); Log.TimingEnd("CAL - PRECONDITION SENSOR", stopwatch); if (preTime.TotalSeconds > 0) // will return zero if no precondition performed/needed. { response.UsedGasEndPoints.Add(new UsedGasEndPoint(gasEndPoint, CylinderUsage.Precondition, preTime)); } if (!Master.Instance.ControllerWrapper.IsDocked()) // Did user undock instrument during preconditioning? { throw new InstrumentNotDockedException(); } // SGF 14-Jun-2011 INS-1732 response.ReadingAfterPreconditioning = _instrumentController.GetSensorReading(_component.Position, sensor.Resolution); response.TimeAfterPreconditioning = DateTime.UtcNow; if (_instrumentController.TestForInstrumentReset(response, "calibrating sensor, sensor preconditioned") == true) { Log.Warning("CALIBRATION: ABORTED DUE TO INSTRUMENT RESET"); return(response); } // SGF Jan-13-2009 DSW-173 stopwatch = Log.TimingBegin("CAL - PAUSE GAS FLOW"); _instrumentController.PauseGasFlow(gasEndPoint, sensor, response); Log.TimingEnd("CAL - PAUSE GAS FLOW", stopwatch); if (_instrumentController.TestForInstrumentReset(response, "calibrating sensor, gas flow paused") == true) { Log.Warning("CALIBRATION: ABORTED DUE TO INSTRUMENT RESET"); return(response); } // Get the sensor's maximum reading. double maximumReading = _instrumentController.GetSensorMaximumReading(_component.Position, sensor.Resolution); response.BaseLine = _instrumentController.GetSensorBaseline(_component.Position); response.ZeroOffset = _instrumentController.GetSensorZeroOffset(_component.Position, sensor.Resolution); response.AccessoryPump = _instrumentController.AccessoryPump; int calFlowRate = _instrumentController.GetSensorCalibrationFlowRate(_component); _instrumentController.OpenGasEndPoint(gasEndPoint, calFlowRate); DateTime startTime = DateTime.UtcNow; int totalReadings = 0; Log.Debug("CALIBRATION: BEGINNING CALIBRATION ON POSITION " + _component.Position + ", UID=" + _component.Component.Uid); // Send the command to begin calibrating. _instrumentController.BeginSensorCalibration(new int[] { _component.Position }); Log.Debug("CALIBRATION: Taking readings every " + _WAIT_INTERVAL + " msecs"); #region CALIBRATION LOOP stopwatch = Log.TimingBegin("CAL - CALIBRATE SENSOR"); Status calibrationStatus = Status.InProgress; bool instResetting = false; bool?isCalibrating = false; bool hasAborted = false; Pump.IsBadPumpTubing = false; do { TimeSpan calTime = DateTime.UtcNow - startTime; if (calTime > calTimeOut) { Log.Debug("CALIBRATION: DS timing out calibration. Setting status to + " + Status.Failed); calibrationStatus = Status.Failed; break; } #if !TEST Thread.Sleep(_WAIT_INTERVAL); #endif if (!Master.Instance.ControllerWrapper.IsDocked()) // watch out for user undocking during the long sleep interval. { break; } //If bad pump tubing is detected, throw flow failed exception //which will further down be handled to report to iNet the situation //and display appropriate error on LCD. if (Master.Instance.PumpWrapper.IsBadPumpTubing()) { string msg = "CALIBRATION: Bad pump tubing is detected. Stopping calibration."; Log.Debug(msg); throw new FlowFailedException(gasEndPoint); } // Get current reading. response.Reading = _instrumentController.GetSensorCalibrationReading(_component.Position, sensor.Resolution); response.Time = DateTime.UtcNow; instResetting = _instrumentController.TestForInstrumentReset(response, "calibrating sensor, getting reading"); totalReadings++; Log.Debug("CALIBRATION: (" + _component.Position + "), Reading #" + totalReadings + ": " + response.Reading + ", Span: " + response.FullSpanReserve); // isCalibrating will be null if the instrument reset (InstrumentAborted) isCalibrating = _instrumentController.IsSensorCalibrating(_component.Position); hasAborted = isCalibrating == null ? true : false; }while (isCalibrating == true && Master.Instance.PumpWrapper.GetOpenValvePosition() > 0 && instResetting == false); Log.TimingEnd("CAL - CALIBRATE SENSOR", stopwatch); #endregion CALIBRATION LOOP // If we detect we're undocked, then assume that's why we broke out of above loop // debug: Do we really need this check? if (!Master.Instance.ControllerWrapper.IsDocked()) { string msg = "CALIBRATION: Aborting on sensor " + _component.Position + " - Undocked instrument."; Log.Debug(msg); throw new InstrumentNotDockedException(); } if (instResetting == false) { instResetting = _instrumentController.TestForInstrumentReset(response, "calibrating sensor, calibration finished"); } bool flowFailed = Master.Instance.PumpWrapper.GetOpenValvePosition() <= 0; TimeSpan elapsedTime = DateTime.UtcNow - startTime; // Put info for the cylinder used during the bump into the Response object. // (iNet needs to know) response.UsedGasEndPoints.Add(new UsedGasEndPoint(gasEndPoint, CylinderUsage.Calibration, elapsedTime)); // If we detect flow failure, then assume that's why we broke out of above loop. if (flowFailed) { // TODO - Abort calibration on instrument? string msg = "CALIBRATION: Aborting on sensor " + _component.Position + " - Flow failed."; Log.Debug(msg); throw new FlowFailedException(gasEndPoint); } if (calibrationStatus == Status.Failed) // Timed out in above loop by IDS? { // TODO - Tell instrument to abort calibration? Log.Debug("CALIBRATION: TIMED OUT by DS after " + elapsedTime.TotalSeconds + " seconds!"); } else if (instResetting == true) { Log.Warning("CALIBRATION: ABORTED DUE TO INSTRUMENT RESET"); return(response); } else // Find out if instrument decided to pass or fail the calibration { calibrationStatus = _instrumentController.GetSensorCalibrationStatus(_component.Position) ? Status.Passed : Status.SpanFailed; response.Time = DateTime.UtcNow; if (_instrumentController.TestForInstrumentReset(response, "calibrating sensor, retrieving calibration status") == true) { Log.Warning("CALIBRATION: ABORTED DUE TO INSTRUMENT RESET"); return(response); } Log.Debug(string.Format("CALIBRATION: Instrument {0} sensor {1} after {2} seconds!", calibrationStatus, _component.Position, elapsedTime.TotalSeconds)); // Get instrument's final span reading response.Reading = _instrumentController.GetSensorSpanReserve(_component.Position); response.SpanCoef = _instrumentController.GetSensorSpanCoeff(_component.Position); response.Status = calibrationStatus; // Checking for obviously screwed up sensor. if (hasAborted) { // we already know the instrument reset response.Status = Status.InstrumentAborted; } else if (response.Status == Status.Passed) { // last calibration time is only changed on the sensor if calibration passed response.PostCal_LastCalibrationTime = _instrumentController.GetSensorLastCalibrationTime(response.Position); // status should never be passed if span reserve is 0 or below if (response.FullSpanReserve <= 0) { Log.Warning(string.Format("CALIBRATION: FullSpanReserve is {0} but status is {1}. DS overriding with a Failed status.", response.FullSpanReserve, response.Status)); response.Status = Status.Failed; } // last calibration time (pre-cal vs post-cal) should have changed else if (response.WasCalibrationInstrumentAborted()) { Log.Warning(string.Format("CALIBRATION: Status is {0}, but LastCalibrationTime did not change. DS overriding with an InstrumentAborted status.", response.Status)); response.Status = Status.InstrumentAborted; // A new response object will be created so most values are cleared before uploading to iNet. } //INS-7282 - Check the sensor span reserve and if the value is less than the configured threshold, set the sensor calibration as failed. Applicable only to repair Accounts. if (IsSensorFailedForRepairAccount(sensor, response, Configuration.DockingStation.SpanReserveThreshold)) { response.Status = Status.Failed; } } } Log.Debug("CALIBRATION: " + response.Status + " - FullSpanReserve=" + response.FullSpanReserve + " SpanReading=" + response.Reading + " max=" + maximumReading); if (response.Status == Status.Passed) { return(response); } alreadyFailed = true; } finally { _instrumentController.CloseGasEndPoint(gasEndPoint); } } // end-while(true) } finally { // How long did this sensor take to calibrate? TimeSpan duration = DateTime.UtcNow - durationStart; response.Duration = Convert.ToInt32(duration.TotalSeconds); // SGF 14-Jun-2011 INS-1732 _cumulativeCalTestResponseTime = _cumulativeCalTestResponseTime + response.Duration; response.CumulativeResponseTime = _cumulativeCalTestResponseTime; ResetTriedGasEndPoints(); string msg = string.Empty; try { if (Master.Instance.ControllerWrapper.IsDocked()) { msg = "SetCalibrationGasConcentration"; //// Make certain oxygen sensors are set to ambient air concentrations. //// //// TODO - Prior to the calibration, the O2 sensor may have had a cal gas //// concentration setting other than 20.9, so we probably shouldn't be blindly setting it back to 20.9. //// This likely needs to be corrected as part of INS-1189 (which used to be DSW-156, which used to be DSZ-1305). //// - JMP, 9/28/2009 //// //if ( sensor.CalibrationGas.Code == GasCode.O2 ) // // Guarantee that the correct calibration gas concentration is available. // SetCalibrationGasConcentration( GetSensorZeroAir( _component, false ) ); // SGF 11-Oct-2010 INS-1189 // Restore the concentration that was present upon entry into this method _instrumentController.SetCalibrationGasConcentration(_component, currentConcentration, true); msg = "GetSensorBumpStatus"; //Suresh 22-Feb-2012 INS-2705 //After calibration is completed , we need to update sensor bump test status because in scheduler we have logic //to force calibration based on sensor BumpTestStatus sensor.BumpTestStatus = _instrumentController.GetSensorBumpStatus(_component.Position); // INETQA-4178 RHP v7.6 Update the return event BumpTestStatus as this is used the eventprocessor to update switch service instrument // this is required for the scheduler logic discussed above Sensor installedSensor = (Sensor)_returnEvent.DockedInstrument.InstalledComponents.Find(ic => ic.Component.Uid == sensor.Uid).Component; if (installedSensor != null) { installedSensor.BumpTestStatus = sensor.BumpTestStatus; } } } catch (Exception e) { Log.Error(msg, e); } } } // end-CalibrateSensor()
/// Zeroes all sensors contained on the instrument. /// /// NOTE: THIS ROUTINE LOOKS LIKE IT CAN ZERO A SPECIFIC SENSOR /// BUT IN ACTUALITY, IT ALWAYS ZEROS ALL SENSORS. /// </summary> /// <param name="installedComponents">Contains InstalledComponents for the instrument being zeroed.</param> private void ZeroSensors( IEnumerable<InstalledComponent> installedComponents ) { Log.Debug( "ZEROING: Preparing to zero" ); // Indicate that the zeroing process is now in progress Master.Instance.ConsoleService.UpdateState( ConsoleState.CalibratingInstrument, ConsoleServiceResources.ZEROING ); // See if we have a CO2 sensor. If so, then we can only zero using zero air. // fresh air is NOT allowed. If no CO2 sensor is installed, then fresh // air may be used as an alternative to zero air, if zero air is not found. bool useZeroAirOnly = false; foreach ( InstalledComponent installedComponent in installedComponents ) { if ( installedComponent.Component.Type.Code == SensorCode.CO2 ) { Sensor sensor = (Sensor)installedComponent.Component; if ( !sensor.Enabled ) // if it's disabled, we won't be zeroing it. continue; Log.Debug( "ZEROING: Found CO2 sensor. Will not use fresh air to zero." ); useZeroAirOnly = true; break; } } GasEndPoint zeroEndPoint = null; DateTime startTime = DateTime.UtcNow; try { _zeroingUsedGasEndPoint = null; // Reset any previous setting (if any). zeroEndPoint = GetSensorZeroAir( null, useZeroAirOnly, false ); // Get the zeroing gas end point for this gas. _instrumentController.OpenGasEndPoint( zeroEndPoint, Pump.StandardFlowRate ); // ZeroSensor will return false if IDS times out before instrument finishes zeroing. // Return value does NOT indicate if zeroing was successful or not! if ( !_instrumentController.ZeroSensors( zeroEndPoint ) ) throw new UnableToZeroInstrumentSensorsException(); // SGF 14-Jun-2011 INS-1732 -- get sensor readings after zeroing has taken place foreach ( InstalledComponent ic in _returnEvent.DockedInstrument.InstalledComponents ) { if ( !( ic.Component is Sensor ) ) // Skip non-sensors. continue; Sensor sensor = (Sensor)ic.Component; if ( !sensor.Enabled ) // Skip disabled sensors continue; SensorGasResponse sgr = _returnEvent.GetSensorGasResponseByUid( sensor.Uid ); if ( sgr != null ) { sgr.ReadingAfterZeroing = _instrumentController.GetSensorReading( ic.Position, sensor.Resolution ); sgr.TimeAfterZeroing = DateTime.UtcNow; } } } catch ( Exception e ) { Log.Error( "Zeroing Sensor", e ); throw; } finally { Log.Debug( "ZEROING: Finished" ); _instrumentController.CloseGasEndPoint( zeroEndPoint ); if ( zeroEndPoint != null ) // how could this ever be null? _zeroingUsedGasEndPoint = new UsedGasEndPoint( zeroEndPoint, CylinderUsage.Zero, DateTime.UtcNow - startTime, 0 ); } }
public virtual void CloseGasEndPoint(GasEndPoint endPoint) { Pump.CloseGasEndPoint(endPoint); }
/// <summary> /// Get the calibration gas concentration. /// </summary> /// <param name="sensor">The sensor to get the concentration for.</param> /// <param name="endPoint">The gas end point that contains the gas.</param> protected double GetCalibrationGasConcentration(InstalledComponent installedComponent, GasEndPoint endPoint) { const string func = "GetCalibrationGasConcentration: "; Sensor sensor = (Sensor)installedComponent.Component; double availableConcentration = DomainModelConstant.NullDouble; string gasCode = sensor.CalibrationGas.Code; double lelMultiplier = GasType.Cache[gasCode].LELMultiplier; MeasurementType sensorMeasurementType = ((SensorType)sensor.Type).MeasurementType; Cylinder cylinder = endPoint.Cylinder; // Get the cylinder. // For nitrogen cylinder's, being used for O2 bumps, we assume 0% O2. if ((gasCode == GasCode.O2) && cylinder.ContainsOnlyGas(GasCode.N2)) { availableConcentration = 0.0d; } else { // Determine the gas concentration of the gas to use. foreach (GasConcentration gasCon in cylinder.GasConcentrations) { if (gasCon.Type.Code == gasCode) { availableConcentration = gasCon.Concentration; break; } else if ((gasCode == GasCode.O2) && (gasCon.Type.Code == GasCode.FreshAir)) { availableConcentration = 209000d; break; } } } // If we didn't find anything with the gas. if (availableConcentration == DomainModelConstant.NullDouble) { throw new CorrectBumpTestGasUnavailable(gasCode); } Log.Debug("Sensor cal gas concentration: " + sensor.CalibrationGasConcentration + " res: " + sensor.Resolution); // Check the measurement type for how to multiply the concentration. if (sensorMeasurementType == MeasurementType.LEL) { availableConcentration *= lelMultiplier; availableConcentration = Master.Instance.ControllerWrapper.Round(availableConcentration, 0); } else if (sensorMeasurementType != MeasurementType.PPM) { availableConcentration /= 10000; } if (availableConcentration == sensor.CalibrationGasConcentration) { return(sensor.CalibrationGasConcentration); // Its the correct concentration. } availableConcentration = Master.Instance.ControllerWrapper.Round(availableConcentration, 2); Log.Debug("gas: " + gasCode + " new conc: " + availableConcentration); // INS- RHP v7.6 - For MX6v4.4 and above, Set the sensor's calibration gas concentration to // match the concentration of gas end point that contains the gas. //if (_returnEvent.DockedInstrument.Type == DeviceType.MX6 && new Version(_returnEvent.DockedInstrument.SoftwareVersion) >= _MX6_v44 // && availableConcentration > 0.0d && sensor.BumpCriterionType != CriterionType.PPMLimit) //{ // // If sensor is %vol, and it has a zero resolution, then we want to round the concentration // // up to the next integer value. e.g., if cylinder contains 2.1% gas, then we want to round // // it to 3. // if (sensorMeasurementType == MeasurementType.VOL && sensor.Resolution == 1.0) // { // Log.Debug(string.Format("{0}Sensor is %VOL and has resolution of zero decimals. Rounding {1} up to next integer", // func, availableConcentration)); // availableConcentration = Math.Ceiling(availableConcentration); // } // Log.Debug(string.Format("{0}SETTING SENSOR FROM CONCENTRATION {1} TO {2}, (res={3})", func, sensor.CalibrationGasConcentration, availableConcentration, sensor.Resolution)); // // Set the sensor's calibration gas concentration. // _instrumentController.SetSensorCalGasConcentration(installedComponent.Position, availableConcentration, sensor.Resolution); // Log.Debug(string.Format("{0}NEW CONCENTRATION: {1}", func, _instrumentController.GetSensorCalGasConcentration(installedComponent.Position, sensor.Resolution))); //} return(availableConcentration); }
/// <summary> /// Get the calibration test gas end point for a sensor. /// </summary> /// <param name="installedComponent">The sensor to get the gas for.</param> /// <returns>The correct gas end point.</returns> /// <exception cref="CorrectCalibrationGasUnavailable"> /// Thrown when no cylinder is provided for the sensor. /// </exception> protected GasEndPoint GetSensorGasEndPoint( InstalledComponent installedComponent ) { Sensor sensor = null; MeasurementType sensorMeasurementType = MeasurementType.Unknown; if (installedComponent != null) { sensor = installedComponent.Component as Sensor; sensorMeasurementType = ((SensorType)sensor.Type).MeasurementType; } #region LogDebug if (sensor != null) { Log.Debug( "Calibration.GetSensorGasEndPoint" ); Log.Debug( "Finding appropriate cal gas for Sensor: " + sensor.Type + ", UID: " + sensor.Uid + ", CalGas Code: " + sensor.CalibrationGas.Code + ", Conc: " + sensor.CalibrationGasConcentration + ", Pos: " + installedComponent.Position ); } #endregion // If this is a sensor that uses 20.9 O2 for its calibration gas, // then attempt to find a cylinder that offers Zero Air; if // Zero Air is not available, find Fresh Air. If neither are // available, then fall out of this code and proceed to the main // processing loop below. if ( sensor.CalibrationGas.Code == GasCode.O2 && sensor.CalibrationGasConcentration == 20.9 ) { GasEndPoint air = GetSensorZeroAir( installedComponent, false, true ); if (air != null) { _triedGasEndPoints[air] = air; Cylinder cyl = air.Cylinder; if (cyl.IsZeroAir) Log.Debug("...SELECTED GasEndPoint. Has ZeroAir for O2 at 20.9."); else if (cyl.IsFreshAir) Log.Debug("...SELECTED GasEndPoint. Has FreshAir for O2 at 20.9."); else // We do not expect to reach this line of code, but it has been placed here to // log that GetSensorZeroAir returned a cylinder that was Fresh Air or Zero Air. Log.Debug(string.Format("...SELECTED GasEndPoint: {0}", cyl.ToString())); return air; } } double sensorConcentration = sensor.CalibrationGasConcentration; double lelMultiplier = GasType.Cache[ sensor.CalibrationGas.Code ].LELMultiplier; int pointCount = 0; Log.Debug( "SCAN 1 (Find appropriate gas with desired concentration)..." ); foreach ( GasEndPoint gasEndPoint in GasEndPoints ) { Cylinder cyl = gasEndPoint.Cylinder; #region LogDebug string msg = "GasEndPoint #" + ++pointCount; Log.Debug(msg); msg = "...Pos=" + gasEndPoint.Position //+ ", ID=" + cyl.ID + ", FactID=" + cyl.FactoryId + ", Part=" + cyl.PartNumber + ", Fresh=" + cyl.IsFreshAir + ", ZeroAir=" + cyl.IsZeroAir + ", Pressure=" + cyl.Pressure.ToString(); if ( cyl.Volume != DomainModelConstant.NullInt ) msg += ", Vol=" + cyl.Volume; Log.Debug( msg ); msg = "......"; foreach ( GasConcentration gasCon in cyl.GasConcentrations ) { msg += "[" + gasCon.Type.Code; msg += " "; msg += ( gasCon.Concentration == DomainModelConstant.NullDouble ) ? "fresh" : gasCon.Concentration.ToString(); msg += "]"; } Log.Debug( msg ); #endregion // 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 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 ) ); } // Ignore cylinders lacking the right gases. if (!cyl.ContainsGas(sensor.CalibrationGas.Code, sensorConcentration, sensorMeasurementType)) { Log.Debug( "...Rejected. Does not contain " + sensor.CalibrationGas.Code + " with desired concentration " + sensorConcentration ); 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 cyl.GasConcentrations ) { if ( gasConcentration.Type.Code == sensor.CalibrationGas.Code ) { cylinderPPM = gasConcentration.Concentration; break; } } if ( cylinderPPM < 0 ) // this should never happen. Which means we better check. { Log.Debug( "...Rejected. Does not contain " + sensor.CalibrationGas.Code ); 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}%%)", sensor.CalibrationGas.Code, 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 " + sensor.CalibrationGas.Code + " with desired concentration " + sensorConcentration ); return gasEndPoint; } // end-foreach 1 Log.Debug( "SCAN 2 (find appropriate gas with any concentration)..." ); pointCount = 0; foreach ( GasEndPoint gasEndPoint in GasEndPoints ) { Cylinder cyl = gasEndPoint.Cylinder; #region LogDebug string msg = "GasEndPoint #" + ++pointCount; Log.Debug(msg); msg = "...Pos=" + gasEndPoint.Position //+ ", ID=" + cyl.ID + ", FactID=" + cyl.FactoryId + ", Part=" + cyl.PartNumber + ", Fresh=" + cyl.IsFreshAir + ", ZeroAir=" + cyl.IsZeroAir + ", Pressure=" + cyl.Pressure.ToString(); if ( cyl.Volume != DomainModelConstant.NullInt ) msg += ", Vol=" + cyl.Volume; Log.Debug( msg ); msg = "......"; foreach ( GasConcentration gasCon in cyl.GasConcentrations ) { msg += "[" + gasCon.Type.Code; msg += " "; msg += ( gasCon.Concentration == DomainModelConstant.NullDouble ) ? "fresh" : gasCon.Concentration.ToString(); msg += "]"; } Log.Debug( msg ); #endregion // Ignore already tried cylinders. if ( _triedGasEndPoints.ContainsKey( gasEndPoint ) ) { Log.Debug( "...Rejected. Already tried cylinder." ); continue; } // Ignore cylinders lack the right gases. if ( ! cyl.ContainsGas( sensor.CalibrationGas.Code ) ) { Log.Debug( "...Rejected. Does not contain " + sensor.CalibrationGas.Code ); 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 right gas. 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 == sensor.CalibrationGas.Code ) { cylinderPPM = gasConcentration.Concentration; break; } } if ( cylinderPPM < 0 ) // this should never happen. Which means we better check. { Log.Debug( "...Rejected. Does not contain " + sensor.CalibrationGas.Code ); 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}%%)", sensor.CalibrationGas.Code, Math.Round( cylinderLEL, 1 ) ) ); Log.Debug( "...Will not use concentration higher than 60%% LEL." ); continue; } } // end-if MeasurementTypes.LEL // Found a cylinder with the correct gas. _triedGasEndPoints[ gasEndPoint ] = gasEndPoint; Log.Debug( "...SELECTED. Contains " + sensor.CalibrationGas.Code ); return gasEndPoint; } // end-foreach 2 // If this is a sensor that uses O2 for its calibration gas, and no cylinder has been found // yet, then attempt to find a cylinder that offers Fresh Air. We don't try to find a Zero // Air cylinder because one of the scans above would have already selected it if one was // available. Also, O2 sensors with a cal gas concentration of 20.9 should have already // selected a Zero Air or Fresh Air cylinder so we don't need to check again. if ( sensor.CalibrationGas.Code == GasCode.O2 && sensor.CalibrationGasConcentration != 20.9 ) { GasEndPoint air = GetSensorFreshAir( installedComponent, true ); if ( air != null ) { _triedGasEndPoints[air] = air; Cylinder cyl = air.Cylinder; if ( cyl.IsFreshAir ) Log.Debug( "...SELECTED GasEndPoint. Has FreshAir for O2." ); else // We do not expect to reach this line of code, but it has been placed here to // log that GetSensorFreshAir returned a cylinder. Log.Debug( string.Format( "...SELECTED GasEndPoint: {0}", cyl.ToString() ) ); return air; } } Log.Debug( "NO APPROPRIATE CALIBRATION GAS FOUND!" ); throw new CorrectCalibrationGasUnavailable( string.Format( "Sensor {0}, CalGas={1}({2})", sensor.Uid, sensor.CalibrationGas.Code, sensor.CalibrationGasConcentration ) ); // No gas end point was found. }
/// <summary> /// Return the information from all smart cards, manifolds and manual cylinders that are present at start-up. /// </summary> /// <param name="installedCylinders">Information about the cylinders is placed into this passed-in list.</param> static private void ReadInstalledCylinders(List <GasEndPoint> gasEndPoints, PortRestrictions port1Restrictions) { const string funcName = "ReadInstalledCylinders: "; // Get all currently attached manifolds and manually-assigned cylinders. List <GasEndPoint> manGasEndPoints = new GasEndPointDataAccess().FindAll().FindAll(m => m.InstallationType == GasEndPoint.Type.Manifold || m.InstallationType == GasEndPoint.Type.Manual); for (int position = 1; position <= Configuration.DockingStation.NumGasPorts; position++) { Log.Debug(funcName + "POSITION " + position); // iGas cylinders take precendence if (!SmartCardManager.IsCardPresent(position)) { Log.Debug(string.Format("{0}Position {1}, No iGas card detected.", funcName, position)); // Does the port have a manifold or manual cylinder attached? Then make sure we include // that cylinder in the returned list. If no cylinder exists on port 1, then create a // virtual fresh air cylinder. GasEndPoint man = manGasEndPoints.Find(m => m.Position == position); if (man != null) { Log.Debug(string.Format("{0}Position {1} {2} found (\"{3}\", \"{4}\", Pressure {5}).", funcName, position, man.InstallationType == GasEndPoint.Type.Manifold ? "Manifold" : "Manual Cylinder", man.Cylinder.FactoryId, man.Cylinder.PartNumber, man.Cylinder.Pressure)); gasEndPoints.Add(man); } else if (position == Controller.FRESH_AIR_GAS_PORT) { Log.Debug(string.Format("{0}Position {1} is assumed to be Fresh Air.", funcName, position)); GasEndPoint freshAirEndPoint = GasEndPoint.CreateFreshAir(position); freshAirEndPoint.GasChangeType = GasEndPoint.ChangeType.Installed; gasEndPoints.Add(freshAirEndPoint); } continue; } // IF WE MAKE IT TO HERE, THEN WE KNOW WE HAVE AN INSERTED SMART CARD WHICH MEANS iGas IS ATTACHED. Cylinder cylinder = SmartCardManager.ReadCard(position); if (cylinder == null) // Check for a valid cylinder. { Log.Debug(string.Format("{0}Position {1}, ReadCard returned null. SKIPPING cylinder.", funcName, position)); continue; } // Dates read from card will be in 'local' time, but everything we deal with is in UTC. cylinder.ExpirationDate = Configuration.ToUniversalTime(cylinder.ExpirationDate); cylinder.RefillDate = Configuration.ToUniversalTime(cylinder.RefillDate); Thread.Sleep(1000); if (SmartCardManager.IsPressureSwitchPresent(position)) { if (SmartCardManager.CheckPressureSwitch(position)) { cylinder.Pressure = PressureLevel.Full; } else { cylinder.Pressure = PressureLevel.Low; } Log.Debug(string.Format("{0}Position {1} Pressure Switch reports {2}.", funcName, position, cylinder.Pressure)); } else { Log.Debug(string.Format("{0}Position {1} Pressure Switch not detected.", funcName, position)); } GasEndPoint gasEndPoint = new GasEndPoint(cylinder, position, GasEndPoint.Type.iGas); // Add the installed cylinder to the DockingStation (IDS). gasEndPoints.Add(gasEndPoint); } return; }