6. 중앙 관제 6.6 중앙 관제에서 라인 제어하기 [Wafer 코팅 시뮬레이션]

안녕하세요. 언제나휴일입니다.

1. 해야 할 일

이번 강의는 Wafer 코팅 시뮬레이션의 마지막 강의입니다.

중앙 관제에서 공장의 WaferLine을 원격 제어하는 부분입니다.

원격 제어로 할 수 있는 것은 Wafer 추가, 코팅액 추가, 스핀 속도 설정, 코팅액 낙하 속도 설정입니다.

2. MsgType에 열거 추가

WaferLineCommLib에 있는 열거형 MsgType에 원격 제어에 관한 부분을 추가합니다.

추가한 이후에 MsgType.cs 소스 코드는 다음과 같습니다.

namespace WaferLineCommLib
{
    public enum MsgType
    {
        MSG_CF_ADDSI,
        MSG_CF_ADDWF,
        MSG_CF_ADDPR,
        MSG_CF_SETSP,
        MSG_CF_SETDR,
        MSG_FC_ADDLN,
        MSG_FC_ADDWF,
        MSG_FC_ADDPR,
        MSG_FC_SETSP,
        MSG_FC_SETDR,
        MSG_FC_ENDPR,
        MSG_FC_ENDCO
    }
}

3. FactoryClient 추가 구현

이번에는 WaferLineCommLib의 FactoryClient에서 원격 제어에 관한 메시지를 전송하는 네 개의 메서드를 추가합니다.

        public void SendAddWafer(int no, int wcnt)
        {
            byte[] packet = new byte[128];
            MemoryStream ms = new MemoryStream(packet);
            BinaryWriter bw = new BinaryWriter(ms);
            bw.Write((int)MsgType.MSG_CF_ADDWF);
            bw.Write(no);
            bw.Write(wcnt);
            bw.Close();
            ms.Close();
            SendPacket(packet);
        }
        public void SendAddPr(int no, int pcnt)
        {
            byte[] packet = new byte[128];
            MemoryStream ms = new MemoryStream(packet);
            BinaryWriter bw = new BinaryWriter(ms);
            bw.Write((int)MsgType.MSG_CF_ADDPR);
            bw.Write(no);
            bw.Write(pcnt);
            bw.Close();
            ms.Close();
            SendPacket(packet);
        }
        public void SendSetSpin(int no, int spin)
        {
            byte[] packet = new byte[128];
            MemoryStream ms = new MemoryStream(packet);
            BinaryWriter bw = new BinaryWriter(ms);
            bw.Write((int)MsgType.MSG_CF_SETSP);
            bw.Write(no);
            bw.Write(spin);
            bw.Close();
            ms.Close();
            SendPacket(packet);
        }
        public void SendSetDrop(int no, int drop)
        {
            byte[] packet = new byte[128];
            MemoryStream ms = new MemoryStream(packet);
            BinaryWriter bw = new BinaryWriter(ms);
            bw.Write((int)MsgType.MSG_CF_SETDR);
            bw.Write(no);
            bw.Write(drop);
            bw.Close();
            ms.Close();
            SendPacket(packet);
        }

FactoryClient.cs 의 전체 코드는 다음과 같습니다.

using System.IO;
using System.Net;
using System.Net.Sockets;

namespace WaferLineCommLib
{
    public class FactoryClient
    {
        string fip;
        int fport;
        public FactoryClient(string fip, int fport)
        {
            this.fip = fip;
            this.fport = fport;
        }
        public void SendMyInfo(string ip, int port)
        {
            byte[] packet = new byte[128];
            MemoryStream ms = new MemoryStream(packet);
            BinaryWriter bw = new BinaryWriter(ms);
            bw.Write((int)MsgType.MSG_CF_ADDSI);
            bw.Write(ip);
            bw.Write(port);
            bw.Close();
            ms.Close();
            SendPacket(packet);
        }

        private void SendPacket(byte[] packet)
        {
            Socket sock = new Socket(AddressFamily.InterNetwork,
                SocketType.Stream, ProtocolType.Tcp);
            IPAddress addr = IPAddress.Parse(fip);
            IPEndPoint ep = new IPEndPoint(addr, fport);
            sock.Connect(ep);
            sock.Send(packet);
            sock.Close();
        }
        public void SendAddWafer(int no, int wcnt)
        {
            byte[] packet = new byte[128];
            MemoryStream ms = new MemoryStream(packet);
            BinaryWriter bw = new BinaryWriter(ms);
            bw.Write((int)MsgType.MSG_CF_ADDWF);
            bw.Write(no);
            bw.Write(wcnt);
            bw.Close();
            ms.Close();
            SendPacket(packet);
        }
        public void SendAddPr(int no, int pcnt)
        {
            byte[] packet = new byte[128];
            MemoryStream ms = new MemoryStream(packet);
            BinaryWriter bw = new BinaryWriter(ms);
            bw.Write((int)MsgType.MSG_CF_ADDPR);
            bw.Write(no);
            bw.Write(pcnt);
            bw.Close();
            ms.Close();
            SendPacket(packet);
        }
        public void SendSetSpin(int no, int spin)
        {
            byte[] packet = new byte[128];
            MemoryStream ms = new MemoryStream(packet);
            BinaryWriter bw = new BinaryWriter(ms);
            bw.Write((int)MsgType.MSG_CF_SETSP);
            bw.Write(no);
            bw.Write(spin);
            bw.Close();
            ms.Close();
            SendPacket(packet);
        }
        public void SendSetDrop(int no, int drop)
        {
            byte[] packet = new byte[128];
            MemoryStream ms = new MemoryStream(packet);
            BinaryWriter bw = new BinaryWriter(ms);
            bw.Write((int)MsgType.MSG_CF_SETDR);
            bw.Write(no);
            bw.Write(drop);
            bw.Close();
            ms.Close();
            SendPacket(packet);
        }
    }
}

4. FactoryServer 추가 구현하기

WaferLineCommLib의 FactoryServer 클래스를 추가 구현합시다.

먼저 제어 메시지를 수신하였을 때 이벤트 전달을 위한 이벤트 멤버를 추가합니다.

using System.IO;
using System.Net;
using System.Net.Sockets;
using WaferLineLib;

namespace WaferLineCommLib
{
    public class FactoryServer
    {
        public event RecvStsEndPtEventHandler RecvStsEndPoint;
        public event AddWaferEventHandler AddedWafer;
        public event AddPREventHandler AddedPR;
        public event SetSpeedEventHandler SettedSpeed;
        public event SetDropEventHandler SettedDrop;

DoIt 메서드에 메시지 수신에 관한 switch 처리문을 추가 구현합니다.

        private void DoIt(Socket dosock)
        {
            byte[] packet = new byte[128];
            dosock.Receive(packet);
            MemoryStream ms = new MemoryStream(packet);
            BinaryReader br = new BinaryReader(ms);
            MsgType msgtype = (MsgType)br.ReadInt32();
            switch(msgtype)
            {
                case MsgType.MSG_CF_ADDSI: SetAddressProc(br); break;
                case MsgType.MSG_CF_ADDPR: AddPRProc(br); break;
                case MsgType.MSG_CF_ADDWF: AddWaferProc(br); break;
                case MsgType.MSG_CF_SETDR: SetDropProc(br); break;
                case MsgType.MSG_CF_SETSP: SetSpeedProc(br); break;
            }
            br.Close();
            ms.Close();
            dosock.Close();
        }

그리고 메시지를 수신했을 때 처리하는 각 메서드를 구현합니다.

        private void SetSpeedProc(BinaryReader br)
        {
            int no = br.ReadInt32();
            int speed = br.ReadInt32();
            if (SettedSpeed != null)
            {
                SettedSpeed(this, new SetSpeedEventArgs(no, speed));
            }
        }
        private void SetDropProc(BinaryReader br)
        {
            int no = br.ReadInt32();
            int drop = br.ReadInt32();
            if (SettedDrop != null)
            {
                SettedDrop(this, new SetDropEventArgs(no, drop));
            }
        }
        private void AddPRProc(BinaryReader br)
        {
            int no = br.ReadInt32();
            int pcnt = br.ReadInt32();
            if (AddedPR != null)
            {
                AddedPR(this, new AddPREventArgs(no, pcnt));
            }
        }
        private void AddWaferProc(BinaryReader br)
        {
            int no = br.ReadInt32();
            int bwcnt = br.ReadInt32();
            if (AddedWafer != null)
            {
                AddedWafer(this, new AddWaferEventArgs(no, bwcnt));
            }
        }

FactoryServer.cs 소스 코드는 다음과 같습니다.

using System.IO;
using System.Net;
using System.Net.Sockets;
using WaferLineLib;

namespace WaferLineCommLib
{
    public class FactoryServer
    {
        public event RecvStsEndPtEventHandler RecvStsEndPoint;
        public event AddWaferEventHandler AddedWafer;
        public event AddPREventHandler AddedPR;
        public event SetSpeedEventHandler SettedSpeed;
        public event SetDropEventHandler SettedDrop;
        public string IP { get; }
        public int Port { get; }
        public FactoryServer(string ip,int port)
        {
            IP = ip;
            Port = port;
        }

        delegate void StartDele();
        public void StartAsync()
        {
            StartDele dele = Start;
            dele.BeginInvoke(null, null);
        }
        Socket sock;
        public void Start()
        {
            sock = new Socket(AddressFamily.InterNetwork,
                SocketType.Stream, ProtocolType.Tcp);
            IPAddress addr = IPAddress.Parse(IP);
            IPEndPoint endp = new IPEndPoint(addr, Port);
            sock.Bind(endp);
            sock.Listen(5);
            AcceptLoop();
        }

        private void AcceptLoop()
        {
            while(true)
            {
                Socket dosock = sock.Accept();
                DoIt(dosock);
            }
        }

        private void DoIt(Socket dosock)
        {
            byte[] packet = new byte[128];
            dosock.Receive(packet);
            MemoryStream ms = new MemoryStream(packet);
            BinaryReader br = new BinaryReader(ms);
            MsgType msgtype = (MsgType)br.ReadInt32();
            switch(msgtype)
            {
                case MsgType.MSG_CF_ADDSI: SetAddressProc(br); break;
                case MsgType.MSG_CF_ADDPR: AddPRProc(br); break;
                case MsgType.MSG_CF_ADDWF: AddWaferProc(br); break;
                case MsgType.MSG_CF_SETDR: SetDropProc(br); break;
                case MsgType.MSG_CF_SETSP: SetSpeedProc(br); break;
            }
            br.Close();
            ms.Close();
            dosock.Close();
        }
        private void SetSpeedProc(BinaryReader br)
        {
            int no = br.ReadInt32();
            int speed = br.ReadInt32();
            if (SettedSpeed != null)
            {
                SettedSpeed(this, new SetSpeedEventArgs(no, speed));
            }
        }
        private void SetDropProc(BinaryReader br)
        {
            int no = br.ReadInt32();
            int drop = br.ReadInt32();
            if (SettedDrop != null)
            {
                SettedDrop(this, new SetDropEventArgs(no, drop));
            }
        }
        private void AddPRProc(BinaryReader br)
        {
            int no = br.ReadInt32();
            int pcnt = br.ReadInt32();
            if (AddedPR != null)
            {
                AddedPR(this, new AddPREventArgs(no, pcnt));
            }
        }
        private void AddWaferProc(BinaryReader br)
        {
            int no = br.ReadInt32();
            int bwcnt = br.ReadInt32();
            if (AddedWafer != null)
            {
                AddedWafer(this, new AddWaferEventArgs(no, bwcnt));
            }
        }
        private void SetAddressProc(BinaryReader br)
        {
            IPAddress ipaddr = IPAddress.Parse(br.ReadString());
            int port = br.ReadInt32();
            if(RecvStsEndPoint != null)
            {
                RecvStsEndPoint(this, new RecvStsEndPtEventArgs(ipaddr, port));
            }
        }
    }
}

5. CentralForm 추가 구현

중앙 관제의 CentralForm을 추가 구현합시다.

btn_wafer의 Click 이벤트 핸들러, btn_pr의 Click 이벤트 핸들러를 등록합니다.

tbar_wafer, tbar_pr, tbar_spin, tbar_drop의 Scroll 이벤트 핸들러를 등록합니다.

        private void tbar_wafer_Scroll(object sender, EventArgs e)
        {
            lb_wafer.Text = tbar_wafer.Value.ToString();
        }

        private void btn_wafer_Click(object sender, EventArgs e)
        {
            ListViewItem lvi = lv_line.SelectedItems[0];
            WaferLine wl = lvi.Tag as WaferLine;
            int wcnt = tbar_wafer.Value;
            fc.SendAddWafer(wl.No, wcnt);
            tbar_wafer.Value = 0;
        }

        private void tbar_pr_Scroll(object sender, EventArgs e)
        {
            lb_pr.Text = tbar_pr.Value.ToString();
        }

        private void btn_pr_Click(object sender, EventArgs e)
        {
            ListViewItem lvi = lv_line.SelectedItems[0];
            WaferLine wl = lvi.Tag as WaferLine;
            int pcnt = tbar_pr.Value;
            fc.SendAddPr(wl.No, pcnt);
            tbar_pr.Value = 0;
        }

        private void tbar_spin_Scroll(object sender, EventArgs e)
        {
            int spin = tbar_spin.Value;
            lb_spin.Text = spin.ToString();
            ListViewItem lvi = lv_line.SelectedItems[0];
            WaferLine wl = lvi.Tag as WaferLine;
            fc.SendSetSpin(wl.No, spin);
        }

        private void tbar_drop_Scroll(object sender, EventArgs e)
        {
            int drop = tbar_drop.Value;
            lb_drop.Text = drop.ToString();
            ListViewItem lvi = lv_line.SelectedItems[0];
            WaferLine wl = lvi.Tag as WaferLine;
            fc.SendSetDrop(wl.No, drop);
        }

다음은 CentralForm.cs 소스 코드입니다.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using WaferLineCommLib;
using WaferLineLib;

namespace 중앙_관제
{
    public partial class CentralForm : Form
    {
        public CentralForm()
        {
            InitializeComponent();
        }

        private void CentralForm_Load(object sender, EventArgs e)
        {
            IPAddress defaddr = MyNetwork.Addresses[0];
            tbox_me_ip.Text = defaddr.ToString();
        }

        FactoryClient fc;
        private void btn_set_fa_Click(object sender, EventArgs e)
        {
            string fip = tbox_fa_ip.Text;
            int fport = int.Parse(tbox_fa_port.Text);
            fc = new FactoryClient(fip, fport);
        }


        private void btn_set_me_Click(object sender, EventArgs e)
        {
            string ip = tbox_me_ip.Text;
            int port = int.Parse(tbox_me_port.Text);
            ControlServer cs = new ControlServer(ip, port);
            cs.AddedLine += Cs_AddedLine;
            cs.AddedWafer += Cs_AddedWafer;
            cs.AddedPR += Cs_AddedPR;
            cs.SettedSpeed += Cs_SettedSpeed;
            cs.SettedDrop += Cs_SettedDrop;
            cs.EndedPR += Cs_EndedPR;
            cs.EndedCoating += Cs_EndedCoating;
            cs.AsyncStart();
            fc.SendMyInfo(ip, port);
        }

        private void Cs_EndedCoating(object sender, EndCoatingEventArgs e)
        {
            if (this.InvokeRequired)
            {
                EndCoatingEventHandler dele = Cs_EndedCoating;
                this.Invoke(dele, new object[] { sender, e });
            }
            else
            {
                ListViewItem lvi = lvi_dic[e.No];                
                WaferLine wl = lvi.Tag as WaferLine;
                wl.EndCoating(e.BWCnt, e.AWCnt);
                lvi.SubItems[1].Text = e.BWCnt.ToString();
                if (lvi.Selected)
                {                    
                    lb_awafer.Text = e.AWCnt.ToString();
                }
            }
        }

        private void Cs_EndedPR(object sender, EndPREventArgs e)
        {
            if (this.InvokeRequired)
            {
                EndPREventHandler dele = Cs_EndedPR;
                this.Invoke(dele, new object[] { sender, e });
            }
            else
            {
                ListViewItem lvi = lvi_dic[e.No];
                WaferLine wl = lvi.Tag as WaferLine;
                wl.PCnt--;                
                if (lvi.Selected)
                {
                    lb_npr.Text = wl.PCnt.ToString();
                }
            }
        }

        private void Cs_SettedDrop(object sender, SetDropEventArgs e)
        {
            if (this.InvokeRequired)
            {
                SetDropEventHandler dele = Cs_SettedDrop;
                this.Invoke(dele, new object[] { sender, e });
            }
            else
            {
                ListViewItem lvi = lvi_dic[e.No];
                WaferLine wl = lvi.Tag as WaferLine;
                wl.Drop = e.Drop;
                if (lvi.Selected)
                {
                    lb_drop.Text = e.Drop.ToString();
                    tbar_drop.Value = e.Drop;
                }
            }
        }

        private void Cs_SettedSpeed(object sender, SetSpeedEventArgs e)
        {
            if (this.InvokeRequired)
            {
                SetSpeedEventHandler dele = Cs_SettedSpeed;
                this.Invoke(dele, new object[] { sender, e });
            }
            else
            {
                ListViewItem lvi = lvi_dic[e.No];
                WaferLine wl = lvi.Tag as WaferLine;
                wl.Spin = e.Speed;
                if (lvi.Selected)
                {
                    lb_spin.Text = e.Speed.ToString();
                    tbar_spin.Value = e.Speed;
                }
            }
        }

        private void Cs_AddedPR(object sender, AddPREventArgs e)
        {
            if (this.InvokeRequired)
            {
                AddPREventHandler dele = Cs_AddedPR;
                this.Invoke(dele, new object[] { sender, e });
            }
            else
            {
                ListViewItem lvi = lvi_dic[e.No];
                WaferLine wl = lvi.Tag as WaferLine;
                int gap = e.PCnt - wl.PCnt;
                wl.InPr(gap);
                if (lv_line.SelectedItems.Count == 0) { return; }
                if (lvi == lv_line.SelectedItems[0])
                {
                    lb_npr.Text = wl.PCnt.ToString();
                }
            }
        }

        private void Cs_AddedWafer(object sender, AddWaferEventArgs e)
        {
            if(this.InvokeRequired)
            {
                AddWaferEventHandler dele = Cs_AddedWafer;
                this.Invoke(dele, new object[] { sender, e });
            }
            else
            {
                ListViewItem lvi = lvi_dic[e.No];
                lvi.SubItems[1].Text = e.BWCnt.ToString();
                WaferLine wl = lvi.Tag as WaferLine;
                int gap = e.BWCnt - wl.BWCnt;
                wl.InWafer(gap);
            }
        }
        Dictionary<int, ListViewItem> lvi_dic = new Dictionary<int, ListViewItem>();
        private void Cs_AddedLine(object sender, AddLineEventArgs e)
        {
            if(this.InvokeRequired)
            {
                AddLineEventHandler dele = Cs_AddedLine;
                this.Invoke(dele, new object[] { sender, e });
            }
            else
            {
                string[] sitems = new string[] { e.No.ToString(), "0" };
                ListViewItem lvi = new ListViewItem(sitems);
                lv_line.Items.Add(lvi);
                lvi_dic[e.No] = lvi;
                WaferLine wl = new WaferLine(e.No);
                lvi.Tag = wl;
            }
        }

        private void lv_line_SelectedIndexChanged(object sender, EventArgs e)
        {
            if(lv_line.SelectedItems.Count ==0)
            {
                SetLineControl(false);
                return;
            }
            SetLineControl(true);
            ListViewItem lvi = lv_line.SelectedItems[0];
            WaferLine wl = lvi.Tag as WaferLine;
            lb_npr.Text = wl.PCnt.ToString();
            tbar_spin.Value = wl.Spin;
            tbar_drop.Value = wl.Drop;
            lb_spin.Text = wl.Spin.ToString();
            lb_drop.Text = wl.Drop.ToString();
        }

        private void SetLineControl(bool flag)
        {
            tbar_wafer.Enabled = flag;
            tbar_pr.Enabled = flag;
            tbar_spin.Enabled = flag;
            tbar_drop.Enabled = flag;
            btn_wafer.Enabled = flag;
            btn_pr.Enabled = flag;
        }

        private void tbar_wafer_Scroll(object sender, EventArgs e)
        {
            lb_wafer.Text = tbar_wafer.Value.ToString();
        }

        private void btn_wafer_Click(object sender, EventArgs e)
        {
            ListViewItem lvi = lv_line.SelectedItems[0];
            WaferLine wl = lvi.Tag as WaferLine;
            int wcnt = tbar_wafer.Value;
            fc.SendAddWafer(wl.No, wcnt);
            tbar_wafer.Value = 0;
        }

        private void tbar_pr_Scroll(object sender, EventArgs e)
        {
            lb_pr.Text = tbar_pr.Value.ToString();
        }

        private void btn_pr_Click(object sender, EventArgs e)
        {
            ListViewItem lvi = lv_line.SelectedItems[0];
            WaferLine wl = lvi.Tag as WaferLine;
            int pcnt = tbar_pr.Value;
            fc.SendAddPr(wl.No, pcnt);
            tbar_pr.Value = 0;
        }

        private void tbar_spin_Scroll(object sender, EventArgs e)
        {
            int spin = tbar_spin.Value;
            lb_spin.Text = spin.ToString();
            ListViewItem lvi = lv_line.SelectedItems[0];
            WaferLine wl = lvi.Tag as WaferLine;
            fc.SendSetSpin(wl.No, spin);
        }

        private void tbar_drop_Scroll(object sender, EventArgs e)
        {
            int drop = tbar_drop.Value;
            lb_drop.Text = drop.ToString();
            ListViewItem lvi = lv_line.SelectedItems[0];
            WaferLine wl = lvi.Tag as WaferLine;
            fc.SendSetDrop(wl.No, drop);
        }
    }
}

6. Manager 추가 구현

WaferLine 공장 시뮬레이션의 Manger를 추가 구현합시다.

먼저 제어 메시지를 수신하였을 때 이벤트 전달을 위한 이벤트 멤버를 추가합니다.

using System.Net;
using WaferLineCommLib;
using WaferLineLib;

namespace WaferLine_공장_시뮬레이션
{
    public class Manager
    {
        public event RecvStsEndPtEventHandler RecvStsEndPoint;
        public event AddWaferEventHandler AddedWafer;
        public event AddPREventHandler AddedPR;
        public event SetSpeedEventHandler SettedSpeed;
        public event SetDropEventHandler SettedDrop;

StartServer 메서드에서 FactoryServer 개체에 이벤트 핸들러를 등록합니다.

        public void StartServer(string ip,int port)
        {
            FactoryServer fs = new FactoryServer(ip, port);
            fs.RecvStsEndPoint += Fs_RecvStsEndPoint;
            fs.AddedWafer += Fs_AddedWafer;
            fs.AddedPR += Fs_AddedPR;
            fs.SettedSpeed += Fs_SettedSpeed;
            fs.SettedDrop += Fs_SettedDrop;
            fs.StartAsync();
        }

그리고 이벤트 핸들러에서 전달받은 메시지를 전달합니다.

        private void Fs_SettedDrop(object sender, SetDropEventArgs e)
        {
            if (SettedDrop != null)
            {
                SettedDrop(this, e);
            }
        }

        private void Fs_SettedSpeed(object sender, SetSpeedEventArgs e)
        {
            if (SettedSpeed != null)
            {
                SettedSpeed(this, e);
            }
        }



        private void Fs_AddedPR(object sender, AddPREventArgs e)
        {
            if (AddedPR != null)
            {
                AddedPR(this, e);
            }
        }

        private void Fs_AddedWafer(object sender, AddWaferEventArgs e)
        {
            if (AddedWafer != null)
            {
                AddedWafer(this, e);
            }
        }

현재까지 작성한 Manager.cs 소스 코드입니다.

using System.Net;
using WaferLineCommLib;
using WaferLineLib;

namespace WaferLine_공장_시뮬레이션
{
    public class Manager
    {
        public event RecvStsEndPtEventHandler RecvStsEndPoint;
        public event AddWaferEventHandler AddedWafer;
        public event AddPREventHandler AddedPR;
        public event SetSpeedEventHandler SettedSpeed;
        public event SetDropEventHandler SettedDrop;
        private Manager()
        {

        }
        static Manager manager = new Manager();
        static public Manager Singleton
        {
            get
            {
                return manager;
            }
        }
        public void StartServer(string ip,int port)
        {
            FactoryServer fs = new FactoryServer(ip, port);
            fs.RecvStsEndPoint += Fs_RecvStsEndPoint;
            fs.AddedWafer += Fs_AddedWafer;
            fs.AddedPR += Fs_AddedPR;
            fs.SettedSpeed += Fs_SettedSpeed;
            fs.SettedDrop += Fs_SettedDrop;
            fs.StartAsync();
        }
        private void Fs_SettedDrop(object sender, SetDropEventArgs e)
        {
            if (SettedDrop != null)
            {
                SettedDrop(this, e);
            }
        }

        private void Fs_SettedSpeed(object sender, SetSpeedEventArgs e)
        {
            if (SettedSpeed != null)
            {
                SettedSpeed(this, e);
            }
        }



        private void Fs_AddedPR(object sender, AddPREventArgs e)
        {
            if (AddedPR != null)
            {
                AddedPR(this, e);
            }
        }

        private void Fs_AddedWafer(object sender, AddWaferEventArgs e)
        {
            if (AddedWafer != null)
            {
                AddedWafer(this, e);
            }
        }

        ControlClient cc;
        private void Fs_RecvStsEndPoint(object sender, RecvStsEndPtEventArgs e)
        {
            IPAddress cip = e.IPAddress;
            int cport = e.Port;
            cc = new ControlClient(cip, cport);
            if(RecvStsEndPoint != null)
            {
                RecvStsEndPoint(this, e);
            }
        }

        public void AddLine(int no)
        {
            if(cc == null)
            {
                return;
            }
            if(cc.SendAddLine(no) == false)
            {
                cc = null;
            }
        }

        public void AddWafer(int no, int bwcnt)
        {
            if (cc == null)
            {
                return;
            }
            if (cc.SendAddWafer(no,bwcnt) == false)
            {
                cc = null;
            }
        }

        public void AddPR(int no, int pcnt)
        {
            if (cc == null)
            {
                return;
            }
            if (cc.SendAddPR(no, pcnt) == false)
            {
                cc = null;
            }
        }

        public void EndedPR(int no)
        {
            if (cc == null)
            {
                return;
            }
            if (cc.SendEndPR(no) == false)
            {
                cc = null;
            }
        }

        public void SetSpeed(int no, int spin)
        {
            if (cc == null)
            {
                return;
            }
            if (cc.SendSetSpeed(no,spin) == false)
            {
                cc = null;
            }
        }

        public void SetDrop(int no, int drop)
        {
            if (cc == null)
            {
                return;
            }
            if (cc.SendSetDrop(no, drop) == false)
            {
                cc = null;
            }
        }

        public void EndedCoating(int no, int bwcnt, int awcnt)
        {
            if (cc == null)
            {
                return;
            }
            if (cc.SendEndedCoating(no, bwcnt, awcnt) == false)
            {
                cc = null;
            }
        }
    }
}

7. MainForm 추가 구현

WaferLine 공장 시뮬레이션의 MainForm을 추가 구현합시다.

MainForm_Load 메서드에서 Manager에 이벤트 핸들러를 등록하는 코드를 추가합니다.

        private void MainForm_Load(object sender, EventArgs e)
        {
            cbox_ip.DataSource = MyNetwork.Addresses;
            Manager manager = Manager.Singleton;
            manager.RecvStsEndPoint += Manager_RecvStsEndPoint;
            manager.AddedWafer += Manager_AddedWafer;
            manager.AddedPR += Manager_AddedPR;
            manager.SettedSpeed += Manager_SettedSpeed;
            manager.SettedDrop += Manager_SettedDrop;
        }

크로스 스레드를 고려하여 등록한 이벤트 핸들러를 구현합니다.

        private void Manager_SettedDrop(object sender, SetDropEventArgs e)
        {
            if(this.InvokeRequired)
            {
                SetDropEventHandler dele = Manager_SettedDrop;
                this.Invoke(dele, new object[] { sender, e });
            }
            else
            {
                ListViewItem lvi = lv_line.Items[e.No - 1];
                WaferLine wl = lvi.Tag as WaferLine;
                wl.Drop = e.Drop;
                WaferLineForm lvf = wdic[e.No];
                lvf.SetStatus();
                if(lvi.Selected)
                {
                    lb_drop.Text = e.Drop.ToString();
                }
            }
        }

        private void Manager_SettedSpeed(object sender, SetSpeedEventArgs e)
        {
            if (this.InvokeRequired)
            {
                SetSpeedEventHandler dele = Manager_SettedSpeed;
                this.Invoke(dele, new object[] { sender, e });
            }
            else
            {
                ListViewItem lvi = lv_line.Items[e.No - 1];
                WaferLine wl = lvi.Tag as WaferLine;
                wl.Spin = e.Speed;
                WaferLineForm lvf = wdic[e.No];
                lvf.SetStatus();
                if (lvi.Selected)
                {
                    lb_spin.Text = e.Speed.ToString();
                }
            }
        }

        private void Manager_AddedPR(object sender, AddPREventArgs e)
        {
            if (this.InvokeRequired)
            {
                AddPREventHandler dele = Manager_AddedPR;
                this.Invoke(dele, new object[] { sender, e });
            }
            else
            {
                ListViewItem lvi = lv_line.Items[e.No - 1];
                WaferLine wl = lvi.Tag as WaferLine;
                wl.InPr(e.PCnt);
                ChangeStatusWaferLine(e.No);
                WaferLineForm lvf = wdic[e.No];
                lvf.Invalidate(true);
            }
        }

        private void Manager_AddedWafer(object sender, AddWaferEventArgs e)
        {
            if (this.InvokeRequired)
            {
                AddWaferEventHandler dele = Manager_AddedWafer;
                this.Invoke(dele, new object[] { sender, e });
            }
            else
            {
                ListViewItem lvi = lv_line.Items[e.No - 1];
                WaferLine wl = lvi.Tag as WaferLine;
                wl.InWafer(e.BWCnt);
                ChangeStatusWaferLine(e.No);
                WaferLineForm lvf = wdic[e.No];
                lvf.Invalidate(true);
            }
        }

다음은 MainForm.cs 소스 코드입니다.

using System;
using System.Collections.Generic;
using System.Windows.Forms;
using WaferLineCommLib;
using WaferLineLib;

namespace WaferLine_공장_시뮬레이션
{
    public partial class MainForm : Form
    {
        public MainForm()
        {
            InitializeComponent();
        }

        int next_lineno = 1;
        Dictionary<int, WaferLineForm> wdic = new Dictionary<int, WaferLineForm>();

        private void btn_add_Click(object sender, EventArgs e)
        {
            int no = next_lineno;
            next_lineno++;
            WaferLine wl = new WaferLine(no);
            string[] sitems = new string[] { no.ToString(), "0", "0" };
            ListViewItem lvi = new ListViewItem(sitems);
            lvi.Tag = wl;
            lv_line.Items.Add(lvi);
            cb_line.Items.Add(wl);
            lb_next_no.Text = next_lineno.ToString();
            WaferLineForm wlf = new WaferLineForm(wl);
            wlf.EndedCoating += Wlf_EndedCoating;
            wlf.AddedWafer += Wlf_AddedWafer;
            wlf.AddedPR += Wlf_AddedPR;
            wlf.SettedSpeed += Wlf_SettedSpeed;
            wlf.SettedDrop += Wlf_SettedDrop;
            wlf.EndedPR += Wlf_EndedPR;
            wdic.Add(no, wlf);
            Manager manager = Manager.Singleton;
            manager.AddLine(no);
        }

        private void Wlf_EndedPR(object sender, EndPREventArgs e)
        {
            ListViewItem lvi = lv_line.Items[e.No - 1];
            if(lvi.Selected)
            {
                WaferLine wl = lvi.Tag as WaferLine;
                lb_pr.Text = wl.PCnt.ToString();
            }
        }

        private void Wlf_SettedDrop(object sender, SetDropEventArgs e)
        {
            ChangeStatusSelectedWaferLine(e.No);
        }

        private void ChangeStatusSelectedWaferLine(int no)
        {
            ListViewItem lvi = lv_line.Items[no - 1];
            if(lvi.Selected)
            {
                WaferLine wl = lvi.Tag as WaferLine;
                lb_spin.Text = wl.Spin.ToString();
                lb_drop.Text = wl.Drop.ToString();
                lb_pr.Text = wl.PCnt.ToString();
            }
        }

        private void Wlf_SettedSpeed(object sender, SetSpeedEventArgs e)
        {
            ChangeStatusSelectedWaferLine(e.No);
        }

        private void Wlf_AddedPR(object sender, AddPREventArgs e)
        {
            ChangeStatusSelectedWaferLine(e.No);
        }

        private void Wlf_AddedWafer(object sender, AddWaferEventArgs e)
        {
            ChangeStatusWaferLine(e.No);
        }
        void ChangeStatusWaferLine(int no)
        {
            ListViewItem lvi = lv_line.Items[no - 1];
            WaferLine wl = lvi.Tag as WaferLine;
            lvi.SubItems[1].Text = wl.BWCnt.ToString();
            lvi.SubItems[2].Text = wl.AWCnt.ToString();
            cb_line.Items[no - 1] = wl;
        }

        private void Wlf_EndedCoating(object sender, EndCoatingEventArgs e)
        {
            ChangeStatusWaferLine(e.No);
            ListViewItem lvi = lv_line.Items[e.No - 1];
            if(lvi.Selected)
            {
                WaferLine wl = lvi.Tag as WaferLine;
                cb_awafer.Items.Add(wl.LastWafer);
                lb_pr.Text = wl.PCnt.ToString();
            }
        }

        private void btn_manage_Click(object sender, EventArgs e)
        {
            if(cb_line.SelectedIndex == -1)
            {
                return;
            }
            WaferLine wl = cb_line.SelectedItem as WaferLine;
            if(wdic[wl.No].Visible == false)
            {
                wdic[wl.No].Show();
            }
        }

        private void cb_awafer_SelectedIndexChanged(object sender, EventArgs e)
        {
            pn_awafer.Wafer = cb_awafer.SelectedItem as Wafer;
            pn_awafer.Invalidate();
        }

        private void MainForm_Load(object sender, EventArgs e)
        {
            cbox_ip.DataSource = MyNetwork.Addresses;
            Manager manager = Manager.Singleton;
            manager.RecvStsEndPoint += Manager_RecvStsEndPoint;
            manager.AddedWafer += Manager_AddedWafer;
            manager.AddedPR += Manager_AddedPR;
            manager.SettedSpeed += Manager_SettedSpeed;
            manager.SettedDrop += Manager_SettedDrop;
        }

        private void Manager_SettedDrop(object sender, SetDropEventArgs e)
        {
            if(this.InvokeRequired)
            {
                SetDropEventHandler dele = Manager_SettedDrop;
                this.Invoke(dele, new object[] { sender, e });
            }
            else
            {
                ListViewItem lvi = lv_line.Items[e.No - 1];
                WaferLine wl = lvi.Tag as WaferLine;
                wl.Drop = e.Drop;
                WaferLineForm lvf = wdic[e.No];
                lvf.SetStatus();
                if(lvi.Selected)
                {
                    lb_drop.Text = e.Drop.ToString();
                }
            }
        }

        private void Manager_SettedSpeed(object sender, SetSpeedEventArgs e)
        {
            if (this.InvokeRequired)
            {
                SetSpeedEventHandler dele = Manager_SettedSpeed;
                this.Invoke(dele, new object[] { sender, e });
            }
            else
            {
                ListViewItem lvi = lv_line.Items[e.No - 1];
                WaferLine wl = lvi.Tag as WaferLine;
                wl.Spin = e.Speed;
                WaferLineForm lvf = wdic[e.No];
                lvf.SetStatus();
                if (lvi.Selected)
                {
                    lb_spin.Text = e.Speed.ToString();
                }
            }
        }

        private void Manager_AddedPR(object sender, AddPREventArgs e)
        {
            if (this.InvokeRequired)
            {
                AddPREventHandler dele = Manager_AddedPR;
                this.Invoke(dele, new object[] { sender, e });
            }
            else
            {
                ListViewItem lvi = lv_line.Items[e.No - 1];
                WaferLine wl = lvi.Tag as WaferLine;
                wl.InPr(e.PCnt);
                ChangeStatusWaferLine(e.No);
                WaferLineForm lvf = wdic[e.No];
                lvf.Invalidate(true);
            }
        }

        private void Manager_AddedWafer(object sender, AddWaferEventArgs e)
        {
            if (this.InvokeRequired)
            {
                AddWaferEventHandler dele = Manager_AddedWafer;
                this.Invoke(dele, new object[] { sender, e });
            }
            else
            {
                ListViewItem lvi = lv_line.Items[e.No - 1];
                WaferLine wl = lvi.Tag as WaferLine;
                wl.InWafer(e.BWCnt);
                ChangeStatusWaferLine(e.No);
                WaferLineForm lvf = wdic[e.No];
                lvf.Invalidate(true);
            }
        }

        private void Manager_RecvStsEndPoint(object sender, RecvStsEndPtEventArgs e)
        {
            if (this.InvokeRequired)
            {
                RecvStsEndPtEventHandler dele = Manager_RecvStsEndPoint;
                this.Invoke(dele, new object[] { sender, e });
            }
            else
            {
                Manager manager = Manager.Singleton;
                foreach(ListViewItem lvi in lv_line.Items)
                {
                    int no = int.Parse(lvi.SubItems[0].Text);
                    manager.AddLine(no);
                    manager.AddWafer(no, int.Parse(lvi.SubItems[1].Text));
                    WaferLine wl = lvi.Tag as WaferLine;
                    manager.AddPR(no, wl.PCnt);
                    manager.SetSpeed(no, wl.Spin);
                    manager.SetDrop(no, wl.Drop);
                }
                ts_lb.Text = string.Format("{0}:{1} 연결", e.IPAddress, e.Port);
            }
        }

        private void btn_set_Click(object sender, EventArgs e)
        {
            int port = int.Parse(tbox_port.Text);
            string ip = cbox_ip.Text;
            Manager manger = Manager.Singleton;
            manger.StartServer(ip, port);
        }

        WaferLine select_line = null;
        private void lv_line_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (lv_line.SelectedItems.Count == 0)
            {
                return;
            }
            ListViewItem lvi = lv_line.SelectedItems[0];
            select_line = lvi.Tag as WaferLine;
            SetSelectLine();
        }

        private void SetSelectLine()
        {
            lb_selno.Text = select_line.No.ToString();
            lb_spin.Text = select_line.Spin.ToString();
            lb_drop.Text = select_line.Drop.ToString();
            lb_pr.Text = select_line.PCnt.ToString();
            cb_awafer.Items.Clear();
            foreach (Wafer wafer in select_line)
            {
                cb_awafer.Items.Add(wafer);
            }
            cb_awafer.Text = "";
            pn_awafer.Invalidate();
        }

    }
}

8. WaferLineForm 추가 구현

WaferLine 공장 시뮬레이션의 WaferLineForm을 추가 구현합시다.

SetStatus 메서드를 추가하여 WaferLineControl에 WaferLine을 설정하는 메서드를 호출합니다.

        internal void SetStatus()
        {
            wlc.SetStatus();
        }

WaferLineControlLib의 WaferLineControl.cs에도 SetStatus 메서드를 추가합니다.

        public void SetStatus()
        {
            if(wl != null)
            {
                lb_wcnt.Text = wl.BWCnt.ToString();
                lb_pcnt.Text = wl.PCnt.ToString();
                tbar_spin.Value = wl.Spin;
                tbar_drop.Value = wl.Drop;
            }
            else
            {
                lb_wcnt.Text = "해당 없음";
                lb_pcnt.Text = "해당 없음";
                tbar_spin.Value = tbar_spin.Minimum;
                tbar_drop.Value = tbar_drop.Minimum;
            }
        }

이상으로 반도체 장비 제어시스템에 관한 프로젝트인 Wafer 코팅 시뮬레이션을 마칠게요.