
//---------------------------------------------------------------------------
#include "AppGlobalF.h"
#include "VMSCThread.h"
#include "FrmSysLogF.h"
#include "FrmVmsInfoF.h"
#include "FrmVmsLogF.h"
#include <winsock.h>
//---------------------------------------------------------------------------
#pragma package(smart_init)
//---------------------------------------------------------------------------

//   Important: Methods and properties of objects in VCL can only be
//   used in a method called using Synchronize, for example:
//
//      Synchronize(&UpdateCaption);
//
//   where UpdateCaption could look like:
//
//      void __fastcall TVMSCThread::UpdateCaption()
//      {
//        Form1->Caption = "Updated in a thread";
//      }
//---------------------------------------------------------------------------

#define     VMSID   FVmsObj->VmsId

/*
 * 스레드 생성자
 *  arguments
 *   void
 *  return
 *   void
 */
 __fastcall TVMSCThread::TVMSCThread(bool CreateSuspended, int Tag, bool *ActiveIndicator)
	: TThread(CreateSuspended)
{
    try
    {
        FUserTerm = false;

        FVmsObj  = (TVmsCtlr*)Tag;
        FLogFile = FVmsObj->FCLog;

        ThreadActiveIndicator = ActiveIndicator;
       *ThreadActiveIndicator = true;

        // 정보 초기화
        ClientInitInfo();

        TcpClient = new TTcpClient(NULL);

		TcpClient->RemoteHost = FVmsObj->IpAddress;
		TcpClient->RemotePort = FVmsObj->LocalNo;
        TcpClient->BlockMode  = bmBlocking;

        TcpClient->OnConnect       = TcpClientConnect;
        TcpClient->OnCreateHandle  = TcpClientCreateHandle;
		TcpClient->OnDestroyHandle = TcpClientDestroyHandle;
        TcpClient->OnDisconnect    = TcpClientDisconnect;
		TcpClient->OnError         = TcpClientError;
		TcpClient->OnReceive       = TcpClientReceive;
		TcpClient->OnSend          = TcpClientSend;

        Priority        = tpNormal;
        FreeOnTerminate = true;
		Resume();
    }
    catch(Exception &e)
    {
        SERROR("Thread Init Error");
        Terminate();
	}
}
//---------------------------------------------------------------------------

/*
 * 스레드 소멸자
 *  arguments
 *   void
 *  return
 *   void
 */
__fastcall TVMSCThread::~TVMSCThread()
{
    try
    {
        FVmsObj->Client.Status = process_fail;
    	SAFE_DELETE(TcpClient);
    }
    catch(Exception &e)
    {
    }
	*ThreadActiveIndicator = false;
}
//---------------------------------------------------------------------------

/*
 * 연결 이벤트 핸들러
 *  arguments
 *   void
 *  return
 *   void
 */
void __fastcall TVMSCThread::TcpClientConnect(TObject *Sender)
{
    SINFO("Server Connect  ok: %s %s", TcpClient->RemoteHost.c_str(), TcpClient->RemotePort.c_str());

    ClientInitInfo();

    FVmsObj->Client.Comm   = state_open;
	FVmsObj->Client.Status = process_run;

    FVmsObj->ConnectTm = Now().DateTimeString();
    FVmsObj->Server.Status = process_run;
    POST_MSG(MAINHANDLE, WM_VMS_THREAD, WM_VMS_SERVER_STTS, (int)FVmsObj);

    POST_MSG(MAINHANDLE, WM_VMS_THREAD, WM_VMS_CLIENT_STTS, (int)FVmsObj);
}
//---------------------------------------------------------------------------

/*
 * 연결 해제 이벤트 핸들러
 *  arguments
 *   void
 *  return
 *   void
 */
void __fastcall TVMSCThread::TcpClientDisconnect(TObject *Sender)
{
    FVmsObj->Client.Comm   = state_close;
	FVmsObj->Client.Status = process_run;
    m_pState->Comm = vms_error;

    FVmsObj->DisconnectTm = Now().DateTimeString();
    FVmsObj->Server.Status == process_fail;

    //POST_MSG(MAINHANDLE, WM_VMS_THREAD, WM_VMS_CLIENT_STTS, (int)FVmsObj);
    SINFO("Server Disconnect: %s %s", TcpClient->RemoteHost.c_str(), TcpClient->RemotePort.c_str());

    POST_MSG(MAINHANDLE, WM_VMS_THREAD, WM_VMS_SERVER_STTS, (int)FVmsObj);
}
//---------------------------------------------------------------------------

/*
 * 핸들 생성 이벤트 핸들러
 *  arguments
 *   void
 *  return
 *   void
 */
void __fastcall TVMSCThread::TcpClientCreateHandle(TObject *Sender)
{
    //LDEBUG("Thread Create Handle");
}
//---------------------------------------------------------------------------

/*
 * 핸들 소멸 이벤트 핸들러
 *  arguments
 *   void
 *  return
 *   void
 */
void __fastcall TVMSCThread::TcpClientDestroyHandle(TObject *Sender)
{
    //LDEBUG("Thread Destroy Handle");
}
//---------------------------------------------------------------------------

void __fastcall TVMSCThread::Close(void)
{
    try
    {
        FVmsObj->Client.Status == process_fail;
        if (TcpClient)
        {
            //if (TcpClient->Connected)
            {
                TcpClient->Close();
                //Sleep(3000);
            }
        }
    }
    catch(Exception &e)
    {
    }
}
//---------------------------------------------------------------------------

/*
 * 에러 처리 이벤트 핸들러
 *  arguments
 *   void
 *  return
 *   void
 */
void __fastcall TVMSCThread::TcpClientError(TObject *Sender, int SocketError)
{
    LPVOID lpMsgBuf = NULL;

    try
    {
        try
        {
            FormatMessage(
                FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
                NULL,
                //GetLastError(),
                //MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
                SocketError,
                MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT),
                (LPTSTR) &lpMsgBuf,
                0,
                NULL
            );

            char *pData = (char*)lpMsgBuf;
            if (strlen(pData) > 2)
            {
                pData[strlen(pData)-2] = 0x00;
                pData[strlen(pData)-1] = 0x00;
            }
            SERROR("SocketError: (%d: %s)", SocketError, pData);
        }
        __finally
        {
            if (lpMsgBuf) LocalFree(lpMsgBuf);
            lpMsgBuf = NULL;
        }
    }
    catch(Exception &e)
    {
    }

    Close();
}
//---------------------------------------------------------------------------

/*
 * 데이터 수신 이벤트 핸들러
 *  arguments
 *   void
 *  return
 *   void
 */
void __fastcall TVMSCThread::TcpClientReceive(TObject *Sender, char *Buf, int &DataLen)
{
    //LDEBUG("VMS Client Receive: %s, %d", VMSID.c_str(), DataLen);
}
//---------------------------------------------------------------------------

/*
 * 데이터 송신 이벤트 핸들러
 *  arguments
 *   void
 *  return
 *   void
 */
void __fastcall TVMSCThread::TcpClientSend(TObject *Sender, char *Buf, int &DataLen)
{
    //LDEBUG("VMS Client Send: %s, %d", VMSID.c_str(), DataLen);
}
//---------------------------------------------------------------------------

bool __fastcall TVMSCThread::SocketActivity(bool &AError)
{
    bool Error, ReadReady, WriteReady, ExcepFlag;

    ReadReady = false;
    AError = false;

    if (!TcpClient) return ReadReady;

    try
    {
        Error = TcpClient->Select(&ReadReady, &WriteReady, &ExcepFlag, 0);
        if ((Error == false))// || (ExcepFlag == true)) //exception flag == o.o.b(out of band data receive)
        {
            AError = true;
            ReadReady = false;
        }
    }
    catch(Exception &e)
    {
        AError = true;
        ReadReady = false;
    }
    return ReadReady;
}
//---------------------------------------------------------------------------

bool __fastcall TVMSCThread::SocketActivity()
{
    bool bResult = false;
    bool Error, ReadReady, WriteReady, ExcepFlag;

    if (!TcpClient) return bResult;

    try
    {
        Error = TcpClient->Select(&ReadReady, &WriteReady, &ExcepFlag, 0);

        if ((Error == false) || (ReadReady == true) || (ExcepFlag == true))
        {
            bResult = true;
        }
    }
    catch(Exception &e)
    {
    }
    return bResult;
}
//---------------------------------------------------------------------------

/*
 * 클라이언트 정보 초기화 루틴
 *  arguments
 *   void
 *  return
 *   void
 */
void __fastcall TVMSCThread::ClientInitInfo(void)
{
    m_RxLen          = 0;
    m_rcvPacketTimer = Now();
	m_WatchDogTimer  = Now();

    m_pVmsFormList    = FVmsObj->pForms;
    m_pState          = &FVmsObj->RSTATE;

	FClient.State = CT_IDLE;

    FClient.IpAddress = FVmsObj->IpAddress;
	FClient.Port      = FVmsObj->LocalNo;
    FClient.Addr      = FVmsObj->Id;
    FClient.VmsId     = FVmsObj->VmsId;
	FClient.TimeOut   = g_AppCfg.comm.nCmdTimeOut;

    FClient.pollingCycleTime = g_AppCfg.comm.nPollingTime;
	FClient.reqStatusTimer   = Now() - ITSCOMM_SECTIME(FClient.pollingCycleTime+10);

	FClient.sendRetry      = VMS_MAX_RETRY_COUNT;
	FClient.sendTimer      = Now();

	//m_strName.sprintf("VMSC%03d", FClient.Addr);
	m_strName = "VMSC" + FVmsObj->VmsId;

	FClient.LocalCenterId = "";
	FClient.CenterId      = "";
	FClient.LocalDomainNm = g_AppCfg.comm.sLocalDomain;
	FClient.DomainNm      = FClient.VmsId;
	FClient.UserName      = g_AppCfg.comm.sLoginUser;
	FClient.UserPasswd    = g_AppCfg.comm.sLoginPswd;

	FClient.MaxHeartbeatTime = VMS_MAX_HEARTBEAT_TIME;
	FClient.DatagramSize     = VMS_MAX_DATAGRAM_SIZE;

    m_DataPacketNumber   = 0;
	m_SubscribeSerialNbr = 0;


	FLocalCmd.GeneralStatus = false;
	FLocalCmd.ModuleStatus  = false;
	FLocalCmd.PowerStatus   = false;
	FLocalCmd.ScreenDataStatusMessage = false;
	FLocalCmd.RealTimeDisplayMessage  = false;

    m_pState->Comm = vms_error;

#if 0
	if (m_pState != NULL)
	{
		m_pState->Cpsw.Enable = bit_enable;
		m_pState->CollectDate = Now().FormatString("yyyymmddhhnnss");

		m_pState->Door             = STATE_UNKNOWN;
		m_pState->Heater           = STATE_UNKNOWN;
		m_pState->Fan              = STATE_UNKNOWN;
		m_pState->ModuleState      = STATE_UNKNOWN;
		m_pState->Power            = STATE_UNKNOWN;
		m_pState->Temp             = 0;
		m_pState->Bright           = 0;
		m_pState->ModuleHorizontal = 0;
		m_pState->ModuleVertical   = 0;
		m_pState->PowerCount       = 0;
		memset(m_pState->ModuleStatus, STATE_UNKNOWN, sizeof(m_pState->ModuleStatus));
		memset(m_pState->PowerStatus,  STATE_UNKNOWN, sizeof(m_pState->PowerStatus));
	}
#endif

    InitRx();

    LINFO("ClientInitInfo ok");
}
//---------------------------------------------------------------------------

void __fastcall TVMSCThread::InitRx()
{
    m_RxPktLen  = 0;
    m_RxLen     = 0;
    m_RxState   = RX_STX;

    memset(m_RxBuff, 0x00, sizeof(m_RxBuff));
}
//---------------------------------------------------------------------------

void __fastcall TVMSCThread::ClientTerminate(void)
{
    try
    {
        FVmsObj->Client.Comm   = state_close;
    	FVmsObj->Client.Status = process_fail;

		FVmsObj->Client.pThread         = NULL;
		FVmsObj->Client.ActiveIndicator = false;

        //POST_MSG(MAINHANDLE, WM_VMS_THREAD, WM_VMS_CLIENT_STTS, (int)FVmsObj);
        SINFO("Thread stop");
    }
    catch(Exception &e)
    {
    }
}
//---------------------------------------------------------------------------

int HexArr2BinArr(unsigned char *AHexData, unsigned char *AResult)
{
    //TODO: 결과를 리턴할 메모리의 크기는 체크하지 않음

    int                  nLen   = 0;
    unsigned const char *pos    = AHexData;
    char                *endptr = NULL;
    int                  count  = (strlen(AHexData) / 2);

    if ((AHexData[0] == NULL) || (strlen(AHexData) % 2))
    {
        //데이터가 없거나 길이가 짝수가 아닌경우
        return -2;
    }

    for(int ii = 0; ii < count; ii++)
    {
        char buf[5] = {'0', 'x', pos[0], pos[1], 0};
        AResult[nLen++] = (unsigned char)strtol(buf, &endptr, 0);
        pos += 2 * sizeof(char);

        if (endptr[0] != '\0') {
            //Hex 문자열이 아님
            return -1;
        }
    }

#if 0
    BYTE     chn, cln, val;

    chn = (BYTE)szData[0];
    cln = (BYTE)szData[1];

    hn = chn > '9' ? chn - 'A' + 10 : chn - '0';
    ln = cln > '9' ? cln - 'A' + 10 : cln - '0';

    val = (BYTE)((hn << 4 ) | ln);
    RxBuff[RxLen] = val;
#endif

    return nLen;
}
//---------------------------------------------------------------------------

void __fastcall TVMSCThread::Execute()
{
    BYTE rcvBuff[DEFAULT_TCP_PACKET_MAX_SIZE];
    int  rcvLen;
    int  nError;
	int  nResult;
    bool bError;

    //static bool first = true;
    try
    {
		NameThreadForDebugging(m_strName);

FErrLine = 0;
        SINFO("Thread start");
        try
        {
            while (!Terminated && !FUserTerm && !g_AppCfg.bThrExit)
            {
                FVmsObj->Client.Status = process_run;
                m_pState->Comm = vms_error;

                SINFO("Server connect try: %s.%s", TcpClient->RemoteHost.c_str(), TcpClient->RemotePort.c_str());
                TcpClient->Open();

                bError = false;

                while (!Terminated && TcpClient->Connected && !FUserTerm && !g_AppCfg.bThrExit)
                {
                    m_pState->Comm = vms_normal;
                    try
                    {
                        if (SYS_ERR_OFFLINE == ClientStateMachine())
                        {
                            if (FClient.State == CT_CLOSE)
                            {
                                break;
                            }
                        }

                        bError = false;
                        if (TcpClient->WaitForData(100) || SocketActivity())
                        {
                            bError = false;

                            memset(rcvBuff, 0, sizeof(rcvBuff));
                            rcvLen = TcpClient->ReceiveBuf(rcvBuff, sizeof(rcvBuff));
                            if (rcvLen > 0)
                            {
                                if ((nResult = RecvPacket(rcvBuff, rcvLen)) != SYS_ERR_NONE)
                                {
                                    ProcErrorState(true, nResult);
                                }
                            }
                            else
                            {
                                bError = true;
                            }
                        }
                        if (bError)
                        {
                            SERROR("Socket Error[Closed]....");
                            nError = -3;
                            Close();
                        }

                        if (FVmsObj->Server.Status != process_run)
                        {
                            nError = -4;
                            Close();
                        }
                    }
                    catch(Exception &e)
                    {
                        SERROR("Thread execute exception: %s, Line: %d", AnsiString(e.Message).c_str(), FErrLine);
                        nError = -2;
                        Close();
                    }
                }

                if (FClient.State == CT_CLOSE || FUserTerm || g_AppCfg.bThrExit)
                {
                    nError = 0;
                    SINFO("Thread exit catched....2");
                    Close();
                    break;
                }

                if (FVmsObj->Client.Status != process_stop)
                {
                    Sleep(g_AppCfg.comm.nConnectWait * 1000);
                }
            }
            SERROR("Term: %d, Conn: %d, Err: %d, Line: %d, AppExit: %d, UserTerm: %d",
                   Terminated, TcpClient->Connected, nError, FErrLine, g_AppCfg.bThrExit, FUserTerm);
        }
		__finally
        {
            TcpClient->Close();
            Terminate();
            FUserTerm = false;
        }
    }
    catch(Exception &e)
    {
        SERROR("Thread execute error: %s", AnsiString(e.Message).c_str());
        Terminate();
    }
    m_pState->Comm = vms_error;
    ClientTerminate();
}
//---------------------------------------------------------------------------

void __fastcall TVMSCThread::DebugState()
{
	switch(FClient.State)
    {
    case 1: break;
    default: break;
    }
}
//---------------------------------------------------------------------------

bool __fastcall TVMSCThread::IsCommandTimeout()
{
    // 마지막 전송시각이 타임아웃 시각보다 큰경우
    return CommUtil_TimeDiff(FClient.sendTimer) > FClient.TimeOut ? true : false;
}
//---------------------------------------------------------------------------

/*
 * 클라이언트 상태에 따른 처리
 *  arguments
 *   void
 *  return
 *   void
 */
int __fastcall TVMSCThread::ClientStateMachine(void)
{
FErrLine = 13;
    int  result;
	bool bRequest;

    result = SYS_ERR_NONE;

    // CMDTIMEOUT 체크
    // 현재 수신데이터가 있고 마지막 수진시각이 타임아웃보다 크면
    // 수신 타임아웃으로 처리한다.
	if (m_RxLen && (CommUtil_TimeDiff(m_rcvPacketTimer) > FClient.TimeOut))
    {
        InitRx();
		m_RxLen = 0;
        ProcErrorState(true, SYS_ERR_RECEIVE_TIMEOUT);
        return result;
	}

    DebugState();

	switch(FClient.State)
    {
	case CT_CLOSE:
        LERROR("STATE: CT_CLOSE");
        Terminate();
        result = SYS_ERR_OFFLINE;
		break;

	case CT_IDLE:
        FClient.reqStatusTimer = Now() - ITSCOMM_SECTIME(CLIENT_CONNECT_RETRY_TIME - CLIENT_CHANGE_TIME);
        FClient.State = CT_SECTION;
		break;

    case CT_SECTION:
#if 0
        if (CommUtil_TimeDiff(m_WatchDogTimer) > g_AppCfg.comm.nWatchDogTime)
        {
			LERROR("STATE: ST_SECTION - WatchDog Time over");

			FClient.State = CT_CLOSE;
            break;
        }
#endif

		if (CommUtil_TimeDiff(FClient.reqStatusTimer) > FClient.pollingCycleTime)
        {
			FClient.reqStatusTimer = Now();

			FLocalCmd.GeneralStatus = false;
			FLocalCmd.ModuleStatus  = false;
			FLocalCmd.PowerStatus   = false;
		}
        FClient.State = CT_LOCAL_COMMAND;
		break;

	case CT_LOCAL_COMMAND:
        result = CheckLocalData(bRequest);
        if (bRequest)
        {
            if (result == SYS_ERR_NONE) FClient.State = CT_LOCAL_WAIT;
            else
            {
                if (--FClient.sendRetry <= 0) FClient.State = CT_CLOSE;
            }
        }
        else FClient.State = CT_CLIENT_COMMAND;

        break;

    case CT_CLIENT_COMMAND:
        result = CheckClientData(bRequest);
		if (bRequest)
        {
            if (result == SYS_ERR_NONE) FClient.State = CT_CLIENT_WAIT;
            else
            {
                if (--FClient.sendRetry <= 0) FClient.State = CT_CLOSE;
            }
        }
        else FClient.State = CT_SECTION;

        break;

	case CT_CLIENT_WAIT:
	case CT_LOCAL_WAIT:
		if (IsCommandTimeout())
		{
            // Local Command에 대한 타임아웃이 발생한 경우
			if (FClient.sendRetry > 0)
            {
                // 타임아웃 카운트 보다 작을 경우 Command를 전송한다.
                if (FClient.State == CT_CLIENT_WAIT) FClient.State = CT_CLIENT_COMMAND;
                else
                if (FClient.State == CT_LOCAL_WAIT) FClient.State = CT_LOCAL_COMMAND;
			}
            else
            {
                // 타임아웃 카운트 보다 큰 경우 종료
				FClient.State = CT_CLOSE;
			}
		}
		break;

    default:
		FClient.State = CT_IDLE;
        break;
    }

    if (result)
    {
        ProcErrorState(false, result);
    }

    return result;
}
//---------------------------------------------------------------------------

/*
 *  프로세스 자체(주기)적으로 VMS로 전송(요청)되어야 할 패킷이 있는지 확인하고 처리한다.
 *  arguments
 *   void
 *  return
 *   void
 */
int __fastcall TVMSCThread::CheckLocalData(bool &ARequest)
{
	int              result = SYS_ERR_NONE;
	COMMAND_ARGUMENT arg;

	memset(&arg,  0x00, sizeof(arg));

    FLocalCmd.OpCode           = 0x00;
	FLocalCmd.obj              = OBJ_None;  /* EN_OBJECT_ID */
	FLocalCmd.DataPacketNumber = 0;         /* DataPacket Number */
    FLocalCmd.Idx              = 0;

    ARequest = true;

    /* 상태정보 요청 확인 */
	if (FLocalCmd.GeneralStatus == false)
    {
        //LINFO("**** REQ_VMS_STATUS");
		arg.Subscription.nbr   = NBR_GENERAL_STATUS;
		//arg.Subscription.mode  = SubscriptionMode_PR_single;
		arg.Subscription.delay = 60;
		arg.Subscription.obj   = OBJ_GeneralStatus;

        FLocalCmd.OpCode           = REQ_VMS_STATUS;
		FLocalCmd.obj              = OBJ_GeneralStatus;
		FLocalCmd.DataPacketNumber = m_DataPacketNumber;

        result = ProcessSendPacket(FLocalCmd.OpCode, &arg);
		return result;
	}

    // 모듈상태 요청 확인
	if (FLocalCmd.ModuleStatus == false)
	{
        //LINFO("**** REQ_VMS_MODULE_STATUS");
		arg.Subscription.nbr   = NBR_MODULE_STATUS;
		//arg.Subscription.mode  = SubscriptionMode_PR_single;
		arg.Subscription.delay = 60;
		arg.Subscription.obj   = OBJ_ModuleStatus;

        FLocalCmd.OpCode           = REQ_VMS_MODULE_STATUS;
		FLocalCmd.obj              = OBJ_ModuleStatus;
		FLocalCmd.DataPacketNumber = m_DataPacketNumber;

        result = ProcessSendPacket(FLocalCmd.OpCode, &arg);
		return result;
	}

	// FORM 다운로드
	if (FVmsObj->CTLMODE->Enable == object_enable)
    {
		m_pVmsFormList->Lock();
		try
		{
            int nFormCnt = m_pVmsFormList->Count();
            for (int ii = 0; ii < nFormCnt; ii++)
            {
                TVmsForm *pVmsForm = m_pVmsFormList->GetItem(ii);
                if (pVmsForm)
                {
                    if (pVmsForm->SvcRes == false)
                    {
                        arg.Publication.SubscribeSerialNbr = NBR_BASE_REALTIMEDISPLAY;
                        arg.Publication.obj                = OBJ_RealTimeDisplay;
                        arg.Publication.Data.Form.Idx      = 0;

                        FLocalCmd.OpCode           = REQ_VMS_MSG_DOWNLOAD;//REQ_VMS_LIB_DOWNLOAD;//REQ_VMS_MSG_DOWNLOAD;
                        FLocalCmd.obj              = OBJ_RealTimeDisplay;
                        FLocalCmd.DataPacketNumber = 0;
                        FLocalCmd.Idx              = nFormCnt;
                        break;
                    }
                }
            }
            arg.Publication.Data.Form.Mode = FVmsObj->CTLMODE->Control;
		}
		__finally
		{
			m_pVmsFormList->UnLock();
		}

        if (FLocalCmd.OpCode != 0x00)
        {
            result = ProcessSendPacket(FLocalCmd.OpCode, &arg);
            return result;
        }
	}

    ARequest = false;
	return result;
}
//---------------------------------------------------------------------------

/*
 *
 *  arguments
 *   void
 *  return
 *   void
 */
int __fastcall TVMSCThread::CheckClientData(bool &ARequest)
{
FErrLine = 24;
    int              nResult = VERR_NONE;
    IPCUDPPACKET    *pPI = NULL;
	TList           *pPackQueue;
	COMMAND_ARGUMENT arg;

    ARequest = false;

    try
	{
    	pPackQueue = FVmsObj->pPackQueue->LockList();

        int nCmdCnt = pPackQueue->Count;
        for (int ii = nCmdCnt-1; ii >= 0; ii--)
        {
            pPI = (IPCUDPPACKET *)pPackQueue->Items[ii];

            if (pPI->Data == NULL)
            {
                delete pPI;
                pPackQueue->Delete(ii);
                continue;
            }

            memset((char*)&FCliCmd, 0x00, sizeof(FCliCmd));
			memset((char*)&arg,     0x00, sizeof(arg));

            FCliCmd.OpCode           = 0x00;
            FCliCmd.obj              = OBJ_None;  /* EN_OBJECT_ID */
            FCliCmd.DataPacketNumber = 0;         /* DataPacket Number */
            FCliCmd.Idx              = 0;

            INT_VMS_POWER_CTL_REQ *pHd = (INT_VMS_POWER_CTL_REQ*)pPI->Data;
            memcpy(FCliCmd.VmsId,   pHd->VmsId,   INT_VMS_MAX_ID);
            memcpy(FCliCmd.OperId,  pHd->OperId,  INT_VMS_MAX_OPER_ID);
            memcpy(FCliCmd.CmdTime, pHd->CmdTime, INT_VMS_MAX_DATETIME);
            FCliCmd.Result = CTL_RESULT_FAIL;

            switch(pPI->OPCode)
            {
            case INT_OP_VMS_POWER_CTL:
                {
                    INT_VMS_POWER_CTL_REQ *pReq = (INT_VMS_POWER_CTL_REQ*)pPI->Data;

                    FCliCmd.OpCode = REQ_SIGNBOARD_POWER_CONTROL;

                    arg.Publication.SubscribeSerialNbr = NBR_MODULE_POWER;
                    arg.Publication.obj       = OBJ_StatusControl;
                    arg.Publication.Data.Ctl  = (pReq->Command == vms_board_power_on) ? 0x01 : 0x00;
                }
                break;

            case INT_OP_VMS_RESET:
                {
                    INT_VMS_RESET_REQ *pReq = (INT_VMS_RESET_REQ*)pPI->Data;

					FCliCmd.OpCode = REQ_VMS_INITIALIZE;
                }
                break;

            case INT_OP_VMS_DIRECT:
                {
                    INT_VMS_DIRECT_CTL_REQ *pReq = (INT_VMS_DIRECT_CTL_REQ*)pPI->Data;

					FCliCmd.OpCode = pReq->Command;
                }
                break;

            case INT_OP_VMS_LUMINANCE_CTL:
                {
                    INT_VMS_LUMINANCE_REQ *pReq = (INT_VMS_LUMINANCE_REQ*)pPI->Data;

                    arg.Publication.SubscribeSerialNbr = NBR_LUMINANCE;
                    arg.Publication.obj                = OBJ_StatusControl;
                    arg.Publication.Data.Ctl           = pReq->Luminance;

                    FCliCmd.OpCode = REQ_VMS_LUMINANCE_LEVEL_SET;
                }
                break;
            case INT_OP_VMS_PARA_SET2:
                {
                    INT_VMS_PARA_SET_REQ2 *pReq = (INT_VMS_PARA_SET_REQ2*)pPI->Data;

                    memcpy(FCliCmd.VmsId,   pReq->VmsId,   INT_VMS_MAX_ID);
                    memcpy(FCliCmd.OperId,  pReq->OperId,  INT_VMS_MAX_OPER_ID);
                    memcpy(FCliCmd.CmdTime, pReq->CmdTime, INT_VMS_MAX_DATETIME);

					arg.Publication.SubscribeSerialNbr  = NBR_STATUS_SETTING;
					arg.Publication.obj                 = OBJ_StatusSetting;

					arg.Publication.Data.Set2.DefCommErr        = pReq->DefCommErr;       // 통신장애 기본값, 제어기가 Host로부터 Poll 또는 명령을 받지 않고 경과할 수 있는 최대시간 (default ; 60초)
					arg.Publication.Data.Set2.SlotCommErr       = pReq->SlotCommErr;      // 통신장애 slot번호, 통신 fail 시 표시할 메시지 번호(default 0번)
					arg.Publication.Data.Set2.SlotPowerErr      = pReq->SlotPowerErr;     // 전원장애 slot번호, 전원장애 시 표시할 메시지 번호(default 0번)
					arg.Publication.Data.Set2.NightLuminance    = pReq->NightLuminance;   // 야간 휘도 값, 0x30 ~ 0x3F
					arg.Publication.Data.Set2.DayLuminance      = pReq->DayLuminance;     // 주간 휘도 값, 0x40 ~ 0x4F
					arg.Publication.Data.Set2.PhaseCycleTime    = pReq->PhaseCycleTime;   // phase시간주기, 장애시 phase주기 (default : 3초, 범위 : 0 ~ 10초)
					arg.Publication.Data.Set2.ModuleFailRate    = pReq->ModuleFailRate;   // 모듈장애율, 한개의 module을 장애로 처리하기 위한 장애 pixel백분율 (default 10%)
					arg.Publication.Data.Set2.ModuleCheckTime   = pReq->ModuleCheckTime;  // 모듈감시 주기, 0 ~ 255 (단위:초)
					arg.Publication.Data.Set2.BoardOnHour       = pReq->BoardOnHour;      // 전광판 On time(시), 0시 ~ 23시
					arg.Publication.Data.Set2.BoardOnMin        = pReq->BoardOnMin;       // 전광판 On time(분), 0시 ~ 23시
					arg.Publication.Data.Set2.BoardOffHour      = pReq->BoardOffHour;     // 전광판 Off time(시), 0시 ~ 23시
					arg.Publication.Data.Set2.BoardOffMin       = pReq->BoardOffMin;      // 전광판 Off time(분), 0시 ~ 23시


                    FVmsObj->VMS_CMNC_ERR_BASS_VAL  = (int)pReq->DefCommErr;
                    FVmsObj->CMNCFAIL_SLOT_NMBR     = (int)pReq->SlotCommErr;     // NUMBER(4)    Y    0        통신장애 SLOT 번호
                    FVmsObj->PWER_FAIL_SLOT_NMBR    = (int)pReq->SlotPowerErr;    // NUMBER(4)    Y    0        전원 장애 SLOT 번호
                    FVmsObj->VMS_NGHT_BRGH_STEP     = (int)pReq->NightLuminance;
                    FVmsObj->VMS_WEEK_BRGH_STEP     = (int)pReq->DayLuminance;
                    //FVmsObj->VMS_PHSE_CHNG_CYCL     = (int)pReq->PhaseCycleTime;
                    FVmsObj->VMS_MODL_ERR_RATE      = (int)pReq->ModuleFailRate;
                    FVmsObj->VMS_MODL_CHK_CYCL      = (int)pReq->ModuleCheckTime;

                    //m_State.ModuleOperatingTemperature = FVmsObj->VMS_CMNC_ERR_BASS_VAL; /* 필수 모듈 전원이 꺼지는 온도값(℃) */

#if 0
                    AnsiString sOn, sOff;
                    sOn.printf("%02d%02d", (int)pReq->BoardOnHour, (int)pReq->BoardOnMin);
                    sOff.printf("%02d%02d", (int)pReq->BoardOffHour, (int)pReq->BoardOffMin);
                    FVmsObj->MODULE.PowerOnTime  = Now().FormatString("yyyymmdd") + sOn;
                    FVmsObj->MODULE.PowerOffTime = Now().FormatString("yyyymmdd") + sOff;
#endif

					FCliCmd.OpCode = REQ_VMS_PARAM_DOWNLOAD;
                }
                break;
#if 0
            case INT_OP_VMS_PARA_SET:
                {
                    INT_VMS_PARA_SET_REQ *pReq = (INT_VMS_PARA_SET_REQ*)pPI->Data;

                    memcpy(FCliCmd.VmsId,   pReq->VmsId,   INT_VMS_MAX_ID);
                    memcpy(FCliCmd.OperId,  pReq->OperId,  INT_VMS_MAX_OPER_ID);
                    memcpy(FCliCmd.CmdTime, pReq->CmdTime, INT_VMS_MAX_DATETIME);

					arg.Publication.SubscribeSerialNbr  = NBR_STATUS_SETTING;
					arg.Publication.obj                 = OBJ_StatusSetting;

					arg.Publication.Data.Set.SchMsgTime = (int)pReq->SchMsgTime;
					arg.Publication.Data.Set.ModuleTemp = (int)pReq->ModuleTemp;
					arg.Publication.Data.Set.FanTemp    = (int)pReq->FanTemp;
					arg.Publication.Data.Set.HeaterTemp = (int)pReq->HeaterTemp;
					arg.Publication.Data.Set.ModuleFail = (int)pReq->ModuleFail;
					arg.Publication.Data.Set.RetryCount = (int)pReq->RetryCount;
					arg.Publication.Data.Set.TimeOut    = (int)pReq->TimeOut;

					FCliCmd.Data.Para.SchMsgTime = (int)pReq->SchMsgTime;
					FCliCmd.Data.Para.ModuleTemp = (int)pReq->ModuleTemp;
					FCliCmd.Data.Para.FanTemp    = (int)pReq->FanTemp;
					FCliCmd.Data.Para.HeaterTemp = (int)pReq->HeaterTemp;
					FCliCmd.Data.Para.ModuleFail = (int)pReq->ModuleFail;
					FCliCmd.Data.Para.RetryCount = (int)pReq->RetryCount;
					FCliCmd.Data.Para.TimeOut    = (int)pReq->TimeOut;

					FCliCmd.OpCode = CTL_TYPE_PARA_SET;
					FCliCmd.obj = AI_StatusSettingMessage;
                }
                break;
#endif
			default:
				nResult = VERR_UNKNOWN_COMMAND;
				break;
            }

			if (nResult == VERR_NONE)
            {
				nResult = ProcessSendPacket(FCliCmd.OpCode, &arg);
			}

			//ClientResponse(nResult);

			if (pPI->Size > 0)
            {
                delete []pPI->Data;
			}
            delete pPI;
            pPI = NULL;

			pPackQueue->Delete(ii);

            ARequest = true;
            break;
        }
    }
    __finally
    {
		FVmsObj->pPackQueue->UnlockList();
    }

    return nResult;
}
//---------------------------------------------------------------------------

void __fastcall TVMSCThread::ClientResponse(int error)
{
#ifdef CENTERCOMM
	BYTE ErrCode;
	int sResult;
	int Flag;
	bool bSave = false;

	switch(error)
	{
	case SYS_ERR_NONE:                 break;
	case SYS_ERR_OTHER:                ErrCode = INT_ERROR_OTHER; break;
	case SYS_ERR_INTERNAL:             ErrCode = INT_ERROR_SYSTEM; break;
	case SYS_ERR_MEMORY:               ErrCode = INT_ERROR_SYSTEM; break;
	case SYS_ERR_DATABASE:             ErrCode = INT_ERROR_SYSTEM; break;
	case SYS_ERR_RESET:                ErrCode = INT_ERROR_SYSTEM; break;
	case SYS_ERR_START:                ErrCode = INT_ERROR_SYSTEM; break;
	case SYS_ERR_OFFLINE:              ErrCode = INT_ERROR_OFFLINE; break;
	case SYS_ERR_NO_RES:               ErrCode = INT_ERROR_NO_RESPONSE; break;
	case SYS_ERR_ACCESS:               ErrCode = INT_ERROR_PROCESS; break;
	case SYS_ERR_INVALID:              ErrCode = INT_ERROR_OTHER; break;
	case SYS_ERR_UNKNOWN:              ErrCode = INT_ERROR_UNKNOWN_CODE; break;
	case SYS_ERR_WRITE_LENGTH:         ErrCode = INT_ERROR_OTHER; break;
	case SYS_ERR_PACKET_SIZE_LARGE:    ErrCode = INT_ERROR_OTHER; break;
	case SYS_ERR_INVALID_TAG:          ErrCode = INT_ERROR_OTHER; break;
	case SYS_ERR_CRC:                  ErrCode = INT_ERROR_OTHER; break;
	case SYS_ERR_LENGTH:               ErrCode = INT_ERROR_LENGTH; break;
	case SYS_ERR_ADDRESS:              ErrCode = INT_ERROR_ADDRESS; break;
	case SYS_ERR_HEADER_OPTIONS:       ErrCode = INT_ERROR_HEADER; break;
	case SYS_ERR_UNKNOWN_COMMAND:      ErrCode = INT_ERROR_UNKNOWN_OPCODE; break;
	case SYS_ERR_RECEIVE_TIMEOUT:      ErrCode = INT_ERROR_OTHER; break;
	case SYS_ERR_DATA_SIZE:            ErrCode = INT_ERROR_DISCORD; break;
	case SYS_ERR_MISMATCH:             ErrCode = INT_ERROR_OTHER; break;
	case SYS_ERR_INVALID_PARA:         ErrCode = INT_ERROR_INVALID_DATA; break;
	case SYS_ERR_MOVEMENT:             ErrCode = INT_ERROR_MOVEMENT; break;
	case SYS_ERR_UNAUTHORIZED:         ErrCode = INT_ERROR_UNAUTHORIZED; break;
	default:                           ErrCode = INT_ERROR_OTHER; break;
	}

	switch (m_Req.OpCode)
    {
	case INT_OP_VMS_POWER_CTL:      /* 0x0303 VMS 통신 서버, VMS 전광판 On/Off 제어 */
		if (error == SYS_ERR_NONE)
        {
			Flag = SEND_ACK;

			m_Set.Data.Control.Result = CTL_RESULT_SUCC;
		}
        else
        {
			Flag = SEND_NACK;
		}

		bSave = true;
		break;
	case INT_OP_VMS_PARA_SET:       /* 0x0308 VMS 통신 서버, VMS 환경설정정보 전송 */
		if (error == SYS_ERR_NONE)
        {
			Flag = SEND_ACK;

			bSave = true;
		}
        else
        {
			Flag = SEND_NACK;
		}
		break;
	case INT_OP_VMS_RESET:          /* 0x0309 VMS 통신 서버, VMS 제어기 리셋 전송 */
		if (error == SYS_ERR_NONE)
        {
			Flag = SEND_ACK;

			m_Set.Data.Control.Result = CTL_RESULT_SUCC;
		}
        else
        {
			Flag = SEND_NACK;
		}

		bSave = true;
		break;
	default:
		Flag = SEND_NONE;
        break;
	}

	if (bSave == true)
    {
		if ((sResult = SendDbThreadDataMessage(WM_DATA_SAVE, (void *)&m_Set, sizeof(m_Set))) != SYS_ERR_NONE)
		{
		}
	}

	if (Flag == SEND_ACK)
    {
		INT_ACK_RES Ack;

		memset(&Ack, 0x00, sizeof(Ack));

		Ack.OPCode.Type = INT_TYPE(m_Req.OpCode);
		Ack.OPCode.Kind = INT_KIND(m_Req.OpCode);
		Ack.MsgSeq = m_Req.MsgSeq;

		if ((sResult = AckRes(&Ack, m_Req.ProcessID)) != UDP_ERR_NONE)
        {
		}
	}
    else
    if (Flag == SEND_NACK)
    {
		INT_NACK_RES Nack;

		memset(&Nack, 0x00, sizeof(Nack));

		Nack.OPCode.Type = INT_TYPE(m_Req.OpCode);
		Nack.OPCode.Kind = INT_KIND(m_Req.OpCode);
		Nack.MsgSeq = m_Req.MsgSeq;
		Nack.ErrCode = ErrCode;

		if ((sResult = NackRes(&Nack, m_Req.ProcessID)) != UDP_ERR_NONE)
        {
		}
	}
#endif
}
//---------------------------------------------------------------------------

int __fastcall TVMSCThread::SendDbThreadMessage(UINT Msg, int wParam, int lParam)
{
    int result;

    result = SYS_ERR_OTHER;

	if (g_SysInfo->State.CommThreadID != NULL)
    {
		if (PostThreadMessage(g_SysInfo->State.CommThreadID, Msg, (WPARAM)wParam, (LPARAM)lParam))
        {
			result = SYS_ERR_NONE;
		}
        else
        {
            result = SYS_ERR_INTERNAL;
        }
    }

	return result;
}
//---------------------------------------------------------------------------

int __fastcall TVMSCThread::SendDbThreadDataMessage(UINT Msg, void *pData, int iLen)
{
    int   nResult;
    char *p;

	nResult = VERR_OTHER;

	if (g_SysInfo->State.CommThreadID != NULL)
    {
        p = new char[iLen];

		if (p != NULL)
        {
            try
            {
                memcpy(p, pData, iLen);

				if (PostThreadMessage(g_SysInfo->State.CommThreadID, Msg, (WPARAM)p, NULL))
                {
                    nResult = VERR_NONE;
                    Sleep(50);
                }
                else
                {
                    nResult = VERR_INTERNAL;
                }
            }
            __finally
            {
                if (nResult != VERR_NONE)
                {
                    delete []p;
                }
            }
        }
        else
        {
            nResult = VERR_MEMORY_ALLOC;
        }
    }

    return nResult;
}
//---------------------------------------------------------------------------

/*
 * 에러 처리
 *  arguments
 *   void
 *  return
 *   void
 */
int __fastcall TVMSCThread::ProcErrorState(bool flag, int result)
{
FErrLine = 14;
#if 1
    {
        AnsiString strLog;

		switch(result)
        {
        case SYS_ERR_NONE:                      strLog.sprintf("no error [%d]", result); break;
        case SYS_ERR_OTHER:                     strLog.sprintf("other [%d]", result); break;
        case SYS_ERR_INTERNAL:                  strLog.sprintf("internal system error(kernel..) [%d]", result); break;
        case SYS_ERR_MEMORY:                    strLog.sprintf("memory overflow [%d]", result); break;
        case SYS_ERR_DATABASE:                  strLog.sprintf("system database error [%d]", result); break;
        case SYS_ERR_RESET:                     strLog.sprintf("system reset [%d]", result); break;
        case SYS_ERR_START:                     strLog.sprintf("system start [%d]", result); break;
        case SYS_ERR_OFFLINE:                   strLog.sprintf("offline [%d]", result); break;
        case SYS_ERR_NO_RES:                    strLog.sprintf("no response [%d]", result); break;
        case SYS_ERR_ACCESS:                    strLog.sprintf("access denied [%d]", result); break;
        case SYS_ERR_INVALID:                   strLog.sprintf("invalid data type [%d]", result); break;
        case SYS_ERR_UNKNOWN:                   strLog.sprintf("unknown data type [%d]", result); break;
        case SYS_ERR_WRITE_LENGTH:              strLog.sprintf("write length [%d]", result); break;
		case SYS_ERR_PACKET_SIZE_LARGE:         strLog.sprintf("packet size large [%d]", result); break;
        case SYS_ERR_INVALID_TAG:               strLog.sprintf("invalid tag [%d]", result); break;
        case SYS_ERR_CRC:                       strLog.sprintf("crc [%d]", result); break;
        case SYS_ERR_LENGTH:                    strLog.sprintf("length [%d]", result); break;
        case SYS_ERR_ADDRESS:                   strLog.sprintf("address [%d]", result); break;
        case SYS_ERR_HEADER_OPTIONS:            strLog.sprintf("header options [%d]", result); break;
        case SYS_ERR_UNKNOWN_COMMAND:           strLog.sprintf("unknown command [%d]", result); break;
        case SYS_ERR_RECEIVE_TIMEOUT:           strLog.sprintf("receive timeout [%d]", result); break;
		case SYS_ERR_DATA_SIZE:                 strLog.sprintf("data size [%d]", result); break;
        case SYS_ERR_MISMATCH:                  strLog.sprintf("mismatch command [%d]", result); break;
        case SYS_ERR_INVALID_PARA:              strLog.sprintf("invalid parameter [%d]", result); break;
        case SYS_ERR_MOVEMENT:                  strLog.sprintf("movement [%d]", result); break;
        case SYS_ERR_UNAUTHORIZED:              strLog.sprintf("unauthorized [%d]", result); break;

		case SYS_ERR_DATEXDATAPACKET_DECODE:    		strLog.sprintf("DatexDataPacket decode [%d]", result); break;
		case SYS_ERR_INVALID_VERSION_NUMBER:    		strLog.sprintf("invalid version number [%d]", result); break;
		case SYS_ERR_C2CAUTHENTICATEDMESSAGE_DECODE:    strLog.sprintf("C2CAuthenticatedMessage decode [%d]", result); break;
		case SYS_ERR_C2CAUTHENTICATEDMESSAGE:   		strLog.sprintf("C2CAuthenticatedMessage [%d]", result); break;
		case SYS_ERR_NOT_LOGIN:              			strLog.sprintf("Not login [%d]", result); break;
		case SYS_ERR_ACCEPT_TYPE:              			strLog.sprintf("Accept Type [%d]", result); break;
		case SYS_ERR_DATEXPUBLISH_FORMAT:       		strLog.sprintf("datexPublish Format [%d]", result); break;
		case SYS_ERR_DATEXPUBLISH_TYPE:         		strLog.sprintf("datexPublish Type [%d]", result); break;
		case SYS_ERR_UNKNOWN_MESSAGE_ID:        		strLog.sprintf("unknown Message id [%d]", result); break;
		case SYS_ERR_MESSAGE_DECODE:            		strLog.sprintf("Message decode [%d]", result); break;
		case SYS_ERR_DATEXDATAPACKET_ENCODE:    		strLog.sprintf("DatexDataPacket encode [%d]", result); break;
		case SYS_ERR_C2CAUTHENTICATEDMESSAGE_ENCODE:	strLog.sprintf("C2CAuthenticatedMessage encode [%d]", result); break;
		case SYS_ERR_MESSAGE_ENCODE:            		strLog.sprintf("Message encode [%d]", result); break;
		case SYS_ERR_PUBLICATIONDATA_ENCODE:    		strLog.sprintf("PublicationData encode [%d]", result); break;
		case SYS_ERR_MISMATCH_DESTINATION_TEXT: 		strLog.sprintf("mismatch Destination text [%d]", result); break;
		case SYS_ERR_DATEXLOGIN_VALUE:          		strLog.sprintf("Login Value [%d]", result); break;
		case SYS_ERR_SUBSCRIPTION_TYPE:         		strLog.sprintf("SubscriptionType Type [%d]", result); break;
		case SYS_ERR_SUBSCRIPTION_STATUS_VALUE: 		strLog.sprintf("SubscriptionType Status Value [%d]", result); break;
		case SYS_ERR_SUBSCRIPTION_MODE_VALUE:   		strLog.sprintf("SubscriptionType Mode Value [%d]", result); break;
		case SYS_ERR_SUBSCRIPTION_FORMAT_VALUE: 		strLog.sprintf("SubscriptionType Format Value [%d]", result); break;
		case SYS_ERR_HANGUL_CONVERSION:         		strLog.sprintf("Hangul Conversion [%d]", result); break;
		case SYS_ERR_INVALID_TAGANDLEN:         		strLog.sprintf("invalid Tag And Len [%d]", result); break;
		case SYS_ERR_PUBLICATIONDATA_DECODE:    		strLog.sprintf("PublicationData decode [%d]", result); break;

		default:                                strLog.sprintf("Unknown Error [%d]", result); break;
        }

        if (flag){
            LERROR("Recv Error %s", strLog.c_str());
        }else{
			LERROR("Send Error %s", strLog.c_str());
        }
	}
#endif
    return 0;
}
//---------------------------------------------------------------------------

/*
 * 상태 변경
 *  arguments
 *   void
 *  return
 *   void
 */
int __fastcall TVMSCThread::SetClientState(int ACase)
{
FErrLine = 15;
	switch(FClient.State)
    {
	case CT_LOGIN_WAIT:
		if (ACase == SET_CLIENT_SUCC)
        {
            if (FVmsObj->FIsOldProtocol)
            {
                //정보요청을 등록해야함(기존 VMS)
                FClient.State  = CT_SECTION;//CT_REGIST;   //TODO
                FClient.reqStatusTimer = Now() - ITSCOMM_SECTIME(FClient.pollingCycleTime);
            }
            else
            {
                FClient.State  = CT_SECTION;
                FClient.reqStatusTimer = Now() - ITSCOMM_SECTIME(FClient.pollingCycleTime);
            }
		}
        else
        if (ACase == SET_CLIENT_FAIL)
        {
			FClient.State = CT_IDLE;
		}
		break;
	case CT_FRED_WAIT:
		FClient.State = CT_SECTION;
		break;
	case CT_LOCAL_WAIT:
		if (ACase == SET_CLIENT_SUCC)
        {
			FClient.State = CT_LOCAL_COMMAND;//CT_CLIENT_COMMAND;
		}
        else
        if (ACase == SET_CLIENT_FAIL)
        {
			FClient.State = CT_LOCAL_COMMAND;
		}
		break;
	case CT_CLIENT_WAIT:
		if (ACase == SET_CLIENT_SUCC)
        {
			FClient.State = CT_SECTION;
		}
        else
        if (ACase == SET_CLIENT_FAIL)
        {
			FClient.State = CT_CLIENT_COMMAND;
		}
		break;
	case CT_REGIST_WAIT:
		if (ACase == SET_CLIENT_SUCC)
        {
			FClient.State = CT_REGIST_COMMAND;
		}
        else
        if (ACase == SET_CLIENT_FAIL)
        {
			FClient.State = CT_CLIENT_COMMAND;
		}
		break;
	default:
		break;
	}
    return 0;
}
//---------------------------------------------------------------------------

void __fastcall TVMSCThread::InfoPacket(BYTE *ABuff, int ALen, bool ASend, int AResult/*=0*/)
{
    VMS_PACKET *Pkt = (VMS_PACKET*)ABuff;
    AnsiString  sCmd = "";
    ACK_NAK     res;
    bool        acknak = true;

	switch(Pkt->hd.OpCode)
    {
    case REQ_VMS_STATUS:
        acknak = false;
        if (ASend) sCmd = "REQ_VMS_STATUS";
        else       sCmd = "RES_VMS_STATUS";
        break;

    case REQ_VMS_MSG_DOWNLOAD:
        if (ASend) sCmd = "REQ_VMS_MSG_DOWNLOAD";
        else       sCmd = "RES_VMS_MSG_DOWNLOAD";
        break;

    case REQ_VMS_LIB_DOWNLOAD:
        if (ASend) sCmd = "REQ_VMS_LIB_DOWNLOAD";
        else       sCmd = "RES_VMS_LIB_DOWNLOAD";
        break;

    case REQ_VMS_PARAM_DOWNLOAD:
        if (ASend) sCmd = "REQ_VMS_PARAM_DOWNLOAD";
        else       sCmd = "RES_VMS_PARAM_DOWNLOAD";
        break;

    case REQ_VMS_BLANK_DISP:
        if (ASend) sCmd = "REQ_VMS_BLANK_DISP";
        else       sCmd = "RES_VMS_BLANK_DISP";
        break;

    case REQ_VMS_DEF_MSG_DISP:
        if (ASend) sCmd = "REQ_VMS_DEF_MSG_DISP";
        else       sCmd = "RES_VMS_DEF_MSG_DISP";
        break;

    case REQ_VMS_MODULE_STATUS:
        acknak = false;
        if (ASend) sCmd = "REQ_VMS_MODULE_STATUS";
        else       sCmd = "RES_VMS_MODULE_STATUS";
        break;

    case REQ_VMS_INITIALIZE:
        if (ASend) sCmd = "REQ_VMS_INITIALIZE";
        else       sCmd = "RES_VMS_INITIALIZE";
        break;

    case REQ_VMS_LUMINANCE_LEVEL_SET:
        if (ASend) sCmd = "REQ_VMS_LUMINANCE_LEVEL_SET";
        else       sCmd = "RES_VMS_LUMINANCE_LEVEL_SET";
        break;

    case REQ_SIGNBOARD_POWER_CONTROL:
        if (ASend) sCmd = "REQ_SIGNBOARD_POWER_CONTROL";
        else        sCmd = "RES_SIGNBOARD_POWER_CONTROL";
        break;

    default:
        if (ASend) LERROR("Send Unknown OpCode: %02X, %d Bytes", Pkt->hd.OpCode, ALen);
        else       LERROR("Recv Unknown OpCode: %02X, %d Bytes", Pkt->hd.OpCode, ALen);
        return;
    }

    if (ASend)
    {
        if (AResult == SYS_ERR_NONE)
            LINFO("Send: %s, %d Bytes", sCmd.c_str(), ALen);
        else
            LINFO("Send Fail: %s, %d Bytes", sCmd.c_str(), ALen);
    }
    else
    {
        if (acknak)
        {
            res.ack = ABuff[POS_ACKNAK];
            if (res.ack == 0x00)
                LINFO("Recv: %s, %d Bytes", sCmd.c_str(), ALen);
            else
                LINFO("Recv: %s, %d Bytes, NAK(%d,%d,%d,%d,%d)", sCmd.c_str(), ALen,
                    res.nak.crc,
                    res.nak.cmd,
                    res.nak.dat,
                    res.nak.nbr,
                    res.nak.chk
                );
        }
        else
        {
            LINFO("Recv: %s, %d Bytes", sCmd.c_str(), ALen);
        }
    }
}
//---------------------------------------------------------------------------

void TVMSCThread::ReqStatus()
{
    try
    {
        FClient.reqStatusTimer = Now() - ITSCOMM_SECTIME(FClient.pollingCycleTime+10);
    }
    catch(Exception &e)
    {
    }
}
//---------------------------------------------------------------------------

int TVMSCThread::LogData(char *ASndRcv, BYTE *AData, int ALen)
{
    int result = -1;
    int nStep = 0;

    if (!FLogFile) return result;
    if (!FLogFile->FLogCfg.Data) return result;

    try
    {
        FLogFile->LogData(ASndRcv, AData, ALen);

        if (FVmsObj->FDispLog)
        {
            IPC_LOG_MESSAGE *pLog = &FLogMsg;//new IPC_LOG_MESSAGE;
            if (pLog)
            {
                pLog->Kind = eLOG_DATA;
                pLog->Flag = ASndRcv[0] == 'S' ? 1 : 2;
                pLog->Len  = ALen > MAX_LOG_BUFFER ? MAX_LOG_BUFFER-1 : ALen;
                pLog->Tm   = Now();
                pLog->Type = 'C';
                memset(pLog->Msg, 0x00, sizeof(pLog->Msg));
                memcpy(pLog->Msg, (char*)AData, pLog->Len);
                pLog->Obj  = (void*)FVmsObj;

                DWORD dwResult = 0;
                LRESULT lResult = SEND_LOGMSG(FrmVmsLog->Handle, WM_LOG_DISPLAY, (WPARAM)pLog, NULL, SMTO_NORMAL, 2000, dwResult);
                if (lResult == 0)
                {
                    dwResult = GetLastError();
                    if (dwResult == ERROR_TIMEOUT)
                    {
                    }
                    //SAFE_DELETE(pLog);
                }
            }
        }
    }
    catch(Exception &e)
    {
    }
    return result;
}
//---------------------------------------------------------------------------

int TVMSCThread::SysLogWrite(int ALogKind, char *AFmt, ...)
{
    va_list     ap;
    int         cnt = 0;
    char        szFmtData[MAX_LOG_BUFFER];
    AnsiString  sLogKind;
    int         nStep = 0;

    if (!FLogFile) return cnt;

    bool bLog = false;
    switch(ALogKind)
    {
    case eLOG_INFO   : bLog = FLogFile->FLogCfg.Info;    sLogKind = " [INF] "; break;
    case eLOG_DATA   : bLog = FLogFile->FLogCfg.Data;    sLogKind = " [DAT] "; break;
    case eLOG_ERROR  : bLog = FLogFile->FLogCfg.Error;   sLogKind = " [ERR] "; break;
    case eLOG_WARNING: bLog = FLogFile->FLogCfg.Warning; sLogKind = " [WAN] "; break;
    case eLOG_DEBUG  : bLog = FLogFile->FLogCfg.Debug;   sLogKind = " [DBG] "; break;
    case eLOG_DETAIL : bLog = FLogFile->FLogCfg.Detail;  sLogKind = " [DET] "; break;
    }
    if (!bLog) return -1;

    try
    {
        va_start(ap, AFmt);
        cnt = vsprintf(szFmtData, AFmt, ap);
        va_end(ap);

        FLogFile->LogWrite(NULL, ALogKind, szFmtData);

        IPC_LOG_MESSAGE *pLog = &FLogMsg;//new IPC_LOG_MESSAGE;
        if (pLog)
        {
            pLog->Kind = ALogKind;
            pLog->Flag = 0;
            pLog->Len  = strlen(szFmtData);
            pLog->Tm   = Now();
            pLog->Type = 'C';
            memset(pLog->Msg,  0x00, sizeof(pLog->Msg));
            sprintf(pLog->Msg, "%s-CLI %s, %s", sLogKind.c_str(), VMSID.c_str(), szFmtData);
            pLog->Obj  = (void*)FVmsObj;

            DWORD   dwResult = 0;
            LRESULT lResult = SEND_LOGMSG(FrmSysLog->Handle, WM_LOG_DISPLAY, pLog, NULL, SMTO_NORMAL, 2000, dwResult);
            if (lResult == 0)
            {
                dwResult = GetLastError();
                if (dwResult == ERROR_TIMEOUT)
                {
                }
                //SAFE_DELETE(pLog);
            }
        }

        if (FVmsObj->FDispLog)
        {
            IPC_LOG_MESSAGE *pLog2 = &FLogMsg;//new IPC_LOG_MESSAGE;
            if (pLog2)
            {
                pLog2->Kind = ALogKind;
                pLog2->Flag = 0;
                pLog2->Len  = strlen(szFmtData);
                pLog2->Tm   = Now();
                pLog2->Type = 'C';
                memset(pLog2->Msg,  0x00, sizeof(pLog2->Msg));
                sprintf(pLog2->Msg, "%s-CLI %s, %s", sLogKind.c_str(), VMSID.c_str(), szFmtData);
                pLog2->Obj  = (void*)FVmsObj;

                DWORD   dwResult = 0;
                LRESULT lResult = SEND_LOGMSG(FrmVmsLog->Handle, WM_LOG_DISPLAY, pLog2, NULL, SMTO_NORMAL, 2000, dwResult);
                if (lResult == 0)
                {
                    dwResult = GetLastError();
                    if (dwResult == ERROR_TIMEOUT)
                    {
                    }
                    //SAFE_DELETE(pLog2);
                }
            }
        }
    }
    catch(Exception &e)
    {
    }
    return cnt;
}
//---------------------------------------------------------------------------

int TVMSCThread::LogWrite(int ALogKind, char *AFmt, ...)
{
    va_list     ap;
    int         cnt = 0;
    char        szFmtData[MAX_LOG_BUFFER];
    AnsiString  sLogKind;
    int         nStep = 0;

    if (!FLogFile) return cnt;

    bool bLog = false;
    switch(ALogKind)
    {
    case eLOG_INFO   : bLog = FLogFile->FLogCfg.Info;    sLogKind = " [INF] "; break;
    case eLOG_DATA   : bLog = FLogFile->FLogCfg.Data;    sLogKind = " [DAT] "; break;
    case eLOG_ERROR  : bLog = FLogFile->FLogCfg.Error;   sLogKind = " [ERR] "; break;
    case eLOG_WARNING: bLog = FLogFile->FLogCfg.Warning; sLogKind = " [WAN] "; break;
    case eLOG_DEBUG  : bLog = FLogFile->FLogCfg.Debug;   sLogKind = " [DBG] "; break;
    case eLOG_DETAIL : bLog = FLogFile->FLogCfg.Detail;  sLogKind = " [DET] "; break;
    }
    if (!bLog) return -1;

    try
    {
        va_start(ap, AFmt);
        cnt = vsprintf(szFmtData, AFmt, ap);
        va_end(ap);

        FLogFile->LogWrite(NULL, ALogKind, szFmtData);

        if (FVmsObj->FDispLog)
        {
            IPC_LOG_MESSAGE *pLog = &FLogMsg;//new IPC_LOG_MESSAGE;
            if (pLog)
            {
                pLog->Kind = ALogKind;
                pLog->Flag = 0;
                pLog->Len  = strlen(szFmtData);
                pLog->Tm   = Now();
                pLog->Type = 'C';
                memset(pLog->Msg,  0x00, sizeof(pLog->Msg));
                sprintf(pLog->Msg, "%s-CLI %s, %s", sLogKind.c_str(), VMSID.c_str(), szFmtData);
                pLog->Obj  = (void*)FVmsObj;

                DWORD   dwResult = 0;
                LRESULT lResult = SEND_LOGMSG(FrmVmsLog->Handle, WM_LOG_DISPLAY, pLog, NULL, SMTO_NORMAL, 2000, dwResult);
                if (lResult == 0)
                {
                    dwResult = GetLastError();
                    if (dwResult == ERROR_TIMEOUT)
                    {
                    }
                    //SAFE_DELETE(pLog);
                }
            }
        }
    }
    catch(Exception &e)
    {
    }
    return cnt;
}
//---------------------------------------------------------------------------

