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; } } }