// EZGemPlusDLL_SampleDlg.cpp : 구현 파일
//

#include "stdafx.h"
#include "EZGemPlusDLL_Sample.h"
#include "EZGemPlusDLL_SampleDlg.h"
#include "afxdialogex.h"
#include <tchar.h>

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

// CEZGemPlusDLL_SampleDlg 대화 상자

CEZGemPlusDLL_SampleDlg::CEZGemPlusDLL_SampleDlg(CWnd* pParent /*=NULL*/)
	: CDialogEx(CEZGemPlusDLL_SampleDlg::IDD, pParent)
	, m_strText(_T(""))
	, m_strMsgInCount(_T(""))
	, m_strMsgOutCount(_T(""))
	, m_strCarrierID(_T(""))
	, m_strPrJobCount(_T(""))
	, m_strPrJobPPID(_T(""))
	, m_strPrJobCarrierCount(_T(""))
	, m_strPrJobParams(_T(""))
	, m_strPrJobState(_T(""))
	, m_strCtrlJobCount(_T(""))
	, m_strSubstIDRead(_T(""))
	, m_strCarrierID_Delete(_T(""))
	, m_strNewAttrVal(_T(""))
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CEZGemPlusDLL_SampleDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_LIST_LOG, m_listLog);
	DDX_Control(pDX, IDC_STATIC_CONNECTION, m_txtConnection);
	DDX_Control(pDX, IDC_STATIC_CONTROLSTATE, m_txtControlState);
	DDX_Text(pDX, IDC_EDIT_MSGIN, m_strMsgInCount);
	DDX_Text(pDX, IDC_EDIT_MSGOUT, m_strMsgOutCount);
	DDX_Control(pDX, IDC_LIST_GEM300LOG, m_listGem300Log);
	DDX_Control(pDX, IDC_COMBO_TRANSFERSTATE, m_comboTransferState);
	DDX_Control(pDX, IDC_CHECK_ACCESSMODE, m_checkPortAccessMode);
	DDX_Control(pDX, IDC_CHECK_CARRIERID_VERIFY_HOST, m_checkCarrierIDVerification);
	DDX_Control(pDX, IDC_CHECK_SLOTMAP_VERIFY_HOST, m_checkSlotMapVerification);
	DDX_Control(pDX, IDC_RADIO_PORT1, m_radioLoadPort1);
	DDX_Control(pDX, IDC_RADIO_PORT2, m_radioLoadPort2);
	DDX_Text(pDX, IDC_EDIT_CARRIERID, m_strCarrierID);
	DDX_Text(pDX, IDC_EDIT_SLOTMAP, m_strSlotMap);
	DDX_Control(pDX, IDC_LIST_PRJOB, m_listPrJob);
	DDX_Text(pDX, IDC_EDIT_PRJOBPPID, m_strPrJobPPID);
	DDX_Control(pDX, IDC_COMBO_PRJOBCARRIER, m_comboCarrier);
	DDX_Text(pDX, IDC_EDIT_PRJOBPARAMS, m_strPrJobParams);
	DDX_Text(pDX, IDC_EDIT_PRJOBSTATE, m_strPrJobState);
	DDX_Control(pDX, IDC_LIST_CTRLJOB, m_listCtrlJob);
	DDX_Control(pDX, IDC_LIST_PRJOBINCTRLJOB, m_listPrJobInCtrlJob);
	DDX_Control(pDX, IDC_LIST_SUBSTRATE, m_listSubstrate);
	DDX_Control(pDX, IDC_LIST_LOCATION, m_listSubstLoc);
	DDX_Control(pDX, IDC_COMBO_SUBST, m_comboSubstrate);
	DDX_Control(pDX, IDC_LIST_BATHLOC1, m_listBatchLoc_1);
	DDX_Control(pDX, IDC_LIST_BATHLOC2, m_listBatchLoc_2);
	DDX_Control(pDX, IDC_LIST_BATCHLOCATION, m_listBatchLocation);
	DDX_Control(pDX, IDC_COMBO_SUBSTLOC, m_comboSubstLoc);
	DDX_Control(pDX, IDC_COMBO_STATEMODE, m_comboSubstStateMode);
	DDX_Control(pDX, IDC_COMBO_SUBSTIDREADRESULT, m_comboSubstIDReadResult);
	DDX_Control(pDX, IDC_COMBO_TRANSTATE, m_comboTransState);
	DDX_Control(pDX, IDC_COMBO_STATEVALUE, m_comboStateValue);
	DDX_Text(pDX, IDC_EDIT_SUBSTIDREAD, m_strSubstIDRead);
	DDX_Text(pDX, IDC_EDIT_CARRIERID_DEL, m_strCarrierID_Delete);
	//  DDX_Control(pDX, IDC_COMBO_ATTRNAME, comboAttrName);
	DDX_Control(pDX, IDC_COMBO_OBJID, m_comboObjID);
	DDX_Control(pDX, IDC_COMBO_ATTRNAME, m_comboAttrName);
	DDX_Control(pDX, IDC_COMBO_OBJTYPE, m_comboObjType);
	DDX_Control(pDX, IDC_LIST_LOADPORTINFO, m_gridLoadPort);
	DDX_Control(pDX, IDC_LIST_CARRIERINFO, m_gridCarrierInfo);
	DDX_Control(pDX, IDC_COMBO_CARRIERACCESS, m_comboCarrierAccessStatus);
	DDX_Text(pDX, IDC_EDIT_NEW_ATTRVAL, m_strNewAttrVal);
	DDX_Control(pDX, IDC_COMBO_CARRIERID, m_comboCarrierID);
	DDX_Control(pDX, IDC_COMBO_CARRIERLOCATION, m_comboCarrierLocation);
}

BEGIN_MESSAGE_MAP(CEZGemPlusDLL_SampleDlg, CDialogEx)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_BN_CLICKED(IDC_BUTTON_START, &CEZGemPlusDLL_SampleDlg::OnBnClickedButtonStart)
	ON_BN_CLICKED(IDC_BUTTON_STOP, &CEZGemPlusDLL_SampleDlg::OnBnClickedButtonStop)
	ON_BN_CLICKED(IDC_BUTTON_OFFLINE, &CEZGemPlusDLL_SampleDlg::OnBnClickedButtonOffline)
	ON_BN_CLICKED(IDC_BUTTON_LOCAL, &CEZGemPlusDLL_SampleDlg::OnBnClickedButtonLocal)
	ON_BN_CLICKED(IDC_BUTTON_REMOTE, &CEZGemPlusDLL_SampleDlg::OnBnClickedButtonRemote)
	ON_BN_CLICKED(IDC_BUTTON_ALARMSET, &CEZGemPlusDLL_SampleDlg::OnBnClickedButtonAlarmset)
	ON_BN_CLICKED(IDC_BUTTON_ALARMCLEAR, &CEZGemPlusDLL_SampleDlg::OnBnClickedButtonAlarmclear)
	ON_BN_CLICKED(IDC_BUTTON_PROCESSSTART, &CEZGemPlusDLL_SampleDlg::OnBnClickedButtonProcessstart)
	ON_BN_CLICKED(IDC_BUTTON_PROCESSEND, &CEZGemPlusDLL_SampleDlg::OnBnClickedButtonProcessend)
	ON_WM_DESTROY()
	ON_BN_CLICKED(IDC_BUTTON_LOADREQUEST, &CEZGemPlusDLL_SampleDlg::OnBnClickedButtonLoadrequest)
	ON_BN_CLICKED(IDC_BUTTON_LOADCOMPLETE, &CEZGemPlusDLL_SampleDlg::OnBnClickedButtonLoadcomplete)
	ON_BN_CLICKED(IDC_BUTTON_UNLOADREQUEST, &CEZGemPlusDLL_SampleDlg::OnBnClickedButtonUnloadrequest)
	ON_BN_CLICKED(IDC_BUTTON_UNLOADCOMPLETE, &CEZGemPlusDLL_SampleDlg::OnBnClickedButtonUnloadcomplete)
	ON_BN_CLICKED(IDC_BUTTON_SETTRANSFERSTATE, &CEZGemPlusDLL_SampleDlg::OnBnClickedButtonSettransferstate)
	ON_BN_CLICKED(IDC_BUTTON_CARRIERID_READ, &CEZGemPlusDLL_SampleDlg::OnBnClickedButtonCarrieridRead)
	ON_BN_CLICKED(IDC_CHECK_ACCESSMODE, &CEZGemPlusDLL_SampleDlg::OnBnClickedCheckAccessmode)
	ON_BN_CLICKED(IDC_BUTTON_DOCKED, &CEZGemPlusDLL_SampleDlg::OnBnClickedButtonDocked)
	ON_BN_CLICKED(IDC_BUTTON_DOOROPEN, &CEZGemPlusDLL_SampleDlg::OnBnClickedButtonDooropen)
	ON_BN_CLICKED(IDC_BUTTON_CLOSED, &CEZGemPlusDLL_SampleDlg::OnBnClickedButtonClosed)
	ON_BN_CLICKED(IDC_BUTTON_CARRIERID_SLOTMAPREAD, &CEZGemPlusDLL_SampleDlg::OnBnClickedButtonCarrieridSlotmapread)
	ON_BN_CLICKED(IDC_BUTTON_UNDOCKED, &CEZGemPlusDLL_SampleDlg::OnBnClickedButtonUndocked)
	ON_BN_CLICKED(IDC_BUTTON_CLAMPED, &CEZGemPlusDLL_SampleDlg::OnBnClickedButtonClamped)
	ON_BN_CLICKED(IDC_BUTTON_UNCLAMPED, &CEZGemPlusDLL_SampleDlg::OnBnClickedButtonUnclamped)
	ON_BN_CLICKED(IDC_BUTTON_TRANSFERBLOCKED, &CEZGemPlusDLL_SampleDlg::OnBnClickedButtonTransferblocked)
	ON_BN_CLICKED(IDC_BUTTON_CARRIEROK, &CEZGemPlusDLL_SampleDlg::OnBnClickedButtonCarrierok)
	ON_BN_CLICKED(IDC_BUTTON_CARRIERNG, &CEZGemPlusDLL_SampleDlg::OnBnClickedButtonCarrierng)
	ON_BN_CLICKED(IDC_BUTTON_SLOTMAPOK, &CEZGemPlusDLL_SampleDlg::OnBnClickedButtonSlotmapok)
	ON_BN_CLICKED(IDC_BUTTON_SLOTMAPNG, &CEZGemPlusDLL_SampleDlg::OnBnClickedButtonSlotmapng)
	ON_BN_CLICKED(IDC_BUTTON_UPDATEPRJOB, &CEZGemPlusDLL_SampleDlg::OnBnClickedButtonUpdateprjob)
	ON_LBN_SELCHANGE(IDC_LIST_PRJOB, &CEZGemPlusDLL_SampleDlg::OnLbnSelchangeListPrJob)
	ON_BN_CLICKED(IDC_BUTTON_READ_PRJOB_PARAMS, &CEZGemPlusDLL_SampleDlg::OnBnClickedButtonReadPrjobParams)
	ON_BN_CLICKED(IDC_BUTTON_SET_PRJOBSTATE, &CEZGemPlusDLL_SampleDlg::OnBnClickedButtonSetPrjobstate)
	ON_BN_CLICKED(IDC_BUTTON_UPDATECJOB, &CEZGemPlusDLL_SampleDlg::OnBnClickedButtonUpdatecjob)
	ON_LBN_SELCHANGE(IDC_LIST_CTRLJOB, &CEZGemPlusDLL_SampleDlg::OnLbnSelchangeListCtrljob)
	ON_LBN_SELCHANGE(IDC_LIST_PRJOBINCTRLJOB, &CEZGemPlusDLL_SampleDlg::OnLbnSelchangeListPrjobinctrljob)
	ON_BN_CLICKED(IDC_BUTTON_DEL_PRJOB, &CEZGemPlusDLL_SampleDlg::OnBnClickedButtonDelPrjob)
	ON_BN_CLICKED(IDC_BUTTON_DEL_ALLPRJOB, &CEZGemPlusDLL_SampleDlg::OnBnClickedButtonDelAllprjob)
	ON_BN_CLICKED(IDC_BUTTON_DEL_CTRLJOB, &CEZGemPlusDLL_SampleDlg::OnBnClickedButtonDelCtrljob)
	ON_BN_CLICKED(IDC_BUTTON_DEL_ALLCTRLJOB, &CEZGemPlusDLL_SampleDlg::OnBnClickedButtonDelAllctrljob)
	ON_BN_CLICKED(IDC_BUTTON_SET_CJOBSTATE, &CEZGemPlusDLL_SampleDlg::OnBnClickedButtonSetCjobstate)
	ON_BN_CLICKED(IDC_BUTTON_CREATEPRJOB, &CEZGemPlusDLL_SampleDlg::OnBnClickedButtonCreateprjob)
	ON_BN_CLICKED(IDC_BUTTON_CREATECTRLJOB, &CEZGemPlusDLL_SampleDlg::OnBnClickedButtonCreatectrljob)
	ON_WM_TIMER()
	ON_BN_CLICKED(IDC_BUTTON_CREATE_SUBST, &CEZGemPlusDLL_SampleDlg::OnButtonCreateSubst)
	ON_BN_CLICKED(IDC_BUTTON_DEL_SUBST, &CEZGemPlusDLL_SampleDlg::OnButtonDelSubst)
	ON_BN_CLICKED(IDC_BUTTON_DEL_ALLSUBST, &CEZGemPlusDLL_SampleDlg::OnBnClickedButtonDelAllsubst)
	ON_BN_CLICKED(IDC_BUTTON_BATCHMOVE_1, &CEZGemPlusDLL_SampleDlg::OnBnClickedButtonBatchmove1)
	ON_BN_CLICKED(IDC_BUTTON_BATCHMOVE_2, &CEZGemPlusDLL_SampleDlg::OnBnClickedButtonBatchmove2)
	ON_BN_CLICKED(IDC_BUTTON_SUBSTMOVE, &CEZGemPlusDLL_SampleDlg::OnBnClickedButtonSubstmove)
	ON_CBN_SELCHANGE(IDC_COMBO_STATEMODE, &CEZGemPlusDLL_SampleDlg::OnCbnSelchangeComboStatemode)
	ON_BN_CLICKED(IDC_BUTTON_SETSTATE, &CEZGemPlusDLL_SampleDlg::OnBnClickedButtonSetstate)
	ON_BN_CLICKED(IDC_BUTTON_SUBSTIDREADING, &CEZGemPlusDLL_SampleDlg::OnBnClickedButtonSubstidreading)
	ON_BN_CLICKED(IDC_BUTTON_DELCARRIER, &CEZGemPlusDLL_SampleDlg::OnBnClickedButtonDelcarrier)
	ON_BN_CLICKED(IDC_BUTTON_DELALLCARRIER, &CEZGemPlusDLL_SampleDlg::OnBnClickedButtonDelallcarrier)
	ON_BN_CLICKED(IDC_BUTTON_ATTRNAME, &CEZGemPlusDLL_SampleDlg::OnBnClickedButtonAttrname)
	ON_BN_CLICKED(IDC_BUTTON_ATTRDATA, &CEZGemPlusDLL_SampleDlg::OnBnClickedButtonAttrdata)
	ON_CBN_SELCHANGE(IDC_COMBO_OBJTYPE, &CEZGemPlusDLL_SampleDlg::OnCbnSelchangeComboObjtype)
	ON_BN_CLICKED(IDC_BUTTON_ALLATTRDATA, &CEZGemPlusDLL_SampleDlg::OnBnClickedButtonAllattrdata)
	ON_BN_CLICKED(IDC_BUTTON_ADD_PJPARAM, &CEZGemPlusDLL_SampleDlg::OnBnClickedButtonAddPjparam)
	ON_BN_CLICKED(IDC_BUTTON_CARRIERACCESSSTATUS, &CEZGemPlusDLL_SampleDlg::OnBnClickedButtonCarrieraccessstatus)
	ON_NOTIFY(LVN_ITEMCHANGED, IDC_LIST_CARRIERINFO, &CEZGemPlusDLL_SampleDlg::OnItemchangedListCarrierinfo)
	ON_BN_CLICKED(IDC_BUTTON_SUBSTRATE_RETURN, &CEZGemPlusDLL_SampleDlg::OnBnClickedButtonSubstrateReturn)
	ON_BN_CLICKED(IDC_BUTTON_OCCUPIED, &CEZGemPlusDLL_SampleDlg::OnBnClickedButtonOccupied)
	ON_BN_CLICKED(IDC_BUTTON_UNOCCUPIED, &CEZGemPlusDLL_SampleDlg::OnBnClickedButtonUnoccupied)
	ON_BN_CLICKED(IDC_BUTTON_SETNEWATTRVAL, &CEZGemPlusDLL_SampleDlg::OnBnClickedButtonSetnewattrval)
	ON_BN_CLICKED(IDC_BUTTON_CARRIERMOVE, &CEZGemPlusDLL_SampleDlg::OnBnClickedButtonCarriermove)
	ON_CBN_DROPDOWN(IDC_COMBO_CARRIERID, &CEZGemPlusDLL_SampleDlg::OnDropdownComboCarrierID)
	ON_CBN_DROPDOWN(IDC_COMBO_CARRIERLOCATION, &CEZGemPlusDLL_SampleDlg::OnDropdownComboCarrierLocation)
END_MESSAGE_MAP()


// CEZGemPlusDLL_SampleDlg 메시지 처리기

BOOL CEZGemPlusDLL_SampleDlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();

	// 시스템 메뉴에 "정보..." 메뉴 항목을 추가합니다.

	// IDM_ABOUTBOX는 시스템 명령 범위에 있어야 합니다.
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != NULL)
	{
		BOOL bNameValid;
		CString strAboutMenu;
		bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
		ASSERT(bNameValid);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}

	// 이 대화 상자의 아이콘을 설정합니다. 응용 프로그램의 주 창이 대화 상자가 아닐 경우에는
	//  프레임워크가 이 작업을 자동으로 수행합니다.
	SetIcon(m_hIcon, TRUE);			// 큰 아이콘을 설정합니다.
	SetIcon(m_hIcon, FALSE);		// 작은 아이콘을 설정합니다.

	m_nMsgIn = 0;
	m_nMsgOut = 0;

	//-----------------------------
	InitGrid();
	//-----------------------------
	OnBnClickedButtonStart();

	return TRUE;  // 포커스를 컨트롤에 설정하지 않으면 TRUE를 반환합니다.
}


void CEZGemPlusDLL_SampleDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
	}
	else
	{
		CDialogEx::OnSysCommand(nID, lParam);
	}
}

// 대화 상자에 최소화 단추를 추가할 경우 아이콘을 그리려면
//  아래 코드가 필요합니다. 문서/뷰 모델을 사용하는 MFC 응용 프로그램의 경우에는
//  프레임워크에서 이 작업을 자동으로 수행합니다.

void CEZGemPlusDLL_SampleDlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); // 그리기를 위한 디바이스 컨텍스트입니다.

		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

		// 클라이언트 사각형에서 아이콘을 가운데에 맞춥니다.
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// 아이콘을 그립니다.
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialogEx::OnPaint();
	}
}

// 사용자가 최소화된 창을 끄는 동안에 커서가 표시되도록 시스템에서
//  이 함수를 호출합니다.
HCURSOR CEZGemPlusDLL_SampleDlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}

//----------------------------------------------------------------------
//  이벤트 콜백 함수 (Callback Function)
//----------------------------------------------------------------------
void OnEZGemPlusEvent(void *lpHandle, short nEventId, long lParam)
{
	CEZGemPlusDLL_SampleDlg *pDlg = (CEZGemPlusDLL_SampleDlg *)lpHandle;
	pDlg->OnMyEvent(nEventId, lParam);
}
//----------------------------------------------------------------------
//  메세지 콜백 함수 (Callback Function)
//----------------------------------------------------------------------
void OnEZGemPlusMsg(void *lpHandle, long lMsgId)
{
	CEZGemPlusDLL_SampleDlg *pDlg = (CEZGemPlusDLL_SampleDlg *)lpHandle;
	pDlg->OnMsgReceived(lMsgId);
}

void CEZGemPlusDLL_SampleDlg::OnBnClickedButtonStart()
{
	//-----------------------------------------------
	// 이벤트 & 메세지 콜백 함수 연결
	//
	m_gem.SetEventHandler(this, OnEZGemPlusEvent);	// EVENT
	m_gem.SetMsgHandler(this, OnEZGemPlusMsg);		// MSG
	//
	//----------------------------------------------

	m_gem.SetPassiveMode(TRUE);
	m_gem.SetPort(5000);

	m_gem.SetModelName(_T("EZGEM+"));	// 장비 모델명 등록
	m_gem.SetSoftRev(_T("V 1.00"));		// 장비 소프트웨어버젼 등록

	m_gem.SetFormatCode(_T("CEID"), _T("U4"));
	m_gem.SetFormatCode(_T("SVID"), _T("U4"));
	m_gem.SetFormatCode(_T("ECID"), _T("U4"));
	m_gem.SetFormatCode(_T("RPTID"), _T("U4"));
	m_gem.SetFormatCode(_T("DATAID"),_T("U4"));
	m_gem.SetFormatCode(_T("ALID"), _T("U2"));
	m_gem.SetFormatCode(_T("TRID"), _T("U2"));

	//---------- 이벤트 등록 --------------------
	m_gem.AddCEID(1001, _T("OFFLINE"), _T(""));
	m_gem.AddCEID(1002, _T("ONLINE LOCAL"), _T(""));
	m_gem.AddCEID(1003, _T("ONLINE REMOTE"), _T(""));
	m_gem.AddCEID(1004, _T("PROCESS STARTED"), _T(""));
	m_gem.AddCEID(1005, _T("PROCESS STOPPPED"), _T(""));
	m_gem.AddCEID(1006, _T("LOT START"), _T(""));
	m_gem.AddCEID(1007, _T("LOT END"), _T(""));
	m_gem.AddCEID(1011, _T("Process Start (Thread)"), _T(""));
	m_gem.AddCEID(1012, _T("Process End (Thread)"), _T(""));

	//----------- SVID 등록 및 값 지정--------------
	m_gem.AddSVID(2001, _T("CONTROL STATE"), _T("U1"), _T(""));	
	m_gem.AddSVID(2002, _T("PPID"), _T("A"), _T(""));
	m_gem.AddSVID(2003, _T("LOTID"), _T("A"), _T(""));
	m_gem.AddSVID(2004, _T("WAFERID"), _T("A"), _T(""));
	m_gem.AddSVID(2005, _T("WAFER SLOT ID"), _T("OBJECT"), _T(""));	 // 사용자가 원하는 대로 정할수 있는 구조의 SVID, FORMAT='OBJECT'
	m_gem.AddSVID(2006, _T("LimitMonitoringTest"), _T("F4"), _T(""));
	m_gem.AddSVID(2007, _T("SLOTSTAT"), _T("BINARY"), _T(""));

	m_gem.AddSVID(2009, _T("DATA_BOOL"), _T("BOOL"), _T(""));
	m_gem.AddSVID(2010, _T("DATA_BINARY"), _T("B"), _T(""));
	m_gem.AddSVID(2011, _T("DATA_U1"), _T("U1"), _T(""));
	m_gem.AddSVID(2012, _T("DATA_U2"), _T("U2"), _T(""));
	m_gem.AddSVID(2013, _T("DATA_U4"), _T("U4"), _T(""));
	m_gem.AddSVID(2014, _T("DATA_U8"), _T("U8"), _T(""));
	m_gem.AddSVID(2015, _T("DATA_I1"), _T("I1"), _T(""));
	m_gem.AddSVID(2016, _T("DATA_I2"), _T("I2"), _T(""));
	m_gem.AddSVID(2017, _T("DATA_I4"), _T("I4"), _T(""));
	m_gem.AddSVID(2018, _T("DATA_I8"), _T("I8"), _T(""));
	m_gem.AddSVID(2019, _T("DATA_F4"), _T("F4"), _T(""));
	m_gem.AddSVID(2020, _T("DATA_F8"), _T("F8"), _T(""));

	m_gem.AddDVID(2101, _T("DVID_001"), _T("U4"));
	m_gem.AddDVID(2102, _T("DVID_002"), _T("U4"));
	m_gem.AddDVID(2103, _T("DVID_003"), _T("U4"));
	m_gem.AddSVID(2222, _T("TEST_OBJ"), _T("OBJECT"), _T(""));

	m_gem.AddSVID(2011, _T("ALARM SET"), _T("L"), _T(""));			// LIST형식의 SVID자동처리 (ALARM SET/CLEAR, EVENT ENABLE/DISABLE)
	m_gem.AddSVID(2012, _T("EVENT DISABLED"), _T("L"), _T(""));		// LIST형식의 SVID자동처리 (ALARM SET/CLEAR, EVENT ENABLE/DISABLE)

	for (int i = 4000; i <= 4100; i++)
	{
		CString strTemp;
		strTemp.Format(_T("SVID_%d"), i);
		m_gem.AddSVID(i, strTemp, _T("A"), _T(""));
	}
	// -----------------------------------------------
	// 장비에서는 상황에 맞춰 실시간으로  VID값 업데이트
	m_gem.SetVIDValue(2002, _T("PPID_007"));   
	m_gem.SetVIDValue(2003, _T("LOTID_007"));
	m_gem.SetVIDValue(2006, _T("0.123"));
	m_gem.SetVIDValue(2007, _T("1,2,3,4,5"));

	m_gem.SetVIDValue(2101, _T("2101"));
	m_gem.SetVIDValue(2102, _T("2102"));
	m_gem.SetVIDValue(2103, _T("2103"));

	//------------ 장비 파라미터 등록 -------------
	m_gem.AddECID(3001, _T("PARAM_U2"), _T("mm"), _T("U2"));
	m_gem.SetECRange(3001, _T("1"), _T("100"));
	m_gem.AddECID(3002, _T("PARAM_A"), _T("gram"), _T("A"));
	m_gem.AddECID(3003, _T("PARAM1_TEST"), _T("mm"), _T("U2"));
	m_gem.AddECID(3004, _T("PARAM2_U2"), _T("mm"), _T("U2"));
	m_gem.AddECID(3005, _T("PARAM3_TEST"), _T("mm"), _T("U2"));
	m_gem.AddECID(3006, _T("PARAM4_U2"), _T("mm"), _T("U2"));
	m_gem.AddECID(3007, _T("PARAM4_F4"), _T("mm"), _T("F4"));
	m_gem.AddECID(3008, _T("PARAM4_F4"), _T("mm"), _T("F4"));
	m_gem.AddECID(3009, _T("PARAM4_F8"), _T("mm"), _T("F8"));

	// 샘플용 알람 등록
	for (int i = 4001; i <= 4999; i++)
	{
		CString strTemp;
		strTemp.Format(_T("ALID_%d"), i);
		m_gem.AddALID(i, strTemp, _T(""));
	}

	//--------- ----------------------------------------
	//	사용자 직접 처리할 메세지 (사용자정의메세지) 선언
	//  해당 메세지 수신시 OnMsgReceived이벤트에서 처리
	m_gem.DisableAutoReply(7, 3);
	m_gem.DisableAutoReply(7, 5);
	m_gem.DisableAutoReply(7, 17);
	m_gem.DisableAutoReply(7, 19);
	m_gem.DisableAutoReply(7, 25);
	//------------------------------------------------
	// S2F41 RCMD(REMOTE COMMAND) 등록
	// 등록하지 않은 명령수신시 자동 NACK처리
	m_gem.AddRemoteCommand(_T("START"));
	m_gem.AddRemoteCommand(_T("STOP"));
	m_gem.AddRemoteCommand(_T("PP-SELECT"));

	m_gem.SetFormatCheck(TRUE);    // FORMAT VALIDATION 사용여부
	m_gem.SetFormatFile(_T("FORMAT.SML"));  // FORMAT FILE등록

	m_gem.SetMaxSpoolCount(5);
	m_gem.SetMaxSpoolTransmitCount(5);
	m_gem.SetTimeFormat(16);

	//-------- 필요시 GEM300 설정파일 경로 및 파일명 변경 가능 
	//m_gem.Set300IniFile("INI\\MYGEM300.INI");
	//m_gem.Set300IniFile("MYGEM300.INI");

	// 로그파일 경로 및 파일명 설정
	m_gem.SetLogFile(_T("LOG\\GEM.LOG"), TRUE);

	//=============================
	//
	long nResult = m_gem.Start();
	//
	//=============================

	if (nResult < RESULT_OK) // 시작 실패
	{
		m_listLog.AddString(_T("EZGEM FAILED TO START"));
		return;
	}
	m_listLog.AddString(_T("EZGEM STARTED - OK"));

	//--------- 첫 연결시 Default Control State 지정
	m_gem.GoOnlineRemote();

	GetDlgItem(IDC_BUTTON_START)->EnableWindow(FALSE);
	GetDlgItem(IDC_BUTTON_STOP)->EnableWindow(TRUE);

	InitGem300Settings();
}

void CEZGemPlusDLL_SampleDlg::InitGrid()
{
	m_gridLoadPort.SetExtendedStyle(LVS_EX_GRIDLINES | LVS_EX_FULLROWSELECT);
	m_gridCarrierInfo.SetExtendedStyle(LVS_EX_GRIDLINES | LVS_EX_FULLROWSELECT);

	LPCTSTR pszLoadPortColText[] =
	{
		_T("Port"),
		_T("LocID"),
		_T("CarrierID"),
		_T("Mode"),
		_T("TransferState"),
		_T("ReservState"),
		_T("AssocState")
	};
	int nLoadPortColWidth[7] = { 50, 60, 140, 70, 130, 130, 130 };
	for (int i = 0; i < 7; i++) m_gridLoadPort.InsertColumn(i, pszLoadPortColText[i], LVCFMT_LEFT, nLoadPortColWidth[i]);
	for (int i = 0; i < MAX_LOADPORT; i++)
	{
		CString strTemp;
		strTemp.Format(_T("%d"), i + 1);
		m_gridLoadPort.InsertItem(i, strTemp);
	}
	LPCTSTR pszCarrierInfoColText[] =
	{
		_T("CarrierID"),
		_T("LocID"),
		_T("ID Status"),
		_T("SlotMap Status"),
		_T("AccessStatus"),
		_T("SlotMap"),
		_T("Usage")
	};
	int nCarrierInfoColWidth[7] = { 100, 60, 100, 110, 110, 160, 100 };
	for (int i = 0; i < 7; i++) m_gridCarrierInfo.InsertColumn(i, pszCarrierInfoColText[i], LVCFMT_LEFT, nCarrierInfoColWidth[i]);
}
void CEZGemPlusDLL_SampleDlg::InitGem300Settings()
{
	// 각 State값은 GEM300.INI에서 설정한 값과 일치시켜야 함.
	m_TransferState[0] = "No State";
	m_TransferState[1] = "OutOfService";
	m_TransferState[2] = "InService";
	m_TransferState[3] = "ReadyToLoad";
	m_TransferState[4] = "ReadyToUnload";
	m_TransferState[5] = "TransferBlocked";

	m_ReservationState[0] = "NotReserved";
	m_ReservationState[1] = "Reserved";
	m_ReservationState[255] = "NoState";

	m_IDState[0] = "NotRead";
	m_IDState[1] = "WaitingForHost";
	m_IDState[2] = "VerifyOK";
	m_IDState[3] = "VerifyFail";

	m_AccessingState[0] = "NotAccessed";
	m_AccessingState[1] = "InAccessed";
	m_AccessingState[2] = "Completed";
	m_AccessingState[3] = "Stopped";

	m_AssocationState[0] = "NotAssociated";
	m_AssocationState[1] = "Associated";
	m_AssocationState[255] = "NoState";

	m_comboTransferState.ResetContent();
	m_comboCarrierAccessStatus.ResetContent();
	m_comboSubstLoc.ResetContent();
	m_comboSubstrate.ResetContent();
	m_comboTransState.ResetContent();
	m_comboSubstStateMode.ResetContent();
	m_comboSubstIDReadResult.ResetContent();
	m_comboObjType.ResetContent();
	m_comboObjType.ResetContent();

	std::map<int, std::string>::iterator it;
	for (it = m_TransferState.begin(); it != m_TransferState.end(); ++it)
	{
		CString strTemp;
		strTemp.Format(_T("%d - %s"), it->first, (CString)it->second.c_str());
		m_comboTransferState.AddString(strTemp);
	}
	for (it = m_AccessingState.begin(); it != m_AccessingState.end(); ++it)
	{
		CString strTemp;
		strTemp.Format(_T("%d - %s"), it->first, (CString)it->second.c_str());
		m_comboCarrierAccessStatus.AddString(strTemp);
	}

	m_radioLoadPort1.SetCheck(1);
	m_radioLoadPort2.SetCheck(0);

	m_checkPortAccessMode.SetCheck(1);
	m_checkCarrierIDVerification.SetCheck(1);
	m_checkSlotMapVerification.SetCheck(1);

	m_strCarrierID = _T("CARRIER_001");
	m_strSubstIDRead = _T("SUBSTID.01");
	m_bCarrierVerifyOK = FALSE;

	UpdateData(FALSE);

	int nAccessMode = 0;
	if (((CButton *)GetDlgItem(IDC_CHECK_ACCESSMODE))->GetCheck()) nAccessMode = 1;

	//-------------------------------------------------------------------
	// 장비로부터 현재의 Load Port상황을 받아  초기세팅함
	// 인자 : Port#, TrasnferState, AccessMode, LocationName, CarrierID
	// PORT는 1~4까지 가능
	//
	// Loadport가 2개 있다고 가정
	//-------------------------------------------------------------------
	m_gem.SetLoadPort(1, 0, nAccessMode, _T("LP01"), _T(""));
	m_gem.SetLoadPort(2, 0, nAccessMode, _T("LP02"), _T(""));

	//-------------------------------------------------------------------
	// 내부버퍼 (INTERNAL BUFFER) 가 있는 장비라면 각 CARRIER LOCATION 생성
	m_gem.SetCarrierInternalBufferMode(1);	//// 0 = FixedBufer Mode, 1 = InternalBufferMode
	m_gem.CreateCarrierLoc(_T("IB_1"));
	m_gem.CreateCarrierLoc(_T("IB_2"));
	m_gem.CreateCarrierLoc(_T("TR"));
	m_gem.CreateCarrierLoc(_T("FIMS"));
	// LOAD PORT에 대한 Location은 SetLoadPort에서 자동 생성됨.
	//-------------------------------------------------------------------

	// 웨이퍼 세정장비라고 가정 (CARRIER -> LOC1("WASH") -> LOC2("DRY") -> LOC3("VISION")
	// BATCH이송 기능이 있다고 가정하고 BATCHLOC 2개 생성

	LPCTSTR subloc[] = { _T("WASH"), _T("DRY"), _T("VISION") };	// SUBST LOCATION
	LPCTSTR batchloc[] = { _T("BATCH_1"), _T("BATCH_2") };		// SUBST BATCH LOCATION
	LPCTSTR transtate[] = { _T("0=AtSource"), _T("1=AtWork"), _T("2=AtDest") };
	LPCTSTR state[] = { _T("Transportation"), _T("Processing"), _T("SubstID Reading") };

	for (int i = 0; i < 3; i++)
	{
		//-------------------------------------------------
		// Substrate Location 생성하는 함수
		long nResult = m_gem.CreateSubstLoc((CString)subloc[i]);
		//-------------------------------------------------
		m_comboSubstLoc.AddString((CString)subloc[i]);
	}
	for (int i = 0; i < 2; i++)
	{
		//-------------------------------------------------
		// Substrate BatchLocation생성함수
		long nResult = m_gem.CreateSubstBatchLoc((CString)batchloc[i]);
		//-------------------------------------------------
	}
	for (int i = 0; i < 5; i++)
	{
		CString strSubstID;
		strSubstID.Format(_T("SUBST.%02d"), i + 1);		// 실제로는 CMS에서 사용된 Host가 내려준 ContentMap이 사용됨
		m_comboSubstrate.AddString(strSubstID);			// for Create/Delete
	}
	for (int i = 0; i < 3; i++)
	{
		m_comboTransState.AddString((CString)transtate[i]);
		m_comboSubstStateMode.AddString((CString)state[i]);
	}
	m_comboSubstIDReadResult.AddString(_T("0 : SubstID Reading - OK"));
	m_comboSubstIDReadResult.AddString(_T("0 : SubstID Reading - FAILED"));

	m_comboObjType.AddString(_T("Carrier"));
	m_comboObjType.AddString(_T("ProcessJob"));
	m_comboObjType.AddString(_T("ControlJob"));
	m_comboObjType.AddString(_T("Substrate"));
	m_comboObjType.AddString(_T("SubstLoc"));
	m_comboObjType.AddString(_T("BatchLoc"));

	SetTimer(1, 2000, NULL);
}

void CEZGemPlusDLL_SampleDlg::OnBnClickedButtonStop()
{
	// -------------------------------------------
	// 필요시 등록된 각종 정보를 텍스트파일로 저장가능
	// m_gem.WriteEZGemStatus();

	//-------------
	//
	m_gem.Stop();
	//
	//-------------

	KillTimer(1);

	m_listLog.AddString(_T("EZGEM STOPPED"));

	GetDlgItem(IDC_BUTTON_START)->EnableWindow(TRUE);
	GetDlgItem(IDC_BUTTON_STOP)->EnableWindow(FALSE);

	m_nMsgIn = 0;
	m_nMsgOut = 0;
}

void CEZGemPlusDLL_SampleDlg::OnHostSentECV(long lMsgId)	// S2F15
{
	long ECID = 0;
	CString strLog, strNewValue;
	while (m_gem.GetHostSetECID(lMsgId, &ECID, &strNewValue)>=0)
	{
		strLog.Format(_T("HOST SENT NEW EC, ECID=%d, VALUE=%s"), ECID, strNewValue);
		m_listLog.AddString(strLog);

		// Validation후 문제없으면 GEM 드라이버와 장비에 반영한다.
		m_gem.SetECValue(ECID, strNewValue);    // gem에 반영
	}
	//--------------------------------------------------------
	m_gem.ReplyHostSetECID(lMsgId, 0);      // 응답내보내기
	//--------------------------------------------------------
}

void CEZGemPlusDLL_SampleDlg::OnRemoteCommand(long lMsgId)	// S2F41
{
	CString strCommand, strName, strValue, strLog;
	short nFormat = 0;
	//-----------------------------------------------------------------
	short nParamCount = m_gem.GetRemoteCommand(lMsgId, strCommand);
	//-----------------------------------------------------------------
	m_listLog.AddString(_T("RCMD=") + strCommand);

	for (short i = 0; i < nParamCount; i++)
	{
		//-----------------------------------------------------------------------------------
		short nRet = m_gem.GetRemoteCommandParam(lMsgId, i, strName, strValue, &nFormat);
		//-----------------------------------------------------------------------------------
		strLog.Format(_T("PARAM: NAME=%s, VALUE=%s, FORMATCODE=%d"), strName, strValue, nFormat);
		m_listLog.AddString(strLog);
	}
	//----------------------------------
	// RCMD와 파라미터로 응답 방향 판단
	short HCACK = 3;
	if (HCACK != RESULT_OK)	// ON ERROR
	{
		// ERROR CODE SAMPLES
		m_gem.SetRemoteCommandErrorCode(lMsgId, strCommand, 0, 3);	// MSGID, RCMD, PARMINDEX, ERRORCODE
		m_gem.SetRemoteCommandErrorCode(lMsgId, strCommand, 2, 1);
	}
	//-------------------------------------------------------------
	m_gem.ReplyRemoteCommand(lMsgId, HCACK);	// S2F42 or  S2F50
	//-------------------------------------------------------------
}

void CEZGemPlusDLL_SampleDlg::OnTerminalMsg(long lMsgId)	// S10F3, S10F5
{
	short TID = 0;
	CString strMsg, strLog;

	while (m_gem.GetTerminalMsg(lMsgId, &TID, &strMsg) >= 0)
	{
		strLog.Format(_T("HOST MESSAGE: (%d) %s"), TID, strMsg);
		m_listLog.AddString(strLog);
	}
}

void CEZGemPlusDLL_SampleDlg::OnMyEvent(short nEventId, long lParam)
{
	long nSysByte = 0;
	CString strTemp;

	if (nEventId >= EVENT_GEMDLL_CMS_TRANSFER_STATE_CHANGE)	// GEM300 EVENT
	{
		OnGem300Event(nEventId, lParam);
		GetDlgItem(IDC_LIST_GEM300LOG)->SendMessage(WM_VSCROLL, SB_PAGEDOWN);
		return;
	}

	switch (nEventId)
	{
	case DLL_EVENT_CONNECTED:   
		m_listLog.AddString(_T("CONNECTED"));       
		m_txtConnection.SetWindowText(_T("CONNECTED"));
		break;
	case DLL_EVENT_DISCONNECTED:    
		m_listLog.AddString(_T("DISCONNECTED"));    
		m_txtConnection.SetWindowText(_T("NOT CONNECTED")); 
		break;
	case EVENT_GEMDLL_CONTROL_HOSTOFFLINE:  
		m_gem.SetSVIDValue(2001, _T("1"));
		m_gem.SendEventReport(1001);
		m_txtControlState.SetWindowText(_T("HOST OFFLINE")); 
		break;
	case EVENT_GEMDLL_CONTROL_ONLINE_LOCAL: 
		m_gem.SetSVIDValue(2001, _T("2"));
		m_gem.SendEventReport(1002);
		m_txtControlState.SetWindowText(_T("ONLINE LOCAL"));
		((CWnd *)GetDlgItem(IDC_BUTTON_CARRIEROK))->EnableWindow(TRUE);
		((CWnd *)GetDlgItem(IDC_BUTTON_CARRIERNG))->EnableWindow(TRUE);
		((CWnd *)GetDlgItem(IDC_BUTTON_SLOTMAPOK))->EnableWindow(TRUE);
		((CWnd *)GetDlgItem(IDC_BUTTON_SLOTMAPNG))->EnableWindow(TRUE);
		break;
	case EVENT_GEMDLL_CONTROL_ONLINE_REMOTE:    
		m_gem.SetSVIDValue(2001, _T("3"));
		m_gem.SendEventReport(1003);
		m_txtControlState.SetWindowText(_T("ONLINE REMOTE"));
		((CWnd *)GetDlgItem(IDC_BUTTON_CARRIEROK))->EnableWindow(FALSE);
		((CWnd *)GetDlgItem(IDC_BUTTON_CARRIERNG))->EnableWindow(FALSE);
		((CWnd *)GetDlgItem(IDC_BUTTON_SLOTMAPOK))->EnableWindow(FALSE);
		((CWnd *)GetDlgItem(IDC_BUTTON_SLOTMAPNG))->EnableWindow(FALSE);
		break;
	case EVENT_GEMDLL_COMM_ESTABLISHED: m_txtControlState.SetWindowText(_T("COMMUNICATING")); break;
	case EVENT_GEMDLL_HOST_SENT_NEWECV: OnHostSentECV(lParam);      break;
	case EVENT_GEMDLL_HOST_COMMAND:     OnRemoteCommand(lParam);    break;
	case EVENT_GEMDLL_TERMMSG:          OnTerminalMsg(lParam);      break;
	case EVENT_GEMDLL_SPOOL_UPDATED:
	{
		CString strTemp;
		strTemp.Format(_T("SPOOL UPDATED. SPOOL COUNT=%d"), m_gem.GetSpoolCount());
		m_listLog.AddString(strTemp);
	}
	break;
	case EVENT_GEMDLL_SPOOL_FULL:
	{
		CString strTemp, strStartTime, strFullTime;
		m_gem.GetSpoolTime(&strStartTime, &strFullTime);
		strTemp.Format(_T("SPOOL FULL. START=%s, FULL=%s"), strStartTime, strFullTime);
		m_listLog.AddString(strTemp);
	}
	break;
	case EVENT_MSG_IN:
	{
		m_nMsgIn++;
		int nStream = lParam / 1000;
		int nFunction = lParam % 1000;

		m_strMsgInCount.Format(_T("%d"), m_nMsgIn);
		GetDlgItem(IDC_EDIT_MSGIN)->SetWindowText(m_strMsgInCount);
		CString strTemp;
		strTemp.Format(_T("MSGIN : S%dF%d ,  msgque=%d"), nStream, nFunction, m_gem.GetMsgQueSize());
		m_listLog.AddString(strTemp);
	}
	break;
	case EVENT_MSG_OUT:
	{
		m_nMsgOut++;
		int nStream = lParam / 1000;
		int nFunction = lParam % 1000;
		m_strMsgOutCount.Format(_T("%d"), m_nMsgOut);
		GetDlgItem(IDC_EDIT_MSGOUT)->SetWindowText(m_strMsgOutCount);
		CString strTemp;
		strTemp.Format(_T("MSGOUT : S%dF%d ,  msgque=%d"), nStream, nFunction, m_gem.GetMsgQueSize());
		m_listLog.AddString(strTemp);
	}
	break;
	case EVENT_GEMDLL_IN_DEADBAND:
	{
		CString strTemp;
		strTemp.Format(_T("Limit Monitoring * In DeadBand -> SVID=%d"), lParam);
		m_listLog.AddString(strTemp);
	}
	default:
		CString strTemp;
		strTemp.Format(_T("OTHER EVENT, EVENTID=%d, PARAM=%d"), nEventId, lParam);
		m_listLog.AddString(strTemp);
		break;
	}
	while (m_listLog.GetCount() >= 20) m_listLog.DeleteString(0);
}

void CEZGemPlusDLL_SampleDlg::OnMsgReceived(long lMsgId)
{
	short nStream = 0, nFunc = 00, nWait = 0;
	long nLength = 0;
	CString strTemp;

	//---------------------------------------------------------------------------------
	long nResult = m_gem.GetMsgInfo(lMsgId, &nStream, &nFunc, &nWait, &nLength);
	//---------------------------------------------------------------------------------
	
	if (nResult < RESULT_OK) return;	// error

	if (nStream == 7 && nFunc == 17)	// S7F17
	{
		CStringArray arrayPPID;
		m_gem.GetListChildItem(lMsgId, &arrayPPID);
		for (int i = 0; i < arrayPPID.GetCount(); i++)
		{
			strTemp.Format(_T("S7F17 [%d] PPID=<%s>"), i + 1, arrayPPID.GetAt(i));
			m_listLog.AddString(strTemp);
		}
		if (nWait == 1)
		{
			lMsgId = m_gem.CreateReplyMsg(lMsgId);
			m_gem.OpenListItem(lMsgId);
			m_gem.CloseListItem(lMsgId);
			m_gem.SendMsg(lMsgId);
		}
		else m_gem.CloseMsg(lMsgId);    //응답이 필요없으면 바로 닫아 메세지큐에서 삭제한다.
	}
	else if (nStream == 3 && nFunc == 17)
	{
		int nItems = m_gem.GetListItemOpen(lMsgId);
		m_gem.ResetMsgReceived(lMsgId);
	}
	else if (nStream == 1 && nFunc == 15)
	{
		m_gem.ResetMsgReceived(lMsgId);
	}
	else if (nStream == 7 && nFunc == 3)	// S7F3
	{
		lMsgId = m_gem.CreateReplyMsg(lMsgId);
		m_gem.SendMsg(lMsgId);
	}
	else if (nStream == 7 && nFunc == 5)
	{
		CString strPPID = 0;
		m_gem.GetAsciiItem(lMsgId, &strPPID);

		lMsgId = m_gem.CreateReplyMsg(lMsgId);
		m_gem.OpenListItem(lMsgId);
		m_gem.AddAsciiItem(lMsgId, strPPID, 20);
		m_gem.AddFileBinaryItem(lMsgId, _T("EZGemPlus_32.dll"));	// RECIPE FILE 첨부
		m_gem.CloseListItem(lMsgId);
		m_gem.SendMsg(lMsgId);
		//-------------------------------------------------
		// 테스트를 위해 S7F3도 연달아 보냄
		/*
		lMsgId = m_gem.CreateMsg(7, 3, TRUE);
		m_gem.OpenListItem(lMsgId);
		m_gem.AddAsciiItem(lMsgId, "EZGEMPLUS_32.DLL", 20);
		m_gem.AddFileBinaryItem(lMsgId, "EZGemPlus_32.dll");	// RECIPE FILE 첨부
		m_gem.CloseListItem(lMsgId);
		m_gem.SendMsg(lMsgId);
		*/
	}
	else if (nStream == 7 && nFunc == 19)	// S7F19
	{
		if (nWait == 1)
		{
			lMsgId = m_gem.CreateReplyMsg(lMsgId);
			m_gem.OpenListItem(lMsgId);
			m_gem.AddAsciiItem(lMsgId, _T("PPID1"), 5);
			m_gem.AddAsciiItem(lMsgId, _T("PPID2"), 5);
			m_gem.AddAsciiItem(lMsgId, _T("PPID3"), 5);
			m_gem.AddAsciiItem(lMsgId, _T("PPID4"), 5);
			m_gem.CloseListItem(lMsgId);
			m_gem.SendMsg(lMsgId);
		}
		else m_gem.CloseMsg(lMsgId);
	}
	else if (nStream == 7 && nFunc == 25)	// S7F25
	{
		lMsgId = m_gem.CreateReplyMsg(lMsgId);
		m_gem.OpenListItem(lMsgId);
		m_gem.AddAsciiItem(lMsgId, _T("PPID001"), 10);
		m_gem.AddAsciiItem(lMsgId, _T("MDLN"), 10);
		m_gem.AddAsciiItem(lMsgId, _T("SOFTREV"), 10);
		for (int i = 0; i < 30; i++)
		{
			m_gem.OpenListItem(lMsgId);
			for (int j = 0; j < 20; j++)
			{
				CString strTemp;
				strTemp.Format(_T("%d"), j);
				m_gem.OpenListItem(lMsgId);
				m_gem.AddAsciiItem(lMsgId, strTemp, strTemp.GetLength());
				m_gem.OpenListItem(lMsgId);
				m_gem.AddAsciiItem(lMsgId, _T("NAME___"), 10);
				m_gem.AddAsciiItem(lMsgId, _T("VAL__"), 5);
				m_gem.CloseListItem(lMsgId);
				m_gem.CloseListItem(lMsgId);
			}
			m_gem.CloseListItem(lMsgId);
		}
		m_gem.CloseListItem(lMsgId);
		m_gem.SendMsg(lMsgId);
	}

	while (m_listLog.GetCount() > 25) m_listLog.DeleteString(0);
}

void CEZGemPlusDLL_SampleDlg::OnBnClickedButtonOffline()
{
/*** DATA TEST

	short BOOL_VAL = 1;
	short BINARY_VAL = 10;
	short I1_VAL = 10;
	short I2_VAL = 32555;
	long  I4_VAL = 655360;
	long  I8_VAL = 24000000;
	//-----------------------------------------------------
	LONGLONG I8_VAL_X64 = 0x7FFFFFFFFFFFFFFF; 	// MAX (9223372036854775807)	
	//-----------------------------------------------------
	short U1_VAL = 250;
	long  U2_VAL = 65000;
	double U4_VAL = 4294967290;
	double U8_VAL = 1844674400;
	//------------------------------------------------------
	ULONGLONG U8_VAL_X64 = 0xFFFFFFFFFFFFFFFF;	// MAX (18446744073709551615)
	//------------------------------------------------------
	float  F4_VAL = 3.402823466e+38f;			// F4 MAX
	double F8_VAL = 1.7976931348623158e+308;	// F8_VAL
	CString ASCII_VAL = "EZGEM300 DLL Data Test !!!";

	long lMsgId = m_gem.CreateMsg(3, 101, 0);
	m_gem.OpenListItem(lMsgId);
	m_gem.AddBoolItem(lMsgId, &BOOL_VAL, 1);
	m_gem.AddBinaryItem(lMsgId, &BINARY_VAL, 1);
	m_gem.AddI1Item(lMsgId, &I1_VAL, 1);
	m_gem.AddI2Item(lMsgId, &I2_VAL, 1);
	m_gem.AddI4Item(lMsgId, &I4_VAL, 1);
	m_gem.AddI8Item(lMsgId, &I8_VAL, 1);
	m_gem.AddI8ItemI64(lMsgId, &I8_VAL_X64, 1);	// NEW
	m_gem.AddU1Item(lMsgId, &U1_VAL, 1);
	m_gem.AddU2Item(lMsgId, &U2_VAL, 1);
	m_gem.AddU4Item(lMsgId, &U4_VAL, 1);
	m_gem.AddU8Item(lMsgId, &U8_VAL, 1);
	m_gem.AddU8ItemU64(lMsgId, &U8_VAL_X64, 1);		// NEW
	m_gem.AddF4Item(lMsgId, &F4_VAL, 1);
	m_gem.AddF8Item(lMsgId, &F8_VAL, 1);
	m_gem.AddAsciiItem(lMsgId, ASCII_VAL, ASCII_VAL.GetLength());
	m_gem.CloseListItem(lMsgId);
	m_gem.SendMsg(lMsgId);

	long SVID = 2222;	// OBJECT_SVID
	m_gem.CloseMsg(SVID);
	//-------------------------
	m_gem.OpenListItem(SVID);
	m_gem.AddBoolItem(SVID, &BOOL_VAL, 1);
	m_gem.AddBinaryItem(SVID, &BINARY_VAL, 1);
	m_gem.AddI1Item(SVID, &I1_VAL, 1);
	m_gem.AddI2Item(SVID, &I2_VAL, 1);
	m_gem.AddI4Item(SVID, &I4_VAL, 1);
	m_gem.AddI8Item(SVID, &I8_VAL, 1);
	m_gem.AddI8ItemI64(SVID, &I8_VAL_X64, 1);	// NEW
	m_gem.AddU1Item(SVID, &U1_VAL, 1);
	m_gem.AddU2Item(SVID, &U2_VAL, 1);
	m_gem.AddU4Item(SVID, &U4_VAL, 1);
	m_gem.AddU8Item(SVID, &U8_VAL, 1);
	m_gem.AddU8ItemU64(SVID, &U8_VAL_X64, 1);		// NEW
	m_gem.AddF4Item(SVID, &F4_VAL, 1);
	m_gem.AddF8Item(SVID, &F8_VAL, 1);
	m_gem.AddAsciiItem(SVID, ASCII_VAL, ASCII_VAL.GetLength());
	m_gem.CloseListItem(SVID);
*/
	//------------------------------------------------------
	m_gem.SetSVIDValue(2001, _T("1"));
	m_gem.SendEventReport(1001);	// EQ OFFLINE
	m_gem.GoOffline();

	m_txtControlState.SetWindowText(_T("EQ OFFLINE"));
}

void CEZGemPlusDLL_SampleDlg::OnBnClickedButtonLocal()
{
	m_gem.GoOnlineLocal();// 함수호출--> 결과가 이벤트로 들어옴
}


void CEZGemPlusDLL_SampleDlg::OnBnClickedButtonRemote()
{
	m_gem.GoOnlineRemote();// 함수호출--> 결과는 이벤트로 들어옴

	BYTE BYTEARRAY[100];
	for (int i = 0; i < 100; i++) BYTEARRAY[i] = i;

	long lMsgId = m_gem.CreateMsg(1, 101, 0);
	m_gem.OpenListItem(lMsgId);
	m_gem.AddBinaryItem(lMsgId, BYTEARRAY, 100);
	m_gem.CloseListItem(lMsgId);
	m_gem.SendMsg(lMsgId);
}


void CEZGemPlusDLL_SampleDlg::OnBnClickedButtonAlarmset()
{
	m_gem.SendAlarmReport(4001, 100 + 0x80);	// ALID, ALCD (SET? + 0x80)

	//	동일 기능의 대체 함수
	//	m_gem.SendAlarmReportEx(4001, 100, 1);
}


void CEZGemPlusDLL_SampleDlg::OnBnClickedButtonAlarmclear()
{
	m_gem.SendAlarmReport(4001, 0);
}


void CEZGemPlusDLL_SampleDlg::OnBnClickedButtonProcessstart()
{
	m_gem.SendEventReport(1004);
}


void CEZGemPlusDLL_SampleDlg::OnBnClickedButtonProcessend()
{
	m_gem.SendEventReport(1005);
}

void CEZGemPlusDLL_SampleDlg::OnBnClickedButtonLoadrequest()
{
	UpdateData(TRUE);
	int nPort = 0;
	if (m_radioLoadPort1.GetCheck()) nPort = 1;
	if (m_radioLoadPort2.GetCheck()) nPort = 2;

	//--------------------------------------------------------------------------
	//
	m_gem.SetTransferState(nPort, TRANSFERSTATE_READYTOLOAD);
	//
	//--------------------------------------------------------------------------

	// CARRIER LOADING이 시작되면 TRANSFERBLOCK 상태로 변함
	m_comboTransferState.SetCurSel(5);	// TRANSFER BLOCK
	GetDlgItem(IDC_COMBO_TRANSFERSTATE)->SetFocus();
}


void CEZGemPlusDLL_SampleDlg::OnBnClickedButtonDelcarrier()
{
	UpdateData(TRUE);
	if (m_strCarrierID_Delete == _T(""))
	{
		AfxMessageBox(_T("CarrierID caanot be empty !!!"));
		GetDlgItem(IDC_EDIT_CARRIERID_DEL)->SetFocus();
		return;
	}
	//-----------------------------------------------------------
	long nResult = m_gem.DeleteCarrier(m_strCarrierID_Delete);
	//-----------------------------------------------------------

	CString strTemp;
	strTemp.Format(_T("DeleteCarrier(%s) -> Result=%d"), m_strCarrierID_Delete, nResult);
	m_listGem300Log.AddString(strTemp);
}

void CEZGemPlusDLL_SampleDlg::OnBnClickedButtonDelallcarrier()
{
	//-----------------------------------------------------------
	long nResult = m_gem.DeleteAllCarrier();
	//-----------------------------------------------------------

	CString strTemp;
	strTemp.Format(_T("DeleteAllCarrier() -> Result=%d"), nResult);
	m_listGem300Log.AddString(strTemp);
}

void CEZGemPlusDLL_SampleDlg::OnBnClickedButtonLoadcomplete()
{
	UpdateData(TRUE);
	int nPort = 0;
	if (m_radioLoadPort1.GetCheck()) nPort = 1;
	if (m_radioLoadPort2.GetCheck()) nPort = 2;

	//------------------------------------------------------------------------------------------
	// 장비의 Presence Sensor = ON, Placement Sensor = ON이 되면 이 함수 호출
	m_gem.SetCarrierArrived(nPort);	// GEM Driver는 이벤트보고함 (CEID = MATERIAL RECEIVED)
	//
	//------------------------------------------------------------------------------------------
}


void CEZGemPlusDLL_SampleDlg::OnBnClickedButtonUnloadrequest()
{
	UpdateData(TRUE);
	int nPort = 0;
	if (m_radioLoadPort1.GetCheck()) nPort = 1;
	if (m_radioLoadPort2.GetCheck()) nPort = 2;

	//-----------------------------------------------------------
	//
	m_gem.SetTransferState(nPort, TRANSFERSTATE_READYTOUNLOAD);
	//
	//-----------------------------------------------------------
}


void CEZGemPlusDLL_SampleDlg::OnBnClickedButtonUnloadcomplete()
{
	UpdateData(TRUE);
	int nPort = 0;
	if (m_radioLoadPort1.GetCheck()) nPort = 1;
	if (m_radioLoadPort2.GetCheck()) nPort = 2;

	//---------------------------------------------------
	//	Presence Sensor = OFF, Placement Sensor = OFF
	//
	m_gem.SetCarrierRemoved(nPort);
	//
	//----------------------------------------------------
}


void CEZGemPlusDLL_SampleDlg::OnBnClickedButtonSettransferstate()
{
	int nSel = m_comboTransferState.GetCurSel();
	if (nSel == LB_ERR)
	{
		MessageBox(_T("No Transfer State selected !!!"));
		return;
	}

	UpdateData(TRUE);
	int nPort = 0;
	if (m_radioLoadPort1.GetCheck()) nPort = 1;
	if (m_radioLoadPort2.GetCheck()) nPort = 2;

	//-------------------------------------
	//
	m_gem.SetTransferState(nPort, nSel);
	//
	//-------------------------------------
}

void CEZGemPlusDLL_SampleDlg::OnEvent_HostSetLoadPortServiceMode(long lMsgId) // S3F25
{
	CString strTemp;
	int nServiceMode = 0;
	CString strPortList;

	strTemp.Format(_T("S3F25, LoadPort ServiceMode Change.  MSGID=%d"), lMsgId);
	m_listGem300Log.AddString(strTemp);
	//---------------------------------------------------------------------------------------
	long nRet = m_gem.GetHostSetLoadPortServiceMode(lMsgId, &nServiceMode, &strPortList);
	//---------------------------------------------------------------------------------------
	strTemp.Format(_T("-> RET=%d, ServiceMode=%d, LoadPortList={%s}"), nRet, nServiceMode, strPortList);
	m_listGem300Log.AddString(strTemp);

	// CAACK = 0 : OK
	// CAACK = 1 : Invalid Command (GEM Driver 내부에서 처리)
	// CAACK = 2 : Cannot Perform Now.
	// CAACK = 3 : Invalid Data or Argument.   (PortID, CarrierID등 맞지 않을 경우)
	// CAACK = 5 : Invalid State.    (현재 장비 상태가 이 명령을 받을 상태가 아닌경우)

	int CAACK = 0;

	if (CAACK > 0)		//	에러시 (상황에 따라) ErrorCode, ErrorText 추가 가능,ErrorCode는 SEMI spec E5  "ERRCODE" 참조
	{
		// 여러개의 에러정보를 추가할 수 있음
		m_gem.SetCarrierActionErrorCode(lMsgId, 47, _T("Invalid PortID"));
		m_gem.SetCarrierActionErrorCode(lMsgId, 49, _T("Load port already in use"));
	}
	m_gem.ReplyCarrierAction(lMsgId, CAACK);	// 응답(S3F26) 전송 
}

void CEZGemPlusDLL_SampleDlg::OnEvent_HostSetLoadPortAccessMode(long lMsgId)	// S3F23/S3F27 LoadPortAccessMode Change
{
	CString strTemp, strPortList;
	int nAccessMode = 0;

	strTemp.Format(_T("S3F23 or S3F27, LoadPort AccessMode Change.  MSGID=%d"), lMsgId);
	m_listGem300Log.AddString(strTemp);

	long nRet = m_gem.GetHostSetLoadPortAccessMode(lMsgId, &nAccessMode, &strPortList);
	strTemp.Format(_T("-> RET=%d, AccessMode=%d, LoadPortList={%s}"), nRet, nAccessMode, strPortList);
	m_listGem300Log.AddString(strTemp);

	// CAACK = 0 : OK
	// CAACK = 1 : Invalid Command (GEM Driver 내부에서 처리)
	// CAACK = 2 : Cannot Perform Now.
	// CAACK = 3 : Invalid Data or Argument.   (PortID, CarrierID등 맞지 않을 경우)
	// CAACK = 5 : Invalid State.    (현재 장비 상태가 이 명령을 받을 상태가 아닌경우)

	int CAACK = 0;

	if (CAACK > 0)		//	에러시 (상황에 따라) ErrorCode, ErrorText 추가 가능,ErrorCode는 SEMI spec E5  "ERRCODE" 참조
	{
		// 여러개의 에러정보를 추가할 수 있음
		m_gem.SetCarrierActionErrorCode(lMsgId, 47, _T("Invalid PortID"));
		m_gem.SetCarrierActionErrorCode(lMsgId, 49, _T("Load port already in use"));
	}
	m_gem.ReplyCarrierAction(lMsgId, CAACK);	// 응답(S3F28) 전송 
}

void CEZGemPlusDLL_SampleDlg::OnEvent_ProceedWithCarrier(long lMsgId)	// S3F17 <ProceedWithCarrier> (1) CarrierID Verification,  (2) SlotMap Verification
{
	CString strTemp, strCarrierID, strContentMap, strSlotMap;
	int nPort = 0, nContentMapCount = 0, nSlotMapCount = 0;

	strTemp.Format(_T("S3F17, ProceedWithCarrier !!!  MSGID=%d"), lMsgId);
	m_listGem300Log.AddString(strTemp);

	//-----------------------------------------------------------------------------------------------------
	// Host가 보낸 S3F17 정보를 읽어옴
	//
	m_gem.GetCarrierActionInfo(lMsgId, &nPort, &strCarrierID, &nContentMapCount, &nSlotMapCount);
	//
	//-----------------------------------------------------------------------------------------------------

	strTemp.Format(_T("PORT=%d, CARRIERID=%s, ContentMapCount=%d, SlotMapCount=%d"), nPort, strCarrierID, nContentMapCount, nSlotMapCount);
	m_listGem300Log.AddString(strTemp);

	for (int i = 0; i < nContentMapCount; i++)	// ContentMap정보가 있으면 읽어들임
	{
		//-----------------------------------------------------
		//
		m_gem.GetContentMapInfo(lMsgId, i, &strContentMap);	//// Host가 보낸 S3F17의 "ContentMap"을 읽어오는 함수
		//
		//-----------------------------------------------------
		m_listGem300Log.AddString(strContentMap);
	}
	if (nSlotMapCount > 0)	// SlotMap정보가 있으면 읽어들임
	{
		//---------------------------------------------
		//
		m_gem.GetSlotMapInfo(lMsgId, strSlotMap);	//	 Host가 보낸 S3F17의 "SlotMap"을 문자열로 받아옴
		//
		//---------------------------------------------
		m_listGem300Log.AddString(strSlotMap);
	}

	// CAACK = 0 : OK
	// CAACK = 1 : Invalid Command (GEM Driver 내부에서 처리)
	// CAACK = 2 : Cannot Perform Now.
	// CAACK = 3 : Invalid Data or Argument.   (PortID, CarrierID등 맞지 않을 경우)
	// CAACK = 5 : Invalid State.    (현재 장비 상태가 이 명령을 받을 상태가 아닌경우)

	int CAACK = 0;	

	if (CAACK > 0)		//	에러시 (상황에 따라) ErrorCode, ErrorText 추가 가능,ErrorCode는 SEMI spec E5  "ERRCODE" 참조
	{
		// 여러개의 에러정보를 추가할 수 있음
		m_gem.SetCarrierActionErrorCode(lMsgId, 47, _T("Invalid parameter"));
		m_gem.SetCarrierActionErrorCode(lMsgId, 49, _T("Load port already in use"));
	}

	//----------------------------------------------------------
	// S3F17에 대해  응답함수 (S3F18을 내보냄)
	// (NG일 경우, 즉 CAACK>0인 경우  추가된 에러코드가 반영되어 응답함

	m_gem.ReplyCarrierAction(lMsgId, CAACK);

	//
	//----------------------------------------------------------
	
	// [중요사항]  장비는 Host가 보내온  "ProceedWithCarrier" 명령
	// (1) CarrierID Verification인지
	// (2) SlotMap Verification인지 판단할수 있어야 함
	// CarrierID Verification이 먼저이고,  다음에 SlotMap Verification 순서임

	if (m_bCarrierVerifyOK == FALSE && CAACK == 0)	// [1] CarrierID Verification인 경우
	{
		//--------------------------------------------------------------------------------
		m_gem.SetCarrierIDStatus(nPort, strCarrierID, CARRIERIDSTATE_VERIFYOK);
		//--------------------------------------------------------------------------------

		m_bCarrierVerifyOK = TRUE;
	}
	else if (m_bCarrierVerifyOK && CAACK == 0) // [2] SlotMap Verification인 경우
	{
		//--------------------------------------------------------------------------------
		m_gem.SetSlotMapStatus(nPort, strCarrierID, SLOTMAPSTATE_VERIFYOK);
		//--------------------------------------------------------------------------------
	}
}

void CEZGemPlusDLL_SampleDlg::OnEvent_CancelCarrier(long lMsgId, BOOL bCancelCarrierAtPort)	// S3F17 <CancelCarrier> (1) CarrierID or (2) SlotMap 이 맞지 않을때 작업취소명령 !!!
{
	// CancelCarrier --> CarrierID를 지정하여 해당 Carrier를 취소->반출 (거의 대부분 이 멸령 사용)
	// CancelCarrierAtPort --> CarrierID에 상관없이 해당 PORT에 있는 Carrier에 대해 취소->반출

	CString strTemp, strCarrierID, strContentMap, strSlotMap;
	int nPort = 0, nContentMapCount = 0, nSlotMapCount = 0;

	if (bCancelCarrierAtPort)	strTemp.Format(_T("S3F17, CancelCarrierAtPort !!!  MSGID=%d"), lMsgId);
	else						strTemp.Format(_T("S3F17, CancelCarrier !!!  MSGID=%d"), lMsgId);
	m_listGem300Log.AddString(strTemp);

	//-----------------------------------------------------------------------------------------------------
	// Host가 보낸 S3F17 정보를 읽어옴
	//
	m_gem.GetCarrierActionInfo(lMsgId, &nPort, &strCarrierID, &nContentMapCount, &nSlotMapCount);
	//
	//-----------------------------------------------------------------------------------------------------
	// CancelCarrier의 경우 PORTID가 지정되지 않을수 있음
	if (nPort == 0)
	{
		if (m_radioLoadPort1.GetCheck()) nPort = 1;
		if (m_radioLoadPort2.GetCheck()) nPort = 2;
	}

	strTemp.Format(_T("PORT=%d, CARRIERID=%s, ContentMapCount=%d, SlotMapCount=%d"), nPort, strCarrierID, nContentMapCount, nSlotMapCount);
	m_listGem300Log.AddString(strTemp);

	int CAACK = 0;
	//-------------------------------------------
	// S3F17에 대해  응답함수 (S3F18을 내보냄)
	//
	m_gem.ReplyCarrierAction(lMsgId, CAACK);
	//
	//-------------------------------------------

	if (m_bCarrierVerifyOK == FALSE)
	{
		//-----------------------------------------------------------------------------------
		// Carrier ID 불일치에 대한 CancelCarrier
		m_gem.SetCarrierIDStatus(nPort, strCarrierID, CARRIERIDSTATE_VERIFYFAIL);
		//-----------------------------------------------------------------------------------
	}
	else
	{
		//-----------------------------------------------------------------------------------
		// SlotMap 불일치에 대한 CancelCarrier
		m_gem.SetSlotMapStatus(nPort, strCarrierID, SLOTMAPSTATE_VERIFYFAIL);
		//-----------------------------------------------------------------------------------
	}

	//-----------------------------------------------------------
	// 장비는 Carrier를 원래의 Position으로 이동후, Unload요청
	// Carrier Door Close->Undock->UnClamping->Unloading
	//
	m_gem.SetTransferState(nPort, TRANSFERSTATE_READYTOUNLOAD);
	//
	//-----------------------------------------------------------
}

void CEZGemPlusDLL_SampleDlg::OnEvent_Bind(long lMsgId)	// S3F17 <'Bind'>
{
	CString strTemp, strCarrierID, strContentMap, strSlotMap;
	int nPort = 0, nContentMapCount = 0, nSlotMapCount = 0;

	strTemp.Format(_T("S3F17, 'Bind'   MSGID=%d"), lMsgId);
	m_listGem300Log.AddString(strTemp);
	//-----------------------------------------------------------------------------------------------------
	// Host가 보낸 S3F17 정보를 읽어옴
	m_gem.GetCarrierActionInfo(lMsgId, &nPort, &strCarrierID, &nContentMapCount, &nSlotMapCount);
	//
	// 중요 1.  해당 Port가 이미 작업중이면 불가
	// 중요 2.  CarrierID가 이미 작업중인 CarrierID면 불가
	//-----------------------------------------------------------------------------------------------------
	strTemp.Format(_T("PORT=%d, CARRIERID=%s, ContentMapCount=%d, SlotMapCount=%d"), nPort, strCarrierID, nContentMapCount, nSlotMapCount);
	m_listGem300Log.AddString(strTemp);

	int CAACK = 0;
	//-------------------------------------------
	// S3F17에 대해  응답함수 (S3F18을 내보냄)
	m_gem.ReplyCarrierAction(lMsgId, CAACK);
	//-------------------------------------------
}

void CEZGemPlusDLL_SampleDlg::OnEvent_CancelBind(long lMsgId)	// S3F17 <'CancelBind'>
{
	// Bind후  Carrier가 Load되고 작업진행중일때는 CancelBind를 받아들일수 없음
	CString strTemp, strCarrierID, strContentMap, strSlotMap;
	int nPort = 0, nContentMapCount = 0, nSlotMapCount = 0;

	strTemp.Format(_T("S3F17, 'CancelBind'   MSGID=%d"), lMsgId);
	m_listGem300Log.AddString(strTemp);
	//-----------------------------------------------------------------------------------------------------
	// Host가 보낸 S3F17 정보를 읽어옴
	m_gem.GetCarrierActionInfo(lMsgId, &nPort, &strCarrierID, &nContentMapCount, &nSlotMapCount);
	//
	// 중요 1.  해당 Port가 이미 작업중이면 불가
	// 중요 2.  CarrierID가 이미 작업중인 CarrierID면 에러
	//-----------------------------------------------------------------------------------------------------

	strTemp.Format(_T("PORT=%d, CARRIERID=%s, ContentMapCount=%d, SlotMapCount=%d"), nPort, strCarrierID, nContentMapCount, nSlotMapCount);
	m_listGem300Log.AddString(strTemp);

	int CAACK = 0;
	//-------------------------------------------
	// S3F17에 대해  응답함수 (S3F18을 내보냄)
	m_gem.ReplyCarrierAction(lMsgId, CAACK);
	//-------------------------------------------
}
void CEZGemPlusDLL_SampleDlg::OnEvent_ReserveAtPort(long lMsgId)	// S3F17 <'ReserveAtPort'>
{
	CString strTemp;
	strTemp.Format(_T("S3F17, 'ReserveAtPort'   MSGID=%d"), lMsgId);
	m_listGem300Log.AddString(strTemp);

	//-------------------------------------------
	// S3F17에 대해  응답함수 (S3F18을 내보냄)
	m_gem.ReplyCarrierAction(lMsgId, RESULT_OK);
	//-------------------------------------------
}

void CEZGemPlusDLL_SampleDlg::OnEvent_CarrierReCreate(long lMsgId)		// S3F17 <'CarrierReCreate'>
{
	// LoadPort TransferState가 ReadyToUnload일때
	// Carrier를 반송하지 않고 다시 생성하여 다시 시작할 경우 Host가 CarrierReCreate를 내려줌.

	CString strTemp, strCarrierID;
	strTemp.Format(_T("S3F17, 'CarrierReCreate'   MSGID=%d"), lMsgId);
	m_listGem300Log.AddString(strTemp);

	int nPort = 0, nContentMapCount = 0, nSlotMapCount = 0;
	//-----------------------------------------------------------------------------------------------------
	// Host가 보낸 S3F17 정보를 읽어옴
	m_gem.GetCarrierActionInfo(lMsgId, &nPort, &strCarrierID, &nContentMapCount, &nSlotMapCount);
	strTemp.Format(_T("PORT=%d, CARRIERID=%s"), nPort, strCarrierID);
	m_listGem300Log.AddString(strTemp);

	int CAACK = 0;
	//-------------------------------------------
	// S3F17에 대해  응답함수 (S3F18을 내보냄)
	m_gem.ReplyCarrierAction(lMsgId, CAACK);
	//-------------------------------------------
}

// ----------------------------------------------------------------------------
// Inernal Buffer 장비에 해당
// 작업완료후 Internal Buffer에 있는 Carrier를 LoadPort로 이동시키는 호스트명령
void CEZGemPlusDLL_SampleDlg::OnEvent_CarrierOut(long lMsgId)		// S3F17 <'CarrierOut'>
{
	CString strTemp, strCarrierID;
	strTemp.Format(_T("S3F17, 'CarrierOut'   MSGID=%d"), lMsgId);
	m_listGem300Log.AddString(strTemp);

	int nPort = 0, nContentMapCount = 0, nSlotMapCount = 0;
	//-----------------------------------------------------------------------------------------------------
	// Host가 보낸 S3F17 정보를 읽어옴
	m_gem.GetCarrierActionInfo(lMsgId, &nPort, &strCarrierID, &nContentMapCount, &nSlotMapCount);

	// PortNo와 CarrierID만 필요함.
	strTemp.Format(_T("PORT=%d, CARRIERID=%s"), nPort, strCarrierID);
	m_listGem300Log.AddString(strTemp);

	int CAACK = RESULT_OK;
	//-------------------------------------------
	// S3F17에 대해  응답함수 (S3F18을 내보냄)
	m_gem.ReplyCarrierAction(lMsgId, CAACK);

	//-------------------------------------------
	// 호스트의 요청에 따라 해당 LoadPort로 Carrier를 이동시킴  (port=1이라 가정)
	// (1) m_gem.SetTransferState(1, TRANSFER_STATE->TRASFER_BLOCKED);
	// (2) m_gem.SetCarrierMove("CARRIER_001","LP01");	// S6F11 (CarrierLocationChanged) 이벤트 전송됨
}

// ----------------------------------------------------------------------------
// Inernal Buffer 장비에 해당
// "CarrierOut명령이 들어온이후 CancelCarrierOut명령이 들어옴
// Internal Buffer에서 LoadPort로 이동시키는 명령(CarrierOut)이 들어왔을때
// 수행하기전에 CancelCarrierOut이 들어오면 이동을 취소함.
void CEZGemPlusDLL_SampleDlg::OnEvent_CancelCarrierOut(long lMsgId)		// S3F17 <'CancelCarrierOut'>
{
	CString strTemp, strCarrierID;
	strTemp.Format(_T("S3F17, 'CancelCarrierOut'   MSGID=%d"), lMsgId);
	m_listGem300Log.AddString(strTemp);

	int nPort = 0, nContentMapCount = 0, nSlotMapCount = 0;
	//-----------------------------------------------------------------------------------------------------
	// Host가 보낸 S3F17 정보를 읽어옴
	m_gem.GetCarrierActionInfo(lMsgId, &nPort, &strCarrierID, &nContentMapCount, &nSlotMapCount);

	// CarrierID만 필요함.
	strTemp.Format(_T("PORT=%d, CARRIERID=%s"), nPort, strCarrierID);
	m_listGem300Log.AddString(strTemp);

	int CAACK = 0;
	//-------------------------------------------
	// S3F17에 대해  응답함수 (S3F18을 내보냄)
	m_gem.ReplyCarrierAction(lMsgId, CAACK);

	//-------------------------------------------
	// 호스트의 요청에 따라 해당 LoadPort로 Carrier를 이동시키는 액션을 취소함
}


//-------------------------------
// S16F11, S16F15
// PRJOBCreate 명령수신
//-------------------------------
void CEZGemPlusDLL_SampleDlg::OnEvent_HostSetPrJobCreate(long lMsgId)	
{
	CString strTemp;
	CString strPrJobID, strPPID, strCarrierID, strSlotList, strParamName, strParamVal;
	int nCarrierCount = 0, nAutoStart = 0, nParams = 0, ERRCODE=0, nPrJobCount = 0;

	nPrJobCount = m_gem.GetHostSetPrJobCount(lMsgId);
	strTemp.Format(_T("S16F15 (or S16F11), HOSE->EQ : PRJob(Multi)Create,  MSGID=%d, JOBCOUNT=%d"), lMsgId, nPrJobCount);
	m_listGem300Log.AddString(strTemp);

	for (int i = 0; i < nPrJobCount; i++)
	{
		m_gem.GetHostSetPrJob(lMsgId, i, &strPrJobID, &strPPID, &nCarrierCount, &nAutoStart, &nParams);

		strTemp.Format(_T("PrJobID=%s, CarrierCount=%d, PPID=%s, AutoStart=%s, RecipeParameter=%d"),
			strPrJobID, nCarrierCount, strPPID, (nAutoStart) ? _T("TRUE") : _T("FALSE"), nParams);
		m_listGem300Log.AddString(strTemp);
		m_listPrJob.AddString(strPrJobID);

		for (int j = 0; j < nCarrierCount; j++)
		{
			if (m_gem.GetPrJobCarrier(strPrJobID, j, &strCarrierID, &strSlotList) == 0)
			{
				strTemp.Format(_T("CarrierID=%s, SlotList=%s"), strCarrierID, strSlotList);
				m_listGem300Log.AddString(strTemp);
			}
		}
		for (int j = 0; j < nParams; j++)
		{
			if (m_gem.GetPrJobParam(strPrJobID, j, &strParamName, &strParamVal) == 0)
			{
				strTemp.Format(_T("%s = %s"), strParamName, strParamVal);
				m_listGem300Log.AddString(strTemp);
			}
		}
	}

	//----------- 만약 장비입장에서  호스트의 명령에  에러가 있다면 아래처럼 해당 PRJob에 대해 ERRCODE내용을 반영
	//
	//	ERRCODE = 1;
	//	m_gem.SetPrJobErrorCode(lMsgId, strErrorPrJob,  ERRCODE , "Invalid Parameter !!!");
	//
	//  *** ERROR가 없는 PRJOB에 대해서는 정상적으로 응답하며  PrJob이 생성됨 

	//---------------------------------
	// PRJob생성에 대해 응답
	m_gem.ReplyHostSetPrJob(lMsgId);
	//---------------------------------
}

// S16F17 HOST->EQ  PRJOB DEQUE(DELETE)
void CEZGemPlusDLL_SampleDlg::OnEvent_HostSetPrJobDeque()
{
	CString strTemp, strPrJobDeleted;

	//---------------------------------------
	m_gem.GetPrJobDeleted(&strPrJobDeleted);
	//---------------------------------------

	strTemp.Format(_T("PrJobDeleted = %s"), strPrJobDeleted);
	m_listGem300Log.AddString(strTemp);

	UpdatePrJobList();
}

// S16F23 HOST->EQ : PrJob Recipe parameter values
void CEZGemPlusDLL_SampleDlg::OnEvent_HostSetPrJobParamValue(long lMsgId)
{
	int nParamCount = 0;
	CString strTemp, strPrJob, strParamName, strParamVal;

	//---------------------------------------------------------------------------
	// 호스트가 보낸 PRJOB이름과 파라미터 갯수를 가져옴
	long nResult = m_gem.GetHostSetPrJobParam(lMsgId, &strPrJob, &nParamCount);
	//---------------------------------------------------------------------------
	strTemp.Format(_T("S16F23 HostSet PrJob Parameter. PRJOB=%s, ParmCount=%d"), strPrJob, nParamCount);
	m_listGem300Log.AddString(strTemp);

	if (nResult == RESULT_OK)
	{
		for (int i = 0; i < nParamCount; i++)
		{
			m_gem.GetPrJobParam(strPrJob, i, &strParamName, &strParamVal);
			strTemp.Format(_T("%s : Parameter[%02d] Name=%s, Val=%s"),strPrJob, i+1, strParamName, strParamVal);
			m_listGem300Log.AddString(strTemp);
		}
	}

	//	에러가 있거나 거부하고자 하는 경우 아래처럼 에러처리
	//----------------------------------------------------------------
	//	int ERRORCODE = 1;
	//	m_gem.SetPrJobErrorCode(lMsgId, (CString)bstrPrJob, ERRORCODE, "Not Supported for this option");
	//----------------------------------------------------------------
	// 에러 처리하지 않고 수용하면 호스트로부터 받은 항목들을 PRJOB PARAMETER 에 반영됨

	m_gem.ReplyHostSetPrJob(lMsgId);
}

// S16F25 PRJob Start Method변경 (HOST->EQ)
void CEZGemPlusDLL_SampleDlg::OnEvent_HostSetPrJobStartMethod(long lMsgId)
{
	CString strTemp, strPrJobList;
	strTemp.Format(_T("S16F25, HOSE->EQ : PRJobSetStartMethod(Auto/Manual)   MSGID=%d"), lMsgId);
	m_listGem300Log.AddString(strTemp);

	int nJobCount = 0, nStartMethod;

	//--------------------------------------------------------------------------------------------------
	// long GetHostSetPrJobStartMethod(MSGID, *JOBCOUNT, *JOBLIST, *STARTMETHOD)
	// ---------------------------------------------------------------------------
	// S16F25로 내려온 정보(PRJOBID, STARTMETHOD)를 가져오는 함수
	// - MSGID : 검색을 위한 Index Key
	// - JOBCOUNT : 대상 PRJOB수
	// - JOBLIST : 대상 PRJOBLIST (1개 이상의 PRJOB이 내려올 경우 콤마(',')로 구분됨)
	// - STARTMETHOD : 호스트가 변경한 START METHOD (1=AUTO, 0=MANUAL)
	// (반환값) 0 = OK,  음수=에러코드

	long nResult = m_gem.GetHostSetPrJobStartMethod(lMsgId, &nJobCount, &strPrJobList, &nStartMethod);
	
	//--------------------------------------------------------------------------------------------------

	if (nResult == RESULT_OK)
	{
		strTemp.Format(_T(" COUNT=%d, PRJOBLIST={%s}, STARTMETHOD=%d"), nJobCount, strPrJobList, nStartMethod);
		m_listGem300Log.AddString(strTemp);
	}
	
	//-------------------------------------------------------------------------------
	// 상황에 맞지않는 에러가 존재하면 아래처럼 에러만 추가하면 자동으로 거부처리됨
	// (참고)PRJOB존재여부및 JOBSTATE(PROCESSING)의 경우 드라이버에서 사전 체크하여 응답처리함

	//	CString strPrJob = (CString)bstrPrJobList;
	//
	//	m_gem.SetPrJobErrorCode(lMsgId, "", 1, "Cannot change now!!!");	// 에러메세지세팅

	//-----------------------------------------------------------
	m_gem.ReplyHostSetPrJob(lMsgId);	// 응답메세지(S16F26) 전송
	//-----------------------------------------------------------
}
void CEZGemPlusDLL_SampleDlg::OnEvent_HostSetControlJobCreate(long lMsgId)
{
	CString strTemp, strControlJob, strPrJobID;
	strTemp.Format(_T("S14F9, HOSE->EQ : CreateObjectRequest[CJOB],  MSGID=%d"), lMsgId);
	m_listGem300Log.AddString(strTemp);

	int nPrJobCount = 0, nAutoStart = 0;

	//--------------------------------------------------------------------------------------------
	// 호스트가 보낸 S14F9 내용을 읽어옴
	long nResult = m_gem.GetHostSetCtrlJob(lMsgId, &strControlJob, &nPrJobCount, &nAutoStart);
	//---------------------------------------------------------------------------------------------
	if (nResult < RESULT_OK) return;

	strTemp.Format(_T("-> CJOB ID = %s, PrJobCount=%d, AutoStart=%d"), strControlJob, nPrJobCount, nAutoStart);
	m_listGem300Log.AddString(strTemp);

	for (int i=0;i<nPrJobCount;i++)
	{ 
		//--------------------------------------------------------------------
		// ControlJob속에 지정된 PrJobID을 읽어옴
		m_gem.GetPrJobInCtrlJob(strControlJob, i, &strPrJobID);
		//--------------------------------------------------------------------
		strTemp.Format(_T("-> PrJobID[%d] = %s"), i + 1, strPrJobID);
		m_listGem300Log.AddString(strTemp);
	}

	CStringArray arrayCarrierInputSpec;
	m_gem.GetCtrlJobCarrierInputSpec(strControlJob, &arrayCarrierInputSpec);
	for (int i = 0; i < arrayCarrierInputSpec.GetCount(); i++)
	{
		m_listGem300Log.AddString(arrayCarrierInputSpec[i]);
	}

	int nMtrlOutMapCount = 0;
	m_gem.GetCtrlJobMtrlOutMapCount(strControlJob, &nMtrlOutMapCount);
	
	for (int i = 0; i < nMtrlOutMapCount; i++)
	{
		CString strSrcCarrier, strSrcSlotList;
		CString strDestCarrier, strDestSlotList;
		nResult = m_gem.GetCtrlJobMtrlOutInfo(strControlJob, i,
			&strSrcCarrier, &strSrcSlotList,
			&strDestCarrier, &strDestSlotList);

		if (nResult == RESULT_OK) // OK
		{
			m_listGem300Log.AddString(strSrcCarrier);
			m_listGem300Log.AddString(strSrcSlotList);
			m_listGem300Log.AddString(strDestCarrier);
			m_listGem300Log.AddString(strDestSlotList);
		}
	}

	// 에러 사항이 있으면 에러내용을 추가
	// m_gem.SetCtrlJobErrorCode(lMsgId, 1, "Invalid state !!!!!!");
	//----------------------------
	// 응답메세지 전송
	m_gem.ReplyCtrlJob(lMsgId);
	//----------------------------
	UpdateCtrlJobList();
}

void CEZGemPlusDLL_SampleDlg::OnEvent_PrJobCommand(long lMsgId)
{
	CString strPrJobID, strCommand;
	// EX) START, STOP, PAUSE, RESUME, ABORT, CANCEL
	//--------------------------------------------------------------------------
	// HOST에서 보내온 S16F5정보를 읽어옴
	//
	long nResult = m_gem.GetPrJobCommand(lMsgId, &strPrJobID, &strCommand);
	//
	//--------------------------------------------------------------------------
	if (nResult < RESULT_OK) return;

	CString strTemp;
	strTemp.Format(_T("S16F5, HOSE->EQ : PRJOBCOMMAND,  MSGID=%d"), lMsgId);
	m_listGem300Log.AddString(strTemp);
	strTemp.Format(_T("PRJOBID=%s,  COMMAND=%s"), strPrJobID, strCommand);
	m_listGem300Log.AddString(strTemp);

	//------------------------------------------------------------------------
	// Command명령에 대해 '거부'시 아래처럼 ERRCODE, ERRTEXT를 입력
	
	m_gem.SetPrJobErrorCode(lMsgId, strPrJobID, 1, _T("INVALID STATE"));
	
	//------------------------------------------------------------------------
	m_gem.ReplyPrJobCommand(lMsgId); // 응답 ( EQ->HOST S16F6 )
	//-------------------------------
}

//	S16F27	CTRLJOB COMMAND
//	SEMI E5 (U1) S16F27
//	1 : CJOB_CMD_START	= 1,
//	2 : CJOB_CMD_PAUSE	= 2,
//	3 : CJOB_CMD_RESUME = 3,
//	4 : CJOB_CMD_CANCEL = 4,
//	5 : CJOB_CMD_DESELECT = 5,
//	6 : CJOB_CMD_STOP	= 6,
//	7 : CJOB_CMD_ABORT	= 7,
//	8 : CJOB_CMD_CJHOQ	= 8,
void CEZGemPlusDLL_SampleDlg::OnEvent_CtrlJobCommand(long lMsgId)
{
	CString strCJobID;
	int nCommand;
	//--------------------------------------------------------------------------
	// HOST에서 보내온 S16F27정보를 읽어옴
	//
	long nResult = m_gem.GetCtrlJobCommand(lMsgId, &strCJobID, &nCommand);
	//
	//--------------------------------------------------------------------------
	if (nResult < RESULT_OK) return;

	CString strTemp;
	strTemp.Format(_T("S16F27, HOSE->EQ : CTRLJOBCOMMAND,  MSGID=%d"), lMsgId);
	m_listGem300Log.AddString(strTemp);
	strTemp.Format(_T("CTRLJOBID=%s,  COMMAND=%d"), strCJobID, nCommand);
	m_listGem300Log.AddString(strTemp);

	//------------------------------------------------------------------------
	// Command명령에 대해 '거부'시 아래처럼 ERRCODE, ERRTEXT를 입력
	//	m_gem.SetCtrlJobErrorCode(lMsgId, 1, "INVALID STATE");
	//------------------------------------------------------------------------

	m_gem.ReplyCtrlJobCommand(lMsgId); // 응답 ( EQ->HOST S16F28 )
	//-------------------------------
}

void CEZGemPlusDLL_SampleDlg::OnEvent_HostSetSubstrateCommand(long lMsgId)
{
	int nCommandMode = 0;
	CString strSubstID, strLocID;
	//-------------------------------------------------------------------------------------
	// 호스트가 내려준 명령(세부적으로 읽어오는 함수)
	int nResult = m_gem.GetSubstHostCommand(lMsgId, &nCommandMode, &strSubstID, &strLocID);

	// (참고사항) nCommand == 1 --> SubstrateCreated		(생성 : 드라이버 자동처리)
	// (참고사항) nCommand == 2 --> SubstrateDeleted		(삭제 : 드라이버 자동처리)
	// (참고사항) nCommand == 3 --> ProceedWithSubstrate	(장비=작업진행 !!!)
	// (참고사항) nCommand == 4 --> CancelSubstrate		(장비=작업취소 !!!)
	//-------------------------------------------------------------------------------------
	CString strTemp;
	int nAckCode = 0, ERRCODE=0, nRet;
	switch (nCommandMode)
	{
	case 1:
		break;
	case 2:
		break;
	case 3:	// S14F19 GenericServiceRequest ("ProceedWithSubstrate")
		strTemp.Format(_T("S14F19, H->E : <ProceedWithSubstrate>, MSGID=%d, SubstID=%s, LocID=%s"), lMsgId, strSubstID, strLocID);
		m_listGem300Log.AddString(strTemp);
		// 사용자 직접 응답 옵션(STS_SUBSTACTION_USERREPLY=1) 사용시 직접응답
		nAckCode = 1;	// NG
		ERRCODE = 11;	// ?? 
		nRet = m_gem.ReplySubstAction(lMsgId, nAckCode, ERRCODE, _T("Some Error Text..."));
		// nReturnCode(ACK)가 0(OK)이면 ERRCODE, ERRTEXT는 반영안됨
		// 옵션없이 실행시 실행되지 않음 (ret:INVALID_MODE)
		// ---------------------------------------------------------
		// PROCEED이므로  장비는 WAFER 작업 시작
		// ---------------------------------------------------------
		break;
	case 4:	// S14F19 GenericServiceRequest ("CancelSubstrate")
		strTemp.Format(_T("S14F19, H->E : <CancelSubstrate>, MSGID=%d, SubstID=%s, LocID=%s"), lMsgId, strSubstID, strLocID);
		m_listGem300Log.AddString(strTemp);
		// 사용자 직접 응답 옵션(STS_SUBSTACTION_USERREPLY=1) 사용시 직접응답
		nRet = m_gem.ReplySubstAction(lMsgId, nAckCode, ERRCODE, _T("Some Error Text..."));
		// nReturnCode(ACK)가 0(OK)이면 ERRCODE, ERRTEXT는 반영안됨
		// 옵션없이 실행시 실행되지 않음 (ret:INVALID_MODE)
		// ---------------------------------------------------------
		// CANCEL이므로  장비는 WAFER 작업 취소
		// ---------------------------------------------------------
		break;
	}
}

void CEZGemPlusDLL_SampleDlg::OnGem300Event(short nEventID, long lParam)
{
	CString strTemp;
	long lMsgId = lParam;
	int  nPort = 0, nState = 0, CAACK = 0, ERRCODE = 0;

	switch (nEventID)
	{
	case EVENT_GEMDLL_CMS_HOST_SET_PORTSERVICE_CHANGE:  OnEvent_HostSetLoadPortServiceMode(lMsgId); break;	// S3F25
	case EVENT_GEMDLL_CMS_HOST_SET_ACCESSMODE_CHANGE:	OnEvent_HostSetLoadPortAccessMode(lMsgId); 	break;	// S3F27
	case EVENT_GEMDLL_CMS_TRANSFER_STATE_CHANGE:
		strTemp.Format(_T("Transfer State Changed.  Port=%d, State=%d"), lParam / 1000, lParam % 1000);
		m_listGem300Log.AddString(strTemp);
		break;
	case EVENT_GEMDLL_CMS_RESERVATION_STATE_CHANGE:
		strTemp.Format(_T("Port-Carrier Reservation State Changed.  Port=%d, State=%d"), lParam / 1000, lParam % 1000);
		m_listGem300Log.AddString(strTemp);
		break;
	case EVENT_GEMDLL_CMS_CARRIERACCESS_STATE_CHANGE:
		strTemp.Format(_T("Carrier Access State Changed.  Port=%d, State=%d"), lParam / 1000, lParam % 1000);
		m_listGem300Log.AddString(strTemp);
		break;
	case EVENT_GEMDLL_CMS_ASSOCIATION_STATE_CHANGE:
		strTemp.Format(_T("Association State Changed.  Port=%d, State=%d"), lParam / 1000, lParam % 1000);
		m_listGem300Log.AddString(strTemp);
		break;
	case EVENT_GEMDLL_CMS_CARRIER_DELETED:  break;
	case EVENT_GEMDLL_CMS_CARRIERID_STATE_CHANGE:
		strTemp.Format(_T("Carrier ID State Changed.  Port=%d, State=%d"), lParam / 1000, lParam % 1000);
		m_listGem300Log.AddString(strTemp);
		break;
	case EVENT_GEMDLL_CMS_CARRIERID_VERIFY_OK:
		strTemp.Format(_T("Carrier ID Verification OK.  Port=%d, State=%d"), lParam / 1000, lParam % 1000);
		m_bCarrierVerifyOK = TRUE;
		m_listGem300Log.AddString(strTemp);
		break;
	case EVENT_GEMDLL_CMS_CARRIERID_VERIFY_FAILED:
		strTemp.Format(_T("Carrier ID Verification FAILED.  Port=%d, State=%d"), lParam / 1000, lParam % 1000);
		m_listGem300Log.AddString(strTemp);
		break;
	case EVENT_GEMDLL_CMS_SLOTMAP_STATE_CHANGE:
		strTemp.Format(_T("SlotMap State Changed.  Port=%d, State=%d"), lParam / 1000, lParam % 1000);
		m_listGem300Log.AddString(strTemp);
		break;
	case EVENT_GEMDLL_CMS_SLOTMAP_VERIFY_OK:
		strTemp.Format(_T("SlotMap Verification OK.  Port=%d, State=%d"), lParam / 1000, lParam % 1000);
		m_listGem300Log.AddString(strTemp);
		break;
	case EVENT_GEMDLL_CMS_SLOTMAP_VERIFY_FAILED:
		strTemp.Format(_T("SlotMap Verification FAILED.  Port=%d, State=%d"), lParam / 1000, lParam % 1000);
		m_listGem300Log.AddString(strTemp);
		break;
	case EVENT_GEMDLL_CMS_HOST_PROCEED_WITH_CARRIER:	OnEvent_ProceedWithCarrier(lMsgId); 	break;	// S3F17
	case EVENT_GEMDLL_CMS_HOST_CANCEL_CARRIER:			OnEvent_CancelCarrier(lMsgId, FALSE);	break;	// S3F17
	case EVENT_GEMDLL_CMS_HOST_CANCEL_CARRIER_AT_PORT:	OnEvent_CancelCarrier(lMsgId, TRUE);	break;	// S3F17
	case EVENT_GEMDLL_CMS_HOST_BIND:					OnEvent_Bind(lMsgId);					break;	// S3F17
	case EVENT_GEMDLL_CMS_HOST_CANCELBIND: 				OnEvent_CancelBind(lMsgId);				break;	// S3F17
	case EVENT_GEMDLL_CMS_HOST_RESERVEATPORT:			OnEvent_ReserveAtPort(lMsgId);			break;	// S3F17
	case EVENT_GEMDLL_CMS_HOST_CARRIER_RECREATE:		OnEvent_CarrierReCreate(lMsgId);		break;	// S3F17
	case EVENT_GEMDLL_CMS_HOST_CARRIER_OUT:				OnEvent_CarrierOut(lMsgId);				break;	// S3F17
	case EVENT_GEMDLL_CMS_HOST_CANCEL_CARRIER_OUT:		OnEvent_CancelCarrierOut(lMsgId);		break;	// S3F17
	case EVENT_GEMDLL_CMS_HOST_CARRIER_NOTIFICATION:
	case EVENT_GEMDLL_CMS_HOST_CANCEL_CARRIER_NOTIFICATION:
	case EVENT_GEMDLL_CMS_HOST_CARRIER_RELEASE:
		m_gem.ReplyCarrierAction(lMsgId, 0);	break;

	case EVENT_GEMDLL_PJM_HOST_SET_PRJOB_CREATE:		OnEvent_HostSetPrJobCreate(lMsgId);		break;	// S16F11, S16F15
	case EVENT_GEMDLL_PJM_HOST_SET_PRJOB_RECIPE_VAL:	OnEvent_HostSetPrJobParamValue(lMsgId);	break;	// S16F23
	case EVENT_GEMDLL_PJM_HOST_SET_PRJOB_STARTMETHOD:	OnEvent_HostSetPrJobStartMethod(lMsgId);break;	// S16F25
	case EVENT_GEMDLL_PJM_HOST_SET_PRJOB_DEQUE:			OnEvent_HostSetPrJobDeque();			break;	// S16F17	
	case EVENT_GEMDLL_PJM_HOST_SET_PRJOB_COMMAND:		OnEvent_PrJobCommand(lMsgId);			break;	// S16F5
	case EVENT_GEMDLL_CJM_HOST_SET_CONTROLJOB_CREATE:	OnEvent_HostSetControlJobCreate(lMsgId);break;	// S14F9
	case EVENT_GEMDLL_CJM_HOST_SET_CTRLJOB_COMMAND:		OnEvent_CtrlJobCommand(lMsgId);			break;	// S16F27
	case EVENT_GEMDLL_CJM_HOST_SET_CONTROLJOB_DELETE:	// S14F11
		m_gem.GetCtrlJobDeleted(&strTemp);
		strTemp.Format(_T("Control Job(%s) Deleted.  CJobCount=%d"), strTemp, m_gem.GetCtrlJobCount());
		m_listGem300Log.AddString(strTemp);
		UpdateCtrlJobList();
		break;
	case EVENT_GEMDLL_STS_HOST_SET_SUBST_CREATE	:		// S14F9
	case EVENT_GEMDLL_STS_HOST_SET_SUBST_DELETE :		// S14F11
	case EVENT_GEMDLL_STS_HOST_SET_PROCEED_SUBST:		// S14F19
	case EVENT_GEMDLL_STS_HOST_SET_CANCEL_SUBST :		// S14F19
		OnEvent_HostSetSubstrateCommand(lMsgId); // 생성,삭제,진행,취소
		break;
	default: strTemp.Format(_T("GEM300 EVENT=%d, PARAM=%d"), nEventID, lParam);
		m_listGem300Log.AddString(strTemp);
	}
}

void CEZGemPlusDLL_SampleDlg::OnBnClickedButtonCarrieridRead()
{
	// 장비가 CARRIER ID를 읽은경우
	UpdateData(TRUE);
	
	m_bCarrierVerifyOK = FALSE;

	int nPort = 0;
	if (m_radioLoadPort1.GetCheck()) nPort = 1;
	if (m_radioLoadPort2.GetCheck()) nPort = 2;

	if (m_strCarrierID == "")	
	{
		// 에러 : CarrierID 인식실패인경우 <<<< 이 상황은 장비로부터 받음
		//-------------------------------------------------------------------------------------
		//
		m_gem.SetCarrierIDRead(nPort, _T(""), CARRIERIDREAD_FAIL);	// CARRIERIDREAD_FAIL == 1
		//
		//-------------------------------------------------------------------------------------
		return;
	}

	// Carrier ID를 정상적으로 읽음
	// GEM DRIVER에게 CARRIER ID를 넘겨줌
	//------------------------------------------------------------------------------------------
	//
	m_gem.SetCarrierIDRead(nPort, m_strCarrierID, CARRIERIDREAD_OK);	// CARRIERIDREAD_OK == 0
	//
	//------------------------------------------------------------------------------------------


	// *** 참고 ***
	// 만약 Online Local Mode이거나 장비쪽에서 Verification하는 경우라면
	// --> 장비에서 직접 읽어들인 CarrierID  결과를 GEM DRIVER에게 넘김
	//
	//	(1) m_gem.SetCarrierIDStatus(nPort, m_strCarrierID, CARRIERIDSTATE_VERIFYOK);	// OK = 일치
	//	(2) m_gem.SetCarrierIDStatus(nPort, m_strCarrierID, CARRIERIDSTATE_VERIFYFAIL);	// NG (FAIL) = 불일치
	//
}


void CEZGemPlusDLL_SampleDlg::OnBnClickedCheckAccessmode()
{
	UpdateData(TRUE);
	
	int nPort = 0;
	if (m_radioLoadPort1.GetCheck()) nPort = 1;
	if (m_radioLoadPort2.GetCheck()) nPort = 2;

	//-------------------------------------------------------------------------------------------------
	//
	int nMode = ((CButton *)GetDlgItem(IDC_CHECK_ACCESSMODE))->GetCheck();
	m_gem.SetLoadPortAccessMode(nPort, nMode);	// 0=Manual, 1=Auto
	//
	//-------------------------------------------------------------------------------------------------
}


void CEZGemPlusDLL_SampleDlg::OnBnClickedButtonDocked()
{
	UpdateData(TRUE);

	int nPort = 0;
	if (m_radioLoadPort1.GetCheck()) nPort = 1;
	if (m_radioLoadPort2.GetCheck()) nPort = 2;

	//-----------------------------------------------------
	//
	m_gem.SetDockState(nPort, 1);	// 1 = CARRIER DOCKED
	//
	//-----------------------------------------------------
}


void CEZGemPlusDLL_SampleDlg::OnBnClickedButtonDooropen()
{
	UpdateData(TRUE);

	int nPort = 0;
	if (m_radioLoadPort1.GetCheck()) nPort = 1;
	if (m_radioLoadPort2.GetCheck()) nPort = 2;

	//-------------------------------------------------------
	//
	m_gem.SetDoorState(nPort, 1);	// 1 = CARRIER DOOR OPEN
	//
	//------------------------------------------------------
}


void CEZGemPlusDLL_SampleDlg::OnBnClickedButtonClosed()
{
	UpdateData(TRUE);

	int nPort = 0;
	if (m_radioLoadPort1.GetCheck()) nPort = 1;
	if (m_radioLoadPort2.GetCheck()) nPort = 2;

	//----------------------------------------------------------
	//
	m_gem.SetDoorState(nPort, 0);	// 0 = CARRIER DOOR CLOSED
	//
	//----------------------------------------------------------
}


void CEZGemPlusDLL_SampleDlg::OnBnClickedButtonCarrieridSlotmapread()
{
	UpdateData(TRUE);

	int nPort = 0;
	if (m_radioLoadPort1.GetCheck()) nPort = 1;
	if (m_radioLoadPort2.GetCheck()) nPort = 2;

	if (m_strSlotMap == "")	
	{
		// SlotMap인식 실패 <---- 장비로부터 이 에러상황을 접수함
		//------------------------------------------------------------
		//
		m_gem.SetSlotMapRead(nPort, m_strCarrierID, m_strSlotMap, 1);	// 0=OK,  1=READING FAIL
		//
		//------------------------------------------------------------
		return;
	}
	
	// 성공적으로 SlotMap을 읽으면 아래 함수 호출
	//--------------------------------------------------------------------------
	//	
	m_gem.SetSlotMapRead(nPort, m_strCarrierID, m_strSlotMap, 0);	// 0=OK
	//
	//--------------------------------------------------------------------------
	// -> GEM Driver는 CEID: WaitForHost를 보고함 (Online Remote인 경우)


	// *** 참고 ***
	// 만약 Online Local Mode이거나 장비쪽에서 Verification하는 경우라면
	// 읽어들인 SlotMap Verification 결과를 GEM DRIVER에게 넘김
	//
	//	(1) m_gem.SetSlotMapStatus(nPort, m_strCarrierID, SLOTMAPSTATE_VERIFYOK);	// OK = 일치
	//	(2) m_gem.SetSlotMapStatus(nPort, m_strCarrierID, SLOTMAPSTATE_VERIFYFAIL);	// NG (FAIL) = 불일치
}

void CEZGemPlusDLL_SampleDlg::OnBnClickedButtonUndocked()
{
	UpdateData(TRUE);

	int nPort = 0;
	if (m_radioLoadPort1.GetCheck()) nPort = 1;
	if (m_radioLoadPort2.GetCheck()) nPort = 2;
	//------------------------------------------------
	//
	m_gem.SetDockState(nPort, 0);	// 0 = UNDOCKED
	//
	//------------------------------------------------
}


void CEZGemPlusDLL_SampleDlg::OnBnClickedButtonClamped()
{
	UpdateData(TRUE);

	int nPort = 0;
	if (m_radioLoadPort1.GetCheck()) nPort = 1;
	if (m_radioLoadPort2.GetCheck()) nPort = 2;
	//-------------------------------------------------
	//
	m_gem.SetClampState(nPort, 1);	// 1 = CLAMPED
	//
	//-------------------------------------------------
}


void CEZGemPlusDLL_SampleDlg::OnBnClickedButtonUnclamped()
{
	UpdateData(TRUE);

	int nPort = 0;
	if (m_radioLoadPort1.GetCheck()) nPort = 1;
	if (m_radioLoadPort2.GetCheck()) nPort = 2;

	//--------------------------------------------------
	//
	m_gem.SetClampState(nPort, 0);	// 0 = UNCLMAPED
	//
	//--------------------------------------------------
}


void CEZGemPlusDLL_SampleDlg::OnBnClickedButtonTransferblocked()
{
	UpdateData(TRUE);
	int nPort = 0;
	if (m_radioLoadPort1.GetCheck()) nPort = 1;
	if (m_radioLoadPort2.GetCheck()) nPort = 2;

	//--------------------------------------------------------------
	//
	m_gem.SetTransferState(nPort, TRANSFERSTATE_TRANSFERBLOCKED);
	//
	//---------------------------------------------------------------
}


void CEZGemPlusDLL_SampleDlg::OnBnClickedButtonCarrierok()
{
	// ONLINE LOCAL 혹은 EQ측 VERIFY-> OK

	UpdateData(TRUE);
	int nPort = 0;
	if (m_radioLoadPort1.GetCheck()) nPort = 1;
	if (m_radioLoadPort2.GetCheck()) nPort = 2;

	//-----------------------------------------------------------------------------
	//
	m_gem.SetCarrierIDStatus(nPort, m_strCarrierID, CARRIERIDSTATE_VERIFYOK);
	//
	//-----------------------------------------------------------------------------
}


void CEZGemPlusDLL_SampleDlg::OnBnClickedButtonCarrierng()
{
	// ONLINE LOCAL 혹은 EQ측 VERIFY-> NG (FAIL)

	UpdateData(TRUE);
	int nPort = 0;
	if (m_radioLoadPort1.GetCheck()) nPort = 1;
	if (m_radioLoadPort2.GetCheck()) nPort = 2;

	//-----------------------------------------------------------------------------
	//
	m_gem.SetCarrierIDStatus(nPort, m_strCarrierID, CARRIERIDSTATE_VERIFYFAIL);
	//
	//-----------------------------------------------------------------------------
}


void CEZGemPlusDLL_SampleDlg::OnBnClickedButtonSlotmapok()
{
	// ONLINE LOCAL 혹은 EQ측 VERIFY-> OK

	UpdateData(TRUE);
	int nPort = 0;
	if (m_radioLoadPort1.GetCheck()) nPort = 1;
	if (m_radioLoadPort2.GetCheck()) nPort = 2;

	//-----------------------------------------------------------------------------
	//
	m_gem.SetSlotMapStatus(nPort, m_strCarrierID, SLOTMAPSTATE_VERIFYOK);
	//
	//-----------------------------------------------------------------------------
}


void CEZGemPlusDLL_SampleDlg::OnBnClickedButtonSlotmapng()
{
	// ONLINE LOCAL 혹은 EQ측 VERIFY -> NG (FAIL)

	UpdateData(TRUE);
	int nPort = 0;
	if (m_radioLoadPort1.GetCheck()) nPort = 1;
	if (m_radioLoadPort2.GetCheck()) nPort = 2;

	//-----------------------------------------------------------------------------
	//
	m_gem.SetSlotMapStatus(nPort, m_strCarrierID, SLOTMAPSTATE_VERIFYFAIL);
	//
	//-----------------------------------------------------------------------------
}

void CEZGemPlusDLL_SampleDlg::UpdatePrJobList()
{
	m_listPrJob.ResetContent();
	m_comboCarrier.ResetContent();

	//-------------------------------------------
	// PROCESS JOB 개수를 읽어오는 함수
	//
	int nPrJobCount = m_gem.GetPrJobCount();
	//
	//--------------------------------------------

	CString strPrJobID, strPPID=0;
	int nCarrierCount=0, nAutoStart=0, nParams=0;

	for (int i = 0; i < nPrJobCount; i++)
	{
		//---------------------------------------------------------------------------------------
		// 등록된 PRJOB 읽어오는 함수 (Key = Index (MSGID->Index))
		m_gem.GetPrJob(i, &strPrJobID, &strPPID, &nCarrierCount, &nAutoStart, &nParams);
		//---------------------------------------------------------------------------------------
		m_listPrJob.AddString(strPrJobID);
	}
}
void CEZGemPlusDLL_SampleDlg::UpdateCtrlJobList()
{
	m_listCtrlJob.ResetContent();
	m_listPrJobInCtrlJob.ResetContent();

	//-------------------------------------------
	// ControlJob 개수를 읽어오는 함수
	//
	int nCtrlJobCount = m_gem.GetCtrlJobCount();
	//
	//--------------------------------------------

	CString strCtrlJobID;
	int nPrJobCount=0, nAutoStart=0;

	for (int i = 0; i < nCtrlJobCount; i++)
	{
		//---------------------------------------------------------------------
		// 등록된 CONTROL JOB전체를 읽어오는 함수 (Key = Index(MSGID->Index))
		m_gem.GetCtrlJob(i, &strCtrlJobID, &nPrJobCount, &nAutoStart);
		//---------------------------------------------------------------------
		m_listCtrlJob.AddString(strCtrlJobID);
	}
}

void CEZGemPlusDLL_SampleDlg::OnBnClickedButtonUpdateprjob()
{
	UpdatePrJobList();
}


void CEZGemPlusDLL_SampleDlg::OnLbnSelchangeListPrJob()
{
	int nPos = m_listPrJob.GetCurSel();
	if (nPos < LB_ERR) return;

	CString strPrJobID, strTemp, strPPID, strCarrierID, strSlotList;
	m_listPrJob.GetText(nPos, strPrJobID);

	int nCarriers = 0, nAutoStart = 0, nParams = 0;

	//--------------------------------------------------------------------------------------
	// PRJOB정보를 읽어오는 함수 (Key = PRJOBID)
	if (m_gem.GetPrJobInfo(strPrJobID, &strPPID, &nCarriers, &nAutoStart, &nParams) < RESULT_OK)
	{
		AfxMessageBox(_T("Faild to read prjob information !!!"));
		return;
	}

	m_strPrJobCarrierCount.Format(_T("%d"), nCarriers);
	GetDlgItem(IDC_EDIT_PRJOBCARRIERS)->SetWindowText(m_strPrJobCarrierCount);

	GetDlgItem(IDC_EDIT_PRJOBPPID)->SetWindowText(strPPID);

	m_strPrJobParams.Format(_T("%d"), nParams);
	GetDlgItem(IDC_EDIT_PRJOBPARAMS)->SetWindowText(m_strPrJobParams);

	if (nAutoStart == 1)
		GetDlgItem(IDC_EDIT_PRJOBAUTOSTART)->SetWindowText(_T("TRUE"));
	else 
		GetDlgItem(IDC_EDIT_PRJOBAUTOSTART)->SetWindowText(_T("FALSE"));

	m_comboCarrier.ResetContent();
	for (int i = 0; i < nCarriers; i++)
	{
		//---------------------------------------------------------------------
		// PRJOB에 등록된 Carrier정보를 읽어옴 (Key = PRJOBID, Index)
		m_gem.GetPrJobCarrier(strPrJobID, i, &strCarrierID, &strSlotList);
		//---------------------------------------------------------------------

		strTemp.Format(_T("%s {Slot=%s}"), strCarrierID, strSlotList);
		m_comboCarrier.AddString(strTemp);
	}
	if (nCarriers > 0) m_comboCarrier.SetCurSel(0);

	int nPrJobState;
	//----------------------------------------------------------
	// 해당 PRJOB STATE를 조회하는 함수 (Key = PRJOBID)

	if (m_gem.GetPrJobState(strPrJobID, &nPrJobState) == RESULT_OK)
	{
		m_strPrJobState.Format(_T("%d"), nPrJobState);
		GetDlgItem(IDC_EDIT_PRJOBSTATE)->SetWindowText(m_strPrJobState);
	}
}

void CEZGemPlusDLL_SampleDlg::OnBnClickedButtonReadPrjobParams()
{
	int nPos = m_listPrJob.GetCurSel();
	if (nPos < LB_ERR)
	{
		AfxMessageBox(_T("PRJOB not selected !!!"));
		return;
	}
	CString strPrJobID, strTemp, strPPID, strParamName, strParamVal;
	m_listPrJob.GetText(nPos, strPrJobID);

	int nCarriers = 0, nAutoStart = 0, nParams = 0, nRecipeMethod = 0;

	//---------------------------------------------------------------------------------------
	// PRJOB 정보를 읽어옴 (Key=PRJOBID)
	if (m_gem.GetPrJobInfo(strPrJobID, &strPPID, &nCarriers, &nAutoStart, &nParams) < RESULT_OK)
	{
		AfxMessageBox(_T("Faild to read prjob information !!!"));
		return;
	}

	//-----------------------------------------
	// 해당 PRJOB의 Recipe parameter값을 읽음
	for (int i = 0; i < nParams; i++)
	{
		//------------------------------------------------------------------------------
		// Recipe parameter 값을 읽는 함수 (Key = PRJOBID, Index)
		m_gem.GetPrJobParam(strPrJobID, i, &strParamName, &strParamVal);
		//------------------------------------------------------------------------------
		strTemp.Format(_T("PRJOB=%s, RecipeParameter[%d] : Name=%s, Value=%s"), strPrJobID, i + 1, strParamName, strParamVal);
		m_listGem300Log.AddString(strTemp);
	}

	m_gem.GetPrJobRecipeMethod(strPrJobID, &nRecipeMethod);
	strTemp.Format(_T("PRJOB=%s, RecipeMethod=%d"), strPrJobID, nRecipeMethod);
	m_listGem300Log.AddString(strTemp);
}

void CEZGemPlusDLL_SampleDlg::OnBnClickedButtonSetPrjobstate()
{
	int nPos = m_listPrJob.GetCurSel();
	if (nPos < LB_ERR)
	{
		AfxMessageBox(_T("PRJOB not selected !!!"));
		GetDlgItem(IDC_LIST_PRJOB)->SetFocus();
		return;
	}
	CString strPrJobID;
	m_listPrJob.GetText(nPos, strPrJobID);

	UpdateData(TRUE);
	if (m_strPrJobState == "")
	{
		AfxMessageBox(_T("PrJob State is empty !!!"));
		GetDlgItem(IDC_EDIT_PRJOBSTATE)->SetFocus();
		return;
	}

	//----------------------------------------------------------
	// PrJobState 변경 !!!
	//
	m_gem.SetPrJobState(strPrJobID, atoi((const char *)m_strPrJobState.GetBuffer()));
	//
	//----------------------------------------------------------
}


void CEZGemPlusDLL_SampleDlg::OnBnClickedButtonUpdatecjob()
{
	UpdateCtrlJobList();
}


void CEZGemPlusDLL_SampleDlg::OnLbnSelchangeListCtrljob()
{
	int nState = 0, nPos = m_listCtrlJob.GetCurSel();
	if (nPos == LB_ERR) return;

	CString strCJobID = _T(""), strTemp, strPrJobID;
	m_listCtrlJob.GetText(nPos, strCJobID);

	int nPrJobCount = 0, nAutoStart = 0;
	//---------------------------------------------------------
	// CONTROL JOB 정보를 읽어오는 함수 (Key = CtrlJobID)
	//
	long nResult = m_gem.GetCtrlJobInfo(strCJobID, &nPrJobCount, &nAutoStart);
	//
	//---------------------------------------------------------
	if (nResult < RESULT_OK)
	{
		AfxMessageBox(_T("Failed"));
		return;
	}

	if (nAutoStart == 1)
		GetDlgItem(IDC_EDIT_CTRLJOBAUTOSTART)->SetWindowText(_T("True"));
	else
		GetDlgItem(IDC_EDIT_CTRLJOBAUTOSTART)->SetWindowText(_T("False"));

	//----------------------------------------
	// 현재의 ControlJob State를 조회
	//
	m_gem.GetCtrlJobState(strCJobID, &nState);
	//
	//----------------------------------------

	strTemp.Format(_T("%d"), nState);
	GetDlgItem(IDC_EDIT_CJOBSTATE)->SetWindowText(strTemp);

	m_listPrJobInCtrlJob.ResetContent();

	for (int i = 0; i < nPrJobCount; i++)
	{
		//-----------------------------------------------------------------------------------
		// CONTROL JOB에 연결된 PROCESS JOB 리스트를 읽어오는 함수 (Key = CtrlJobID, Index)
		m_gem.GetPrJobInCtrlJob(strCJobID, i, &strPrJobID);
		//------------------------------------------------------------------------------------

		m_listPrJobInCtrlJob.AddString(strPrJobID);
	}

	CStringArray arrayCarrierInputSpec;
	m_gem.GetCtrlJobCarrierInputSpec(strCJobID, &arrayCarrierInputSpec);
	for (int i = 0; i < arrayCarrierInputSpec.GetCount(); i++)
	{
		strTemp.Format(_T("CarrierInputSpec[%d]=%s"), i+1, arrayCarrierInputSpec[i]);
		m_listGem300Log.AddString(strTemp);
	}

	int nMtrlOutMapCount = 0;
	m_gem.GetCtrlJobMtrlOutMapCount(strCJobID, &nMtrlOutMapCount);
	for (int i = 0; i < nMtrlOutMapCount; i++)
	{
		CString strSrcCarrier, strSrcSlotList;
		CString strDestCarrier, strDestSlotList;
		
		long nResult = m_gem.GetCtrlJobMtrlOutInfo(strCJobID, i, 
			&strSrcCarrier, &strSrcSlotList, 
			&strDestCarrier, &strDestSlotList);

		if (nResult == RESULT_OK)	// OK
		{
			m_listGem300Log.AddString(strSrcCarrier);
			m_listGem300Log.AddString(strSrcSlotList);

			m_listGem300Log.AddString(strDestCarrier);
			m_listGem300Log.AddString(strDestSlotList);
		}
	}
}


void CEZGemPlusDLL_SampleDlg::OnLbnSelchangeListPrjobinctrljob()
{
	int nPos = m_listPrJobInCtrlJob.GetCurSel();
	if (nPos == LB_ERR) return;

	CString strPrJobID = _T("");
	m_listPrJobInCtrlJob.GetText(nPos, strPrJobID);

	nPos = m_listPrJob.FindString(-1, strPrJobID);
	if (nPos == LB_ERR) return;

	m_listPrJob.SetCurSel(nPos);
	OnLbnSelchangeListPrJob();
}


void CEZGemPlusDLL_SampleDlg::OnBnClickedButtonDelPrjob()
{
	int nPos = m_listPrJob.GetCurSel();
	if (nPos == LB_ERR)
	{
		AfxMessageBox(_T("PRJOB not selected !!!"));
		GetDlgItem(IDC_LIST_PRJOB)->SetFocus();
		return;
	}
	CString strPrJobID= _T("");
	m_listPrJob.GetText(nPos, strPrJobID);
	//------------------------------
	//  PrJob 삭제함수
	m_gem.DeletePrJob(strPrJobID);
	//
	//------------------------------
	UpdatePrJobList();
}


void CEZGemPlusDLL_SampleDlg::OnBnClickedButtonDelAllprjob()
{
	if (MessageBox(_T("Are you sure ?"), _T("DeleteAllPrJob"), MB_YESNO) == IDNO) return;

	//----------------------
	// GEM 드라이버가 갖고 있는
	// 모든 PRJOB을 삭제
	//
	m_gem.DeleteAllPrJob();
	//
	//----------------------

	UpdatePrJobList();
}


void CEZGemPlusDLL_SampleDlg::OnBnClickedButtonDelCtrljob()
{
	int nPos = m_listCtrlJob.GetCurSel();
	if (nPos == LB_ERR)
	{
		AfxMessageBox(_T("CTRLJOB not selected !!!"));
		GetDlgItem(IDC_LIST_CTRLJOB)->SetFocus();
		return;
	}
	CString strCtrlJobID = _T("");
	m_listCtrlJob.GetText(nPos, strCtrlJobID);
	//-----------------------------------------
	//
	m_gem.DeleteCtrlJob(strCtrlJobID);
	//
	//-----------------------------------------
	UpdateCtrlJobList();
}


void CEZGemPlusDLL_SampleDlg::OnBnClickedButtonDelAllctrljob()
{
	if (MessageBox(_T("Are you sure ?"), _T("DeleteAllCtrlJob"), MB_YESNO) == IDNO) return;

	//-------------------------
	//
	m_gem.DeleteAllCtrlJob();
	//
	//-------------------------

	UpdateCtrlJobList();
}


void CEZGemPlusDLL_SampleDlg::OnBnClickedButtonSetCjobstate()
{
	int nPos = m_listCtrlJob.GetCurSel();
	if (nPos < LB_ERR)
	{
		AfxMessageBox(_T("CtrlJOB not selected !!!"));
		GetDlgItem(IDC_LIST_CTRLJOB)->SetFocus();
		return;
	}
	CString strCtrlJobID;
	m_listCtrlJob.GetText(nPos, strCtrlJobID);

	CString strState = _T("");
	GetDlgItem(IDC_EDIT_CJOBSTATE)->GetWindowText(strState);
	if (strState == "")
	{
		AfxMessageBox(_T("CtrlJob State is empty !!!"));
		GetDlgItem(IDC_EDIT_CJOBSTATE)->SetFocus();
		return;
	}

	//----------------------------------------------------------
	// CtrlJobState 변경 !!!
	//
	m_gem.SetCtrlJobState(strCtrlJobID, atoi((const char *)(LPSTR)strState.GetBuffer()));
	//
	//----------------------------------------------------------
}


void CEZGemPlusDLL_SampleDlg::OnBnClickedButtonCreateprjob()
{
	long nRet = m_gem.CreatePrJob(_T("PRJOBID_NEW"), 0, _T("CARRIER_001"), _T("1111100000111110000011111"), _T("PPID"));
	if (nRet == RESULT_OK)	//성공
	{
		UpdatePrJobList();
	}
	else
	{
		if (nRet == ERROR_GEM300_ALREADY_EXIST)	// = -906 
			AfxMessageBox(_T("PRJOB ID가 이미 존재합니다"));
		else if (nRet == ERROR_GEM300_INVALID_CARRIER)	// = -907
			AfxMessageBox(_T("Carrier정보가 잘못되었습니다"));
		else if (nRet == ERROR_GEM300_INVALID_SLOT)	// = -908
			AfxMessageBox(_T("Slot정보가 잘못되었습니다"));
		else if (nRet == ERROR_GEM300_INVALID_RECIPE)	// = -909
			AfxMessageBox(_T("PPID가 잘못되었습니다"));
	}
}


void CEZGemPlusDLL_SampleDlg::OnBnClickedButtonCreatectrljob()
{
	long nRet = m_gem.CreateCtrlJob(_T("CJ_NEW"), _T("PJ001, PJ002"), 0);
	if (nRet == RESULT_OK)	//성공
	{
		m_gem.AddCtrlJobCarrierInputSpec(_T("CJ_NEW"), _T("CARRIER_001"));
		m_gem.AddCtrlJobMtrlOutSpec(_T("CJ_NEW"), _T("CARRIER_001"), _T("1,2,3"), _T("CARRIER_001"), _T("11,12,13"));
		UpdateCtrlJobList();
	}
	else
	{
		if (nRet == ERROR_GEM300_ALREADY_EXIST)	// = -906 
			AfxMessageBox(_T("CtrlJobID가 이미 존재합니다"));
		else if (nRet == ERROR_GEM300_INVALID_PRJOB)	// = -907
			AfxMessageBox(_T("PrJob정보가 잘못되었습니다"));
	}
}

void CEZGemPlusDLL_SampleDlg::OnTimer(UINT_PTR nIDEvent)
{
	m_gridCarrierInfo.DeleteAllItems();

	for (int i = 0; i < MAX_LOADPORT; i++)
	{
		CString strLocID, strCarrierID;
		int nAccessMode = 0, nTransferState = 0, nReservationState = 0, nAssociationState = 0;
		if (m_gem.GetLoadPortInfo(i + 1, &strLocID, &strCarrierID, &nAccessMode, &nTransferState, &nReservationState, &nAssociationState) == 0)
		{
			CString strTemp;
			m_gridLoadPort.SetItemText(i, 1, strLocID);
			m_gridLoadPort.SetItemText(i, 2, strCarrierID);
			m_gridLoadPort.SetItemText(i, 3, (nAccessMode == 1) ? _T("Auto") : _T("Manual"));
			m_gridLoadPort.SetItemText(i, 4, (CString)m_TransferState[nTransferState].c_str());
			m_gridLoadPort.SetItemText(i, 5, (CString)m_ReservationState[nReservationState].c_str());
			m_gridLoadPort.SetItemText(i, 6, (CString)m_AssocationState[nAssociationState].c_str());
		}
	}

	for (int i = 0; i < m_gem.GetCarrierCount(); i++)
	{
		CString strCarrierID, strLoc, strSlotMap, strUsage;
		if (m_gem.GetCarrierList(i, &strCarrierID, &strLoc) == 0)
		{
			m_gridCarrierInfo.InsertItem(i, _T(""));
		}
		int nCarrierIDStatus = 0, nSlotMapStatus = 0, nAccessStatus = 0;
		if (m_gem.GetCarrierInfo(strCarrierID, &strLoc, &nCarrierIDStatus, &nSlotMapStatus, &nAccessStatus, &strSlotMap, &strUsage) == 0)
		{
			CString strTemp;
			if (strSlotMap == "") strSlotMap = "0000000000000000000000000";
			m_gridCarrierInfo.SetItemText(i, 0, strCarrierID);
			m_gridCarrierInfo.SetItemText(i, 1, strLoc);
			m_gridCarrierInfo.SetItemText(i, 2, (CString)m_IDState[nCarrierIDStatus].c_str());
			m_gridCarrierInfo.SetItemText(i, 3, (CString)m_IDState[nSlotMapStatus].c_str());
			m_gridCarrierInfo.SetItemText(i, 4, (CString)m_AccessingState[nAccessStatus].c_str());
			m_gridCarrierInfo.SetItemText(i, 5, strSlotMap);
			m_gridCarrierInfo.SetItemText(i, 6, strUsage);
		}
	}

	//------------- Subst Location List Update ------------------
	m_listSubstLoc.ResetContent();
	CString strList = _T("");

	long nSubstLocCount = m_gem.GetSubstLocCount();	// 등록된 LOCATION 수량을 읽어오는 함수
	for (int i = 0; i < nSubstLocCount; i++)
	{
		CString strLocID, strSubstID;
		int nLocState = -1;

		//------------------------------------------------------------------------------
		// 각 LOCATION별로 현재 정보를 읽어오는 함수 (LOC이름, SUBSTID, LOCSTATE)

		long nResult = m_gem.GetSubstLocation(i, &strLocID, &strSubstID, &nLocState);

		//------------------------------------------------------------------------------
		CString strLocState = (nLocState == 0) ? _T("UNOCCUPIED") : _T("OCCUPIED");
		if (nResult == 0)
		{
			strList.Format(_T(" %-12s  %-12s  %-12s"), strLocID, strSubstID, strLocState);
			m_listSubstLoc.AddString(strList);
		}
	}
	//------------- Substrate List Update ------------------
	// EZGEM300.INI에 등록된 값 기준으로...
	char *sTranState[] = { "Atsource", "AtWork", "AtDest" };
	char *sProcState[] = { "NeedProcess", "InProcess", "Processed", "Aborted", "Stopped", "Rejected", "Lost", "Skipped" };
	char *sReadState[] = { "NotConfirmed", "WaitingForHost", "Confirmed", "ConfirmFailed" };

	m_listSubstrate.ResetContent();
	strList = "";

	//---------------------------------------------
	// 현재 생성되어 있는 Substrate개수를 읽어오는 함수

	long nSubstCount = m_gem.GetSubstrateCount();

	//---------------------------------------------

	for (int i = 0; i < nSubstCount; i++)
	{
		//---------------------------------------------------------------
		// 생성된 SUBSTRATE 정보를 읽어옴 (SUBSTID, LOCID)
		CString strSubstID, strLocID;
		long nResult = m_gem.GetSubstrate(i, &strSubstID, &strLocID);

		//----------------------------------------------------------------
		if (nResult == 0)
		{
			int nTranState = -1, nProcState = -1, nReadState = -1;
			CString strLoc = strLocID;
			CString strProcState = _T(""), strTranState = _T(""), strReadState = _T("");
			if (strLoc == "") strLoc = "( Undefined )";

			//------------------------------------------------------------------------------------
			// SUBSTRATE의 각 상태값 (Transportation / Processing / ID Reading)을 조회하는 함수
			m_gem.GetSubstrateState(strSubstID, &nTranState, &nProcState, &nReadState);
			//
			//------------------------------------------------------------------------------------
			if (nTranState == -1) strTranState = "NoState";
			else strTranState = sTranState[nTranState];
			if (nProcState == -1) strProcState = "NoState";
			else strProcState = sProcState[nProcState];
			if (nReadState == -1) strReadState = "NoState";
			else strReadState = sReadState[nReadState];

			strList.Format(_T("%-15s %-20s %-12s %-12s %-12s"), strSubstID, strLoc, strTranState, strProcState, strReadState);
			m_listSubstrate.AddString(strList);

			if (m_comboSubstrate.FindString(-1, strSubstID) == LB_ERR) m_comboSubstrate.AddString(strSubstID);
		}
	}
	//------------- Subst Batch Location List Update ------------------
	m_listBatchLocation.ResetContent();
	long nBatchLocCount = m_gem.GetSubstBatchLocCount();	// 등록된 BATCH LOCATION 수량을 읽어오는 함수
	for (int i = 0; i < nBatchLocCount; i++)
	{
		CString strBatchLocID = _T("");
		CStringArray saSubstList;
		int nCount = 0;
		//-------------------------------------------------------------------------------
		long nResult = m_gem.GetSubstBatchLoc(i, &strBatchLocID, &nCount, &saSubstList);
		//-------------------------------------------------------------------------------
		if (nResult < RESULT_OK) continue;

		strList.Format(_T("%-15s  %d"), strBatchLocID, nCount);
		m_listBatchLocation.AddString(strList);

		if (i == 0) m_listBatchLoc_1.ResetContent();
		if (i == 1) m_listBatchLoc_2.ResetContent();

		for (int j = 0; j < nCount; j++)
		{
			if (i == 0)	m_listBatchLoc_1.AddString(saSubstList.GetAt(j));
			if (i == 1) m_listBatchLoc_2.AddString(saSubstList.GetAt(j));
		}
	}
	CDialogEx::OnTimer(nIDEvent);
}


void CEZGemPlusDLL_SampleDlg::OnButtonCreateSubst()
{
	CString strSubstID = _T("");
	if (m_comboSubstrate.GetCurSel() == LB_ERR)
	{
		m_comboSubstrate.SetFocus();
		AfxMessageBox(_T("[CREATE SUBSTRATE] Select SubstrateID (sample)!!!"));
		return;
	}
	m_comboSubstrate.GetLBText(m_comboSubstrate.GetCurSel(), strSubstID);

	//------------------------------------------------------------------------------
	// 작업할 SUBSTRATE 객체를 생성하는 함수  ( CMS HOST 에서 내려준 CONTENTMAP정보 반영 )

	long nResult = m_gem.CreateSubstrate(strSubstID);
	//------------------------------------------------------------------------------

	CString strTemp;
	strTemp.Format(_T("CreateSubstrate('%s') -> Result=%d"), strSubstID, nResult);
	m_listGem300Log.AddString(strTemp);
	if (nResult < RESULT_OK)
	{
		AfxMessageBox(_T("Failed. Substrate alreaddy exist"));
	}
}


void CEZGemPlusDLL_SampleDlg::OnButtonDelSubst()
{
	CString strSubstID = _T("");
	if (m_comboSubstrate.GetCurSel() == LB_ERR)
	{
		m_comboSubstrate.SetFocus();
		AfxMessageBox(_T("[DELETE SUBSTRATE] Select SubstrateID (sample)!!!"));
		return;
	}
	m_comboSubstrate.GetLBText(m_comboSubstrate.GetCurSel(), strSubstID);

	//---------------------------------------------------
	// SUBSTRATE객체를 삭제하는 함수

	long nResult = m_gem.DeleteSubstrate(strSubstID);
	//---------------------------------------------------
	CString strTemp;
	strTemp.Format(_T("DeleteSubstrate('%s') -> Result=%d"), strSubstID, nResult);
	m_listGem300Log.AddString(strTemp);

	if (nResult < RESULT_OK)
	{
		AfxMessageBox(_T("Failed. Not Exist !!!"));
		return;
	}
	m_comboSubstrate.DeleteString(m_comboSubstrate.FindString(-1, strSubstID));
}


void CEZGemPlusDLL_SampleDlg::OnBnClickedButtonDelAllsubst()
{
	//----------------------------------
	// 전체 SUBSTRATE객체를 삭제하는 함수
	m_gem.DeleteAllSubstrate();
	//----------------------------------
}


void CEZGemPlusDLL_SampleDlg::OnBnClickedButtonBatchmove1()
{
	CStringArray arrSubst;
	for (int i = 0; i < m_gem.GetSubstrateCount(); i++)
	{
		CString strSubstID, strLoc;
		long nResult = m_gem.GetSubstrate(i, &strSubstID, &strLoc);
		if (nResult == 0)
		{
			arrSubst.Add(strSubstID);
		}
	}
	if (arrSubst.GetCount() == 0)
	{
		AfxMessageBox(_T("No substrate to move !!!"));
		return;
	}
	//-----------------------------------------------------------------------------------------------
	// BatchMove (이동수량, 이동대상리스트,  어디로, 몇번째위치, 이송상태값) 
	long nResult = m_gem.SetSubstBatchMove(arrSubst.GetCount(), &arrSubst, _T("BATCH_1"), 1, 1);
	//-----------------------------------------------------------------------------------------------

	CString strTemp;
	strTemp.Format(_T("SetSubstBatchMove() -> Result=%d"), nResult);
	m_listGem300Log.AddString(strTemp);
}


void CEZGemPlusDLL_SampleDlg::OnBnClickedButtonBatchmove2()
{
	CStringArray arrSubst;
	for (int i = 0; i < m_gem.GetSubstrateCount(); i++)
	{
		CString strSubstID, strLoc;
		long nResult = m_gem.GetSubstrate(i, &strSubstID, &strLoc);
		if (nResult == 0)
		{
			arrSubst.Add(strSubstID);
		}
	}
	if (arrSubst.GetCount() == 0)
	{
		AfxMessageBox(_T("No substrate to move !!!"));
		return;
	}
	//-----------------------------------------------------------------------------------------------
	// BatchMove (이동수량, 이동대상리스트,  어디로, 몇번째위치, 이송상태값) 
	long nResult = m_gem.SetSubstBatchMove(arrSubst.GetCount(), &arrSubst, _T("BATCH_2"), 1, 1);
	//-----------------------------------------------------------------------------------------------

	CString strTemp;
	strTemp.Format(_T("SetSubstBatchMove() -> Result=%d"), nResult);
	m_listGem300Log.AddString(strTemp);
}


void CEZGemPlusDLL_SampleDlg::OnBnClickedButtonSubstmove()
{
	int nSelSubst = m_comboSubstrate.GetCurSel();
	if (nSelSubst == LB_ERR)
	{
		AfxMessageBox(_T("Select SubstrateID (sample)!!!"));
		m_comboSubstrate.SetFocus();
		return;
	}
	int nSelLoc = m_comboSubstLoc.GetCurSel();
	if (nSelLoc == LB_ERR)
	{
		AfxMessageBox(_T("Select (Dest)Location to move !!!"));
		m_comboSubstLoc.SetFocus();
		return;
	}
	int nTransState = m_comboTransState.GetCurSel();
	if (nTransState == LB_ERR)
	{
		AfxMessageBox(_T("Select TransferState"));
		m_comboTransState.SetFocus();
		return;
	}
	CString strSubstID = _T(""), strLocID = _T("");
	m_comboSubstrate.GetLBText(nSelSubst, strSubstID);
	m_comboSubstLoc.GetLBText(nSelLoc, strLocID);

	//-----------------------------------------------------------------------
	// Location이동이 발생하는 경우 호스트로 보고

	long nResult = m_gem.SetSubstrateMove(strSubstID, strLocID, nTransState);

	// (참고) Location을 변경하지 않고 TransportationState면 변경하는 경우
	// --> GEM.SetSubstTranState(SubstID, nTranState)와 같은 역할/같은 결과
	//-----------------------------------------------------------------------

	CString strTemp;
	strTemp.Format(_T("SetSubstrateMove(%s,%s,%d) -> Result=%d"), strSubstID, strLocID, nTransState, nResult);
	m_listGem300Log.AddString(strTemp);

	if (nResult < RESULT_OK) AfxMessageBox(_T("Failed !!!"));
	// 실패하는 경우. 
	//	(1) GEM START이전, 
	//	(2) SUBSTID 존재하지 않음  
	//	(3) LOCID가 존재하지 않음 
	//	(4) 존재하지 않는 STATE}
}


void CEZGemPlusDLL_SampleDlg::OnCbnSelchangeComboStatemode()
{
	m_comboStateValue.ResetContent();
	int nSelStateWhat = m_comboSubstStateMode.GetCurSel();
	if (nSelStateWhat == 0)	// TransState
	{
		char *sState[] = { "0 : AtSource", "1 : AtWork", "2 : AtDest" };
		for (int i = 0; i < 3; i++) m_comboStateValue.AddString((CString)sState[i]);
	}
	else if (nSelStateWhat == 1) // ProcState
	{
		char *sState[] = { "0 : NeedProcessing", "1 : InProcess", "2 : Processed", "3 : Aborted", "4 : Stopped", "5 : Rejected", "6 : Lost", "7 : Skipped" };
		for (int i = 0; i < 8; i++) m_comboStateValue.AddString((CString)sState[i]);
	}
	else if (nSelStateWhat == 2) // ID Reading State
	{
		char *sState[] = { "0 : NotConfirmed", "1 : WaitingForHost", "2 : Confirmed", "3 : ConfirmationFailed" };
		for (int i = 0; i < 4; i++) m_comboStateValue.AddString((CString)sState[i]);
	}
	m_comboStateValue.SetCurSel(0);
	m_comboStateValue.SetFocus();
}


void CEZGemPlusDLL_SampleDlg::OnBnClickedButtonSetstate()
{
	int nSelSubst = m_comboSubstrate.GetCurSel();
	if (nSelSubst == LB_ERR)
	{
		AfxMessageBox(_T("Select a substrate (sample) !!!"));
		m_comboSubstrate.SetCurSel(0);
		m_comboSubstrate.SetFocus();
		return;
	}
	CString strSubstID = _T("");
	m_comboSubstrate.GetLBText(nSelSubst, strSubstID);
	int nSelStateMode = m_comboSubstStateMode.GetCurSel();
	if (nSelStateMode == LB_ERR)
	{
		AfxMessageBox(_T("Select a substrate state (Transportation, Processing, Reading)"));
		m_comboSubstStateMode.SetFocus();
		return;
	}
	int nSelStateVal = m_comboStateValue.GetCurSel();
	if (nSelStateVal == LB_ERR)
	{
		AfxMessageBox(_T("Select a substrate state value !!!"));
		m_comboStateValue.SetCurSel(0);
		m_comboStateValue.SetFocus();
		return;
	}
	//---------------------------------------------------------------------------------------------------------
	if		(nSelStateMode == 0) m_gem.SetSubstTranState(strSubstID, nSelStateVal);	// 이송상태값 보고
	else if (nSelStateMode == 1) m_gem.SetSubstProcState(strSubstID, nSelStateVal); // Processing 상태값 보고
	else if (nSelStateMode == 2) m_gem.SetSubstReadState(strSubstID, nSelStateVal); // ID Reading 상태값 보고
	//---------------------------------------------------------------------------------------------------------
}


void CEZGemPlusDLL_SampleDlg::OnBnClickedButtonSubstidreading()
{
	CString strSubstID = _T("");
	int nSel = m_comboSubstrate.GetCurSel();
	if (nSel == LB_ERR)
	{
		AfxMessageBox(_T("Select a substrate (sample) !!!"));
		m_comboSubstrate.SetCurSel(0);
		m_comboSubstrate.SetFocus();
		return;
	}
	m_comboSubstrate.GetLBText(nSel, strSubstID);
	UpdateData(TRUE);
	int nResult = m_comboSubstIDReadResult.GetCurSel();
	if (nResult == LB_ERR)
	{
		m_comboSubstIDReadResult.SetFocus();
		AfxMessageBox(_T("Select a Reading Result !!!"));
		return;
	}

	//-------------------------------------------------------------------------------
	// SubstrateID Reading기능이 있는 설비의 경우,  읽은 값을 호스트로 전송하는 함수

	long nReturn = m_gem.SetSubstIdRead(strSubstID, m_strSubstIDRead, nResult);
	//-------------------------------------------------------------------------------

	// 전송후 호스트로부터 판단(명령)을 기다림   ( 작업진행 or 작업취소 )
	// 그 명령을 받으면 이벤트 발생됨 아래의 값으로 이벤트 발생
	// EVENT_PROCEED_SUBSTRATE = 2003, //  <<--- HOST : S14F19, (ProceedWithSubstrate)
	// EVENT_CANCEL__SUBSTRATE = 2004, //  <<--- HOST : S14F19, (CancelSubstrate)
	//-------------------------------------------------------------------------------}
}

void CEZGemPlusDLL_SampleDlg::OnBnClickedButtonAttrname()
{
	if (m_comboObjType.GetCurSel() == LB_ERR)
	{
		AfxMessageBox(_T("Select a object type"));
		m_comboObjType.SetFocus();
		if (m_comboObjType.GetCount() > 0) m_comboObjType.SetCurSel(0);
		return;
	}
	CString strObjType = _T("");
	m_comboObjType.GetLBText(m_comboObjType.GetCurSel(), strObjType);

	CStringArray arrAttrName;
	//-----------------------------------------------------------
	long nResult = m_gem.GetAttrName(strObjType, &arrAttrName);
	//-----------------------------------------------------------
	CString strTemp;
	strTemp.Format(_T("GetAttrName(%s) -> Result=%d"), strObjType, nResult);
	m_listGem300Log.AddString(strTemp);
	if (nResult >= 0) m_comboAttrName.ResetContent();
	for (int i = 0; i < arrAttrName.GetCount(); i++)
	{
		strTemp.Format(_T("[%s](%02d) : AttrName=<%s>"), strObjType, i + 1, arrAttrName.GetAt(i));
		m_listGem300Log.AddString(strTemp);
		m_comboAttrName.AddString(arrAttrName.GetAt(i));
	}

	m_listGem300Log.SetCurSel(m_listGem300Log.GetCount() - 1);
}

void CEZGemPlusDLL_SampleDlg::OnBnClickedButtonAttrdata()
{
	if (m_comboObjType.GetCurSel() == LB_ERR)
	{
		AfxMessageBox(_T("Select a object type"));
		m_comboObjType.SetFocus();
		if (m_comboObjType.GetCount() > 0) m_comboObjType.SetCurSel(0);
		return;
	}
	if (m_comboObjID.GetCurSel() == LB_ERR)
	{
		AfxMessageBox(_T("Select a object ID"));
		m_comboObjID.SetFocus();
		if (m_comboObjID.GetCount() > 0) m_comboObjID.SetCurSel(0);
		return;
	}
	if (m_comboAttrName.GetCurSel() == LB_ERR)
	{
		AfxMessageBox(_T("Select a attribute name"));
		m_comboAttrName.SetFocus();
		if (m_comboAttrName.GetCount() > 0) m_comboAttrName.SetCurSel(0);
		return;
	}
	CString strObjType = _T(""), strObjID = _T(""), strAttrName = _T(""), strTemp;
	m_comboObjType.GetLBText(m_comboObjType.GetCurSel(), strObjType);
	m_comboObjID.GetLBText(m_comboObjID.GetCurSel(), strObjID);
	m_comboAttrName.GetLBText(m_comboAttrName.GetCurSel(), strAttrName);

	CStringArray arrAttrData;
	//----------------------------------------------------------------------------------
	long nResult = m_gem.GetAttrData(strObjType, strObjID, strAttrName, &arrAttrData);
	//----------------------------------------------------------------------------------
	strTemp.Format(_T("GetAttrData(%s, %s, %s) -> Result=%d"), strObjType, strObjID, strAttrName, nResult);
	m_listGem300Log.AddString(strTemp);
	for (int i = 0; i < arrAttrData.GetCount(); i++)
	{
		strTemp.Format(_T("[%s] %s : (%02d) Name=<%s>,Val=<%s>"), strObjType, strObjID, i+1, strAttrName, arrAttrData.GetAt(i));
		m_listGem300Log.AddString(strTemp);
	}
	m_listGem300Log.SetCurSel(m_listGem300Log.GetCount() - 1);
}


void CEZGemPlusDLL_SampleDlg::OnCbnSelchangeComboObjtype()
{
	int nSel = m_comboObjType.GetCurSel();
	if (nSel == LB_ERR) return;

	CString strObjType = _T("");
	m_comboObjType.GetLBText(nSel, strObjType);

	CStringArray arrObjList;
	//--------------------------------------------------------------
	long nResult = m_gem.GetObjectList(strObjType, &arrObjList);
	//--------------------------------------------------------------
	if (nResult < RESULT_OK) return;
	if (arrObjList.GetCount() > 0) m_comboObjID.ResetContent();
	for (int i = 0; i < arrObjList.GetCount(); i++)
	{
		m_comboObjID.AddString(arrObjList.GetAt(i));
	}

	CStringArray arrAttr;
	m_gem.GetAttrName(strObjType, &arrAttr);
	m_comboAttrName.ResetContent();
	for (int i = 0; i < arrAttr.GetCount(); i++)
	{
		m_comboAttrName.AddString(arrAttr.GetAt(i));
	}
}


void CEZGemPlusDLL_SampleDlg::OnBnClickedButtonAllattrdata()
{
	if (m_comboObjType.GetCount() == 0) return;

	CString strObjType;
	CStringArray arrayObject, arrayAttrName;
	FILE *fp = fopen("ALL_DATA.TXT", "w+t");
	for (int i = 0; i < m_comboObjType.GetCount(); i++)
	{
		strObjType = "";
		m_comboObjType.GetLBText(i, strObjType);
		if (strObjType == "") continue;

		//--------------------------------------------------
		m_gem.GetObjectList(strObjType, &arrayObject);
		m_gem.GetAttrName(strObjType, &arrayAttrName);
		//--------------------------------------------------
		
		for (int j = 0; j < arrayObject.GetCount(); j++)
		{
			CString strObjID = arrayObject.GetAt(j);
			for (int k = 0; k < arrayAttrName.GetCount(); k++)
			{
				CString strAttr = arrayAttrName.GetAt(k);
				CStringArray arrayData;
				//--------------------------------------------------------------------------
				long nCount = m_gem.GetAttrData(strObjType, strObjID, strAttr, &arrayData);
				//--------------------------------------------------------------------------
				for (int n = 0; n < arrayData.GetCount(); n++)
				{
#ifdef _UNICODE
					wchar_t temp[0xFF];
					swprintf(temp, 0xFF, _T("[%s:%s] : %s=<%s>\n"),
						strObjType, strObjID, strAttr, arrayData.GetAt(n));
					fputws(temp, fp);
#else
					CString strTemp;
					strTemp.Format("[%s:%s] : %s=<%s>\n", strObjType, strObjID, strAttr, arrayData.GetAt(n));
					fputs(strTemp, fp);
#endif
				}
			}
		}
	}
	fclose(fp);
	
	AfxMessageBox(_T("ALL_DATA.TXT file created ..."));

	ShellExecute(NULL, _T("open"), _T("notepad"), _T("ALL_DATA.TXT"), NULL, SW_SHOW);
}

void CEZGemPlusDLL_SampleDlg::OnBnClickedButtonAddPjparam()
{
	int nPos = m_listPrJob.GetCurSel();
	if (nPos == LB_ERR)
	{
		AfxMessageBox(_T("PRJOB not selected !!!"));
		GetDlgItem(IDC_LIST_PRJOB)->SetFocus();
		return;
	}
	CString strPrJobID = _T("");
	m_listPrJob.GetText(nPos, strPrJobID);

	CString strName, strVal;
	int nCount = 0;
	for (int i = 0; i < 20; i++)
	{
		strName.Format(_T("Name_%02d"), i + 1);
		strVal.Format(_T("Value_%02d"), i + 1);
		if (m_gem.AddPrJobParam(strPrJobID, strName, strVal) == RESULT_OK) nCount++;
	}
	strName.Format(_T("%d paramter added"), nCount);
	AfxMessageBox(strName);
}

void CEZGemPlusDLL_SampleDlg::OnBnClickedButtonCarrieraccessstatus()
{
	int nSel = m_comboCarrierAccessStatus.GetCurSel();
	if (nSel == LB_ERR)
	{
		AfxMessageBox(_T("Accessing Status not selected !!!"));
		return;
	}
	int nPort = 0;
	if (m_radioLoadPort1.GetCheck()) nPort = 1;
	if (m_radioLoadPort2.GetCheck()) nPort = 2;
	//----------------------------------------------------------
	m_gem.SetCarrierAccessState(nPort, nSel, m_strCarrierID);
	//----------------------------------------------------------
}

// 모든 Slot정보를 보고싶을때,  캐리어를 선택하면  해당 캐리어의 각 slot정보를 로그창에 표시하는 기능
// SlotType, LotID, WaferID(SubstrateID) 표시  <- S3F17로 호스트가 이 정보를 내려준 이후에 조회됨
void CEZGemPlusDLL_SampleDlg::OnItemchangedListCarrierinfo(NMHDR *pNMHDR, LRESULT *pResult)
{
	LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);

	if ((pNMLV->uChanged & LVIF_STATE) && (pNMLV->uNewState & LVIS_SELECTED))
	{
		int selectedIndex = pNMLV->iItem;
		CString strCarrierID = m_gridCarrierInfo.GetItemText(selectedIndex, 0); // 첫 번째 열 -> CarrierID

		int nSlotType;
		CString strLotID = nullptr, strWaferID = nullptr;

		for (int i = 0; i < MAX_SLOT; i++)
		{
			//-----------------------------------------------------------------------------------------
			// 각 Slot별 정보를 가져오는 함수  (SlotType, LotID, WaferID)
			long nResult = m_gem.GetSlotInfo(strCarrierID, i + 1, &nSlotType, &strLotID, &strWaferID);
			//-----------------------------------------------------------------------------------------
			if (nResult == 0)
			{
				CString strTemp;
				strTemp.Format(_T("[%s].%02d  : <%d><%s><%s>"),
					strCarrierID, i + 1, nSlotType,
					strLotID, strWaferID);

				m_listGem300Log.AddString(strTemp);
			}
		}
		m_listGem300Log.SendMessage(WM_VSCROLL, SB_BOTTOM);
	}
	*pResult = 0;
}


void CEZGemPlusDLL_SampleDlg::OnBnClickedButtonSubstrateReturn() // 작업완료후 원래자리로 돌아감
{
	int nSelSubst = m_comboSubstrate.GetCurSel();
	if (nSelSubst == LB_ERR)
	{
		AfxMessageBox(_T("Select SubstrateID (sample)!!!"));
		m_comboSubstrate.SetFocus();
		return;
	}
	// AtDest
	int nTransState = 2;	// AtDest

	CString strSubstID = _T(""), strLocID = _T(""), strDest;
	m_comboSubstrate.GetLBText(nSelSubst, strSubstID);
	m_gem.GetAttrData(_T("Substrate"), strSubstID, _T("SubstDestination"), &strDest);
	strLocID = strDest;

	//-----------------------------------------------------------------------
	// Location이동이 발생하는 경우 호스트로 보고

	long nResult = m_gem.SetSubstrateMove(strSubstID, strLocID, nTransState);

	// (참고) Location을 변경하지 않고 TransportationState면 변경하는 경우
	// --> GEM.SetSubstTranState(SubstID, nTranState)와 같은 역할/같은 결과
	//-----------------------------------------------------------------------

	CString strTemp;
	strTemp.Format(_T("SetSubstrateMove(%s,%s,%d) -> Result=%d"), strSubstID, strLocID, nTransState, nResult);
	m_listGem300Log.AddString(strTemp);

	if (nResult < RESULT_OK) AfxMessageBox(_T("Failed !!!"));
	// 실패하는 경우. 
	//	(1) GEM START이전, 
	//	(2) SUBSTID 존재하지 않음  
	//	(3) LOCID가 존재하지 않음 
	//	(4) 존재하지 않는 STATE}
}


void CEZGemPlusDLL_SampleDlg::OnBnClickedButtonOccupied()
{
	int nSelLoc = m_comboSubstLoc.GetCurSel();
	if (nSelLoc == LB_ERR)
	{
		AfxMessageBox(_T("Select Location to set !!!"));
		m_comboSubstLoc.SetFocus();
		return;
	}
	CString strLocID = _T("");
	m_comboSubstLoc.GetLBText(nSelLoc, strLocID);

	m_gem.SetSubstLocState(strLocID, 1);	// 1 = OCCUPIED
}


void CEZGemPlusDLL_SampleDlg::OnBnClickedButtonUnoccupied()
{
	int nSelLoc = m_comboSubstLoc.GetCurSel();
	if (nSelLoc == LB_ERR)
	{
		AfxMessageBox(_T("Select Location to set !!!"));
		m_comboSubstLoc.SetFocus();
		return;
	}
	CString strLocID = _T("");
	m_comboSubstLoc.GetLBText(nSelLoc, strLocID);

	m_gem.SetSubstLocState(strLocID, 0);	// 0 = UNOCCUPIED
}


void CEZGemPlusDLL_SampleDlg::OnBnClickedButtonSetnewattrval()
{
	UpdateData(TRUE);
	CString strObjType = _T(""), strObjID = _T(""), strAttrName = _T("");
	int nSel = m_comboObjType.GetCurSel();
	if (nSel == LB_ERR)
	{
		AfxMessageBox(_T("ObjType not selected !!!"));
		GetDlgItem(IDC_COMBO_OBJTYPE)->SetFocus();
		return;
	}
	m_comboObjType.GetLBText(nSel, strObjType);

	nSel = m_comboObjID.GetCurSel();
	if (nSel == LB_ERR)
	{
		AfxMessageBox(_T("ObjID not selected !!!"));
		GetDlgItem(IDC_COMBO_OBJID)->SetFocus();
		return;
	}
	m_comboObjID.GetLBText(nSel, strObjID);

	nSel = m_comboAttrName.GetCurSel();
	if (nSel == LB_ERR)
	{
		AfxMessageBox(_T("Attribute not selected !!!"));
		GetDlgItem(IDC_COMBO_ATTRNAME)->SetFocus();
		return;
	}
	m_comboAttrName.GetLBText(nSel, strAttrName);

	if (m_strNewAttrVal.IsEmpty())
	{
		GetDlgItem(IDC_EDIT_NEW_ATTRVAL)->SetFocus();
		if (IDNO == MessageBox(_T("Are you sure to set empty string for new value?"), _T("Warning"), MB_YESNO))
		{
			return;
		}
	}
	m_gem.SetAttrData(strObjType, strObjID, strAttrName, m_strNewAttrVal);
}


void CEZGemPlusDLL_SampleDlg::OnBnClickedButtonCarriermove()
{
	int nPos = m_comboCarrierID.GetCurSel();
	if (nPos == LB_ERR)
	{
		AfxMessageBox(_T("CarrierID not selected to move !!!"));
		GetDlgItem(IDC_COMBO_CARRIERID)->SetFocus();
		return;
	}
	CString strCarrierID = _T("");
	m_comboCarrierID.GetLBText(nPos, strCarrierID);

	nPos = m_comboCarrierLocation.GetCurSel();
	if (nPos == LB_ERR)
	{
		AfxMessageBox(_T("Carrier Location not selected to move !!!"));
		GetDlgItem(IDC_COMBO_CARRIERLOCATION)->SetFocus();
		return;
	}
	CString strCarrierLocation = _T("");
	m_comboCarrierLocation.GetLBText(nPos, strCarrierLocation);

	long nRet = m_gem.SetCarrierMove(strCarrierID, strCarrierLocation);
	if (nRet == RESULT_OK)
	{
		MessageBox(_T("Carrier Move - OK"));
	}
	else
	{
		MessageBox(_T("Carrier Move - ERROR !!"));
	}
}

void CEZGemPlusDLL_SampleDlg::OnDropdownComboCarrierID()
{
	m_comboCarrierID.ResetContent();
	int nCount = m_gem.GetCarrierCount();
	for (int i = 0; i < nCount; i++)
	{
		CString strCarrierID, strLoc;
		m_gem.GetCarrierList(i, &strCarrierID, &strLoc);
		m_comboCarrierID.AddString(strCarrierID);
	}
}


void CEZGemPlusDLL_SampleDlg::OnDropdownComboCarrierLocation()
{
	m_comboCarrierLocation.ResetContent();
	int nCount = m_gem.GetCarrierLocCount();
	for (int i = 0; i < nCount; i++)
	{
		CString strCarrierID, strLoc;
		m_gem.GetCarrierLocList(i, &strLoc, &strCarrierID);
		m_comboCarrierLocation.AddString(strLoc);
	}
}
