You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Rs.DeweyTester/Rs.DeweyTester/Entitys/TestFixtureManager.cs

1032 lines
35 KiB
C#

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

using log4net.Util;
using NPOI.SS.Format;
using NPOI.SS.Formula.Functions;
using NPOI.SS.Formula.PTG;
using Rs.Framework;
using Rs.MotionPlat.Commom;
using Rs.MotionPlat.Flow;
using Rs.MotionPlat.Flow.NormalFlow;
using Rs.MotionPlat.Vision;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Web;
using System.Windows.Forms;
namespace Rs.MotionPlat.Entitys
{
/// <summary>
/// 测试治具状态
/// </summary>
public enum ETestFixtureStatus
{
/// <summary>
/// 未连接
/// </summary>
NoConnect,
/// <summary>
/// 未知
/// </summary>
None,
/// <summary>
/// 空闲
/// </summary>
IDLE,
/// <summary>
/// 测试中
/// </summary>
Testing,
/// <summary>
/// 报警中
/// </summary>
Warning,
/// <summary>
/// 暂停
/// </summary>
Pause,
/// <summary>
/// 回原中
/// </summary>
Homing
}
/// <summary>
/// 测试治具
/// </summary>
public class TestFixture:INotifyPropertyChanged
{
bool exit = false;
public TestFixture()
{
//PrintCommunitionLog();
QueryStatus();
StartRecive();
}
public event Action<string, object> OnProChange;
private TestProduct _Product;
public TestProduct Product
{
get { return _Product; }
set
{
if (_Product != value)
{
_Product = value;
if(OnProChange != null)
{
OnProChange(nameof(Product), value);
}
}
}
}
public void AddTestRecordToProduct()
{
if (Product != null && !string.IsNullOrEmpty(Result))
{
Product.AddResult(this.Index, "", "");
}
}
public void Clear()
{
this.Product = null;
//this.Result = "";
}
public void ClearData()
{
this.Product = null;
this.Result = "";
this.PassCount = 0;
this.TotalCount = 0;
this.LastCT = 0;
this.Yield = 0;
}
private int _Index;
/// <summary>
/// 治具序号
/// </summary>
public int Index {
get { return _Index; }
set
{
if (_Index != value)
{
_Index = value;
if (OnProChange != null)
{
OnProChange(nameof(Index), value);
}
}
}
}
public string _MachineID;
/// <summary>
/// 机器编码
/// </summary>
public string MachineID
{
get { return _MachineID; }
set
{
if (_MachineID != value)
{
_MachineID = value;
OnPropertyChanged(nameof(MachineID));
}
}
}
/// <summary>
/// 放料偏移X
/// </summary>
public double PlaceProductOffsetX { get; set; }
/// <summary>
/// 放料偏移Y
/// </summary>
public double PlaceProductOffsetY { get; set; }
/// <summary>
/// 连接状态
/// </summary>
public bool Connected { get; set; } = false;
private ETestFixtureStatus _Status;
/// <summary>
/// 治具状态
/// </summary>
public ETestFixtureStatus Status
{
get { return _Status; }
set {
if(_Status != value)
{
_Status = value;
OnProChange?.Invoke(nameof(Status), value);
//OnPropertyChanged(nameof(Status));
//if (OnProChange != null)
//{
// OnProChange(nameof(Status), value);
//}
}
}
}
/// <summary>
/// 开始测试时间
/// </summary>
public DateTime StartTestTime { get; set; }
/// <summary>
/// 结束测试时间
/// </summary>
public DateTime EndTestTime { get; set; }
private double _LastCT;
public double LastCT
{
get { return _LastCT; }
set
{
if (_LastCT != value)
{
_LastCT = value;
OnProChange?.Invoke(nameof(LastCT), value);
//OnPropertyChanged(nameof(LastCT));
}
}
}
public string Lot { get; set; }
private bool _Enable = false;
/// <summary>
/// 是否启用
/// </summary>
public bool Enable {
get { return _Enable; }
set
{
//if (_Enable != value)
{
_Enable = value;
OnProChange?.Invoke(nameof(Enable), value);
}
}
}
private int _PassCount;
/// <summary>
/// OK数量
/// </summary>
public int PassCount
{
get { return _PassCount; }
set
{
if (_PassCount != value)
{
_PassCount = value;
OnPropertyChanged(nameof(PassCount));
}
}
}
private int _TotalCount;
/// <summary>
/// 总数量
/// </summary>
public int TotalCount
{
get { return _TotalCount; }
set
{
if (_TotalCount != value)
{
_TotalCount = value;
OnPropertyChanged(nameof(TotalCount));
}
}
}
private double _Yield;
/// <summary>
/// 良率
/// </summary>
public double Yield
{
get { return _Yield; }
set
{
if (_Yield != value)
{
_Yield = value;
OnProChange?.Invoke(nameof(Yield), value);
}
}
}
private string _Result;
/// <summary>
/// 测试结果
/// </summary>
public string Result
{
get { return _Result; }
set
{
//if (_Result != value)
{
_Result = value;
// OnPropertyChanged(nameof(Result));
OnProChange?.Invoke(nameof(Result), value);
}
}
}
/// <summary>
/// 是否是第一个启用的治具
/// </summary>
public bool IsFirstFixture { get; set; } = false;
/// <summary>
/// CSV文件标题
/// </summary>
public string CsvTitle { get; set; }
private Socket _socket;
public void SetSocket(Socket socket)
{
_socket = socket;
}
List<byte> data = new List<byte>();
public int Send(string content)
{
byte[] data=Encoding.ASCII.GetBytes(content);
return _socket.Send(data);
}
//ManualResetEvent dataEvent=new ManualResetEvent(true);
AutoResetEvent dataEvent = new AutoResetEvent(true);
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
public void SetEvent()
{
dataEvent.Set();
}
public void QueryStatus()
{
Task.Run(() => {
while (!exit)
{
if(!Connected)
{
Thread.Sleep(50);
continue;
}
while (true)
{
if (dataEvent.WaitOne(100))
{
break;
}
else
{
Thread.Sleep(100);
}
}
Send("Status$");
//dataEvent.Reset();
if (CheckPrintLog())
{
AddLog($"<<< TC{Index} status$");
//logs.Enqueue($"<<< TC{Index} status$");
//lock(this)
//{
// File.AppendAllText($"d:\\1\\{Index}.txt", $"<<< 治具{Index} status$\r\n");
//}
}
Thread.Sleep(100);
}
});
}
/// <summary>
/// 通知治具回原
/// </summary>
public void Home()
{
while (true)
{
if (dataEvent.WaitOne(100))
{
break;
}
else
{
Thread.Sleep(100);
}
}
Send($"Reset$");
Result = "";
if (CheckPrintLog())
{
AddLog($"<<< TC{Index} Reset$");
}
}
/// <summary>
/// 通知治具暂停
/// </summary>
public void Pause()
{
while (true)
{
if (dataEvent.WaitOne(100))
{
break;
}
else
{
Thread.Sleep(100);
}
}
Send($"Pause#1$");
if (CheckPrintLog())
{
AddLog($"<<< TC{Index} Pause#1$");
}
}
/// <summary>
/// 通知治具启动测试
/// </summary>
public void StartTest(string sn="")
{
while (true)
{
if (dataEvent.WaitOne(100))
{
break;
}
else
{
Thread.Sleep(100);
}
}
//先把侧相机数据清空
VisionHelper.sideCameraVision.ClearQueue(this.Index);
int noise = GlobalVar.Noise ? 1 : 0;
int mtcp=GlobalVar.Mtcp ? 1 : 0;
int isFirstFixture = IsFirstFixture ? 1 : 0;
string msg = string.Empty;
if(string.IsNullOrEmpty(sn))
{
//StartTest#SN#Machine#User#Config#Lot#Mode#SiteID#ProjectID#RetryMode#Mes#Mtcp#configD#DualMode#TakeIndex#SubLotName$
//msg = $"StartTest#{Product.SN}#MS001#OP#DXD#GRR_GRR_DXD_202203120320#Production#LF1#MOS#T1#0#0#Paint#0#R1C5#SP0012#1$";
msg = $"StartTest#{Product.SN}#{GlobalVar.MachineID}#op#{GlobalVar.Config}#{GlobalVar.LotName}#{GlobalVar.TestMode}#{GlobalVar.SiteID}#{GlobalVar.ProjectID}#T1#0#{mtcp}#{GlobalVar.ConfigName}#0#{Product.From}#{GlobalVar.SubLotName}#{noise}#{isFirstFixture}#{GlobalVar.RelCategory}#{GlobalVar.RelCp}#{GlobalVar.HostType}$";
}
else
{
msg = $"StartTest#{sn}#MS001#OP#DXD#GRR_GRR_DXD_202203120320#Production#LF1#MOS#T1#0#0#Paint#0#R1C5#SP0012#1$";
}
LogHelper.Debug(msg);
// string msg = $"StartTest#123#{GlobalVar.MachineID}#op#{GlobalVar.Config}#Lot#Mode#SiteID#ProjectID#RetryMode#{mtcp}#Mtcp#configD#DualMode#R1C1#SubLotName#{noise}$";
//msg = $"StartTest#{Product.SN}#MS001#OP#DXD#GRR_GRR_DXD_202203120320#Production#LF1#MOS#T1#0#0#Paint#0#R1C5#SP0012#1$";
Send(msg);
if(CheckPrintLog())
{
AddLog($"<<< TC{Index} {msg}");
}
}
private ConcurrentQueue<string> logs = new ConcurrentQueue<string>();
public void StartRecive()
{
Task.Run(() => {
while (!exit)
{
if(!Connected)
{
Thread.Sleep(100);
continue;
}
byte[] bytes=new byte[1024 *10];
try
{
int len = _socket.Receive(bytes);
if (len > 0)
{
for(int i=0;i<len;i++)
{
if (bytes[i] != (byte)'$')
{
data.Add(bytes[i]);
}
else
{
MessageParse();
data.Clear();
}
}
//string data = Encoding.ASCII.GetString(bytes, 0, len);
//MessageQueue.Instance.Insert(data);
}
else
{
MessageQueue.Instance.Warn($"TC{Index} disconned!");
Status = ETestFixtureStatus.NoConnect;
Connected = false;
}
}
catch (SocketException ex)
{
Status = ETestFixtureStatus.NoConnect;
MessageQueue.Instance.Warn($"TC{Index} disconned!");
Connected = false;
}
Thread.Sleep(10);
}
});
}
private void MessageParse()
{
if(data!=null&&data.Count>0)
{
string content = Encoding.ASCII.GetString(data.ToArray());
if (CheckPrintLog())
{
AddLog($">>> TC{Index},{content}");
}
string[] items = content.Split('#');
string command = items[0];
switch (command)
{
case "Status":
switch (items[1])
{
case "0":
//非就绪状态,查询错误代码
Send("ErrorCode$");
if (CheckPrintLog())
{
//lock (this)
//{
// File.AppendAllText($"d:\\1\\{Index}.txt", $"<<< 治具{Index} ErrorCode$\r\n");
//}
AddLog($"<<< TC{Index} ErrorCode$");
}
break;
case "1":
//就绪状态,如果有产品就查询测试结果
if(Status == ETestFixtureStatus.Testing ||(Status== ETestFixtureStatus.IDLE && Product!=null &&String.IsNullOrEmpty(Result)))
{
Send("Result$");
LogHelper.Debug($"<<< TC{Index} Result$");
if (CheckPrintLog())
{
//lock (this)
//{
// File.AppendAllText($"d:\\1\\{Index}.txt", $"<<< 治具{Index} Result$\r\n");
//}
AddLog($"<<< TC{Index} Result$");
}
}
else
{
dataEvent.Set();
Status = ETestFixtureStatus.IDLE;
}
break;
case "2":
dataEvent.Set();
Status = ETestFixtureStatus.Homing;
break;
case "3":
//侧相机测试失败
EButtonType sideCameraSelect = Msgbox.ShowTipDialog(EButtonType.Retry | EButtonType.Cancel, $"Please check DUT{Index} is placed okok continue test click retrystop test click Cancel","warn",true);
if(sideCameraSelect== EButtonType.Retry)
{
string msg = "ContinueTest#1$";
Send(msg);
}
else if(sideCameraSelect== EButtonType.Cancel)
{
string msg = "ContinueTest#0$";
Send(msg);
}
dataEvent.Set();
break;
}
break;
case "StartTest":
//if (writeLogs.Contains(Index))
//{
// LogHelper.Info($">>> 治具{Index} StartTest");
//}
this.Result = "";
this.StartTestTime=DateTime.Now;
this.Status= ETestFixtureStatus.Testing;
dataEvent.Set();
break;
case "Result":
//if(items!=null && items.Length>=6)
{
lock(this)
{
if (Product != null)
{
LogHelper.Debug($"治具{Index}测试完成,测试总数量由{TotalCount}增加到{TotalCount + 1}");
if (items[2] == "1")
{
Result = "PASS";
PassCount++;
}
else
{
Result = "NG";
}
Product.Result = Result;
Product.Bin = items[6];
this.EndTestTime = DateTime.Now;
this.LastCT = (EndTestTime - StartTestTime).TotalSeconds;
TotalCount++;
Yield = (double)((double)PassCount / TotalCount);
AddTestRecordToProduct();
//this.Product.AddResult(this.Index, Result, items[6]);
}
string csvContent = string.Join(",", items[3], items[4], items[5]);
LogHelper.Debug($"Result:{items[2]},{items[3]}");
DevLog.Summary(CsvTitle, csvContent);
Status = ETestFixtureStatus.IDLE;
dataEvent.Set();
}
}
break;
case "ErrorCode":
//if (writeLogs.Contains(Index))
//{
// LogHelper.Info($">>> 治具{Index} ErrorCode");
//}
string code = items[1];
if(code!="0")
{
if(Status != ETestFixtureStatus.Warning)
{
Status = ETestFixtureStatus.Warning;
Task.Run(() => {
string errInfo = $"tc{Index} test,code:{items[1]},desc:{items[2]}";
MessageQueue.Instance.Warn(errInfo);
Msgbox.ShowTipDialog(EButtonType.Ok, errInfo,"testfixture error",true);
});
}
}
else
{
Status = ETestFixtureStatus.Testing;
}
dataEvent.Set();
break;
case "Grip":
dataEvent.Set();
break;
case "Vlog":
//dataEvent.Set();
DevLog.Breakdown(items[1], items[2]);
break;
case "Reset":
dataEvent.Set();
break;
case "GR":
VisionHelper.sideCameraVision.Grab(Index, items[1]);
//dataEvent.Set();
break;
case "Pause":
dataEvent.Set();
break;
case "ReadIO":
// dataEvent.Set();
try
{
string ioname = items[1];
int value = Ops.IsOutOn(ioname)?1:0;
Send($"ReadIO#{value}$");
}
catch (Exception ex)
{
LogHelper.Error($"ReadIO error:{ex.Message}");
}
break;
case "WriteIO":
try
{
string ioname = items[1];
int value = int.Parse(items[2]);
if (value == 1)
Ops.On(ioname);
else
Ops.Off(ioname);
Send($"WriteIO#0$");
}
catch (Exception)
{
Send($"WriteIO#-1$");
}
break;
case "TrayInfo":
try
{
string splitChar = ";";
string title = $"TrayInfo#LotName,TrayType,Endtime,SerialNumber,Tray_X_O,Tray_Y_O{splitChar}";
List<string> dataList = new List<string>();
string lotname = items[1];
string querySql = $"select * from records where lotname='{lotname}'";
DataSet ds = MySqlHelper.GetDataSet(querySql);
if (ds != null && ds.Tables.Count > 0 && ds.Tables[0].Rows.Count > 0)
{
foreach (DataRow row in ds.Tables[0].Rows)
{
(int r, int c) = TrayHelper.GetRC(int.Parse(row["toIndex"].ToString()),16,16);
string data = $"{row["lotname"].ToString()},{row["traytype"].ToString()},{row["placetime"].ToString()},{row["sn"].ToString()},{r + 1},{c + 1}";
dataList.Add(data);
}
}
string sendData = $"{title}{string.Join($"{splitChar}", dataList)},$";
Send(sendData);
}
catch (Exception ex)
{
}
break;
}
}
}
public void AddLog(string log)
{
if(logs.Count>500)
{
int i = 0;
while (true)
{
i++;
logs.TryDequeue(out string msg);
if(i>=500)
{
break;
}
}
}
logs.Enqueue(log);
}
public string GetLog()
{
StringBuilder msg = new StringBuilder();
while (logs.Count > 0)
{
bool b = logs.TryDequeue(out string content);
if(b)
{
msg.Append($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")} {content}\r\n");
}
}
return msg.ToString();
}
//private void PrintCommunitionLog()
//{
// Task.Run(() => {
// while (true)
// {
// if(logs.Count > 0)
// {
// bool ret = logs.TryDequeue(out string log);
// if (ret)
// {
// //打印日志
// string logDir = $"d:\\Communition\\{DateTime.Now.ToString("yyyyMMdd")}";
// if(!Directory.Exists(logDir))
// {
// Directory.CreateDirectory(logDir);
// }
// string logFileName = $"{logDir}\\{Index}.txt";
// File.AppendAllText(logFileName, $"{DateTime.Now.ToString("HH:mm:ss fff")} {log}\r\n");
// }
// }
// else
// {
// Thread.Sleep(100);
// }
// }
// });
//}
/// <summary>
/// 检测是否需要打印日志
/// </summary>
/// <returns></returns>
private bool CheckPrintLog()
{
return true;
switch (Index)
{
case 1:
return GlobalVar.PrintTC1Communicate;
case 2:
return GlobalVar.PrintTC2Communicate;
case 3:
return GlobalVar.PrintTC3Communicate;
case 4:
return GlobalVar.PrintTC4Communicate;
case 5:
return GlobalVar.PrintTC5Communicate;
case 6:
return GlobalVar.PrintTC6Communicate;
default: return false;
}
}
/// <summary>
/// 夹头夹紧
/// </summary>
public void ColletOn(string className)
{
Ops.On($"治具夹{Index}");
string logInfo = $"{className} 治具夹{Index}夹紧";
MessageQueue.Instance.Insert(logInfo);
Thread.Sleep(GlobalVar.ColletCloseDelaytime);
}
/// <summary>
/// 夹头松开
/// </summary>
public void ColletOff(string className)
{
Ops.Off($"治具夹{Index}");
Thread.Sleep(GlobalVar.ColletOpenDelaytime);
string logInfo = $"{className} 治具夹{Index}松开";
MessageQueue.Instance.Insert(logInfo);
}
/// <summary>
/// 获取拍照位置
/// </summary>
/// <returns></returns>
public TargetPosition GetGrabPos()
{
TargetPosition targetPos = new TargetPosition();
switch (Index)
{
case 1:
targetPos.X = GlobalVar.Fixture1GrabImageX;
targetPos.Y1 = GlobalVar.FixtureSideY1;
targetPos.Y2 = GlobalVar.Fixture1GrabImageY2;
break;
case 2:
targetPos.X = GlobalVar.Fixture2GrabImageX;
targetPos.Y1 = GlobalVar.FixtureSideY1;
targetPos.Y2 = GlobalVar.Fixture2GrabImageY2;
break;
case 3:
targetPos.X = GlobalVar.Fixture3GrabImageX;
targetPos.Y1 = GlobalVar.FixtureSideY1;
targetPos.Y2 = GlobalVar.Fixture3GrabImageY2;
break;
case 4:
targetPos.X = GlobalVar.Fixture4GrabImageX;
targetPos.Y1 = GlobalVar.FixtureSideY1;
targetPos.Y2 = GlobalVar.Fixture4GrabImageY2;
break;
case 5:
targetPos.X = GlobalVar.Fixture5GrabImageX;
targetPos.Y1 = GlobalVar.FixtureSideY1;
targetPos.Y2 = GlobalVar.Fixture5GrabImageY2;
break;
case 6:
targetPos.X = GlobalVar.Fixture6GrabImageX;
targetPos.Y1 = GlobalVar.FixtureSideY1;
targetPos.Y2 = GlobalVar.Fixture6GrabImageY2;
break;
}
return targetPos;
}
}
public class TestFixtureManager
{
TestFixture[] testFixtures=new TestFixture[6];
private TestFixtureManager()
{
for (int i = 1; i <= 6; i++)
{
testFixtures[i-1] = new TestFixture();
testFixtures[i-1].Index = i;
}
serverSocket=new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
}
private static TestFixtureManager instance;
public static TestFixtureManager Instance
{
get
{
if(instance == null)
instance = new TestFixtureManager();
return instance;
}
}
Socket serverSocket;
List<Socket> clientSockets = new List<Socket>();
public TestFixture GetTestFixture(int index)
{
return testFixtures.Where(t => t.Index == index).FirstOrDefault();
}
/// <summary>
/// 查询有产品的治具列表
/// </summary>
/// <returns></returns>
public List<TestFixture> GetHaveProductFixtureList()
{
return testFixtures.Where(t=>t.Enable&&t.Product!=null).ToList();
}
public void StartLister()
{
Task.Run(() => {
MessageQueue.Instance.Insert("start lister");
serverSocket.Bind(new IPEndPoint(IPAddress.Any, 6050));
serverSocket.Listen(10);
while (true)
{
Socket clientSocket = serverSocket.Accept();
clientSockets.Add(clientSocket);
IPEndPoint endPoint = ((IPEndPoint)clientSocket.RemoteEndPoint);
MessageQueue.Instance.Insert($"ip:{endPoint.Address.ToString()},port:{endPoint.Port.ToString()} connected!");
ThreadPool.QueueUserWorkItem((obj) => {
List<byte> registData=new List<byte>();
Socket soct=(Socket)obj;
IPEndPoint ep = ((IPEndPoint)soct.RemoteEndPoint);
byte[] buffer = new byte[1024 * 10];
bool stop = false;
while (!stop)
{
int len = soct.Receive(buffer);
if (len > 0)
{
for(int i=0;i<len;i++)
{
if (buffer[i] !=36)
{
registData.Add(buffer[i]);
}
else
{
string content=Encoding.ASCII.GetString(registData.ToArray());
//MessageQueue.Instance.Insert($">>> ip:{ep.Address.ToString()},port:{ep.Port.ToString()},{content}");
string[] items = content.TrimEnd(new char[] { '$' }).Split('#');
Thread.Sleep(500);
string reg = "Register#1$";
int sendLen = clientSocket.Send(Encoding.ASCII.GetBytes(reg));
MessageQueue.Instance.Insert($"<<< ip:{ep.Address.ToString()},port:{ep.Port.ToString()},{reg}");
TestFixture tf = GetTestFixture(int.Parse(items[2]));
tf.SetSocket(soct);
tf.AddLog(" <<< " + content);
tf.AddLog(" >>> " + reg);
tf.MachineID = items[1];
tf.Connected = true;
tf.Status = ETestFixtureStatus.None;
tf.CsvTitle = items[3];
tf.SetEvent();
stop = true;
break;
}
}
}
Thread.Sleep(10);
}
}, clientSocket);
Thread.Sleep(10);
}
});
}
/// <summary>
/// 获取启用的治具列表
/// </summary>
/// <returns></returns>
public List<TestFixture> GetEnableFixtureList()
{
return testFixtures.Where(t=>t.Enable).ToList();
}
/// <summary>
/// 获取有产品治具数量
/// </summary>
/// <returns></returns>
public int GetHasProuctFixtureCount()
{
return testFixtures.Where(t=>t.Enable && t.Product!=null).Count();
}
/// <summary>
/// 获取空闲的治具
/// </summary>
/// <returns></returns>
public TestFixture GetIdleFixture()
{
List<TestFixture> lt = testFixtures.Where(t => t.Enable && t.Product == null).ToList();
if(lt!=null&&lt.Count>0)
{
return lt.First();
}
return null;
}
}
}