using SocketCommunication;
using System;
using System.Collections;
using System.Net;
using System.Text;
using System.Threading;
using log4net;
using log4net.Appender;
using log4net.Layout;
using log4net.Repository.Hierarchy;
using System.Collections.Generic;
namespace SHARP_CLAS_UI
{
public class CIM_Client : IDisposable
{
#region Logger
///
/// Alarm Log
///
private ILog Client_Log = LogManager.GetLogger("CIM_Client");
///
/// Alarm Log Write
///
/// Method name of exception that occurred
/// exception
private void Write_Client_Log(string message)
{
if (Client_Log != null) Client_Log.Debug($"{message}");
}
///
/// Create excepton logger
///
private void Create_Server_logger()
{
Hierarchy hierarchy = (Hierarchy)LogManager.GetRepository();
RollingFileAppender rollingAppender = new RollingFileAppender();
PatternLayout layout = new PatternLayout();
hierarchy.Configured = true;
rollingAppender.Name = "Client_RoolingFile";
rollingAppender.LockingModel = new RollingFileAppender.MinimalLock();
rollingAppender.File = $@"D:\Logger\Cim_Client\";
rollingAppender.AppendToFile = true;
rollingAppender.DatePattern = "yyyy\\\\MM\\\\'Client'_dd'.csv'";
rollingAppender.RollingStyle = RollingFileAppender.RollingMode.Composite;
rollingAppender.MaxSizeRollBackups = 10;
rollingAppender.MaximumFileSize = "100MB";
rollingAppender.StaticLogFileName = false;
rollingAppender.Encoding = Encoding.UTF8;
rollingAppender.PreserveLogFileNameExtension = true;
layout = new PatternLayout("%d{yyyy/MM/dd HH:mm:ss.fff},%m%n");
layout.ActivateOptions();
rollingAppender.Layout = layout;
rollingAppender.ActivateOptions();
hierarchy.GetLogger("CIM_Client");
ILog log = LogManager.GetLogger("CIM_Client");
Logger l = (Logger)log.Logger;
l.Level = log4net.Core.Level.Debug;
l.AddAppender(rollingAppender);
Client_Log = LogManager.GetLogger("CIM_Client");
}
#endregion
#region Property
public bool isConnected { get { return client == null ? false : client.isConnected; } }
public string Ip { get { return ip; } }
public int Port { get { return port; } }
#endregion
#region Field
Equipment _equip;
private SocketClient client;
private StringBuilder received_data;
public Queue commandlist;
public readonly string Clientname = "CIM_Client";
public readonly string ip = "10.214.122.84";
public readonly int port = 5571;
private bool IsDisposed = false;
private Thread communicationThread;
private Dictionary Command_Acks = new Dictionary();
private Dictionary Command_Results = new Dictionary();
private Queue send_datas;
private bool online;
#endregion
#region Construct
public CIM_Client(Equipment _equip, string ip = "10.214.122.84", int port = 5571)
{
this._equip = _equip;
this.ip = ip;
this.port = port;
commandlist = new Queue();
send_datas = new Queue();
received_data = new StringBuilder();
received_data.Clear();
Create_Server_logger();
Init_Client();
Init_List();
communicationThread = new Thread(Command_trigger);
communicationThread.Start();
}
#endregion
#region Function
private void Init_Client()
{
if (client != null && client.isConnected) client.Disconnect();
client = new SocketClient(IPAddress.Parse(ip), port, Clientname);
client.Add_received_event(Received);
}
private void Init_List()
{
foreach(En_Cim_Command command in Enum.GetValues(typeof(En_Cim_Command)))
{
Command_Acks.Add(command, true);
Command_Results.Add(command, false);
}
}
public void Received(object sender, ReceiveEventArgs events)
{
received_data.Append(events.stateobject.Received_data.ToString());
if(received_data.ToString().Contains("\r\n"))
{
string[] commands = received_data.ToString().Split(new string[] { "\r\n" }, StringSplitOptions.None);
commandlist.Enqueue(commands[0]);
received_data.Clear();
}
}
public void Command_trigger()
{
while (!IsDisposed)
{
try
{
Thread.Sleep(10);
if (send_datas.Count > 0)
{
Cim_Send_Data csd = send_datas.Dequeue();
switch (csd.command)
{
case En_Cim_Command.ONLRT:
{
_equip.cim_server.Set_Command_Ack(En_Cim_Command.ONLCK, false);
Command_Results[En_Cim_Command.ONLRT] = Check_Receive_Data(csd.data, En_Cim_Command.ONLRT);
Set_Command_Ack(En_Cim_Command.ONLRT, true);
if (Command_Results[En_Cim_Command.ONLRT])
{
if(online)
{
_equip.cim_mode = En_Cim_Mode.Online;
Send_Equipment_Status("E1234567");
}
else
{
_equip.cim_mode = En_Cim_Mode.Offline;
}
}
break;
}
case En_Cim_Command.EQSTR:
{
Command_Results[En_Cim_Command.EQSTR] = Check_Receive_Data(csd.data, En_Cim_Command.EQSTR);
Set_Command_Ack(En_Cim_Command.EQSTR, true);
break;
}
case En_Cim_Command.PTSTR:
{
Command_Results[En_Cim_Command.PTSTR] = Check_Receive_Data(csd.data, En_Cim_Command.PTSTR);
Set_Command_Ack(En_Cim_Command.PTSTR, true);
break;
}
case En_Cim_Command.ALMRT:
{
Command_Results[En_Cim_Command.ALMRT] = Check_Receive_Data(csd.data, En_Cim_Command.ALMRT);
Set_Command_Ack(En_Cim_Command.ALMRT, true);
break;
}
case En_Cim_Command.INCRQ:
{
_equip.cim_server.Set_Command_Ack(En_Cim_Command.INCRT, false);
Command_Results[En_Cim_Command.INCRQ] = Check_Receive_Data(csd.data, En_Cim_Command.INCRQ);
Set_Command_Ack(En_Cim_Command.INCRQ, true);
break;
}
case En_Cim_Command.TINRQ:
{
_equip.cim_server.Set_Command_Ack(En_Cim_Command.TINRT, false);
Command_Results[En_Cim_Command.TINRQ] = Check_Receive_Data(csd.data, En_Cim_Command.TINRQ);
Set_Command_Ack(En_Cim_Command.TINRQ, true);
break;
}
case En_Cim_Command.PREND:
{
Command_Results[En_Cim_Command.PREND] = Check_Receive_Data(csd.data, En_Cim_Command.PREND);
Set_Command_Ack(En_Cim_Command.PREND, true);
break;
}
case En_Cim_Command.PTINR:
{
Command_Results[En_Cim_Command.PTINR] = Check_Receive_Data(csd.data, En_Cim_Command.PTINR);
Set_Command_Ack(En_Cim_Command.PTINR, true);
break;
}
case En_Cim_Command.PCMRT:
{
Command_Results[En_Cim_Command.PCMRT] = Check_Receive_Data(csd.data, En_Cim_Command.PCMRT);
Set_Command_Ack(En_Cim_Command.PCMRT, true);
break;
}
case En_Cim_Command.STPRP:
{
Command_Results[En_Cim_Command.STPRP] = Check_Receive_Data(csd.data, En_Cim_Command.STPRP);
Set_Command_Ack(En_Cim_Command.STPRP, true);
break;
}
default:
{
break;
}
}
}
}
catch (Exception ex)
{
}
}
}
public void Dispose()
{
IsDisposed = true;
client.Disconnect();
}
///
/// ASCII로 변환하여 Byte 전송.
///
///
///
public bool Send_Data(string str)
{
try
{
if (client != null && client.isConnected)
{
return client.SendData(str + "\r\n");
}
else
throw new Exception($"{Clientname.ToString()} is not connected.");
}
catch (Exception ex)
{
return false;
}
}
private bool Get_Data(out string command)
{
command = string.Empty;
Time_Checker time_check = new Time_Checker();
time_check.Start();
while (true)
{
if (commandlist.Count > 0)
{
command = (string)commandlist.Dequeue();
return true;
}
else if (time_check.Seconds > 10)
return false;
Thread.Sleep(10);
}
}
private bool Check_Receive_Data(string data, En_Cim_Command cmd)
{
commandlist.Clear();
try
{
Init_Client();
if (client.Connect())
{
if (Send_Data(data))
{
Write_Client_Log($"[Send Success] {data}");
string recv_data;
if (Get_Data(out recv_data))
{
Write_Client_Log($"[Receive Success] {recv_data}");
string[] datas = recv_data.Split(',');
if (datas.Length == 4)
{
string sequence_no = datas[0];
string command = datas[1];
string control = datas[2];
string data_1 = datas[3];
if (command == cmd.ToString())
{
if (data_1 == "0")
return true;
}
else
{
Write_Client_Log($"[Matching Fail] Command is Different {cmd.ToString()} <-> {command}");
}
}
else
{
Write_Client_Log($"[Matching Fail] datas length is not 4.");
}
return false;
}
else
{
Write_Client_Log($"[Receive Fail] Receive ACK fail {cmd.ToString()}");
return false;
}
}
else
{
Write_Client_Log($"[Send Fail] Send Data fail {cmd.ToString()}");
Alarm_Manager.Instance.Occurred(En_Alarm_List.AL_0920_CIM_COMMUNICATION_ERROR);
return false;
}
}
else
{
Write_Client_Log($"[Connection Fail] Connection fail {cmd.ToString()}");
Alarm_Manager.Instance.Occurred(En_Alarm_List.AL_0921_CIM_CLIENT_CONNECTION_ERROR);
return false;
}
}
finally
{
//is_communicate = false;
client.Disconnect();
}
}
public bool Send_On_Line(string seq_num, bool online)
{
try
{
if (Command_Acks[En_Cim_Command.ONLRT] == false)
{
return false;
}
string command = string.Empty;
string status = online ? "ONL" : "OFL";
this.online = online;
command = $"{seq_num},{En_Cim_Command.ONLRT.ToString()},ENQ,{_equip.equipment_info.Device_ID},{status}";
Set_Command_Ack(En_Cim_Command.ONLRT, false);
send_datas.Enqueue(new Cim_Send_Data(En_Cim_Command.ONLRT, command));
return true;
//return Check_Receive_Data(command, En_Cim_Command.ONLRT);
}
finally
{
}
}
public bool Send_Equipment_Status(string seq_num)
{
try
{
if (Command_Acks[En_Cim_Command.EQSTR] == false)
{
return false;
}
string command = string.Empty;
string data_1 = _equip.equipment_info.Device_ID;
string data_2 = _equip.equip_status_code.ToString(); //장치 상태 code
string data_3 = _equip.Cur_Main_Recipe.Name; // recipe Id
string data_4 = _equip.equipment_info.Program_Name; // program name
string data_5 = _equip.equipment_info.Program_Version; // program version
string data_6 = _equip.equipment_info.Module_Model_ID; // module 기종명
string data_7 = _equip.Mode.Agv_Skip ? "1" : "0"; // AGV 반송 모드 0 : 반출입 ok , 1 : 반출입 no
string data_8 = _equip.equipment_info.Purpose_Code; // 목적 Code
string data_9 = _equip.equipment_info.Mass_Production_Code; // 양산 Code
string data_10 = _equip.equipment_info.Prototype_Name; // 시제작 명칭
string data_11 = _equip.equipment_info.Person_In_Charge_Code; // 처리담당자 Code
string data_12 = _equip.equipment_info.Team.ToString(); // 조
command = $"{seq_num},{En_Cim_Command.EQSTR.ToString()},ENQ,{data_1},{data_2},{data_3},{data_4},{data_5},{data_6},{data_7},{data_8},{data_9},{data_10},{data_11},{data_12}";
Set_Command_Ack(En_Cim_Command.EQSTR, false);
send_datas.Enqueue(new Cim_Send_Data(En_Cim_Command.EQSTR, command));
return true;
//return Check_Receive_Data(command, En_Cim_Command.EQSTR);
}
catch(Exception )
{
return false;
}
}
public bool Send_Port_Status(string seq_num, En_Port_ID port_id, En_Tray_Code tray_code, bool is_empty, En_Port_Status port_status, string cover_tray_id = "")
{
if (Command_Acks[En_Cim_Command.PTSTR] == false)
{
return false;
}
string command = string.Empty;
string data_1 = _equip.equipment_info.Device_ID;
string data_2 = port_id.ToString(); // port id
string data_3 = tray_code.ToString(); // tray 종별
data_3 += is_empty ? "0" : "1";
string data_4 = port_status.ToString(); // port 상태 Code
string data_5 = cover_tray_id;// cover tray id
command = $"{seq_num},{En_Cim_Command.PTSTR.ToString()},ENQ,{data_1},{data_2},{data_3},{data_4},{data_5}";
Set_Command_Ack(En_Cim_Command.PTSTR, false);
send_datas.Enqueue(new Cim_Send_Data(En_Cim_Command.PTSTR, command));
return true;
//return Check_Receive_Data(command, En_Cim_Command.PTSTR);
}
public bool Send_Alarm(string seq_num, bool alarm_occurred, Alarm_Occurred alarm_info)
{
if (Command_Acks[En_Cim_Command.ALMRT] == false)
{
return false;
}
string command = string.Empty;
string data_1 = _equip.equipment_info.Device_ID;
string data_2 = alarm_occurred ? "100" : "000"; // Alarm Code 1 byte ( 1 : alarm 발생, 0 :alarm 해제), 2~3 byte 알람분류(00 고정)
string data_3 = $"{(int)alarm_info.Code:d4}"; // Alarm Id (4자리)
string data_4 = alarm_info.Description; // Alarm Text (UTF-8)
command = $"{seq_num},{En_Cim_Command.ALMRT.ToString()},ENQ,{data_1},{data_2},{data_3},{data_4}";
Set_Command_Ack(En_Cim_Command.ALMRT, false);
send_datas.Enqueue(new Cim_Send_Data(En_Cim_Command.ALMRT, command));
return true;
//return Check_Receive_Data(command, En_Cim_Command.ALMRT);
}
public bool Send_Panel_In_Check(string seq_num, string panel_id)
{
if (Command_Acks[En_Cim_Command.INCRQ] == false)
{
return false;
}
string command = string.Empty;
string data_1 = _equip.equipment_info.Device_ID;
string data_2 = _equip.equipment_info.Process_Number; // 공정번호
string data_3 = _equip.equipment_info.Module_Model_ID; // module 기종병
string data_4 = panel_id; // panel id
command = $"{seq_num},{En_Cim_Command.INCRQ.ToString()},ENQ,{data_1},{data_2},{data_3},{data_4}";
Set_Command_Ack(En_Cim_Command.INCRQ, false);
send_datas.Enqueue(new Cim_Send_Data(En_Cim_Command.INCRQ, command));
return true;
//return Check_Receive_Data(command, En_Cim_Command.INCRQ);
}
public bool Send_Tray_In_Check(string seq_num, string cover_tray_id)
{
if (Command_Acks[En_Cim_Command.TINRQ] == false)
{
return false;
}
string command = string.Empty;
string data_1 = _equip.equipment_info.Device_ID;
string data_2 = _equip.equipment_info.Process_Number; // 공정번호
string data_3 = _equip.equipment_info.Module_Model_ID; // module 기종병
string data_4 = cover_tray_id; // tray id
command = $"{seq_num},{En_Cim_Command.TINRQ.ToString()},ENQ,{data_1},{data_2},{data_3},{data_4}";
Set_Command_Ack(En_Cim_Command.TINRQ, false);
send_datas.Enqueue(new Cim_Send_Data(En_Cim_Command.TINRQ, command));
return true;
//return Check_Receive_Data(command, En_Cim_Command.TINRQ);
}
public bool Send_Process_End(string seq_num, Panel_Info info)
{
if (Command_Acks[En_Cim_Command.PREND] == false)
{
return false;
}
string command = string.Empty;
//Data 1 ~ 380 까지 존재
string data_1 = _equip.equipment_info.Device_ID; //장치 ID
string data_2 = _equip.equipment_info.Process_Number.ToString(); //공정번호
string data_3 = _equip.Cur_Main_Recipe.Name; //recipe Id
string data_4 = _equip.equipment_info.Program_Name; //program name
string data_5 = _equip.equipment_info.Program_Version; //program version
string data_6 = _equip.equipment_info.Module_Model_ID; //module 기종명
string data_7 = _equip.equipment_info.Purpose_Code; //목적 Code
string data_8 = _equip.equipment_info.Mass_Production_Code; //양산 Code
string data_9 = _equip.equipment_info.Prototype_Name; //시제작 명칭
string data_10 = info.Panel_ID; //panel id
string data_11 = _equip.equipment_info.Person_In_Charge_Code; //처리담당자 Code
string data_12 = _equip.equipment_info.Team.ToString(); // 조
string data_13 = info.Start_Time.ToString("yyyyMMddHHmmssff"); //처리개시일시
string data_14 = info.End_Time.ToString("yyyyMMddHHmmssff"); //처리종료일시
string data_15 = _equip.equipment_info.Line_Name; //Line 명칭
string data_16 = info.Measurement_Result ? "0" : "4";//판정Code
string data_17 = info.Measurement_Result ? string.Empty : $"{(int)(En_Judgement_Reason.Ng):d7}";
string data_etc = string.Empty;
for (int i = 18; i < 81; i++)
{
data_etc += $",";
}
data_etc += (info.Stage_Num + 1).ToString() + ",";
data_etc += $"{info.Mark1Point1:f3}" + ",";
data_etc += $"{info.Mark1Point2:f3}" + ",";
data_etc += $"{info.Mark2Point1:f3}" + ",";
data_etc += $"{info.Mark2Point2:f3}" + ",";
data_etc += $"{info.Mark3Point1:f3}" + ",";
data_etc += $"{info.Mark3Point2:f3}" + ",";
data_etc += $"{info.Mark4Point1:f3}" + ",";
data_etc += $"{info.Mark4Point2:f3}" + ",";
data_etc += $"{info.AblationPower:f3}" + ",";
data_etc += $"{info.AblationTargetPower:f3}" + ",";
data_etc += $"{info.Film_Judge_Result:f3}" + ",";
data_etc += $"{info.Fine_Align_Distatnce:f3}" + ",";
data_etc += $"{info.Mark1Width:f3}" + ",";
data_etc += $"{info.Mark2Width:f3}" + ",";
data_etc += $"{info.Mark3Width:f3}" + ",";
data_etc += $"{info.Mark4Width:f3}" + ",";
data_etc += $"{info.Mark5Width:f3}" + ",";
data_etc += $"{info.Mark6Width:f3}" + ",";
data_etc += $"{info.Mark7Width:f3}" + ",";
data_etc += $"{info.Mark8Width:f3}" + ",";
for (int i = 86; i < 380; i++)
{
data_etc += $",";
}
command = $"{seq_num},{En_Cim_Command.PREND.ToString()},ENQ,{data_1},{data_2},{data_3},{data_4},{data_5},{data_6},{data_7},{data_8},{data_9},{data_10},{data_11},{data_12},{data_13},{data_14},{data_15},{data_16},{data_17},{data_etc}";
Set_Command_Ack(En_Cim_Command.PREND, false);
send_datas.Enqueue(new Cim_Send_Data(En_Cim_Command.PREND, command));
return true;
}
public bool Send_Panel_Tray_In(string seq_num, string tray_id, string panel_id, string location, En_Port_ID port_id)
{
if (Command_Acks[En_Cim_Command.PTINR] == false)
{
return false;
}
string command = string.Empty;
string data_1 = _equip.equipment_info.Device_ID; //장치 ID
string data_2 = tray_id; // tray id
string data_3 = panel_id; // panel id
string data_4 = location; // 수납 위치
string data_5 = port_id.ToString(); // port id
command = $"{seq_num},{En_Cim_Command.PTINR.ToString()},ENQ,{data_1},{data_2},{data_3},{data_4},{data_5}";
Set_Command_Ack(En_Cim_Command.PTINR, false);
send_datas.Enqueue(new Cim_Send_Data(En_Cim_Command.PTINR, command));
return true;
//return Check_Receive_Data(command, En_Cim_Command.PTINR);
}
public bool Send_Panel_Form_Report(string seq_num, string tray_id, En_Port_ID port_id)
{
if (Command_Acks[En_Cim_Command.PCMRT] == false)
{
return false;
}
string command = string.Empty;
string data_1 = _equip.equipment_info.Device_ID; //장치 ID
string data_2 = _equip.equipment_info.Process_Number; //공정 번호
string data_3 = tray_id; // cover tray id
string data_4 = port_id.ToString(); // port id
command = $"{seq_num},{En_Cim_Command.PCMRT.ToString()},ENQ,{data_1},{data_2},{data_3},{data_4}";
Set_Command_Ack(En_Cim_Command.PCMRT, false);
send_datas.Enqueue(new Cim_Send_Data(En_Cim_Command.PCMRT, command));
return true;
//return Check_Receive_Data(command, En_Cim_Command.PCMRT);
}
public bool Send_Earthquake_Stop(string seq_num)
{
if (Command_Acks[En_Cim_Command.STPRP] == false)
{
return false;
}
string command = string.Empty;
string data_1 = _equip.equipment_info.Device_ID; //장치 ID
string data_2 = "0"; // 정지 레벨 0 : 정지 없음.
string data_3 = "0"; // 정지 결과 0 : OK
command = $"{seq_num},{En_Cim_Command.STPRP.ToString()},ENQ,{data_1},{data_2},{data_3}";
Set_Command_Ack(En_Cim_Command.STPRP, false);
send_datas.Enqueue(new Cim_Send_Data(En_Cim_Command.STPRP, command));
return true;
//return Check_Receive_Data(command, En_Cim_Command.STPRP);
}
private void Set_Command_Ack(En_Cim_Command command, bool value)
{
Command_Acks[command] = value;
}
public bool Get_Command_Ack(En_Cim_Command command)
{
return Command_Acks[command];
}
private void Set_Command_Result(En_Cim_Command command, bool value)
{
Command_Results[command] = value;
}
public bool Get_Command_Result(En_Cim_Command command)
{
return Command_Results[command];
}
#endregion
}
public struct Cim_Send_Data
{
public En_Cim_Command command { get; set; }
public string data { get; set; }
public Cim_Send_Data(En_Cim_Command command, string data)
{
this.command = command;
this.data = data;
}
}
}