using Aitex.Core.RT.DataCenter; using Aitex.Core.RT.Device; using Aitex.Core.RT.Log; using Aitex.Core.RT.OperationCenter; using Aitex.Core.RT.SCCore; using Aitex.Core.Util; using MECF.Framework.Common.Beckhoff.ModuleIO; using MECF.Framework.Common.CommonData.Metal; using MECF.Framework.Common.CommonData.PlatingCell; using MECF.Framework.Common.CommonData.Reservoir; using MECF.Framework.Common.Equipment; using MECF.Framework.Common.IOCore; using MECF.Framework.Common.Persistent.Reservoirs; using MECF.Framework.Common.ToolLayout; using PunkHPX8_Core; using PunkHPX8_RT.Devices.AXIS; using PunkHPX8_RT.Devices.LinMot; using PunkHPX8_RT.Devices.PowerSupplier; using PunkHPX8_RT.Devices.Reservoir; using PunkHPX8_RT.Devices.VpwMain; using PunkHPX8_RT.Modules; using PunkHPX8_RT.Modules.PlatingCell; using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Text; using System.Threading.Tasks; namespace PunkHPX8_RT.Devices.PlatingCell { public class PlatingCellDevice : BaseDevice, IDevice { #region 常量 private const string PERSISTENT_VALUE = "PersistentValue"; private const string PLATINGCELLDATA = "PlatingCellData"; private const string AUTO = "Auto"; private const string MANUAL = "Manual"; private const string STRATUS = "Stratus"; private const string DISABLED = "Disabled"; private const string IS_HEAD_TILT = "IsHeadTilt"; private const string IS_HEAD_VERTICAL = "IsHeadVertical"; private const string CLAMSHELL_DISTANCE = "ClamShellDistance"; private const string CLAMSHELL_CYLINDER_PRESSURE = "ClamShellCylinderPressure"; private const string OVERFLOW_LEVEL = "OverFlowLevel"; private const string CLAMSHELL_CLOSE = "ClamShellClose"; private const string HEAD_TILT = "HeadTilt"; private const string CCR_ENABLE = "CCREnable"; private const string RINSE_ENABLE = "RinseEnable"; #endregion #region 内部变量 /// 变量是否初始化字典 /// private Dictionary _variableInitializeDic = new Dictionary(); /// /// 操作当前状态 /// protected RState _status; /// /// 持久化数据 /// protected PlatingCellPersistentValue _persistentValue; /// /// PlatingCell项 /// private PlatingCellItem _platingCellItem; /// /// overflow /// private int _overflowLevelHigh = 85; private int _overflowLevelLow = 25; /// /// 对应reservoir的名字 /// private string _reservoirName; /// /// PowerSupplier /// protected CellPowerSupplier _powerSupplier; /// /// vertical电机 /// private JetAxisBase _verticalAxis; /// /// vertical电机 /// private JetAxisBase _rotationAxis; /// /// CCR当前执行步骤 /// private string _currentCCRStep = ""; /// /// CCR当前剩余时间 /// private double _timeRemain; #endregion #region 属性 /// /// 状态 /// public RState Status { get { return _status; } } /// /// 是否禁用 /// public bool IsDisable { get { return _persistentValue == null || _persistentValue.OperatingMode == DISABLED; } } /// /// 操作模式 /// public string OperationMode { get { return _persistentValue.OperatingMode; } } /// /// 工程模式 /// public string EngineerMode { get { return _persistentValue.RecipeOperatingMode; } } /// /// 是否为Auto /// public bool IsAuto { get { return _persistentValue != null ? _persistentValue.OperatingMode == AUTO : false; } } /// /// 是否为Auto /// public bool IsManual { get { return _persistentValue != null ? _persistentValue.OperatingMode == MANUAL : false; } } /// /// A面PowerSupplier /// public CellPowerSupplier PowerSupplier { get { return _powerSupplier; } } #endregion #region 共享变量 /// /// 数据 /// protected PlatingCellData _platingCellData = new PlatingCellData(); /// /// 对应reservoir数据 /// protected ReservoirData _reservoirData = new ReservoirData(); #endregion #region 属性 /// /// 设备数据 /// public PlatingCellData PlatingCellDeviceData { get { return _platingCellData; } } #endregion /// /// 构造函数 /// /// public PlatingCellDevice(string moduleName) : base(moduleName, moduleName, moduleName, moduleName) { } /// /// 初始化 /// /// public virtual bool Initialize() { InitializeParameter(); SubscribeData(); InitializeOperation(); SubscribeValueAction(); return true; } /// /// 定时器执行 /// public bool OnTimer(int interval) { if (_verticalAxis != null) { _verticalAxis.OnTimer(); } if (_rotationAxis != null) { _rotationAxis.OnTimer(); } return true; } /// /// 初始化参数 /// private void InitializeParameter() { _persistentValue = PlatingCellPersistentManager.Instance.GetPlatingCellPersistentValue(Module); if (_persistentValue == null) { LOG.WriteLog(eEvent.ERR_RESERVOIR, Module, "Persistent Value Object is not exist"); } _platingCellItem = PlatingCellItemManager.Instance.GetPlatingCellItem(Module); if (_platingCellItem != null) { } _platingCellItem = PlatingCellItemManager.Instance.GetPlatingCellItem(Module); if (_platingCellItem != null) { _powerSupplier = DEVICE.GetDevice(_platingCellItem.PlatingPowerSupplyID); } _overflowLevelHigh = SC.GetValue($"PlatingCell.OverflowLevelHigh"); _overflowLevelLow = SC.GetValue($"PlatingCell.OverflowLevelLow"); _reservoirData = GetReservoirDevice().ReservoirData; _reservoirName = GetReservoirDevice().Module; if("PlatingCell1".Equals(Module) || "PlatingCell2".Equals(Module)) { _verticalAxis = DEVICE.GetDevice("PlatingCell1_2.Vertical"); } else { _verticalAxis = DEVICE.GetDevice("PlatingCell3_4.Vertical"); } _rotationAxis = DEVICE.GetDevice($"{Module}.Rotation"); } protected virtual void SubscribeValueAction() { IoSubscribeUpdateVariable(IS_HEAD_TILT); IoSubscribeUpdateVariable(IS_HEAD_VERTICAL); IoSubscribeUpdateVariable(CLAMSHELL_DISTANCE); IoSubscribeUpdateVariable(CLAMSHELL_CYLINDER_PRESSURE); IoSubscribeUpdateVariable(OVERFLOW_LEVEL); IoSubscribeUpdateVariable(CLAMSHELL_CLOSE); IoSubscribeUpdateVariable(HEAD_TILT); IoSubscribeUpdateVariable(CCR_ENABLE); IoSubscribeUpdateVariable(RINSE_ENABLE); } /// /// 订阅IO变量 /// /// protected void IoSubscribeUpdateVariable(string variable) { _variableInitializeDic[variable] = false; IOModuleManager.Instance.SubscribeModuleVariable(Module, variable, UpdateVariableValue); } /// /// 更新变量数值 /// /// /// private void UpdateVariableValue(string variable, object value) { if (!_platingCellData.IsDataInitialized) { _platingCellData.IsDataInitialized = true; } PropertyInfo property = _platingCellData.GetType().GetProperty(variable); if (property != null) { property.SetValue(_platingCellData, value); if (variable == OVERFLOW_LEVEL) { double waterLevel = CurrentToWaterLevel(Convert.ToDouble(value)); _platingCellData.OverFlowLevel = waterLevel; if (_platingCellData.OverFlowLevel >= _overflowLevelHigh) { _platingCellData.OverFlowStatus = "High"; } else if(_platingCellData.OverFlowLevel <= _overflowLevelLow) { _platingCellData.OverFlowStatus = "Empty"; } else { _platingCellData.OverFlowStatus = "Full"; } } } if (_variableInitializeDic.ContainsKey(variable) && !_variableInitializeDic[variable]) { _variableInitializeDic[variable] = true; } } /// /// 把电流mA转成水深mm /// /// private double CurrentToWaterLevel(double current) { double result = (current - 4) / 8 / 9.8 * 1000; return result; } /// /// 写变量 /// /// /// /// protected bool WriteVariableValue(string variable, object value) { string ioName = BeckhoffModuleIOManager.Instance.GetIoNameByInnerModuleName($"{Module}.{variable}"); return IOModuleManager.Instance.WriteIoValue(ioName, value); } /// /// 订阅数据 /// private void SubscribeData() { DATA.Subscribe($"{Module}.{PERSISTENT_VALUE}", () => _persistentValue, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.{PLATINGCELLDATA}", () => _platingCellData, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.ReservoirCommonData", () => _reservoirData, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.ReservoirName", () => _reservoirName, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.CurrentCCRStep", () => _currentCCRStep, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.CurrentCCRTimeRemain", () => _timeRemain, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.PowerSupplierData", () => _powerSupplier.PowerSupplierData, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.PowerSupplier.ID", () => _powerSupplier.Module, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.PowerSupplier.IsConnected", () => _powerSupplier.IsConnected, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.PowerSupplier.Voltage", () => _powerSupplier.PowerSupplierData.Voltage, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.PowerSupplier.Current", () => _powerSupplier.PowerSupplierData.Current, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.PowerSupplier.SetPoint", () => _powerSupplier.PowerSupplierData.SetPoint, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.PowerSupplier.RunModel", () => _powerSupplier.PowerSupplierData.PowerRunModelContent, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.PowerSupplier.PowerControl", () => _powerSupplier.PowerSupplierData.PowerControlContent, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.PowerSupplier.PowerStatus", () => _powerSupplier.PowerSupplierData.PowerStatusContent, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.PowerSupplier.Enable", () => _powerSupplier.PowerSupplierData.Enabled, SubscriptionAttribute.FLAG.IgnoreSaveDB); DATA.Subscribe($"{Module}.PowerSupplier.PowerGrade", () => _powerSupplier.PowerSupplierData.PowerGradeContent, SubscriptionAttribute.FLAG.IgnoreSaveDB); } /// /// 初始化操作 /// protected virtual void InitializeOperation() { OP.Subscribe($"{Module}.DisabledAction", DisabledOperation); OP.Subscribe($"{Module}.ManualAction", ManualOperation); OP.Subscribe($"{Module}.AutoAction", AutoOperation); OP.Subscribe($"{Module}.EngineeringModeAction", EngineeringModeOperation); OP.Subscribe($"{Module}.ProductionModeAction", ProductionModeOperation); OP.Subscribe($"{Module}.SetPlatingCellWaferSize", (cmd, args) => { return SetPlatingCellWaferSize(cmd, args); }); OP.Subscribe($"{Module}.ClamShellClose", (cmd, para) => { return ClamShellClose(); }); OP.Subscribe($"{Module}.ClamShellOpen", (cmd, para) => { return ClamShellOpen(); }); OP.Subscribe($"{Module}.HeadtTilt", (cmd, para) => { return HeadtTiltAction(); }); OP.Subscribe($"{Module}.HeadVertical", (cmd, para) => { return HeadtVerticalAction(); }); OP.Subscribe($"{Module}.CCREnable", (cmd, para) => { return CCREnableAction(); }); OP.Subscribe($"{Module}.CCRDisable", (cmd, para) => { return CCRDisableAction(); }); OP.Subscribe($"{Module}.RinseEnable", (cmd, para) => { return RinseEnableAction(); }); OP.Subscribe($"{Module}.RinseDisable", (cmd, para) => { return RinseDisableAction(); }); OP.Subscribe($"{Module}.StartRotation", StartRotationAction); OP.Subscribe($"{Module}.StopRotation", StopRotationAction); } #region Operation private bool StartRotationAction(string cmd, object[] args) { if (args.Length < 2 && (int)args[0] < 0 && (int)args[1] < 0) { LOG.WriteLog(eEvent.ERR_VPW, Module, $"Start rotation paramater is wrong"); return false; } double targetPostion = (int)args[0] * 6 * (int)args[1]; object[] param = new object[] { "", targetPostion }; int degSpeed = (int)args[0] * 6; SetRotationSpeed(degSpeed); double AfterChangetargetPostion = (int)args[0] * 6 * (int)args[1]; return RotationProfilePosition(AfterChangetargetPostion); } private bool StopRotationAction(string cmd, object[] args) { return _rotationAxis.StopPositionOperation(); } public bool ClamShellClose() { return WriteVariableValue(CLAMSHELL_CLOSE, true); } public bool ClamShellOpen() { return WriteVariableValue(CLAMSHELL_CLOSE, false); } public bool HeadtTiltAction() { return WriteVariableValue(HEAD_TILT, true); } public bool HeadtVerticalAction() { return WriteVariableValue(HEAD_TILT, false); } public bool CCREnableAction() { return WriteVariableValue(CCR_ENABLE, true); } public bool CCRDisableAction() { return WriteVariableValue(CCR_ENABLE, false); } public bool RinseEnableAction() { return WriteVariableValue(RINSE_ENABLE, true); } public bool RinseDisableAction() { return WriteVariableValue(RINSE_ENABLE, false); } /// /// DisabledAction /// /// /// /// public bool DisabledOperation(string cmd, object[] args) { string currentOperation = "Disabled"; PlatingCellEntity platingCellEntity = Singleton.Instance.GetModule(Module); if (platingCellEntity != null && _persistentValue != null && _persistentValue.OperatingMode != currentOperation) { string preOperation = _persistentValue.OperatingMode; if (platingCellEntity.IsBusy) { LOG.WriteLog(eEvent.ERR_METAL, Module, $"{Module} is Busy, can't switch to Disabled mode"); return false; } //if (SchedulerMetalTimeManager.Instance.Contained(Module)) //{ // LOG.WriteLog(eEvent.ERR_METAL, Module, $"{Module} is in scheduler, can't switch to Disabled mode"); // return false; //} platingCellEntity.EnterInit(); _persistentValue.OperatingMode = currentOperation; LOG.WriteLog(eEvent.INFO_METAL, Module, $"Operating mode is switched from {preOperation} to {currentOperation}"); } PlatingCellPersistentManager.Instance.UpdatePersistentValue(Module); return true; } /// /// ManualAction /// /// /// /// public bool ManualOperation(string cmd, object[] args) { string currentOperation = "Manual"; PlatingCellEntity platingCellEntity = Singleton.Instance.GetModule(Module); if (platingCellEntity != null && _persistentValue != null && _persistentValue.OperatingMode != currentOperation) { string preOperation = _persistentValue.OperatingMode; if (platingCellEntity.IsBusy) { LOG.WriteLog(eEvent.ERR_METAL, Module, $"{Module} is Busy, can't switch to Manual mode"); return false; } //if (SchedulerMetalTimeManager.Instance.Contained(Module)) //{ // LOG.WriteLog(eEvent.ERR_METAL, Module, $"{Module} is in scheduler, can't switch to Manual mode"); // return false; //} platingCellEntity.EnterInit(); _persistentValue.OperatingMode = currentOperation; LOG.WriteLog(eEvent.INFO_METAL, Module, $"Operating mode is switched from {preOperation} to {currentOperation}"); } PlatingCellPersistentManager.Instance.UpdatePersistentValue(Module); return true; } /// /// AutoAction /// /// /// /// public bool AutoOperation(string cmd, object[] args) { string currentOperation = "Auto"; PlatingCellEntity platingCellEntity = Singleton.Instance.GetModule(Module); if (platingCellEntity != null && _persistentValue != null && _persistentValue.OperatingMode != currentOperation) { string preOperation = _persistentValue.OperatingMode; if (platingCellEntity.IsBusy) { LOG.WriteLog(eEvent.ERR_METAL, Module, $"{Module} is Busy, can't switch to Auto mode"); return false; } platingCellEntity.EnterInit(); _persistentValue.OperatingMode = currentOperation; LOG.WriteLog(eEvent.INFO_METAL, Module, $"Operating mode is switched from {preOperation} to {currentOperation}"); } PlatingCellPersistentManager.Instance.UpdatePersistentValue(Module); return true; } /// /// EngineeringModeAction /// /// /// /// private bool EngineeringModeOperation(string cmd, object[] args) { string currentRecipeOperation = "Engineering"; if (_persistentValue != null) { _persistentValue.RecipeOperatingMode = currentRecipeOperation; } PlatingCellPersistentManager.Instance.UpdatePersistentValue(Module); return true; } /// /// ProductionAction /// /// /// /// private bool ProductionModeOperation(string cmd, object[] args) { string currentRecipeOperation = "Production"; if (_persistentValue != null) { _persistentValue.RecipeOperatingMode = currentRecipeOperation; } PlatingCellPersistentManager.Instance.UpdatePersistentValue(Module); return true; } private bool SetPlatingCellWaferSize(string cmd, object[] args) { string metalWaferSize = args[0] as string; if (_persistentValue != null) { _persistentValue.PlatingCellWaferSize = int.Parse(metalWaferSize); } PlatingCellPersistentManager.Instance.UpdatePersistentValue(Module); return true; } /// /// 获取Reservoir设备 /// /// private ReservoirDevice GetReservoirDevice() { string reservoir = ReservoirItemManager.Instance.GetReservoirByPlatingCell(Module); return DEVICE.GetDevice(reservoir); } /// /// CCR当前步骤 /// /// public void UpdateStatus(string tmp) { _currentCCRStep = tmp; } /// /// CCR当前步骤剩余时间 /// /// public void UpdateCCRTimeRemain(double timeRemain) { _timeRemain = timeRemain; } #endregion #region RotationAxis /// /// 电机是否上电 /// /// public bool CheckRotationSwitchOn() { return _rotationAxis.IsSwitchOn; } /// /// Home rotation /// /// public bool HomeRotation() { return _rotationAxis.Home(); } /// /// 检验Rotation Home结果 /// /// public bool CheckHomeEndStatus() { return CheckRotationEndStatus() && _rotationAxis.IsHomed; } /// /// 检验Rotation结束状态 /// /// public bool CheckRotationEndStatus() { return _rotationAxis.Status == PunkHPX8_Core.RState.End; } /// /// 检验Rotation失败状态 /// /// public bool CheckRotationStopStatus() { return _rotationAxis.Status == PunkHPX8_Core.RState.Failed; } /// /// 设置速度 /// /// /// public bool SetRotationSpeed(int speed) { _rotationAxis.SetProfileSpeed(speed); return true; } /// /// 改变速度 /// /// /// public bool ChangeRotationSpeed(int speed) { return _rotationAxis.ChangeSpeed(speed); } /// /// 电机运动 /// /// /// public bool RotationProfilePosition(double position) { return _rotationAxis.ProfilePositionOperation(position); } /// /// 停止运动 /// /// public bool StopProfilePosition() { return _rotationAxis.StopPositionOperation(); } /// /// 是否Rotation运动 /// /// public bool CheckRotationRunning() { return _rotationAxis.IsRun; } #endregion public virtual void Monitor() { } public virtual void Reset() { } public virtual void Terminate() { } } }