Sic.Framework/MECF.Framework.RT.Equipment.../HardwareUnits/MachineVision/Keyence/KeyenceCVX300F.cs

566 lines
16 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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<byte> liReceivedData = new List<byte>();
byte bEnd = 0x0d;
//bool bStaGood = true;
//bool bCanBeat = false;
//int iBeatTimes = 0;
private int _iArea = 0;
public string _sResult;
//
private PeriodicJob _thread;
private LinkedList<HandlerBase> _lstHandler = new LinkedList<HandlerBase>();
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<bool>($"{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;
}
/// <summary>
/// 设置属性
/// </summary>
private void SetAttr()
{
//DATA.Subscribe($"{Module}.{Name}.Area", () => _iArea);
DATA.Subscribe($"{Module}.{Name}.Result", () => this._sResult);
}
/// <summary>
/// 设置操作
/// </summary>
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 = "";
}
/// <summary>
/// 转到运行模式
/// </summary>
public void RunR0()
{
Set("R0", "R0");
EV.PostInfoLog(Module, $"{Name} Run R0 command.");
}
/// <summary>
/// 获取拍照比对结果
/// </summary>
/// <param name="iConId">执行条件编号</param>
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.");
}
/// <summary>
/// 设置输出文件名
/// </summary>
/// <param name="sFileName"></param>
public void SetFileName(string sFileName)
{
string sCmd = "STW,1," + sFileName.Trim();//1为相机内文件名编号相机输出时调用编号
Set("STW", sCmd);
EV.PostInfoLog(Module, $"{Name} Set file name:" + sFileName);
}
/// <summary>
/// 写入执行条件:EXW,n
/// </summary>
/// <param name="iConId">条件编号</param>
public void SetExecCond(int iConId)
{
string sCmd = "EXW," + iConId.ToString();//执行条件编号现在是点1处使用条件1点2处使用条件2
Set("EXW", sCmd);
EV.PostInfoLog(Module, $"{Name} Set condition no.");
}
/// <summary>
/// 加入命令队列
/// </summary>
/// <param name="strCmd">命令 Ascii格式</param>
public void Set(string name, string strCmd)
{
lock (_locker)
{
_lstHandler.Clear();
if (_connection.IsBusy)
{
_connection.ForceClear();
}
List<byte> liCmd = Encoding.ASCII.GetBytes(strCmd).ToList<byte>();
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<bool>($"{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<byte> liData = new List<byte>();
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);
}
}
}