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


#pragma hdrstop

#include "VMSCThread.h"
#include "VMSCThreadSendF.h"

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

#pragma package(smart_init)

/*
 * 송신 패킷 처리
 *  arguments
 *   void
 *  return
 *   void
 */
int __fastcall TVMSCThread::ProcessSendPacket(BYTE AOpCode, COMMAND_ARGUMENT *AArg)
{
FErrLine = 10;
    VMS_PACKET *Pkt    = (VMS_PACKET*)m_TxBuff;
    int         result = SYS_ERR_NONE;
	int         nData  = 0;
    int         sndLen = 0;

    unsigned crc;
	unsigned short year, mon, day;
	unsigned short hour, min, sec, msec;

	Now().DecodeDate(&year, &mon, &day);
	Now().DecodeTime(&hour, &min, &sec, &msec);

    Pkt->hd.STX    = VMS_STX;   // STX, 0x02
    Pkt->hd.ID     = 0x00;      // Reserved, 0x00
    Pkt->hd.OpCode = AOpCode;   // OpCode
    sprintf(Pkt->hd.ADDR, "%04d", FVmsObj->Id); // Address

	switch(AOpCode)
    {
    case REQ_VMS_STATUS://                  0x50        // Status 요청,  센터->VMS
        Pkt->data[nData++] = (BYTE)HIBYTE(year);
        Pkt->data[nData++] = (BYTE)LOBYTE(year);
        Pkt->data[nData++] = (BYTE)mon;
        Pkt->data[nData++] = (BYTE)day;
        Pkt->data[nData++] = (BYTE)hour;
        Pkt->data[nData++] = (BYTE)min;
        Pkt->data[nData++] = (BYTE)sec;
        break;
    case REQ_VMS_MSG_DOWNLOAD://            0x51        // 문안 전송 요청, 센터->VMS
        nData = MakeMsgDownload(Pkt->data, AArg);
        if (nData <= 0)
        {
            LERROR(">>> MakeMsgDownload Faild");
            return SYS_ERR_DATABASE;
        }
        break;
    case REQ_VMS_LIB_DOWNLOAD://            0x52        // Library download 요청, 센터->VMS
        nData = MakeLibDownload(Pkt->data, AArg);
        if (nData <= 0)
        {
            LERROR(">>> MakeLibDownload Faild");
            return SYS_ERR_DATABASE;
        }
        break;
    case REQ_VMS_PARAM_DOWNLOAD://          0x53        // Parameter download 요청, 센터->VMS
		Pkt->data[nData++] = AArg->Publication.Data.Set2.DefCommErr;                           // 통신장애 기본값, 제어기가 Host로부터 Poll 또는 명령을 받지 않고 경과할 수 있는 최대시간 (default ; 60초)
		Pkt->data[nData++] = (BYTE)HIBYTE(AArg->Publication.Data.Set2.SlotCommErr);                          // 통신장애 slot번호, 통신 fail 시 표시할 메시지 번호(default 0번)
		Pkt->data[nData++] = (BYTE)LOBYTE(AArg->Publication.Data.Set2.SlotCommErr);                          // 통신장애 slot번호, 통신 fail 시 표시할 메시지 번호(default 0번)
		Pkt->data[nData++] = (BYTE)HIBYTE(AArg->Publication.Data.Set2.SlotPowerErr);                         // 전원장애 slot번호, 전원장애 시 표시할 메시지 번호(default 0번)
		Pkt->data[nData++] = (BYTE)LOBYTE(AArg->Publication.Data.Set2.SlotPowerErr);                         // 전원장애 slot번호, 전원장애 시 표시할 메시지 번호(default 0번)
		Pkt->data[nData++] = AArg->Publication.Data.Set2.NightLuminance;                       // 야간 휘도 값, 0x30 ~ 0x3F
		Pkt->data[nData++] = AArg->Publication.Data.Set2.DayLuminance;                         // 주간 휘도 값, 0x40 ~ 0x4F
		Pkt->data[nData++] = AArg->Publication.Data.Set2.PhaseCycleTime;                       // phase시간주기, 장애시 phase주기 (default : 3초, 범위 : 0 ~ 10초)
		Pkt->data[nData++] = AArg->Publication.Data.Set2.ModuleFailRate;                       // 모듈장애율, 한개의 module을 장애로 처리하기 위한 장애 pixel백분율 (default 10%)
		Pkt->data[nData++] = AArg->Publication.Data.Set2.ModuleCheckTime;                      // 모듈감시 주기, 0 ~ 255 (단위:초)
		Pkt->data[nData++] = AArg->Publication.Data.Set2.BoardOnHour;                          // 전광판 On time(시), 0시 ~ 23시
		Pkt->data[nData++] = AArg->Publication.Data.Set2.BoardOnMin;                           // 전광판 On time(분), 0시 ~ 23시
		Pkt->data[nData++] = AArg->Publication.Data.Set2.BoardOffHour;                         // 전광판 Off time(시), 0시 ~ 23시
	    Pkt->data[nData++] = AArg->Publication.Data.Set2.BoardOffMin;                          // 전광판 Off time(분), 0시 ~ 23시
#if 0
11 통신장애 기본값 제어기가 Host로부터 Poll 또는 명령을 받지 않고 경과할 수 있는 최대시간 (default ; 60초)
12 통신장애 slot번호 통신 fail 시 표시할 메시지 번호(default 0번)
13
14 전원장애 slot번호 전원장애 시 표시할 메시지 번호(default 0번)
15
16 야간 휘도 값 0x30 ~ 0x3F
17 주간 휘도 값 0x40 ~ 0x4F
18 phase시간주기 장애시 phase주기 (default : 3초, 범위 : 0 ~ 10초)
19 모듈장애율 한개의 module을 장애로 처리하기 위한 장애 pixel백분율 (default 10%)
20 모듈감시 주기 0 ~ 255 (단위:초)
21 전광판 On time(시) 0시 ~ 23시 0x00000000 : 없음
22 전광판 On time(분) 0분 ~ 59분
23 전광판 Off time(시) 0시 ~ 23시
24 전광판 Off time(분) 0분 ~ 59분
#endif
        break;
    case REQ_VMS_BLANK_DISP://              0x54        // Blank 요청, 센터->VMS
        //설정데이터없이 헤더로 정보로 전송
        break;
    case REQ_VMS_DEF_MSG_DISP://            0x55        // Default message display 요청, 센터->VMS
        //설정데이터없이 헤더로 정보로 전송
        break;
    case REQ_VMS_MODULE_STATUS://           0x56        // Module status upload 요청, 센터->VMS
        //설정데이터없이 헤더로 정보로 전송
        break;
    case REQ_VMS_INITIALIZE://              0x57        // Initialize 요청, 센터->VMS
        //설정데이터없이 헤더로 정보로 전송
        break;
    case REQ_VMS_LUMINANCE_LEVEL_SET://     0x58        // Luminance level set 요청, 센터->VMS
        Pkt->data[nData++] = AArg->Publication.Data.Ctl;
        break;
    case REQ_SIGNBOARD_POWER_CONTROL://     0x59        // Signboard power control 요청, 센터->VMS
        Pkt->data[nData++] = AArg->Publication.Data.Ctl;
        break;
	default:
        LERROR(">>> Unknown ProcessSendPacket: 0x%02X", AOpCode);
        return SYS_ERR_UNKNOWN_COMMAND;
	}

#if 0
BYTE    STX;
BYTE    ID;
BYTE    OpCode;
UINT    Size;
char    ADDR[4];
char    DATA[n];
char    CRC[2];
char    ETX;
#endif
    sndLen = nData+1+1+4+4+2; // ID부터 CRC까지의 전체 길이(byte order준수)
    Pkt->hd.Size = CommUtil_swapl((DWORD)sndLen);

    crc = CommUtil_MakeCrc16((void*)&Pkt->hd.ID, (WORD)(sndLen-2));    //ID부터 DATA까지의 CRC-16 생성다항식에 의해 계산된 값
    Pkt->data[nData++] = HIBYTE(crc);   // CRC
    Pkt->data[nData++] = LOBYTE(crc);   // CRC
    Pkt->data[nData++] = VMS_ETX;       // ETX, 0x03

    result = SendPacket((BYTE*)Pkt, sndLen+2);  //STX+Pkt->Size+ETX

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

int __fastcall TVMSCThread::MakeMsgDownload(BYTE *ABuff, COMMAND_ARGUMENT *AArg)
{
	int nData  = 0;
    int nForms = 0;
    unsigned int nImgSize;

	TVmsForm  *pVmsForm = NULL;

	AnsiString MessageId;
	int        ii;
    bool       bException = false;

    try
    {
        m_pVmsFormList->Lock();
        int nFormCnt = m_pVmsFormList->Count();
        if (nFormCnt > 9) nFormCnt = 9;
        if (nFormCnt <= 0)
        {
            SERROR("Msg Download Form Count is zero ! ! !");
            return -1;
        }

        ABuff[nData++] = 0x07;  // 정지화면 (Stationary)
        ABuff[nData++] = 0x02;  // Left(오른쪽에서 왼쪽으로)

        int nDispTime = FVmsObj->VMS_PHSE_CHNG_CYCL;
        if (FVmsObj->VMS_PHSE_CHNG_CYCL <  3) nDispTime = 3;
        if (FVmsObj->VMS_PHSE_CHNG_CYCL > 10) nDispTime = 10;

        ABuff[nData++] = (BYTE)nDispTime;//0x05;  // 표출 시간/기간

        ABuff[nData++] = (BYTE)nFormCnt-1;  // PHASE 갯수(0x00-1EA, 0x01 ~ 0x08=9EA)

LDEBUG("Display Time: %d sec, Forms: %d", nDispTime, nFormCnt);
        for (int ii = 0; ii < nFormCnt; ii++)
        {
            pVmsForm = m_pVmsFormList->GetItem(ii);
            if (!pVmsForm)
            {
                SERROR("Msg FormId Memory Not Found: %d", ii);
                continue;
            }
#if 0
            LINFO("            pVmsForm->DisplayTime: %d", pVmsForm->DisplayTime);
            LINFO("pVmsForm->DisplayMode.ToIntDef(0): %d", pVmsForm->DisplayMode.ToIntDef(0));
            LINFO(" pVmsForm->DisplayDir.ToIntDef(0): %d", pVmsForm->DisplayDir.ToIntDef(0));
            LINFO("          pVmsForm->pStream->Size: %d", pVmsForm->pStream->Size);
#endif

            nImgSize = pVmsForm->pStream->Size;

            ABuff[nData++] = 'G';   //G: 그래픽, T: Text, B: Bar, S: Symbol
            ABuff[nData++] = (BYTE)(nImgSize >> 24) & 0xFFFFFFFF;
            ABuff[nData++] = (BYTE)(nImgSize >> 16) & 0xFFFFFFFF;
            ABuff[nData++] = (BYTE)(nImgSize >>  8) & 0xFFFFFFFF;
            ABuff[nData++] = (BYTE)(nImgSize      ) & 0xFFFFFFFF;

            try
            {
                pVmsForm->pStream->Position = 0;
                memcpy((char*)&ABuff[nData], (char *)pVmsForm->pStream->Memory, nImgSize);
                nData += nImgSize;
            }
            catch(Exception &e)
            {
                bException = true;
                SERROR("MemoryStream Allocation error: %s, FormId: %s", AnsiString(e.Message).c_str(), pVmsForm->FormId.c_str());
            }
        }
    }
    __finally
    {
        m_pVmsFormList->UnLock();
    }

    return nData;
}
//---------------------------------------------------------------------------

int __fastcall TVMSCThread::MakeLibDownload(BYTE *ABuff, COMMAND_ARGUMENT *AArg)
{
	int nData  = 0;
    int nForms = 0;
    unsigned int nImgSize;

	TVmsForm  *pVmsForm = NULL;

	AnsiString MessageId;
	int        ii;
    bool       bException = false;

    try
    {
        m_pVmsFormList->Lock();
        int nFormCnt = m_pVmsFormList->Count();
        if (nFormCnt > 9) nFormCnt = 9;
        if (nFormCnt <= 0)
        {
            SERROR("Msg Download Form Count is zero ! ! !");
            return -1;
        }

#if 0
□ LIBRARY 메시지 번호의 범위
  - Text Message Number			    : 1000 - 5999
  - Graphic Symbol Message Number	: 6000 - 8999
  - Full Graphic Message Number		: 9000 - 9999
  - Message Number 0 은 Default Message
#endif

        int nLibNo = 0;
        ABuff[nData++] = 0x07;  // 정지화면 (Stationary)
        ABuff[nData++] = 0x02;  // Left(오른쪽에서 왼쪽으로)

        ABuff[nData++] = (BYTE)(nLibNo >>  8) & 0xFFFFFFFF;
        ABuff[nData++] = (BYTE)(nLibNo      ) & 0xFFFFFFFF;

        ABuff[nData++] = (BYTE)nFormCnt;  // PHASE 갯수(0x00-1EA, 0x01 ~ 0x08=9EA)

LDEBUG("Lib Download: Forms: %d", nFormCnt);

        for (int ii = 0; ii < nFormCnt; ii++)
        {
            pVmsForm = m_pVmsFormList->GetItem(ii);
            if (!pVmsForm)
            {
                SERROR("Msg FormId Memory Not Found: %d", ii);
                continue;
            }
#if 0
            LINFO("            pVmsForm->DisplayTime: %d", pVmsForm->DisplayTime);
            LINFO("pVmsForm->DisplayMode.ToIntDef(0): %d", pVmsForm->DisplayMode.ToIntDef(0));
            LINFO(" pVmsForm->DisplayDir.ToIntDef(0): %d", pVmsForm->DisplayDir.ToIntDef(0));
            LINFO("          pVmsForm->pStream->Size: %d", pVmsForm->pStream->Size);
#endif

            nImgSize = pVmsForm->pStream->Size;

            ABuff[nData++] = 'S';   //G: 그래픽, T: Text, B: Bar, S: Symbol
            ABuff[nData++] = (BYTE)(nImgSize >> 24) & 0xFFFFFFFF;
            ABuff[nData++] = (BYTE)(nImgSize >> 16) & 0xFFFFFFFF;
            ABuff[nData++] = (BYTE)(nImgSize >>  8) & 0xFFFFFFFF;
            ABuff[nData++] = (BYTE)(nImgSize      ) & 0xFFFFFFFF;

            try
            {
                pVmsForm->pStream->Position = 0;
                memcpy((char*)&ABuff[nData], (char *)pVmsForm->pStream->Memory, nImgSize);
                nData += nImgSize;
            }
            catch(Exception &e)
            {
                bException = true;
                SERROR("MemoryStream Allocation error: %s, FormId: %s", AnsiString(e.Message).c_str(), pVmsForm->FormId.c_str());
            }
        }
    }
    __finally
    {
        m_pVmsFormList->UnLock();
    }

    return nData;
}
//---------------------------------------------------------------------------

/*
 * 패킷 송신
 *  arguments
 *   void
 *  return
 *   void
 */
int __fastcall TVMSCThread::SendPacket(BYTE *ACmdBuff, int AReqSendLen)
{
    int result = SYS_ERR_NONE;

    try
    {
        int nSendBytes = TcpClient->SendBuf(ACmdBuff, AReqSendLen);
        if (nSendBytes == AReqSendLen)
        {
            FClient.sendRetry--;
            FClient.sendTimer = Now();
        }
        else
        {
            result = SYS_ERR_WRITE_LENGTH;
        }

        if (SYS_ERR_NONE == result) LogData("SEND",      ACmdBuff, AReqSendLen);
        else                        LogData("SEND Fail", ACmdBuff, nSendBytes);

        InfoPacket(ACmdBuff, nSendBytes, true, result);
    }
    catch(Exception &e)
    {
        result = SYS_ERR_MEMORY;
    }
	return result;
}
//---------------------------------------------------------------------------

