| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597 | using Aitex.Common.Util;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.ParameterCenter;using Aitex.Core.RT.SCCore;using Aitex.Core.RT.Tolerance;using Aitex.Core.Util;using MECF.Framework.Common.CommonData;using MECF.Framework.Common.Device.Bases;using MECF.Framework.Common.Equipment;using MECF.Framework.Common.Event;using System;using System.Collections.Generic;using System.Diagnostics;using System.IO;using System.Linq;using System.Text;using System.Threading.Tasks;using System.Xml;namespace FurnaceRT.Devices{    public class IoHeater : HeaterBase    {        public IoHeater(string module, XmlElement node, string ioModule = "")        {            base.Module = string.IsNullOrEmpty(node.GetAttribute("module")) ? module : node.GetAttribute("module");            base.Name = node.GetAttribute("id");            base.Display = node.GetAttribute("display");            base.DeviceID = node.GetAttribute("schematicId");            formatString = node.GetAttribute("formatString");            InstallZone = node.GetAttribute("installzone");            _uniqueName = $"{Module}{Name}";            _isFloatAioType = !string.IsNullOrEmpty(node.GetAttribute("aioType")) && (node.GetAttribute("aioType") == "float");            _aiCascadePV = ParseAiNode("aiCascadePV", node, ioModule);            _aiHeaterPV = ParseAiNode("aiHeaterPV", node, ioModule);            _aiWorkingOutput = ParseAiNode("aiWorkingOutput", node, ioModule);            _aiOverTemp = ParseAiNode("aiOverTemp", node, ioModule);            _aoCascadeControlModeSetPoint = ParseAoNode("aoCascadeControlModeSetPoint", node, ioModule);            _aoHeaterControlModeSetPoint = ParseAoNode("aoHeaterControlModeSetPoint", node, ioModule);            _aoCascadePID_P = ParseAoNode("aoCascadePID_P", node, ioModule);            _aoCascadePID_I = ParseAoNode("aoCascadePID_I", node, ioModule);            _aoCascadePID_D = ParseAoNode("aoCascadePID_D", node, ioModule);            _aoHeaterPID_P = ParseAoNode("aoHeaterPID_P", node, ioModule);            _aoHeaterPID_I = ParseAoNode("aoHeaterPID_I", node, ioModule);            _aoHeaterPID_D = ParseAoNode("aoHeaterPID_D", node, ioModule);            _aoUpRate = ParseAoNode("aoUpRate", node, ioModule);            _aoDownRate = ParseAoNode("aoDownRate", node, ioModule);            _diCascadePVSBrk = ParseDiNode("diCascadePVSBrk", node, ioModule);            _diHeaterPVSBrk = ParseDiNode("diHeaterPVSBrk", node, ioModule);            _diEnableOutput = ParseDiNode("diEnableOutput", node, ioModule);            _doEnableIn = ParseDoNode("doEnableIn", node, ioModule);            _doAutoManual = ParseDoNode("doAutoManual", node, ioModule);            _doSelect = ParseDoNode("doMainPVSelect", node, ioModule);            _doCascadeMode = ParseDoNode("doCascadeMode", node, ioModule);            _scRoot = node.GetAttribute("scRoot");        }        #region fields        private AIAccessor _aiCascadePV;        private AIAccessor _aiHeaterPV;        private AIAccessor _aiWorkingOutput;        private AIAccessor _aiOverTemp;        private AOAccessor _aoCascadeControlModeSetPoint;        private AOAccessor _aoHeaterControlModeSetPoint;        private AOAccessor _aoCascadePID_P;        private AOAccessor _aoCascadePID_I;        private AOAccessor _aoCascadePID_D;        private AOAccessor _aoHeaterPID_P;        private AOAccessor _aoHeaterPID_I;        private AOAccessor _aoHeaterPID_D;        private AOAccessor _aoUpRate;        private AOAccessor _aoDownRate;        private DIAccessor _diCascadePVSBrk;        private DIAccessor _diHeaterPVSBrk;        private DIAccessor _diEnableOutput;        private DOAccessor _doEnableIn;        private DOAccessor _doAutoManual;        private DOAccessor _doSelect;        private DOAccessor _doCascadeMode;        private string formatString;        private const int physicalMax = 16000;        private ToleranceChecker _toleranceCheckerWarning = new ToleranceChecker();        private ToleranceChecker _toleranceCheckerAlarm = new ToleranceChecker();        //tolerance check        private float _alarmJudgmentRange;        private float _warningJudgmentRange;        private float _alarmJudgmentTime;        private float _warningJudgmentTime;        private float _toleranceJudgmentDelayTime;        private DeviceTimer _toleranceJudgmentDelayTimer = new DeviceTimer();        //stable check        private Stopwatch _stableJudgmentTimer = new Stopwatch();        private float _stableJudgmentTime = 1;        private float _stableMinValue;        private float _stableMaxValue;        private SCConfigItem _scEnableCalibration;        private SCConfigItem _scCalibrationTable;        private SCConfigItem _scRange;        private SCConfigItem _scRampRate;//°C/min        private List<CalibrationItem> _calibrationTable = new List<CalibrationItem>();        private string _previousSetting;        private DeviceTimer _rampTimer = new DeviceTimer();        private double _rampTarget;        private double _rampInitValue;        private int _rampTime;        private DeviceTimer _stableTimer = new DeviceTimer();        private bool _isWarned;        private string _uniqueName;        private float _tempSetpoint = 0.0f;        private string _scRoot;        private bool _isStartRamp = false;        private bool _isFloatAioType = false;        private Dictionary<string, int> _pidTableAssociate;        #region temp correct        private float _profileTemp = 0;        private float _profileCorrect = 0;        private float _profileTCCalib = 0;        private float _cascadeTCCorrect = 0;        public string CurrentCorrectFileName { get; private set; }        public int CurrentCorrectIndex { get; private set; }        private string _writeLog = "";        #endregion        #region temp profile        private float _preheatTime = 0;        private float _checkTime = 0;        private float _checkLimit = 0;        private float _alarmLimit = 0;        private float _totalTime = 0;        private Stopwatch _profileTimer = new Stopwatch();        private Stopwatch _profileStableTimer = new Stopwatch();        public bool IsProfileMode => _profileTimer != null && _profileTimer.IsRunning;        public bool IsProfileSuccess { get; set; }        private R_TRIG _profileTotalTimeoutTrig = new R_TRIG();        private R_TRIG _profileAlarmLimitTrig = new R_TRIG();        private R_TRIG _profileSuccessTrig = new R_TRIG();        private bool _isWait;        private float _waitHigh;        private float _waitLow;        private bool _isInit = false;        private Stopwatch _initTimer = new Stopwatch();        #endregion        #endregion        #region properties        public string InstallZone { get; set; }        public double Range => _scRange.DoubleValue;        public AlarmEventItem AlarmToleranceWarning { get; set; }        public AlarmEventItem AlarmToleranceAlarm { get; set; }        public AlarmEventItem InterlockAlarm { get; set; }        public AlarmEventItem HeaterErrorAlarm { get; set; }        public AlarmEventItem HeaterErrorRecoveryWarning { get; set; }        public AlarmEventItem HeaterStripBreakAlarm { get; set; }        public AlarmEventItem HeaterStripBreakWarning { get; set; }        public bool IsHeaterStripBreak { get; set; }        private RD_TRIG _trigHeaterErrorSignalOn = new RD_TRIG();        public R_TRIG TrigHeaterStripBreakSignalOn = new R_TRIG();        public DeviceTimer HeaterStripBreakTimer = new DeviceTimer();        public string InstallPosition => SC.GetStringValue($"{_scRoot}.Heater.{InstallZone}.{Name}.InstallPosition");        public bool IsError => _diCascadePVSBrk == null || _diHeaterPVSBrk == null ? false : _diCascadePVSBrk.Value || _diHeaterPVSBrk.Value;        public bool IsStable        {            get            {                if (_stableJudgmentTimer.IsRunning)                {                    if (DeviceData.FeedBack < (DeviceData.SetPoint - _stableMinValue) ||                        DeviceData.FeedBack > (DeviceData.SetPoint + _stableMaxValue))                    {                        _stableJudgmentTimer.Restart();                    }                    if (_stableJudgmentTimer.ElapsedMilliseconds >= _stableJudgmentTime * 1000)                    {                        return true;                    }                }                else                {                    _stableJudgmentTimer.Restart();                }                return false;            }        }        public override float TempSetPoint        {            get            {                return _tempSetpoint;            }            set            {                if (_aoCascadeControlModeSetPoint != null && _aoHeaterControlModeSetPoint != null)                {                    if (_isFloatAioType)                    {                        if(ControlMode == 0)                        {                            if (Math.Abs(_aoCascadeControlModeSetPoint.FloatValue - value) > 0.0001)                                _aoCascadeControlModeSetPoint.FloatValue = value;                        }                        else                        {                            if (Math.Abs(_aoHeaterControlModeSetPoint.FloatValue - value) > 0.0001)                                _aoHeaterControlModeSetPoint.FloatValue = value;                        }                    }                }            }        }        public float HeaterPID_P        {            get            {                return _aoHeaterPID_P.FloatValue;            }            set            {                if (Math.Abs(_aoHeaterPID_P.FloatValue - value) > 0.0001)                    _aoHeaterPID_P.FloatValue = value;            }        }        public float HeaterPID_I        {            get            {                return _aoHeaterPID_I.FloatValue;            }            set            {                if (Math.Abs(_aoHeaterPID_I.FloatValue - value) > 0.0001)                    _aoHeaterPID_I.FloatValue = value;            }        }        public float HeaterPID_D        {            get            {                return _aoHeaterPID_D.FloatValue;            }            set            {                if (Math.Abs(_aoHeaterPID_D.FloatValue - value) > 0.0001)                    _aoHeaterPID_D.FloatValue = value;            }        }        public float CascadePID_P        {            get            {                return _aoCascadePID_P.FloatValue;            }            set            {                if (Math.Abs(_aoCascadePID_P.FloatValue - value) > 0.0001)                    _aoCascadePID_P.FloatValue = value;            }        }        public float CascadePID_I        {            get            {                return _aoCascadePID_I.FloatValue;            }            set            {                if (Math.Abs(_aoCascadePID_I.FloatValue - value) > 0.0001)                    _aoCascadePID_I.FloatValue = value;            }        }        public float CascadePID_D        {            get            {                return _aoCascadePID_D.FloatValue;            }            set            {                if (Math.Abs(_aoCascadePID_D.FloatValue - value) > 0.0001)                    _aoCascadePID_D.FloatValue = value;            }        }        public float UpRate        {            get            {                return _aoUpRate.FloatValue;            }            set            {                if (Math.Abs(_aoUpRate.FloatValue - value) > 0.0001)                    _aoUpRate.FloatValue = value;            }        }        public float DownRate        {            get            {                return _aoDownRate.FloatValue;            }            set            {                if (Math.Abs(_aoDownRate.FloatValue - value) > 0.0001)                    _aoDownRate.FloatValue = value;            }        }        public int ControlMode        {            get            {                if (_doSelect != null && _doCascadeMode != null)                {                    if (!_doSelect.Value && !_doCascadeMode.Value)                    {                        // Furnace control                        return 0;                    }                    else if (!_doSelect.Value && _doCascadeMode.Value)                    {                        // Heater control                        return 1;                    }                    else if (_doSelect.Value && _doCascadeMode.Value)                    {                        //Furnace Diect control                        return 2;                    }                }                return 0;            }        }        public override float TempFeedback => (float)(ControlMode == 1 ? (_aiHeaterPV == null ? 0 : _aiHeaterPV.FloatValue - _profileTCCalib) : (_aiCascadePV == null ? 0 : _aiCascadePV.FloatValue - _profileTCCalib));        #endregion        public override bool Initialize()        {            DeviceData = new AITHeaterData()            {                DeviceName = Name,                DeviceSchematicId = DeviceID,                DisplayName = Display,                Module = Module,                               //Scale = SC.GetValue<double>($"{_scRoot}.{Name}.Range"),                Scale = 1200,                Unit = "°C",                //SetPoint = TempSetPoint,                FeedBack = TempFeedback,            };            _pidTableAssociate = new Dictionary<string, int>()            {                { "HeaterU",0 },                { "HeaterCU",1 },                { "HeaterC",2 },                { "HeaterCL",3 },                { "HeaterL",4 },            };            _scEnableCalibration = SC.GetConfigItem($"{_scRoot}.{Name}.EnableCalibration");            _scCalibrationTable = SC.GetConfigItem($"{_scRoot}.{Name}.CalibrationTable");            //_scRange = SC.GetConfigItem($"{_scRoot}.{Name}.Range");            _scRampRate = SC.GetConfigItem($"{_scRoot}.{Name}.RampRate");            //AlarmToleranceWarning = SubscribeAlarm($"{_scRoot}.{Name}.ToleranceWarning", "", ResetWarningChecker, EventLevel.Warning);            //AlarmToleranceAlarm = SubscribeAlarm($"{_scRoot}.{Name}.ToleranceAlarm", "", ResetAlarmChecker);            //AlarmToleranceWarning.Id = SC.ContainsItem($"{_scRoot}.{Name}.ToleranceWarningID") ? SC.GetValue<int>($"{_scRoot}.{Name}.ToleranceWarningID") : 0;            //AlarmToleranceAlarm.Id = SC.ContainsItem($"{_scRoot}.{Name}.ToleranceAlarmID") ? SC.GetValue<int>($"{_scRoot}.{Name}.ToleranceAlarmID") : 0;            //_stableJudgmentTime = (float)SC.GetValue<double>($"{_scRoot}.{Name}.Stabilize.JudgmentTime");            //_stableMinValue = (float)SC.GetValue<double>($"{_scRoot}.{Name}.Stabilize.MinusValue");            //_stableMaxValue = (float)SC.GetValue<double>($"{_scRoot}.{Name}.Stabilize.PlusValue");            DATA.Subscribe($"{Module}.{Name}.CascadePV", () => (float)DeviceData.CascadePV);            DATA.Subscribe($"{Module}.{Name}.HeaterPV", () => (float)DeviceData.HeaterPV);            DATA.Subscribe($"{Module}.{Name}.CascadePID_P", () => (float)DeviceData.CascadePID_P);            DATA.Subscribe($"{Module}.{Name}.CascadePID_I", () => (float)DeviceData.CascadePID_I);            DATA.Subscribe($"{Module}.{Name}.CascadePID_D", () => (float)DeviceData.CascadePID_D);            DATA.Subscribe($"{Module}.{Name}.HeaterPID_P", () => (float)DeviceData.HeaterPID_P);            DATA.Subscribe($"{Module}.{Name}.HeaterPID_I", () => (float)DeviceData.HeaterPID_I);            DATA.Subscribe($"{Module}.{Name}.HeaterPID_D", () => (float)DeviceData.HeaterPID_D);            DATA.Subscribe($"{Module}.{Name}.CascadeControlModeSV", () => _aoCascadeControlModeSetPoint != null ? _aoCascadeControlModeSetPoint.FloatValue : 0.0f);            DATA.Subscribe($"{Module}.{Name}.HeaterControlModeSV", () => _aoHeaterControlModeSetPoint != null ? _aoHeaterControlModeSetPoint.FloatValue : 0.0f);            DATA.Subscribe($"{Module}.{Name}.UpRate", () => UpRate);            DATA.Subscribe($"{Module}.{Name}.DownRate", () => DownRate);            DATA.Subscribe($"{Module}.{Name}.WorkingOutput", () => _aiWorkingOutput.FloatValue);            DATA.Subscribe($"{Module}.{Name}.OverTemp", () => _aiOverTemp.FloatValue);            DATA.Subscribe($"{Module}.{Name}.IsCascadePVBreak", () => _diCascadePVSBrk.Value);            DATA.Subscribe($"{Module}.{Name}.IsHeaterPVBreak", () => _diHeaterPVSBrk.Value);            DATA.Subscribe($"{Module}.{Name}.IsEnableOutput", () => _diEnableOutput.Value);            DATA.Subscribe($"{Module}.{Name}.IsEnableIn", () => _doEnableIn.Value);            DATA.Subscribe($"{Module}.{Name}.IsAutoManual", () => _doAutoManual.Value);            DATA.Subscribe($"{Module}.{Name}.IsSelect", () => _doSelect.Value);            DATA.Subscribe($"{Module}.{Name}.IsCascadeMode", () => _doCascadeMode.Value);            DATA.Subscribe($"{Module}.{Name}.ControlMode", () => ControlMode);            OP.Subscribe($"{Module}.{Name}.SetRemoteMode", SetRemoteMode);            OP.Subscribe($"{Module}.{Name}.SetAutoTuning", SetAutoTuning);            OP.Subscribe($"{Module}.{Name}.SetOnOff", SetOnOff);            OP.Subscribe($"{Module}.{Name}.SetUpDownRate", (out string reason, int time, object[] param) =>            {                reason = string.Empty;                SetUpDownRate(param);                return true;            });            OP.Subscribe($"{Module}.{Name}.SetManualParameters", (out string reason, int time, object[] param) =>            {                reason = string.Empty;                SetManualParameters(param);                return true;            });            //recipe            OP.Subscribe($"PM1.{Name}.SetParameters", (out string reason, int time, object[] param) =>            {                reason = string.Empty;                SetParameters(param);                return true;            });            _doEnableIn?.SetValue(true, out _);            SetCorrectParameters(SC.GetStringValue("PM1.TempCorrection"));            return base.Initialize();        }        public override void Monitor()        {            if(!string.IsNullOrEmpty(_writeLog))            {                LOG.Write(_writeLog);                _writeLog = "";            }            if (!_isInit)            {                if (!_initTimer.IsRunning)                    _initTimer.Start();                if (_initTimer.ElapsedMilliseconds > 5 * 1000)                {                    _initTimer.Stop();                    _isInit = true;                    if (_tempSetpoint == 0)                    {                        if(ControlMode == 0)                        {                            if(_aoCascadeControlModeSetPoint != null && _aoCascadeControlModeSetPoint.FloatValue > 0)                            {                                _tempSetpoint = _aoCascadeControlModeSetPoint.FloatValue;                            }                        }                        else                        {                            if (_aoCascadeControlModeSetPoint != null && _aoHeaterControlModeSetPoint.FloatValue > 0)                            {                                _tempSetpoint = _aoHeaterControlModeSetPoint.FloatValue;                            }                        }                    }                    SetPIDParameters(SC.GetStringValue("PM1.Heater.PID"));                }            }                        if(DeviceData != null)            {                DeviceData.CascadePID_P = _aoCascadePID_P == null ? 0 : _aoCascadePID_P.FloatValue;                DeviceData.CascadePID_I = _aoCascadePID_I == null ? 0 : _aoCascadePID_I.FloatValue;                DeviceData.CascadePID_D = _aoCascadePID_D == null ? 0 : _aoCascadePID_D.FloatValue;                DeviceData.HeaterPID_P = _aoHeaterPID_P == null ? 0 : _aoHeaterPID_P.FloatValue;                DeviceData.HeaterPID_I = _aoHeaterPID_I == null ? 0 : _aoHeaterPID_I.FloatValue;                DeviceData.HeaterPID_D = _aoHeaterPID_D == null ? 0 : _aoHeaterPID_D.FloatValue;                DeviceData.OverTemp = _aiOverTemp == null ? 0 : _aiOverTemp.FloatValue;                DeviceData.CascadePV = _aiCascadePV == null ? 0 : _aiCascadePV.FloatValue;                DeviceData.HeaterPV = _aiHeaterPV == null ? 0 : _aiHeaterPV.FloatValue;                DeviceData.FeedBack = TempFeedback;                DeviceData.SetPoint = _tempSetpoint;                DeviceData.ManipulatedVariable = _aiWorkingOutput == null ? 0 : _aiWorkingOutput.FloatValue;                DeviceData.RampSetPoint = TempSetPoint;//Ramp的过程值                DeviceData.Ramping = _aoUpRate == null ? 0 : _aoUpRate.FloatValue;                DeviceData.ControlMode = ControlMode;// 控制模式                DeviceData.IsAlarm = IsError;                DeviceData.UpRateSetPoint = UpRate;                DeviceData.DownRateSetPoint = DownRate;                DeviceData.EnableOutput = _diEnableOutput.Value;                DeviceData.IsCascadePVBreak = _diCascadePVSBrk.Value;                DeviceData.IsHeaterPVBreak = _diHeaterPVSBrk.Value;                DeviceData.IsProfiling = IsProfileMode;                if(_profileTimer != null && _profileTimer.IsRunning)                {                    DeviceData.ProfileTotalTime = _totalTime - _profileTimer.ElapsedMilliseconds / 1000 > 0 ? _totalTime - _profileTimer.ElapsedMilliseconds / 1000 : 0;                    DeviceData.ProfilePreheatTime = _preheatTime - _profileTimer.ElapsedMilliseconds / 1000 > 0 ? _preheatTime - _profileTimer.ElapsedMilliseconds / 1000 : 0;                }                if(_profileStableTimer != null && _profileStableTimer.IsRunning)                {                    DeviceData.ProfileCheckTime = _checkTime - _profileStableTimer.ElapsedMilliseconds / 1000 > 0 ? _checkTime - _profileStableTimer.ElapsedMilliseconds / 1000 : 0;                }            }                       MonitorTolerance();            Ramping();            base.Monitor();        }        public override void SetTemperature(float temperature)        {            //if (temperature != SetpointFeedback)            {                var _rampTime = _scRampRate.DoubleValue != 0 ? (Math.Abs(temperature - TempFeedback) / _scRampRate.DoubleValue) * 60 * 1000 : 0;                Ramp(temperature, (int)_rampTime);            }        }        public void SetRamping(float ramping)        {            SaveRampRate(ramping.ToString("F1"));        }        private void SetManualParameters(object[] param)        {            //value:ramp            if (param == null || param.Length < 1)            {                EV.PostWarningLog(ModuleName.PM1.ToString(), $"Invalid heater temperature set parameter");                return;            }            var array = param[0].ToString().Split(';');            if (array == null || array.Length < 2)            {                EV.PostWarningLog(ModuleName.PM1.ToString(), $"Invalid heater temperature set parameter");                return;            }            float.TryParse(array[0], out float temperature);            float.TryParse(array[1], out float rampTime);//°C/min            DeviceData.SetPoint = temperature;            DeviceData.RampSetPoint = rampTime;            var profileCorrect = 0.0f;            var profileTCCalib = 0.0f;            //var actualSet = temperature - profileCorrect < 0 ? 0 : temperature - profileCorrect;            var actualSet = temperature + _profileTCCalib;//加上flat zone的值              UpRate = rampTime;            DownRate = rampTime;            var controlMode = "";            if (array.Length > 2)            {                controlMode = array.Length > 2 ? array[2].ToString() : "";                SetControlMode(controlMode);            }            _tempSetpoint = temperature;            TempSetPoint = actualSet;            LOG.Write($"{Name} setpoint={temperature} control mode={controlMode}");            //Ramp(actualSet, (int)rampTime);        }        public void SetControlMode(string mode, string recipeProfileFileName = "")        {            var reason = "";            DeviceData.ControlModeSetpoint = mode;            switch(mode.ToLower())            {                case "heater":                case "heater control":                    if(_doSelect.Value)                        _doSelect.SetValue(false, out reason);                    if (!_doCascadeMode.Value)                        _doCascadeMode.SetValue(true, out reason);                    break;                case "furnace":                case "furnace control":                    if (_doSelect.Value)                        _doSelect.SetValue(false, out reason);                    if (_doCascadeMode.Value)                        _doCascadeMode.SetValue(false, out reason);                    break;                case "furnace direct":                case "furnace direct control":                    if (!_doSelect.Value)                        _doSelect.SetValue(true, out reason);                    if (!_doCascadeMode.Value)                        _doCascadeMode.SetValue(true, out reason);                    break;                default:                    if(mode.ToLower().StartsWith("profile"))                    {                        var arry = mode.Replace(")","").Split('(');                        if(arry != null && arry.Length > 1)                        {                            var profileArray = arry[1].Split(',');                            if(profileArray != null && profileArray.Length > 2)                            {                                var profileFileName = profileArray[0];                                int.TryParse(profileArray[1], out int profileTableIndex);                                GetProfileParameters(profileFileName, profileTableIndex, recipeProfileFileName);                                _profileTimer.Restart();                                _profileStableTimer.Stop();                                _profileTotalTimeoutTrig.RST = true;                                _profileAlarmLimitTrig.RST = true;                                _profileSuccessTrig.RST = true;                                IsProfileSuccess = false;                                DeviceData.ProfileResult = 0;                                LOG.Write($"{Name} profile start preheatTime={_preheatTime} checkTime={_checkTime} totalTime={_totalTime} checkLimit={_checkLimit} alarmLimit={_alarmLimit}");                            }                        }                    }                    break;            }        }        private void SetUpDownRate(object[] param)        {        }        public void SetParameters(object[] param)        {            if (param != null && param.Length > 0)            {                string zoneName = "";                float temperature = 0.0f;                string tempUnit = "";                float ramp = 0.0f;                string rampUnit = "";                string controlMode = "";                string correct = "";                string PID = "";                var array = param[0].ToString().Split(';');//zoneName;temp;tempUnit;ramp;rampUnit;checkWait;tempHigh;tempLow;unitStepCompletionCondition;controlMode;correct;PID                if (System.Text.RegularExpressions.Regex.Match(array[1].ToString(), @"[a-zA-Z]").Success)                {                    var table = array[1].ToString().Split(':');//AssociateParameterTable                    if (SC.ContainsItem($"PM1.RecipeEditParameter.TempSetting.{table[0]}.{Name}"))                    {                        temperature = (float)SC.GetValue<double>($"PM1.RecipeEditParameter.TempSetting.{table[0]}.{Name}");                    }                }                else                {                    float.TryParse(array[1].ToString(), out temperature);                }                tempUnit = array.Length > 2 ? array[2].ToString() : "";                if (array.Length > 3)                {                    float.TryParse(array[3], out ramp);                }                rampUnit = array.Length > 4 ? array[4].ToString() : "";                if (array.Length > 5)                {                    bool.TryParse(array[5], out _isWait);                }                if (array.Length > 6)                {                    float.TryParse(array[6], out _waitHigh);                }                if (array.Length > 7)                {                    float.TryParse(array[7], out _waitLow);                }                var unitStepCompletionCondition = array.Length > 8 ? array[8].ToString() : "";                _stableJudgmentTimer.Stop();                controlMode = array.Length > 9 ? array[9].ToString() : "";                correct = array.Length > 10 ? array[10].ToString() : "";                PID = array.Length > 11 ? array[11].ToString() : "";                var correctileName = array.Length > 12 ? array[12].ToString() : "";                var PIDFileName = array.Length > 13 ? array[13].ToString() : "";                var profileFileName = array.Length > 14 ? array[14].ToString() : "";                var DPR = array.Length > 16 ? (array[15].ToString().ToLower() == "open" ? true : false) : false;                var BWR = array.Length > 16 ? (array[15].ToString().ToLower() == "open" ? true : false) : false;                SetControlMode(controlMode, profileFileName);                SetPIDParameters(PID, PIDFileName);                SetCorrectParameters(correct, correctileName, profileFileName);                var profileCorrect = 0.0f;                var profileTCCalib = 0.0f;                //var actualSet = temperature - profileCorrect < 0 ? 0 : temperature - profileCorrect;                var actualSet = temperature + _profileTCCalib;//加上flat zone的值                  float _rampTime = 0;                if(DPR && BWR)                {                    DownRate = 0;                    UpRate = 0;                }                else                {                    if (ramp == 0)                    {                        DownRate = Math.Abs(TempFeedback - actualSet);//单位是°C/min                        UpRate = Math.Abs(TempFeedback - actualSet);//单位是°C/min                    }                    else if (rampUnit.ToLower() == "time")                    {                        DownRate = Math.Abs(TempFeedback - actualSet) / ramp;//单位是°C/min                        UpRate = Math.Abs(TempFeedback - actualSet) / ramp;//单位是°C/min                    }                    else                    {                        DownRate = ramp;//单位是°C/min                        UpRate = ramp;//单位是°C/min                    }                }                               DeviceData.SetPoint = temperature;                DeviceData.RampSetPoint = _rampTime;                _tempSetpoint = temperature;                TempSetPoint = actualSet;                //LOG.Write($"{Name} setpoint={temperature} control mode={controlMode}, PID={PID}, correct={correct}");                _writeLog = $"{Name} setpoint={temperature} control mode={controlMode}, PID={PID}, correct={correct}";                //Ramp(actualSet, (int)_rampTime);            }            return;        }        private bool SetRemoteMode(out string reason, int time, params object[] param)        {            reason = string.Empty;            if (param == null || param.Length == 0)            {                reason = $"invalid parameter";                return false;            }            bool.TryParse(param[0].ToString(), out bool isRemoteMode);            //_doRemoteControl.SetValue(isRemoteMode, out _);            return true;        }        private bool SetOnOff(out string reason, int time, params object[] param)        {            reason = string.Empty;            if (param == null || param.Length == 0)            {                reason = $"invalid parameter";                return false;            }            bool.TryParse(param[0].ToString(), out bool isOn);            //if (!_doStartHeating.Check(isOn, out reason))            //{            //    return false;            //}            //return _doStartHeating.SetValue(isOn, out reason);            return true;        }        public void SetRun(bool isOn)        {            //_doStartHeating.SetValue(isOn, out _);            EV.PostInfoLog(Name, $"{Name}.SetRun({isOn})");        }        public void SetRemote(bool isRemote)        {            //_doRemoteControl.SetValue(isRemote, out _);        }        private bool SetAutoTuning(out string reason, int time, params object[] param)        {            reason = string.Empty;            if (param == null || param.Length == 0)            {                reason = $"invalid parameter";                return false;            }            bool.TryParse(param[0].ToString(), out bool isAutoSetAutoTuning);            if (isAutoSetAutoTuning)            {                //_doCanWritePara.SetPulseValue(true, 2000);                //_doStopAutoTunningMode.SetValue(false, out _);                //_doStartAutoTunningMode.SetPulseValue(true, 2000);            }            else            {                //_doCanWritePara.SetPulseValue(true, 2000);                //_doStartAutoTunningMode.SetValue(false, out _);                //_doStopAutoTunningMode.SetPulseValue(true, 2000);            }            return true;        }        public override void Terminate()        {            ProfileFinish();            base.Terminate();        }        public void ProfileFinish()        {            _profileTimer.Stop();            _profileStableTimer.Stop();            _profileTotalTimeoutTrig.RST = true;            _profileAlarmLimitTrig.RST = true;            _profileSuccessTrig.RST = true;            IsProfileSuccess = false;            DeviceData.ProfileTable = "";            DeviceData.ProfileTotalTime = 0;            DeviceData.ProfilePreheatTime = 0;            DeviceData.ProfileCheckTime = 0;            DeviceData.ProfileAlarmLimit = 0;            DeviceData.ProfileCheckLimit = 0;        }        public bool SetEnable(bool isEnable)        {            return _doEnableIn.SetValue(isEnable, out _);        }                public bool ResetWarningChecker()        {            _toleranceCheckerWarning.Reset(_warningJudgmentTime);            return true;        }        public bool ResetAlarmChecker()        {            _toleranceCheckerAlarm.Reset(_alarmJudgmentTime);            return true;        }        public override void Reset()        {            AlarmToleranceWarning?.Reset();            AlarmToleranceAlarm?.Reset();            _toleranceJudgmentDelayTimer?.Stop();        }        public void ResetHeaterError()        {            _trigHeaterErrorSignalOn.RST = true;            if (HeaterErrorAlarm != null)                HeaterErrorAlarm.IsAcknowledged = true;        }        public void ResetHeaterStripBreak()        {            TrigHeaterStripBreakSignalOn.RST = true;            if (HeaterStripBreakAlarm != null)                HeaterStripBreakAlarm.IsAcknowledged = true;        }        private void MonitorTolerance()        {            if (IsHeaterStripBreak || TempSetPoint < 0.001 || _toleranceJudgmentDelayTimer.IsIdle() || _toleranceJudgmentDelayTimer.GetElapseTime() < _toleranceJudgmentDelayTime * 1000)            {                _toleranceCheckerWarning.RST = true;                _toleranceCheckerAlarm.RST = true;                return;            }            if (_alarmJudgmentRange != 0 && _alarmJudgmentTime > 0)            {                _toleranceCheckerAlarm.Monitor(DeviceData.FeedBack, DeviceData.RampSetPoint - Math.Abs(_alarmJudgmentRange), DeviceData.RampSetPoint + Math.Abs(_alarmJudgmentRange), _alarmJudgmentTime);            }            if (_warningJudgmentRange != 0 && _warningJudgmentTime > 0)            {                _toleranceCheckerWarning.Monitor(DeviceData.FeedBack, DeviceData.RampSetPoint - Math.Abs(_warningJudgmentRange), DeviceData.RampSetPoint + Math.Abs(_warningJudgmentRange), _warningJudgmentTime);            }        }        public override bool CheckToleranceAlarm()        {            return _toleranceCheckerAlarm.Result;        }        public override bool CheckToleranceWarning()        {            return _toleranceCheckerWarning.Result;        }        public void SetToleranceAlarm()        {            AlarmToleranceAlarm.Description = $"{Display} temperature out of range {_alarmJudgmentRange} °C in {_alarmJudgmentTime:F0} seconds";            AlarmToleranceAlarm.Set();        }        public void SetToleranceWarning()        {            AlarmToleranceWarning.Description = $"{Display} temperature out of range {_warningJudgmentRange} °C in {_warningJudgmentTime:F0} seconds";            AlarmToleranceWarning.Set();        }        public void Ramp(double target, int time)        {            target = Math.Max(0, target);            //target = Math.Min(Range, target);            _rampInitValue = TempFeedback;    //ramp 初始值取当前设定值,而非实际读取值.零漂问题            _rampTime = time;            _rampTarget = target;            _rampTimer.Start(_rampTime);            _isStartRamp = true;        }        private void Ramping()        {            //只有修改了温度,才开始ramp,避免一开机温度设定值大于0的问题。            if (!_isStartRamp)                return;            if (_rampTimer.IsTimeout() || _rampTime == 0)            {                TempSetPoint = (float)_rampTarget;            }            else            {                TempSetPoint = (float)(_rampInitValue + (_rampTarget - _rampInitValue) * _rampTimer.GetElapseTime() / _rampTime);            }        }        private void SaveRampRate(string ramping)        {            SC.SetItemValueFromString($"{_scRoot}.{Name}.RampRate", ramping);        }        public void SetCorrectParameters(string name, string recipeCorrectFileName = null, string recipeProfileFileName = null)        {            //"Heater;Parameter\\TempCorrection\\tempCorrect,2,Name2;Parameter\\TempPID\\tempPID,3,Name3"            //var defaultPID = SC.GetStringValue("PM1.APCPID");            if (string.IsNullOrEmpty(name))            {                //EV.PostWarningLog(ModuleName.PM1.ToString(), $"Heater temperature correct file is empty");                name = SC.GetStringValue("PM1.TempCorrection");            }            var array = name.Split(',');            if (array == null || array.Length < 2)            {                //EV.PostWarningLog(ModuleName.PM1.ToString(), $"Invalid heater temperature correct parameter");                name = SC.GetStringValue("PM1.TempCorrection");                array = name.Split(',');            }            if (!File.Exists($"{PathManager.GetParameterDir()}\\{array[0]}.rcp"))            {                name = SC.GetStringValue("PM1.TempCorrection");                var temp = name.Split(',');                if (temp != null && array.Length > 0)                {                    array[0] = temp[0];                    name = string.Join(",", array);                }            }            if (array == null || array.Length < 2)            {                return;            }            var fileNameAndPath = array[0];            int.TryParse(array[1], out int index);            var para = fileNameAndPath.Split('\\').ToList().Skip(2);//"Parameter\\TempCorrection"            if (para == null)            {                //EV.PostWarningLog(ModuleName.PM1.ToString(), $"Heater temperature correct file is empty");                return;            }            var fileName = string.Join("\\", para.ToArray());            if (!string.IsNullOrEmpty(recipeCorrectFileName))                fileName = recipeCorrectFileName;                        CurrentCorrectFileName = fileName;            CurrentCorrectIndex = index;            var content = ParameterFileManager.Instance.LoadParameter("Parameter\\TempCorrection", fileName, false);            if (string.IsNullOrEmpty(content))            {                //EV.PostWarningLog(ModuleName.PM1.ToString(), $"{fileNameAndPath} heater temperature correct file is empty");                return;            }            var doc = new XmlDocument();            doc.LoadXml(content);            XmlNodeList nodeSteps = doc.SelectNodes($"Aitex/TableParameterData/Module[@Name='']/Step");            if (nodeSteps == null)                nodeSteps = doc.SelectNodes($"Aitex/TableParameterData/Step");            if (nodeSteps == null)            {                EV.PostWarningLog(ModuleName.PM1.ToString(), $"Invalid heater temperature correct file {fileNameAndPath}");                return;            }            Dictionary<int, CorrectTableParameter> dic = new Dictionary<int, CorrectTableParameter>();            for(int i= 0;i < nodeSteps.Count;i++)            {                var step = nodeSteps[i];                XmlElement stepNode = step as XmlElement;                var correctTableParameter = new CorrectTableParameter();                correctTableParameter.CorrectParameterLst = new List<CorrectParameter>();                int tableIndex = i + 1;                foreach (XmlAttribute att in stepNode.Attributes)                {                    switch (att.Name.ToLower())                    {                        case "index":                            int.TryParse(att.Value, out int no);                            correctTableParameter.No = no;                            break;                        case "name":                            correctTableParameter.Name = att.Value;                            break;                        case "tableuserangemax":                            float.TryParse(att.Value, out float tableuserangemax);                            correctTableParameter.TableUseRangeMax = tableuserangemax;                            break;                        case "tableuserangemin":                            float.TryParse(att.Value, out float tableuserangemin);                            correctTableParameter.TableUseRangeMin = tableuserangemin;                            break;                        case "profileconditiontableno":                            int.TryParse(att.Value, out int profileconditiontableno);                            correctTableParameter.ProfileConditionTableNo = profileconditiontableno;                            break;                        case "pemppidtableno":                            int.TryParse(att.Value, out int pemppidtableno);                            correctTableParameter.TempPIDTableNo = pemppidtableno;                            break;                        case "profiletccalibtemp":                            float.TryParse(att.Value, out float profiletccalibtemp);                            correctTableParameter.ProfileTCCalibTemp = profiletccalibtemp;                            break;                    }                    if (att.Name.ToLower() == "correctiondata" && !dic.ContainsKey(tableIndex))                    {                        //"Index:1;Name:U;ProfileTemp:0;ProfileCorrect:0;CascadeTCCorrect:0;ProfileTCCalib:0|Index:2;Name:CU;ProfileTemp:0;ProfileCorrect:0;CascadeTCCorrect:0;ProfileTCCalib:0|Index:3;Name:C;ProfileTemp:0;ProfileCorrect:0;CascadeTCCorrect:0;ProfileTCCalib:0|Index:4;Name:CL;ProfileTemp:0;ProfileCorrect:0;CascadeTCCorrect:0;ProfileTCCalib:0|Index:5;Name:L;ProfileTemp:0;ProfileCorrect:0;CascadeTCCorrect:0;ProfileTCCalib:0"                        var correctionDataString = att.Value;                        if (string.IsNullOrEmpty(correctionDataString))                        {                            //EV.PostWarningLog(ModuleName.PM1.ToString(), $"Heater temperature correct file is empty");                            return;                        }                        var correctionDatas = correctionDataString.Split('|');                        if (correctionDatas.Length < 5)                        {                            EV.PostWarningLog(ModuleName.PM1.ToString(), $"Heater temperature correct file data length is invalid");                            return;                        }                        foreach (var datas in correctionDatas)                        {                            var dataArry = datas.Split(';');                            if (dataArry.Length < 6)                            {                                EV.PostWarningLog(ModuleName.PM1.ToString(), $"Heater temperature correct file data length is invalid");                                return;                            }                            var correctParameter = new CorrectParameter();                            foreach (var item in dataArry)                            {                                var itemArry = item.Split(':');                                if (itemArry.Length < 2)                                {                                    EV.PostWarningLog(ModuleName.PM1.ToString(), $"Heater temperature correct file data length is invalid");                                    return;                                }                                switch (itemArry[0].ToLower())                                {                                    case "index":                                        int.TryParse(itemArry[1], out int no);                                        correctParameter.No = no;                                        break;                                    case "name":                                        correctParameter.Name = itemArry[1];                                        break;                                    case "profiletemp":                                        float.TryParse(itemArry[1], out float profiletemp);                                        correctParameter.ProfileTemp = profiletemp;                                        break;                                    case "profilecorrect":                                        float.TryParse(itemArry[1], out float profilecorrect);                                        correctParameter.ProfileCorrect = profilecorrect;                                        break;                                    case "cascadetccorrect":                                        float.TryParse(itemArry[1], out float cascadetccorrect);                                        correctParameter.CascadeTCCorrect = cascadetccorrect;                                        break;                                    case "profiletccalib":                                        float.TryParse(itemArry[1], out float profiletccalib);                                        correctParameter.ProfileTCCalib = profiletccalib;                                        break;                                }                            }                            correctTableParameter.CorrectParameterLst.Add(correctParameter);                        }                        break;                    }                }                dic.Add(tableIndex, correctTableParameter);            }            if(dic.ContainsKey(index))            {                var item = dic[index];                var heaterIndex = GetHeaterIndex() - 1;//U的index是0                if(item.CorrectParameterLst.Count > heaterIndex)                {                    _profileTemp = item.CorrectParameterLst[heaterIndex].ProfileTemp;                    _profileCorrect = item.CorrectParameterLst[heaterIndex].ProfileCorrect;                    _profileTCCalib = item.CorrectParameterLst[heaterIndex].ProfileTCCalib;                    _cascadeTCCorrect = item.CorrectParameterLst[heaterIndex].CascadeTCCorrect;                                  }                else                {                    _profileTemp = 0;                    _profileCorrect = 0;                    _profileTCCalib = 0;                    _cascadeTCCorrect = 0;                }                GetProfileParameters(SC.GetStringValue("PM1.TempProfile"), item.ProfileConditionTableNo, recipeProfileFileName);            }            else            {                _profileTemp = 0;                _profileCorrect = 0;                _profileTCCalib = 0;                _cascadeTCCorrect = 0;                //auto select            }            var temperature = DeviceData.SetPoint;            var actualSet = temperature + _profileTCCalib;            if(temperature > 0)                TempSetPoint = (float)actualSet;            DeviceData.CorrectTable = name;            if (SC.GetStringValue("PM1.TempCorrection") != name)                SC.SetItemValueFromString("PM1.TempCorrection", name);        }        public void SetPIDParameters(string name, string recipePIDFileName = null)        {            //"Heater;Parameter\\TempCorrection\\tempCorrect,2,Name2;Parameter\\TempPID\\tempPID,3,Name3"            //var defaultPID = SC.GetStringValue("PM1.APCPID");            if (string.IsNullOrEmpty(name))            {                //EV.PostWarningLog(ModuleName.PM1.ToString(), $"Heater temperature PID file is empty");                return;            }            var array = name.Split(',');            if (array == null || array.Length < 2)            {                //EV.PostWarningLog(ModuleName.PM1.ToString(), $"Invalid heater temperature PID parameter");                return;            }            if (!File.Exists($"{PathManager.GetParameterDir()}\\{array[0]}.rcp"))                return;            var fileNameAndPath = array[0];            int.TryParse(array[1], out int index);            var para = fileNameAndPath.Split('\\').ToList().Skip(2);//"Parameter\\TempPID"            if (para == null)            {                //EV.PostWarningLog(ModuleName.PM1.ToString(), $"Heater temperature PID file is empty");                return;            }            var fileName = string.Join("\\", para.ToArray());            if (!string.IsNullOrEmpty(recipePIDFileName))                fileName = recipePIDFileName;            var content = ParameterFileManager.Instance.LoadParameter("Parameter\\TempPID", fileName, false);            if (string.IsNullOrEmpty(content))            {                //EV.PostWarningLog(ModuleName.PM1.ToString(), $"{fileNameAndPath} heater temperature PID file is empty");                return;            }            var doc = new XmlDocument();            doc.LoadXml(content);            XmlNodeList nodeSteps = doc.SelectNodes($"Aitex/TableParameterData/Module[@Name='']/Step");            if (nodeSteps == null)                nodeSteps = doc.SelectNodes($"Aitex/TableParameterData/Step");            if (nodeSteps == null)            {                EV.PostWarningLog(ModuleName.PM1.ToString(), $"Invalid heater temperature PID file {fileNameAndPath}");                return;            }            Dictionary<int, List<PIDParameter>> dic = new Dictionary<int, List<PIDParameter>>();            for (int i = 0; i < nodeSteps.Count; i++)            {                var step = nodeSteps[i];                XmlElement stepNode = step as XmlElement;                var pidParameters = new List<PIDParameter>();                int tableIndex = i + 1;                foreach (XmlAttribute att in stepNode.Attributes)                {                    if (att.Name == "PIDData" && !dic.ContainsKey(tableIndex))                    {                        //"Index:1;Name:HT.U;P:11.5;I:12;D:13|Index:2;Name:HTCU;P:21.5;I:22;D:23|Index:3;Name:HT.C;P:31.5;I:32;D:33|Index:4;Name:HTCL;P:41.5;I:42;D:43|Index:5;Name:HT.L;P:51.5;I:52;D:53|Index:6;Name:PR.U;P:0.5;I:10;D:0|Index:7;Name:PRCU;P:0.5;I:10;D:0|Index:8;Name:PR.C;P:0.5;I:10;D:0|Index:9;Name:PRCL;P:0.5;I:10;D:0|Index:10;Name:PR.L;P:0.5;I:10;D:0"                        var PIDDataString = att.Value;                        if (string.IsNullOrEmpty(PIDDataString))                        {                            //EV.PostWarningLog(ModuleName.PM1.ToString(), $"Heater temperature PID file is empty");                            return;                        }                        var pidDatas = PIDDataString.Split('|');                        if (pidDatas.Length < 5)                        {                            EV.PostWarningLog(ModuleName.PM1.ToString(), $"Heater temperature PID file data length is invalid");                            return;                        }                        foreach (var datas in pidDatas)                        {                            var dataArry = datas.Split(';');                            if (dataArry.Length < 5)                            {                                EV.PostWarningLog(ModuleName.PM1.ToString(), $"Heater temperature PID file data length is invalid");                                return;                            }                            var pidParameter = new PIDParameter();                            foreach (var item in dataArry)                            {                                var itemArry = item.Split(':');                                if (itemArry.Length < 2)                                {                                    EV.PostWarningLog(ModuleName.PM1.ToString(), $"Heater temperature PID file data length is invalid");                                    return;                                }                                switch (itemArry[0].ToLower())                                {                                    case "index":                                        int.TryParse(itemArry[1], out int no);                                        pidParameter.No = no;                                        break;                                    case "name":                                        pidParameter.Name = itemArry[1];                                        break;                                    case "p":                                        float.TryParse(itemArry[1], out float p);                                        pidParameter.P = p;                                        break;                                    case "i":                                        float.TryParse(itemArry[1], out float ii);                                        pidParameter.I = ii;                                        break;                                    case "d":                                        float.TryParse(itemArry[1], out float d);                                        pidParameter.D = d;                                        break;                                }                            }                            pidParameters.Add(pidParameter);                        }                        break;                    }                }                dic.Add(tableIndex, pidParameters);            }            if (dic.ContainsKey(index))            {                var item = dic[index];                if (_pidTableAssociate.ContainsKey(Name) && item.Count > _pidTableAssociate[Name] + 5)                {                    HeaterPID_P = item[_pidTableAssociate[Name]].P;                    HeaterPID_I = item[_pidTableAssociate[Name]].I;                    HeaterPID_D = item[_pidTableAssociate[Name]].D;                    CascadePID_P = item[_pidTableAssociate[Name] + 5].P;                    CascadePID_I = item[_pidTableAssociate[Name] + 5].I;                    CascadePID_D = item[_pidTableAssociate[Name] + 5].D;                }            }            else            {                //auto select            }            if (SC.GetStringValue("PM1.Heater.PID") != name)                SC.SetItemValueFromString("PM1.Heater.PID", name);            DeviceData.PIDTable = name;        }        public void GetProfileParameters(string fileNameAndPath, int index, string recipeProfileFileName = null)        {            //"Heater;Parameter\\TempCorrection\\tempCorrect,2,Name2;Parameter\\TempPID\\tempPID,3,Name3"            if (string.IsNullOrEmpty(fileNameAndPath))            {                DeviceData.ProfileTable = "";                //EV.PostWarningLog(ModuleName.PM1.ToString(), $"Heater temperature Profile file is empty");                return;            }            if (!File.Exists($"{PathManager.GetParameterDir()}\\{fileNameAndPath}.rcp"))                return;            var para = fileNameAndPath.Split('\\').ToList().Skip(2);//"Parameter\\TempPID"            if (para == null)            {                DeviceData.ProfileTable = "";                //EV.PostWarningLog(ModuleName.PM1.ToString(), $"Heater temperature Profile file is empty");                return;            }            var fileName = string.Join("\\", para.ToArray());            if (!string.IsNullOrEmpty(recipeProfileFileName))                fileName = recipeProfileFileName;            var content = ParameterFileManager.Instance.LoadParameter("Parameter\\TempProfile", fileName, false);            if (string.IsNullOrEmpty(content))            {                DeviceData.ProfileTable = "";                //EV.PostWarningLog(ModuleName.PM1.ToString(), $"{fileNameAndPath} heater temperature Profile file is empty");                return;            }            var doc = new XmlDocument();            doc.LoadXml(content);            XmlNodeList nodeSteps = doc.SelectNodes($"Aitex/TableParameterData/Module[@Name='']/Step");            if (nodeSteps == null)                nodeSteps = doc.SelectNodes($"Aitex/TableParameterData/Step");            if (nodeSteps == null)            {                DeviceData.ProfileTable = "";                EV.PostWarningLog(ModuleName.PM1.ToString(), $"Invalid heater temperature Profile file {fileNameAndPath}");                return;            }            Dictionary<int, ProfileParameter> dic = new Dictionary<int, ProfileParameter>();            for (int i = 0; i < nodeSteps.Count; i++)            {                var step = nodeSteps[i];                XmlElement stepNode = step as XmlElement;                var profileParameter = new ProfileParameter();                int tableIndex = i + 1;                foreach (XmlAttribute att in stepNode.Attributes)                {                    switch (att.Name.ToLower())                    {                        case "index":                            int.TryParse(att.Value, out int no);                            profileParameter.No = no;                            break;                        case "name":                            profileParameter.Name = att.Value;                            break;                        case "preheattime":                            float.TryParse(att.Value, out float preheattime);                            profileParameter.PreheatTime = preheattime;                            break;                        case "checktime":                            float.TryParse(att.Value, out float checktime);                            profileParameter.CheckTime = checktime;                            break;                        case "totaltime":                            int.TryParse(att.Value, out int totaltime);                            profileParameter.TotalTime = totaltime;                            break;                        case "alarmlimit":                            int.TryParse(att.Value, out int alarmlimit);                            profileParameter.AlarmLimit = alarmlimit;                            break;                        case "u":                            float.TryParse(att.Value, out float u);                            profileParameter.U = u;                            break;                        case "cu":                            float.TryParse(att.Value, out float cu);                            profileParameter.CU = cu;                            break;                        case "c":                            float.TryParse(att.Value, out float c);                            profileParameter.C = c;                            break;                        case "cl":                            float.TryParse(att.Value, out float cl);                            profileParameter.CL = cl;                            break;                        case "l":                            float.TryParse(att.Value, out float l);                            profileParameter.L = l;                            break;                    }                }                dic.Add(tableIndex, profileParameter);            }            if (dic.ContainsKey(index))            {                var item = dic[index];                _preheatTime = item.PreheatTime;                _checkTime = item.CheckTime;                _alarmLimit = item.AlarmLimit;                _totalTime = item.TotalTime;                DeviceData.ProfileTable = $"{fileNameAndPath},{index},{item.Name}";                switch (Name)                {                    case "HeaterU":                        _checkLimit = item.U;                        break;                    case "HeaterCU":                        _checkLimit = item.CU;                        break;                    case "HeaterC":                        _checkLimit = item.C;                        break;                    case "HeaterCL":                        _checkLimit = item.CL;                        break;                    case "HeaterL":                        _checkLimit = item.L;                        break;                }                DeviceData.ProfileTotalTime = _totalTime;                DeviceData.ProfilePreheatTime = _preheatTime;                DeviceData.ProfileCheckTime = _checkTime;                DeviceData.ProfileAlarmLimit = _alarmLimit;                DeviceData.ProfileCheckLimit = _checkLimit;                DeviceData.ProfileStatus = "PreHeat";            }            else            {                _checkLimit = 0;                _preheatTime = 0;                _checkTime = 0;                _alarmLimit = 0;                _totalTime = 0;                DeviceData.ProfileTable = "";                DeviceData.ProfileTotalTime = 0;                DeviceData.ProfilePreheatTime = 0;                DeviceData.ProfileCheckTime = 0;                DeviceData.ProfileAlarmLimit = 0;                DeviceData.ProfileCheckLimit = 0;            }        }        public bool CheckProfileFinish(out string reason)        {            reason = "";            if (_profileTimer != null && _profileTimer.IsRunning)            {                _profileTotalTimeoutTrig.CLK = _profileTimer.ElapsedMilliseconds >= _totalTime * 1000;                if (_profileTotalTimeoutTrig.Q)                {                    LOG.Write($"{Name} profile timeout={_totalTime}");                    EV.PostWarningLog(ModuleName.PM1.ToString(), $"{Name} profile timeout={_totalTime}");//超过total time之后,只是报warning提示                }                if (_profileTimer.ElapsedMilliseconds >= _preheatTime * 1000)//preheat time之后,才开始判断                {                    DeviceData.ProfileStatus = "Profile Check";                    if (_profileStableTimer != null)                    {                        if (!_profileStableTimer.IsRunning)                            _profileStableTimer.Restart();                        if(Math.Abs(TempFeedback - TempSetPoint)  > _checkLimit)                            _profileStableTimer.Restart();                                     _profileAlarmLimitTrig.CLK = Math.Abs(TempFeedback - TempSetPoint) > _alarmLimit && _alarmLimit > 0;                        if (_profileAlarmLimitTrig.Q)                            EV.PostWarningLog(ModuleName.PM1.ToString(), $"{Name} profile success setpoint={TempSetPoint} feedback={TempFeedback}, difference={Math.Abs(TempFeedback - TempSetPoint)} is more than alarm limit={_alarmLimit}");                        _profileSuccessTrig.CLK = _profileStableTimer.ElapsedMilliseconds > _checkTime * 1000;                        if (_profileStableTimer.ElapsedMilliseconds > _checkTime * 1000)                        {                            IsProfileSuccess = true;                            if(_profileSuccessTrig.Q)                                LOG.Write($"{Name} profile success setpoint={TempSetPoint} feedback={TempFeedback}");                            return true;                        }                    }                }                reason = $"{Name} profile not finish";                return false;            }            else            {                return true;            }        }        private int GetHeaterIndex()        {            int.TryParse(Name.Replace("Heater", ""), out int heaterIndex);//改了heater数量这边需要改            switch (Name)            {                case "HeaterU":                    heaterIndex = 1;                    break;                case "HeaterCU":                    heaterIndex = 2;                    break;                case "HeaterC":                    heaterIndex = 3;                    break;                case "HeaterCL":                    heaterIndex = 4;                    break;                case "HeaterL":                    heaterIndex = 5;                    break;            }            return heaterIndex;        }        public bool CheckWaitCondition(out string reason)        {            reason = "";            if (!_isWait || _waitHigh == 0 || _waitLow == 0)                return true;            if (_stableJudgmentTimer.IsRunning)            {                if (TempFeedback < _tempSetpoint - _waitLow ||                    TempFeedback > _tempSetpoint + _waitHigh)                {                    _stableJudgmentTimer.Restart();                }                if (_stableJudgmentTimer.ElapsedMilliseconds >= _stableJudgmentTime * 1000)                {                    return true;                }            }            else            {                _stableJudgmentTimer.Restart();            }            reason = $"{Name} feedback={TempFeedback}, wait limit is ({_tempSetpoint - _waitLow}, {_tempSetpoint + _waitHigh})";            return false;        }        struct PIDParameter        {            public int No { get; set; }            public string Name { get; set; }            public float P { get; set; }            public float I { get; set; }            public float D { get; set; }        }        struct CorrectTableParameter        {            public int No { get; set; }            public string Name { get; set; }            public float ProfileTCCalibTemp { get; set; }            public float TableUseRangeMin { get; set; }            public float TableUseRangeMax { get; set; }            public int ProfileConditionTableNo { get; set; }            public int TempPIDTableNo { get; set; }            public List<CorrectParameter> CorrectParameterLst{ get; set; }        }        struct ProfileParameter        {            public int No { get; set; }            public string Name { get; set; }            public float PreheatTime { get; set; }            public float CheckTime { get; set; }            public float TotalTime { get; set; }            public float AlarmLimit { get; set; }            public float U { get; set; }            public float CU { get; set; }            public float C { get; set; }            public float CL { get; set; }            public float L { get; set; }        }    }    public struct CorrectParameter    {        public int No { get; set; }        public string Name { get; set; }        public float ProfileTemp { get; set; }        public float ProfileTCCalib { get; set; }        public float ProfileCorrect { get; set; }        public float CascadeTCCorrect { get; set; }    }}
 |