using System; using System.Collections; using System.Text.RegularExpressions; using Aitex.Core.Common.DeviceData; using Aitex.Core.RT.DataCenter; using Aitex.Core.RT.Event; using Aitex.Core.RT.IOCore; using Aitex.Core.RT.Log; using Aitex.Core.RT.OperationCenter; using Aitex.Core.RT.SCCore; using Aitex.Core.RT.Tolerance; using Aitex.Core.Util; using MECF.Framework.Common.Communications; using MECF.Framework.Common.DataCenter; using MECF.Framework.Common.Device.Bases; using MECF.Framework.Common.Equipment; using VirgoCommon; using VirgoRT.Modules; namespace VirgoRT.Devices { class RevtechGenerator : RfPowerBase { // ----------------------------Fields-------------------------- // private int QUERY_INTERVAL = 5000; private const string INFO_PATTERN = @"(\d{7})\s(\d{5})\s(\d{5})\s(\d{5})\s(\d{5})"; private double _total; private double _fromLast; private bool _cmdRFPowerOn = false; private readonly AsyncSerialPort _serial; private readonly DeviceTimer _timerQueryStatus = new DeviceTimer(); private readonly DeviceTimer _timerTotal = new DeviceTimer(); private readonly DeviceTimer _timerFromLast = new DeviceTimer(); private readonly DeviceTimer _timerRFTurnOn = new DeviceTimer(); private DateTime _powerOnStartTime; private TimeSpan _powerOnElapsedTime; private readonly RD_TRIG _rfOnTrigger = new RD_TRIG(); private readonly R_TRIG _ErrTrigger = new R_TRIG(); private readonly R_TRIG _trigPMNeeded = new R_TRIG(); private readonly RD_TRIG _trigOnOff = new RD_TRIG(); private ToleranceChecker _checkerPower; private ToleranceChecker _checkerReflectPower; private readonly double _scPowerAlarmTime; private readonly double _scPowerAlarmRange; private readonly double _scPowerWarningTime; private readonly double _scPowerWarningRange; private readonly double _scReflectPowerAlarmTime; private readonly double _scReflectPowerAlarmRange; private readonly double _scPowerRange; private readonly DIAccessor _diIntlk; private StatsDataItemRFAndPump _statRFOnTime; private object _lockerCmdPowerOn = new object(); private string _title = "Revtech TEC"; // --------------------------Properties------------------------ // public bool ConnectedStatus { get; set; } public override float ScalePower => (float)_scPowerRange; public GeneratorStatus Status { get; set; } public string LastPMTime { get { return _statRFOnTime != null ? _statRFOnTime.LastPMTime.ToString() : ""; } } public double DaysFromLastPM { get { return _statRFOnTime == null ? 0 : _statRFOnTime.fromLastPM; } set { if (_statRFOnTime != null) _statRFOnTime.fromLastPM = value; } } public double TotalDays { get { return _statRFOnTime != null ? _statRFOnTime.Total : 0; } set { if (_statRFOnTime != null) _statRFOnTime.Total = value; } } public double PMIntervalDays { get { return _statRFOnTime != null ? _statRFOnTime.PMInterval : 0; } } public bool IsPMNeeded { get { return DaysFromLastPM > PMIntervalDays; } } public bool EnableAlarm { get { return _statRFOnTime == null || _statRFOnTime.AlarmEnable; } } public override bool IsPowerOn { get => Status == GeneratorStatus.ON; set { } } public override bool IsError { get => Status == GeneratorStatus.ERROR; set { } } [Subscription("PowerOnTime")] public string PowerOnTime { get { if (_cmdRFPowerOn) _powerOnElapsedTime = DateTime.Now - _powerOnStartTime; return $"{(int)_powerOnElapsedTime.TotalHours:00}:{_powerOnElapsedTime.Minutes:00}:{(_powerOnElapsedTime.Seconds > 0 ? (_powerOnElapsedTime.Seconds + 1) : 0):00}"; } } public bool RFInterlock => _diIntlk == null || _diIntlk.Value; private float _forwardPower; public override float ForwardPower { get { return _forwardPower; } set { _forwardPower = CalibrationData(value, false); } } public new AITRfData DeviceData => new AITRfData { Module = Module, DeviceName = Name, ScalePower = ScalePower, ForwardPower = ForwardPower, ReflectPower = ReflectPower, IsRfOn = IsPowerOn, PowerSetPoint = PowerSetPoint, PowerOnElapsedTime = PowerOnTime, IsInterlockOk = RFInterlock, WorkMode = (int)RfMode.ContinuousWaveMode, DisplayName = "Source RF", }; // --------------------------Constructor----------------------- // public RevtechGenerator(ModuleName mod, string name) : base(mod.ToString(), name) { var portNum = SC.GetStringValue($"{mod}.{name}.Port"); this.Status = GeneratorStatus.Unknown; _serial = new AsyncSerialPort(portNum, 9600, 8, System.IO.Ports.Parity.None, System.IO.Ports.StopBits.One, "\r\r"); _scPowerAlarmTime = SC.GetValue($"{Module}.{Name}.PowerAlarmTime"); _scPowerAlarmRange = SC.GetValue($"{Module}.{Name}.PowerAlarmRange"); _scPowerWarningTime = SC.GetValue($"{Module}.{Name}.PowerWarningTime"); _scPowerWarningRange = SC.GetValue($"{Module}.{Name}.PowerWarningRange"); _scReflectPowerAlarmTime = SC.GetValue($"{Module}.{Name}.ReflectPowerAlarmTime"); _scReflectPowerAlarmRange = SC.GetValue($"{Module}.{Name}.ReflectPowerAlarmRange"); _scPowerRange = SC.GetValue($"{Module}.{Name}.PowerRange"); _scEnableCalibration = SC.GetConfigItem($"{Module}.{Name}.EnableCalibration"); _scCalibrationTable = SC.GetConfigItem($"{Module}.{Name}.CalibrationTable"); _scRFPhysicalMaxPower = SC.GetConfigItem($"{Module}.{Name}.RFPhysicalMaxPower"); _scCurrentRFMaxPower = SC.GetConfigItem($"{Module}.{Name}.CurrentRFMaxPower"); _diIntlk = IO.DI[$"{Module}.DI_Generator_Hardware_Interlock"]; } ~RevtechGenerator() { _serial?.Close(); } public override bool Initialize() { base.Initialize(); DATA.Subscribe($"{Module}.{Name}.DeviceData", () => DeviceData); OP.Subscribe($"{Module}.{Name}.{AITRfOperation.SetPowerOnOff}", (out string reason, int time, object[] param) => { SetPowerOnOff(Convert.ToBoolean((string)param[0]), out reason); return true; }); OP.Subscribe($"{Module}.{Name}.{AITRfOperation.SetPower}", (out string reason, int time, object[] param) => { reason = ""; ushort val = Convert.ToUInt16(param[0]); SetPower(val); return true; }); OP.Subscribe($"{Module}.{Name}.{AITRfOperation.SetContinuousPower}", (out string reason, int time, object[] param) => { reason = ""; ushort val = Convert.ToUInt16(param[0]); SetPower(val); return true; }); if (_serial.Open()) { this.ConnectedStatus = true; _serial.OnDataChanged += SerialPortDataReceived; _serial.OnErrorHappened += SerialPortErrorOccurred; } else { this.ConnectedStatus = false; EV.PostAlarmLog(this.Module, $"{_title} 射频发生器串口无法打开"); return false; } _statRFOnTime = StatsDataManager.Instance.GetItemRFAndPump($"{Module}.RfOnTime"); _timerQueryStatus.Start(QUERY_INTERVAL); _checkerPower = new ToleranceChecker(_scPowerAlarmTime); _checkerReflectPower = new ToleranceChecker(_scReflectPowerAlarmTime); SetCommunicationMode(1); return true; } public override void Monitor() { // 状态查询 if (_timerQueryStatus.IsTimeout()) { this.SendCmd(AdTecRfMessage.QUERY); _timerQueryStatus.Start(QUERY_INTERVAL); } // power on triggered _rfOnTrigger.CLK = IsPowerOn; if (_rfOnTrigger.R) { _total = TotalDays; _fromLast = DaysFromLastPM; _timerTotal.Start(0); _timerFromLast.Start(0); _powerOnStartTime = DateTime.Now; _checkerPower.Reset(_scPowerAlarmTime); _checkerReflectPower.Reset(_scReflectPowerAlarmTime); _alarmChecker.Reset(_scPowerAlarmTime); _warningChecker.Reset(_scPowerWarningTime); } if (_rfOnTrigger.M) { TotalDays = _total + _timerTotal.GetElapseTime() / 1000 / 60 / 60; DaysFromLastPM = _fromLast + _timerFromLast.GetElapseTime() / 1000 / 60 / 60; //_checkerPower.Monitor(ForwardPower, PowerSetPoint - _scPowerAlarmRange, PowerSetPoint + _scPowerAlarmRange, _scPowerAlarmTime); //if (_checkerPower.Trig) //{ // EV.PostAlarmLog($"{Module}", // $"{Display} Forward power {ForwardPower:0} out of range[{PowerSetPoint - _scPowerAlarmRange:0},{PowerSetPoint + _scPowerAlarmRange:0}] in {_scPowerAlarmTime:0} seconds"); // SetPowerOnOff(false, out _); //} if (_recipeAlarmRange > 0 && _recipeAlarmRange / 100.0 * PowerSetPoint < _scPowerAlarmRange) { if (_recipeIgnoreTimer.GetElapseTime() > _recipeIgnoreTimeMS) { _recipeAlarmChecker.Monitor(ForwardPower, PowerSetPoint - Math.Abs(_recipeAlarmRange / 100.0 * PowerSetPoint), PowerSetPoint + Math.Abs(_recipeAlarmRange / 100.0 * PowerSetPoint), _scPowerAlarmTime); if (_recipeAlarmChecker.Trig) { EV.PostAlarmLog(Module, Display + $" out of tolerance in {_scPowerAlarmTime:0} seconds"); SetPowerOnOff(false, out _); } } } else { _alarmChecker.Monitor(ForwardPower, PowerSetPoint - Math.Abs(_scPowerAlarmRange), PowerSetPoint + Math.Abs(_scPowerAlarmRange), _scPowerAlarmTime); if (_alarmChecker.Trig) { EV.PostAlarmLog(Module, Display + $" out of tolerance in {_scPowerAlarmTime:0} seconds"); } } if (_recipeWarningRange > 0 && _recipeWarningRange / 100.0 * PowerSetPoint < _scPowerWarningRange) { if (_recipeIgnoreTimer.GetElapseTime() > _recipeIgnoreTimeMS) { _recipeWarningChecker.Monitor(ForwardPower, PowerSetPoint - Math.Abs(_recipeWarningRange / 100.0 * PowerSetPoint), PowerSetPoint + Math.Abs(_recipeWarningRange / 100.0 * PowerSetPoint), _scPowerWarningTime); if (_recipeWarningChecker.Trig) { EV.PostWarningLog(Module, Display + $" out of tolerance in {_scPowerWarningTime:0} seconds"); } } } else { _warningChecker.Monitor(ForwardPower, PowerSetPoint - Math.Abs(_scPowerWarningRange), PowerSetPoint + Math.Abs(_scPowerWarningRange), _scPowerWarningTime); if (_warningChecker.Trig) { EV.PostWarningLog(Module, Display + $" out of tolerance in {_scPowerWarningTime:0} seconds"); } } _checkerReflectPower.Monitor(ReflectPower, double.MinValue, _scReflectPowerAlarmRange, _scReflectPowerAlarmTime); if (_checkerReflectPower.Trig) { EV.PostAlarmLog($"{Module}", $"{Display} Reflect power {ReflectPower:0} out of range[0,{_scReflectPowerAlarmRange:0}] in {_scReflectPowerAlarmTime:0} seconds"); SetPowerOnOff(false, out _); } } if (PMIntervalDays > 0) { _trigPMNeeded.CLK = IsPMNeeded; if (_trigPMNeeded.Q) { if (EnableAlarm) { EV.PostAlarmLog($"{Module}", "rf on time value larger than setting interval days"); } } } if (_rfOnTrigger.T) StatsDataManager.Instance.Increase($"{Module}.RfOnTime", $"{Module} RfOnTime", DaysFromLastPM, TotalDays); if (!_rfOnTrigger.CLK) { ForwardPower = 0; ReflectPower = 0; } // 通信 checking, 2 second 一次 //if (_timerComm.IsTimeout() && !_bQueryComm) //{ // this.SendCmd(AdTecRfMessage.CHK_COMM); // _bQueryComm = true; // _timerComm.Start(CHK_COMM_INTERVAL); //} // RF Turn On & Off Timeout Check lock (_lockerCmdPowerOn) { if (IsPowerOn) { _timerRFTurnOn.Stop(); } else { if (_cmdRFPowerOn && _timerRFTurnOn.IsTimeout()) { EV.PostAlarmLog($"{Module}", "RF Turn On Failed"); _timerRFTurnOn.Stop(); } } } base.Monitor(); } public override void Terminate() { _serial?.Close(); } public override void Reset() { _rfOnTrigger.RST = true; _ErrTrigger.RST = true; _trigPMNeeded.RST = true; this.SendCmd(AdTecRfMessage.RESET); this.Status = GeneratorStatus.OFF; _cmdRFPowerOn = false; base.Reset(); } public void SetRfMode(RfMode mode) { throw new NotImplementedException(); } public override void SetCommunicationMode(int mode) { CommunicationType t1 = (CommunicationType)mode; switch (t1) { case CommunicationType.Analogue: this.SendCmd(AdTecRfMessage.ANALOG); break; case CommunicationType.RS232: this.SendCmd(AdTecRfMessage.RS232); break; default: throw new ArgumentOutOfRangeException("Communication mode error"); } } public override void SetPower(float val) { if (!(this.ControlMode == EnumRfPowerControlMode.RS232Mode)) SetCommunicationMode(1); ushort a = !_scEnableCalibration.BoolValue ? (ushort)val : (ushort)CalibrationData(val, true); if (SendCmd($"{a:D4}{AdTecRfMessage.SET_POWER}")) { PowerSetPoint = val; } } public override bool SetPowerOnOff(bool on, out string str) { if (!(this.ControlMode == EnumRfPowerControlMode.RS232Mode)) SetCommunicationMode(1); str = ""; if (on) { lock (_lockerCmdPowerOn) { _cmdRFPowerOn = true; _timerRFTurnOn.Start(SC.GetValue($"{Module}.Rf.RFTurnOnTimeout") * 1000); } SendCmd(AdTecRfMessage.RF_ON); QUERY_INTERVAL = 500; } else { lock (_lockerCmdPowerOn) { _cmdRFPowerOn = false; _timerRFTurnOn.Stop(); } SendCmd(AdTecRfMessage.RF_OFF); ForwardPower = 0; ReflectPower = 0; QUERY_INTERVAL = 500; _ErrTrigger.RST = true; } _timerQueryStatus.Start(QUERY_INTERVAL); return true; } //----------------------------------Private Method------------------------------- // private void SerialPortDataReceived(string str) { if (string.IsNullOrEmpty(str)) { EV.PostAlarmLog(Module, $"{_title} RFG 无数据反馈"); return; } string str2 = str.Trim('\r'); if (str2 == AdTecRfMessage.ERR_RES) { EV.PostWarningLog(Module, $"{_title} 收到 [{str2}]"); return; } try { //LOG.Info($"{Module} Generator rec [{str2}]"); Match match1 = Regex.Match(str2, INFO_PATTERN); if (!match1.Success) { //EV.PostWarningLog(Module, "AdTec 数据格式错误"); if (!SC.GetValue("System.IsSimulatorMode")) { LOG.Write($"{Module}, {_title} 数据格式错误"); } return; } string[] str1 = { match1.Groups[1].Value, match1.Groups[2].Value, match1.Groups[3].Value, match1.Groups[4].Value, match1.Groups[5].Value }; this.ParseQueryData(str1); } catch (Exception ex) { LOG.Write(ex); } } private void ParseQueryData(string[] strInfo) { // Control mode string s2 = strInfo[0].Substring(0, 1); this.ControlMode = (EnumRfPowerControlMode)Convert.ToUInt16(s2); // output mode string s0 = strInfo[0].Substring(1, 1); this.WorkMode = (EnumRfPowerWorkMode)Convert.ToUInt16(s0); // ON/OFF char s1 = strInfo[0][2]; if (s1 == '1') { Status = GeneratorStatus.ON; } else if (s1 == '0') { Status = GeneratorStatus.OFF; } string errCode = strInfo[0].Substring(5, 2); _ErrTrigger.CLK = errCode != "00"; if (_ErrTrigger.Q) { string code = errCode == "88" ? "EEPROM or FPGA.... Error" : errCode == "99" ? "ITLK Error" : errCode == "26" ? "Humidity Alarm" : errCode == "05" ? "High Temperature Alarm" : errCode == "12" ? "Amplifier Unbalance" : errCode == "17" ? "Abnormal Power" : $"Unkown error code:{errCode}"; if (!string.IsNullOrWhiteSpace(code)) { if (errCode == "99") EV.PostInfoLog(Module, "Source Generator " + code); else EV.PostAlarmLog(Module, "Source Generator " + code); } } // forward power this.ForwardPower = Convert.ToUInt64(strInfo[2]); // reflect power this.ReflectPower = Convert.ToUInt64(strInfo[3]); } private void SerialPortErrorOccurred(string obj) { Status = GeneratorStatus.ERROR; EV.PostAlarmLog(Module, $"{_title} RFG serial port error, [{obj}]"); } private bool SendCmd(string str) { if (str != AdTecRfMessage.QUERY) { EV.PostInfoLog(Module, $"{_title} Generator send [{str}]"); } return _serial.Write(str + "\r"); } } }