using Aitex.Core.RT.DataCenter; using Aitex.Core.RT.Device; using Aitex.Core.RT.Event; using Aitex.Core.RT.Log; using Aitex.Core.RT.OperationCenter; using Aitex.Core.RT.SCCore; using Aitex.Core.Util; using MECF.Framework.Common.Communications; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; namespace MECF.Framework.RT.EquipmentLibrary.HardwareUnits.MachineVision.Keyence { public class KeyenceCVX300F : BaseDevice, IConnection, IDevice { private KeyenceCVX300FConnection _connection; private bool _isOn; private bool _activeMonitorStatus; private int _errorCode; private string _lastError = string.Empty; //private RD_TRIG _trigPumpOnOff = new RD_TRIG(); //private R_TRIG _trigError = new R_TRIG(); //private R_TRIG _trigOverTemp = new R_TRIG(); //private R_TRIG _trigWarningMessage = new R_TRIG(); private R_TRIG _trigCommunicationError = new R_TRIG(); private R_TRIG _trigRetryConnect = new R_TRIG(); uint iCurrentOper = 0xff; List liReceivedData = new List(); byte bEnd = 0x0d; //bool bStaGood = true; //bool bCanBeat = false; //int iBeatTimes = 0; private int _iArea = 0; public string _sResult; // private PeriodicJob _thread; private LinkedList _lstHandler = new LinkedList(); private object _locker = new object(); private bool _enableLog = true; private string _scRoot; private string _strCmd; #region 属性 public string Address { get; set; } public bool IsConnected { get { return _connection != null && _connection.IsConnected; } } //属性 public bool AlarmStatus { get; set; } public bool PositionComplete { get; set; } public bool MotorBusy { get; set; } // public bool IsBusy { get; set; } //public bool IsStbOff { get; set; } //StbOff消息是否发送 public int AreaData { get { return _iArea; } } #endregion public bool Connect() { return true; } public bool Disconnect() { return true; } public KeyenceCVX300F(string module, string scRoot, string name) : base(module, name, name, name) { _scRoot = scRoot; _activeMonitorStatus = true; // } public bool Initialize() { // string portName = SC.GetStringValue($"{_scRoot}.{Module}.{Name}.Address"); string sAddress = SC.GetStringValue($"{Name}.Address"); Address = sAddress; _enableLog = SC.GetValue($"{Name}.EnableLogMessage"); _connection = new KeyenceCVX300FConnection(sAddress); _connection.EnableLog(_enableLog); // _sResult = ""; // if (_connection.Connect()) { EV.PostInfoLog(Module, $"{Module}.{Name} connected"); } //设置属性 this.SetAttr(); //设置操作 this.SetOP(); // _thread = new PeriodicJob(200, OnTimer, $"{Name} MonitorHandler", true); // //this.InitMachine(); // ConnectionManager.Instance.Subscribe($"{Name}", this); //SetServoOn(); return true; } /// /// 设置属性 /// private void SetAttr() { //DATA.Subscribe($"{Module}.{Name}.Area", () => _iArea); DATA.Subscribe($"{Module}.{Name}.Result", () => this._sResult); } /// /// 设置操作 /// private void SetOP() { //读取面积 //OP.Subscribe($"{Module}.{Name}.CVXCheckArea", (cmd, param) => //{ // //Set("T1","T1"); // //EV.PostInfoLog(Module, $"{Name} Get area data."); // return true; //}); //读取结果 OP.Subscribe($"{Module}.{Name}.GetResult", (cmd, param) => { GetResult(Convert.ToInt32(param[0])); // return true; }); //转至运行模式 OP.Subscribe($"{Module}.{Name}.RunR0", (cmd, param) => { RunR0(); return true; }); //清除结果 OP.Subscribe($"{Module}.{Name}.ClearResult", (cmd, param) => { this.ClearResult(); return true; }); } public void ClearResult() { this._sResult = ""; } /// /// 转到运行模式 /// public void RunR0() { Set("R0", "R0"); EV.PostInfoLog(Module, $"{Name} Run R0 command."); } /// /// 获取拍照比对结果 /// /// 执行条件编号 public void GetResult(int iConId) { SetExecCond(iConId); //this._strCmd = param[0] as string; //if (this._strCmd.Length > 0) //{ // Set(this._strCmd, this._strCmd); // EV.PostInfoLog(Module, $"{Name} Get result."); //} // //Set("T1", "T1"); EV.PostInfoLog(Module, $"{Name} Get result."); } /// /// 设置输出文件名 /// /// public void SetFileName(string sFileName) { string sCmd = "STW,1," + sFileName.Trim();//1为相机内文件名编号,相机输出时调用编号 Set("STW", sCmd); EV.PostInfoLog(Module, $"{Name} Set file name:" + sFileName); } /// /// 写入执行条件:EXW,n /// /// 条件编号 public void SetExecCond(int iConId) { string sCmd = "EXW," + iConId.ToString();//执行条件编号,现在是点1处使用条件1,点2处使用条件2 Set("EXW", sCmd); EV.PostInfoLog(Module, $"{Name} Set condition no."); } /// /// 加入命令队列 /// /// 命令 Ascii格式 public void Set(string name, string strCmd) { lock (_locker) { _lstHandler.Clear(); if (_connection.IsBusy) { _connection.ForceClear(); } List liCmd = Encoding.ASCII.GetBytes(strCmd).ToList(); liCmd.Add(0x0d); //CR //liCmd.Add(0x0a); //LF 不可颠倒 byte[] bCmd = liCmd.ToArray(); //_lstHandler.AddLast(new HwAlignerGuideQueryHandler(this, strCmd, bCmd)); _lstHandler.AddLast(new KeyenceCVX300FSetHandler(this, name, bCmd)); } } public int _connecteTimes { get; set; } private bool OnTimer() { try { // _connection.MonitorTimeout(); //若断,重连 if ((!_connection.IsConnected) || _connection.IsCommunicationError) { lock (_locker) { //_trigSevroOn.RST = true; //IsBusy = false; _lstHandler.Clear(); } // _trigRetryConnect.CLK = _connection.IsConnected; //不可重复置值,否则Q会有变化 if (_connection.Connect()) { // //if (_trigRetryConnect.Q) //{ EV.PostInfoLog(Module, $"{Module}.{Name} connected"); LOG.Write($"{Module}.{Name} connected"); //} //转至运行模式,此命令可以重入 this.RunR0(); this.SetFileName("sic"); _trigRetryConnect.CLK = true; } else { if (_trigRetryConnect.Q) { EV.PostInfoLog(Module, $"Trying to connect {Module}.{Name} with address: {_connection.Address}"); LOG.Write($"Trying to connect {Module}.{Name} with address: {_connection.Address}"); } } Thread.Sleep(2000);//降低重连频率 } //处理命令队列 HandlerBase handler = null; if (!_connection.IsBusy) { lock (_locker) { if (_lstHandler.Count == 0 && _activeMonitorStatus && !IsBusy) { //Query(); } if (_lstHandler.Count > 0) { handler = _lstHandler.First.Value; _lstHandler.RemoveFirst(); } } if (handler != null) { _connection.Execute(handler); } } // return true; } catch (Exception ex) { LOG.Write(ex); } return true; } internal void NoteError() { } public void Monitor() { try { _connection.EnableLog(_enableLog); //if (_connecteTimes < 4) return; _trigCommunicationError.CLK = _connection.IsCommunicationError; if (_trigCommunicationError.Q) { EV.PostAlarmLog(Module, $"{Module}.{Name} communication error, {_connection.LastCommunicationError}"); } } catch (Exception ex) { LOG.Write(ex); } } public void Terminate() { try { if (_connection != null) { _connection.Disconnect(); _connection = null; } } catch (Exception ex) { LOG.Write(ex); } } public void Reset() { // _connecteTimes = 0; _connection.SetCommunicationError(false, "");//这里重置了CommunicationError ,就是去了OnTimer里面的重连的触发,所以需要另设变量以触发之(使用timeout来触发的情况) _enableLog = SC.GetValue($"{Name}.EnableLogMessage"); _trigCommunicationError.RST = true; _trigRetryConnect.RST = true; // } public void SetActiveMonitor(bool active) { _activeMonitorStatus = active; } //internal void NoteOnOff(bool isOn) //{ // _isOn = isOn; //} public bool _PraseData(string name, byte[] buffer) { bool bRes = false; // try { this.bEnd = 0x0d; this.liReceivedData.AddRange(buffer); List liData = new List(); int iIndex = this.liReceivedData.LastIndexOf(bEnd); //int iIndex = this.liReceivedData.IndexOf(bEnd); if (iIndex > 0) { liData.AddRange(this.liReceivedData.GetRange(0, iIndex + 1)); this.liReceivedData.RemoveRange(0, iIndex + 1); } else { return false; } string sAnswer = Encoding.ASCII.GetString(liData.ToArray()); //string sAnswer = Encoding.ASCII.GetString(buffer); //返回一次 "T1\r" ,再次返回 "T1\r00004422,0\r" string[] sCmds = sAnswer.Split('\n', '\r'); foreach (string sOneCmd in sCmds) { if (sOneCmd.Length > 0 && sOneCmd.Trim().CompareTo(name) != 0) { //bRes = this.DoOneCmd(name, sOneCmd); } } } catch (Exception ex) { string sEx = $"{Module}.{Name} Exception:" + ex.Message; EV.PostAlarmLog(Module, sEx); LOG.Write(sEx); } // return bRes; } public bool PraseData(string name, byte[] buffer) { // string sCmdBack = Encoding.ASCII.GetString(buffer); bool bRes = false; // if (sCmdBack.Trim().Length > 0) { // if (name.CompareTo("T1") == 0) { if (sCmdBack.CompareTo("T1\r") == 0) { bRes = false; } else { bool bResult = sCmdBack.Replace("T1\r", "").Contains("0"); // if (bResult) { this._sResult = "OK"; } else { this._sResult = "NG"; } bRes = true; } } else if (name.CompareTo("EXW") == 0) { Set("T1", "T1"); bRes = true; } else { if (sCmdBack.Contains("ER,")) { EV.PostWarningLog(Module, "Keyence CCD camera get an error answer."); } bRes = true; } } // return bRes; } //public void SetErrorCode(int errorCode) //{ // _errorCode = errorCode; //} //public void SetError(string reason) //{ // _trigWarningMessage.CLK = true; // if (_trigWarningMessage.Q) // { // EV.PostWarningLog(Module, $"{Module}.{Name} error, {reason}"); // } //} private static byte[] ModRTU_CRC(byte[] buffer) { ushort crc = 0xFFFF; // var buf = System.Text.Encoding.UTF8.GetBytes(String.Join(Environment.NewLine, buffer)); var buf = buffer; var len = buffer.Length; for (var pos = 0; pos < len; pos++) { crc ^= buf[pos]; // XOR byte into least sig. byte of crc for (var i = 8; i != 0; i--) // Loop over each bit if ((crc & 0x0001) != 0) { // If the LSB is set crc >>= 1; // Shift right and XOR 0xA001 crc ^= 0xA001; } else // Else LSB is not set { crc >>= 1; // Just shift right } } // Note, this number has low and high bytes swapped, so use it accordingly (or swap bytes) return BitConverter.GetBytes(crc); } } }