shjung 2 years ago
parent
commit
15d36494fc

+ 0 - 1
conf/vms-comm-server.pid

@@ -1 +0,0 @@
-256076

+ 26 - 38
src/main/java/com/its/vms/dto/TbVmsCtlrDto.java

@@ -18,9 +18,11 @@ import com.its.vms.xnettcp.vms.handler.VmsServerIdleStateHandler;
 import com.its.vms.xnettcp.vms.process.TcpServerSendData;
 import com.its.vms.xnettcp.vms.process.TcpServerSendDataProcess;
 import com.its.vms.xnettcp.vms.protocol.VmsReqFramePacket;
-import com.its.vms.xnettcp.vms.protocol.dto.*;
+import com.its.vms.xnettcp.vms.protocol.dto.VmsFormDataDto;
+import com.its.vms.xnettcp.vms.protocol.dto.VmsFormDto;
+import com.its.vms.xnettcp.vms.protocol.dto.VmsFormObj;
+import com.its.vms.xnettcp.vms.protocol.dto.VmsFormObjBitmapId;
 import com.its.vms.xnettcp.vms.protocol.enums.eVmsFileSaveLocation;
-import com.its.vms.xnettcp.vms.protocol.enums.eVmsFormObjectKind;
 import com.its.vms.xnettcp.vms.protocol.enums.eVmsImageType;
 import com.its.vms.xnettcp.vms.protocol.enums.eVmsOpCode;
 import com.its.vms.xnettcp.vms.protocol.impl.*;
@@ -34,7 +36,6 @@ import java.io.Serializable;
 import java.net.InetSocketAddress;
 import java.nio.ByteBuffer;
 import java.text.SimpleDateFormat;
-import java.util.List;
 import java.util.Map;
 import java.util.Timer;
 import java.util.concurrent.ConcurrentHashMap;
@@ -543,7 +544,7 @@ public class TbVmsCtlrDto implements Serializable {
             //e_vms_file_download          = 0x82,//    데이터 다운로드                         송신    INI, CFG , Bitmap , Data파일송신            센터 → VMS
             //e_vms_download_schedule_form = 0x96,//    Display Schedule Form                   송신    계획된 Form 표출 요구                       센터 → VMS
             //e_vms_blank                  = 0x9E,//    Blank                                   송신    schedule 표출                               센터 → VMS
-            downloadDefaultFrom();
+            downloadDefaultForm();
         }
         else {
             // 스케쥴 모드인 경우(A:자동, F:고정)
@@ -561,48 +562,31 @@ public class TbVmsCtlrDto implements Serializable {
      * 제어기에서 FID0000 인 폼이 기본 표출폼 이기 때문이다.
      * @return
      */
-    public boolean downloadDefaultFrom() {
+    public boolean downloadDefaultForm() {
         // Download Form  (기본폼은 하나의 폼에 여러폼을 다운로드한다.)
         int formCnt = this.downloadData.getMaxSchedule();
         if (formCnt <= 0) {
-            log.info("downloadDefaultFrom: VMS {}, Download Schedule Form Count Zero. {} EA.", this.vmsCtlrNmbr, formCnt);
+            log.info("downloadDefaultForm: VMS {}, Download Schedule Form Count Zero. {} EA.", this.vmsCtlrNmbr, formCnt);
             return true;
         }
 
-        log.info("downloadDefaultFrom: VMS {}, Form {} EA.", this.vmsCtlrNmbr, formCnt);
-        VmsFormDataDto formData = new VmsFormDataDto(0, formCnt);
+        log.info("downloadDefaultForm: VMS {}, Form {} EA.", this.vmsCtlrNmbr, formCnt);
+        VmsFormDataDto formData = new VmsFormDataDto(VmsConstants.DEFAULT_FORM_ID, formCnt);
         VmsDownloadData.VmsDownloadDataInfo[] units = this.downloadData.getUnits();
         for (int ii = 0; ii < formCnt; ii++) {
             VmsForm pForm = this.formManager.getItem(units[ii].getFormIdx());
-            List<VmsFormObject> objects = pForm.getObjects();
-            VmsFormDto formDto = formData.addForm(units[ii].getVmsFormId(), units[ii].getDisplaySec(), units[ii].getDisplayType(), units[ii].getBkClr(), objects.size());
-            for (int jj = 0; jj < objects.size(); jj++) {
-                VmsFormObject formObj = objects.get(jj);
-
-                int objSize = formObj.getObjectSize();
-                int blinking = formObj.getBlinking();
-                int posX = formObj.getPosX();
-                int posY = formObj.getPosY();
-                int bkClr = formObj.getBkColor();
-
-                VmsFormObj formObjDto;
-                if (objects.get(jj).getObjectKind() == eVmsFormObjectKind.OBJECT_TEXT) {
-                    int clrR = formObj.getFontClr().getRed();
-                    int clrG = formObj.getFontClr().getGreen();
-                    int clrB = formObj.getFontClr().getBlue();
-                    formObjDto = new VmsFormObjText(objSize, blinking, posX, posY, bkClr, clrR, clrG, clrB, formObj.getFontSize(), formObj.getFontNameCd(), formObj.getFontBold(), formObj.getTextData());
-                }
-                else if (objects.get(jj).getObjectKind() == eVmsFormObjectKind.OBJECT_BITMAP_ID) {
-                    formObjDto = new VmsFormObjBitmapId(objSize, blinking, posX, posY, bkClr, formObj.getDsplWidth(), formObj.getDsplHeight(), eVmsImageType.VMS_IMAGE_TYPE_BMP.getValue(), units[ii].getBitmapId());
-                }
-                else {
-                    //formObjDto = new VmsFormObjBitmapId(objSize, blinking, posX, posY, bkClr, object.getDsplWidth(), object.getDsplHeight(), eVmsImageType.VMS_IMAGE_TYPE_BMP.getValue(), units[ii].getBitmapId());
-                    formObjDto = new VmsFormObjBitmap(objSize, blinking, posX, posY, bkClr, formObj.getDsplWidth(), formObj.getDsplHeight(), eVmsImageType.VMS_IMAGE_TYPE_BMP.getValue(), formObj.getImageData());
-                }
-                formObjDto.calSize();
-                formDto.addObject(formObjDto);
-            }
-            formDto.calObjCount();
+
+            int bitmapId = units[ii].getBitmapId();
+            int objSize = 1;
+            int blinking = pForm.getVmsFormDsplMthdCd();
+            int posX = 0;
+            int posY = 0;
+            int bkClr = units[ii].getBkClr();
+
+            VmsFormDto formDto = formData.addForm(units[ii].getVmsFormId(), units[ii].getDisplaySec(), units[ii].getDisplayType(), units[ii].getBkClr(), objSize);
+            VmsFormObj formObjDto= new VmsFormObjBitmapId(objSize, blinking, posX, posY, bkClr, this.vmsWidth, this.vmsHeight, eVmsImageType.VMS_IMAGE_TYPE_BMP.getValue(), bitmapId);
+            formObjDto.calSize();
+            formDto.addObject(formObjDto);
         }
         formData.calFormCount();
 
@@ -782,7 +766,11 @@ public class TbVmsCtlrDto implements Serializable {
         log.info("downloadFormSchedule: VMS {}, Schedule {} EA, Default Schedule {}.", this.vmsCtlrNmbr, formCnt, this.downloadData.isDefault());
         if (this.downloadData.isDefault()) {
             formId[0] = (short)VmsConstants.DEFAULT_FORM_ID;
-            dispSec[0] = 4;
+            dispSec[0] = 0;
+            VmsDownloadData.VmsDownloadDataInfo[] units = this.downloadData.getUnits();
+            for (int ii = 0; ii < formCnt; ii++) {
+                dispSec[0] += units[ii].getDisplaySec();
+            }
             log.info("downloadFormSchedule: VMS {}, Schedule {} EA, Default Schedule {}.", this.vmsCtlrNmbr, formCnt, this.downloadData.isDefault());
         }
         else {

+ 657 - 0
src/main/java/com/its/vms/dto/TbVmsCtlrDtoBack.java

@@ -0,0 +1,657 @@
+package com.its.vms.dto;
+
+import com.its.app.AppUtils;
+import com.its.vms.config.ApplicationConfig;
+import com.its.vms.domain.*;
+import com.its.vms.domain.enums.eVmsFormType;
+import com.its.vms.domain.task.VmsCommandTimeoutTask;
+import com.its.vms.entity.TbVmsCtlrStts;
+import com.its.vms.entity.TbVmsCtrlHs;
+import com.its.vms.entity.VmsCtlrParam;
+import com.its.vms.process.DbmsData;
+import com.its.vms.process.DbmsDataProcess;
+import com.its.vms.process.DbmsDataType;
+import com.its.vms.service.VmsFormService;
+import com.its.vms.xnettcp.vms.protocol.VmsReqFramePacket;
+import com.its.vms.xnettcp.vms.protocol.dto.*;
+import com.its.vms.xnettcp.vms.protocol.enums.eVmsFileSaveLocation;
+import com.its.vms.xnettcp.vms.protocol.enums.eVmsFormObjectKind;
+import com.its.vms.xnettcp.vms.protocol.enums.eVmsImageType;
+import com.its.vms.xnettcp.vms.protocol.impl.VmsReqBlank;
+import com.its.vms.xnettcp.vms.protocol.impl.VmsReqDataDownload;
+import com.its.vms.xnettcp.vms.protocol.impl.VmsReqDownloadForm;
+import com.its.vms.xnettcp.vms.protocol.impl.VmsReqDownloadFormSchedule;
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelFuture;
+import lombok.*;
+import lombok.extern.slf4j.Slf4j;
+
+import java.io.Serializable;
+import java.net.InetSocketAddress;
+import java.nio.ByteBuffer;
+import java.util.List;
+import java.util.Map;
+import java.util.Timer;
+import java.util.concurrent.ConcurrentHashMap;
+
+@Slf4j
+@Getter
+@Setter
+@ToString
+@Builder
+@NoArgsConstructor//(access = AccessLevel.PROTECTED)
+@AllArgsConstructor
+public class TbVmsCtlrDtoBack implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    private int  index;
+    private Long vmsCtlrNmbr;
+    private Long groupNo;
+    private Integer ctlrLocalNo;
+    private String ctlrId;
+    private String name;
+    private String ctlrIp;
+    private String ctlrPort;
+    private String usagTypeCd;
+    private String frmTypeCd;
+    private String typeCd;
+    private String modlTypeCd;
+    private String operMode;
+    private Integer cmncfailSlotNmbr;
+    private Integer pwerFailSlotNmbr;
+    private String cmtrinfrCnctYn;
+    private String wthrinfrCnctYn;
+    private String envrinfrCnctYn;
+    private Integer maxPhaseNum;
+    private String istlLctnNm;
+    private String istlLctnAddr;
+    private String trfcStrgUseYn;
+    private Long locIfscId;
+
+    private Integer defPhseChngCycl;    // 기본메시지주기
+    private String panlOnTime;          // 전광판 ON TIME
+    private String panlOffTime;         // 전광판 OFF TIME
+    private Integer panlPwerMode;        // 전광판 전원 모드(0x00:꺼짐,0x01:켜짐,0x02:자동,0x09:알수없음)
+    private Integer fanMode;            // FAN 동작모드(0x00:꺼짐,0x01:켜짐,0x02:자동,0x09:알수없음)
+    private Integer fanRunTmpr;          // 팬 동작 온도
+    private Integer hetrMode;           // 히터 동작모드(0x00:꺼짐,0x01:켜짐,0x02:자동,0x09:알수없음)
+    private Integer hetrRunTmpr;         // 히터 동작 온도
+    private Integer brghMode;           // 휘도 모드(0x00:주간,0x01:야간,0x02:자동,0x09:수동)
+    private Integer brghCurrStep;       // 휘도 현재 단계(0~100)
+    private Integer brghWeekStep;       // 휘도 주간 단계(0~100)
+    private Integer brghNghtStep;       // 휘도 야간 단계(0~100)
+    private Integer modlErrRate;        // VMS 모듈 오류 율
+    private Integer cmncFailRate;       // VMS 통신 오류 기본 값
+
+    private Integer protocolVer;
+    private String delYn;
+
+    private int vmsWidth;
+    private int vmsHeight;
+    private int modlRowNum;
+    private int modlColNum;
+    private int powrRowNum;
+    private int powrColNum;
+
+    private String localFormDir;
+    private String ftpFormDir;
+    private boolean ftpDownload;
+    private boolean symbolDownload;
+
+    private int maxCngstForm;        // 정체폼 생성 최대 갯수
+    private int cngstForms;
+    private boolean existCngsForm;
+    private boolean provide;
+    private boolean evehIngForm;
+    private boolean evehEndForm;
+
+    private VmsFormManager formManager;
+
+    /**
+     * VMS 메시지 생성 메모리
+     */
+    private VmsEvehicle evechile;
+    private VmsSchedule schedule;   // 스케쥴 정보
+    private VmsEvent incident;      // 돌발정보
+    private VmsEvent event;         // 공사행사정보
+
+    private VmsModule module;
+    private VmsLuminance luminance;
+    private VmsControlMode controlMode;
+    private byte txtOpCode;
+
+    private TbVmsCtlrStts     stts;
+    private int 			  netState;
+    private boolean           isDupCon;
+    private boolean           isDupLogin;
+    private String 		      dstIpAddr;
+    private Channel           channel = null;
+    private Channel           dupChannel = null;
+    private InetSocketAddress cliReq;
+    private long              syncTime;
+    private VmsFrameSequence  seq;
+
+    private Integer downloadFormId;
+    private VmsDownloadFile downloadFile;           // 제어기로 다운로드할 파일정보(TB_VMS_DOWNLOAD)
+    private VmsDownloadData downloadData;           // 제어기로 다운로드할 파일 데이터
+    private ConcurrentHashMap<Integer, VmsDownloadForm> downloadFormMap = null;
+    private ConcurrentHashMap<Integer, TbVmsSymbLibDnldDto> dnldSymbMap = null;
+    private ConcurrentHashMap<Integer, VmsScheduleSymbDto> reqDnldSymbMap;
+    Integer dnldSymbLibNmbr;
+
+    private ConcurrentHashMap<Long, TbVmsRltnIfscDto> rltnIfscMap = null;   // VMS 에 설정된 VMS 정보제공구간 목록
+
+    private ConcurrentHashMap<Short, Timer> registeredCommandTimer = null;
+    private ConcurrentHashMap<Short, VmsCommandTimeoutTask> registeredCommand = null;
+
+    private ConcurrentHashMap<Long, TbVmsCtrlHs> userCommands = null;
+
+    private int connectCount;
+    private String connectTm;
+    private String disConnectTm;
+    private long lastRecvTime;
+
+    /**
+     * Channel Send Data
+     * @param packet
+     * @param retryCnt
+     * @return
+     */
+    public synchronized boolean sendData(VmsReqFramePacket packet, int retryCnt) {
+        boolean result = false;
+
+        ByteBuffer sendBuffer = packet.getByteBuffer();
+        String packetDesc = packet.getOpCodeDesc();
+
+        log.info("~REQUEST-{}. VMS {}, {} Bytes.", packetDesc, this.vmsCtlrNmbr, sendBuffer.capacity());
+        if (this.channel != null) {
+            ChannelFuture f = this.channel.writeAndFlush(sendBuffer);
+            f.awaitUninterruptibly();
+            if (f.isDone() || f.isSuccess()) {
+                result = true;
+            } else {
+                log.error("~REQUEST-{}. VMS {}, sendData Failed. {} Bytes.", packetDesc, this.vmsCtlrNmbr, sendBuffer.array().length);
+            }
+        } else {
+            log.error("~REQUEST-{}. VMS {}, sendData Failed. Not Connected. {} Bytes.", packetDesc, this.vmsCtlrNmbr, sendBuffer.array().length);
+        }
+        if (result) {
+            //VmsCommandTimeoutTask cmdTimeoutTask = new VmsCommandTimeoutTask(this, packet, retryCnt);
+            //addRegisteredCommandsTimer(cmdTimeoutTask);
+        }
+        return result;
+    }
+
+    /**
+     * 제어기에 메시지를 표출하기 위한 작업.
+     * 1. 제어기에 표출할 폼 정보를 다운로드 한다. - downloadForm
+     * 2. 파일 다운로드(이미지, 심볼) - downloadFile
+     * 3. 폼 스케쥴 다운로드 - downloadFormSchedule
+     * 4. Blank - downloadBlank
+     * @return
+     */
+    public boolean downloadForm() {
+        VmsFormService formService = (VmsFormService) AppUtils.getBean(VmsFormService.class);
+        this.txtOpCode = (byte)0x00;
+        this.downloadData.init();
+
+        int forms = 0;
+        int formCnt = this.formManager.count();
+        if (formCnt == 0) {
+            log.info("downloadForm: VMS {}, Form Data Not Found.", this.vmsCtlrNmbr);
+            return true;
+        }
+        if (formCnt > this.maxPhaseNum) {
+            log.error("downloadForm: VMS {}, Form Count Over: {}/{} EA.", this.vmsCtlrNmbr, formCnt, this.maxPhaseNum);
+            formCnt = this.maxPhaseNum;
+        }
+
+        VmsDownloadData.VmsDownloadDataInfo[] units = this.downloadData.getUnits();
+        for (int ii = 0; ii < formCnt; ii++) {
+            VmsForm pForm = this.formManager.getItem(ii);
+            if (!pForm.isSuccess()) {
+                log.error("downloadForm: VMS {}, SEQ {}, SUCCESS {}", this.vmsCtlrNmbr, ii, pForm.isSuccess());
+                continue;
+            }
+            Integer vmsFormId = pForm.getVmsFormId();
+            TbVmsFormDto vmsForm = formService.find(vmsFormId);
+            if (vmsForm == null) {
+                log.error("downloadForm: VMS {}, SEQ {}, FORM ID {} Not Found.", this.vmsCtlrNmbr, ii, vmsFormId);
+                continue;
+            }
+
+            units[forms].setVmsFormId(vmsFormId);
+            units[forms].setDownload(true);
+            units[forms].setFormIdx(ii);
+            //units[forms].setBitmapId(forms + 1000);
+            units[forms].setBitmapId(pForm.getDnldFormNo());
+            units[forms].setFormNo(9000 + forms);
+            units[forms].setDisplaySec(pForm.getDsplHh());
+            units[forms].setDisplayType(pForm.getVmsFormDsplMthdCd());
+            units[forms].setBkClr(pForm.getVmsFormColrCd());
+
+            if (vmsForm.getVmsFormTypeCd() == eVmsFormType.eFormTp_hongbo.getValue()) {
+                // 다운로드 할 폼이 홍보폼이면 여러번 다운로드 하지 않도록 메모리에서 관리하자.
+                VmsDownloadForm downloadForm = this.downloadFormMap.get(vmsFormId);
+                if (downloadForm != null) {
+                    // 이전에 다운로드한 폼 정보가 존재하면
+                    if (!vmsForm.getUpdtDt().equals(downloadForm.getUpdtDt())) {
+                        // 업데이트시각이 다르기때문에 신규폼으로 판단한다.
+                        downloadForm.setAlreadyDownload(false);
+                        downloadForm.setUpdtDt(vmsForm.getUpdtDt());
+                        units[forms].setDownload(true); // 현재 스케쥴폼으로 다운로드 플래그 설정
+                    }
+                    if (downloadForm.isAlreadyDownload()) {
+                        // 이미 이전에 다운로드를 했기때문에 이번에는 제어기로 다운로드를 하지 않는다.
+                        units[forms].setDownload(false);
+                    }
+                }
+                else {
+                    // 이전에 다운로드 한 정보가 없기때문에 메모리에 저장해 놓는다.
+                    downloadForm = new VmsDownloadForm();
+                    downloadForm.setVmsFormId(vmsFormId);
+                    downloadForm.setAlreadyDownload(false);
+                    downloadForm.setUpdtDt(vmsForm.getUpdtDt());
+                    this.downloadFormMap.put(vmsFormId, downloadForm);
+                }
+            }
+
+            forms++;
+        }
+
+        for (int ii = 0; ii < forms; ii++) {
+            log.info("downloadForm: VMS {}, Form schedule({}), VMS_FORM_ID: {}, FormIdx: {}, FormId: {}, BitmapId: {}, IsDownload: {}",
+                    this.vmsCtlrNmbr, ii, units[ii].getVmsFormId(), units[ii].getFormIdx(), units[ii].getFormNo(), units[ii].getBitmapId(), units[ii].isDownload());
+        }
+
+        this.downloadData.setMaxSchedule(forms);
+        this.downloadData.setDownloadCnt(0);
+        this.downloadData.setDefault("B".equals(this.operMode));
+        if (this.downloadData.isDefault()) {
+            // 기본모드인 경우
+            // 폼 ID "FID0000" 에 여러개의 폼을 다운로드 해야함.
+            //e_vms_download_form          = 0x9A,//    Download Form                           송신    Form download                               센터 → VMS
+            //e_vms_file_download          = 0x82,//    데이터 다운로드                         송신    INI, CFG , Bitmap , Data파일송신            센터 → VMS
+            //e_vms_download_schedule_form = 0x96,//    Display Schedule Form                   송신    계획된 Form 표출 요구                       센터 → VMS
+            //e_vms_blank                  = 0x9E,//    Blank                                   송신    schedule 표출                               센터 → VMS
+            downloadDefaultForm();
+        }
+        else {
+            // 스케쥴 모드인 경우(A:자동, F:고정)
+            //e_vms_download_form          = 0x9A,//    Download Form                           송신    Form download                               센터 → VMS
+            //e_vms_file_download          = 0x82,//    데이터 다운로드                         송신    INI, CFG , Bitmap , Data파일송신            센터 → VMS
+            //e_vms_download_schedule_form = 0x96,//    Display Schedule Form                   송신    계획된 Form 표출 요구                       센터 → VMS
+            //e_vms_blank                  = 0x9E,//    Blank                                   송신    schedule 표출                               센터 → VMS
+            downloadAutoFixForm();
+        }
+        return true;
+    }
+
+    /**
+     * 기본 스케쥴의 폼 정보는 하나의 폼 패킷에 다운로드 해야 여러 폼을 표출할 수 있다.
+     * 제어기에서 FID0000 인 폼이 기본 표출폼 이기 때문이다.
+     * @return
+     */
+    public boolean downloadDefaultForm() {
+        // Download Form  (기본폼은 하나의 폼에 여러폼을 다운로드한다.)
+        int formCnt = this.downloadData.getMaxSchedule();
+        if (formCnt <= 0) {
+            log.info("downloadDefaultForm: VMS {}, Download Schedule Form Count Zero. {} EA.", this.vmsCtlrNmbr, formCnt);
+            return true;
+        }
+
+        log.info("downloadDefaultForm: VMS {}, Form {} EA.", this.vmsCtlrNmbr, formCnt);
+        VmsFormDataDto formData = new VmsFormDataDto(0, formCnt);
+        VmsDownloadData.VmsDownloadDataInfo[] units = this.downloadData.getUnits();
+        for (int ii = 0; ii < formCnt; ii++) {
+            VmsForm pForm = this.formManager.getItem(units[ii].getFormIdx());
+            List<VmsFormObject> objects = pForm.getObjects();
+            VmsFormDto formDto = formData.addForm(units[ii].getVmsFormId(), units[ii].getDisplaySec(), units[ii].getDisplayType(), units[ii].getBkClr(), objects.size());
+            for (int jj = 0; jj < objects.size(); jj++) {
+                VmsFormObject formObj = objects.get(jj);
+
+                int objSize = formObj.getObjectSize();
+                int blinking = formObj.getBlinking();
+                int posX = formObj.getPosX();
+                int posY = formObj.getPosY();
+                int bkClr = formObj.getBkColor();
+
+                VmsFormObj formObjDto;
+                if (objects.get(jj).getObjectKind() == eVmsFormObjectKind.OBJECT_TEXT) {
+                    int clrR = formObj.getFontClr().getRed();
+                    int clrG = formObj.getFontClr().getGreen();
+                    int clrB = formObj.getFontClr().getBlue();
+                    formObjDto = new VmsFormObjText(objSize, blinking, posX, posY, bkClr, clrR, clrG, clrB, formObj.getFontSize(), formObj.getFontNameCd(), formObj.getFontBold(), formObj.getTextData());
+                }
+                else if (objects.get(jj).getObjectKind() == eVmsFormObjectKind.OBJECT_BITMAP_ID) {
+                    formObjDto = new VmsFormObjBitmapId(objSize, blinking, posX, posY, bkClr, formObj.getDsplWidth(), formObj.getDsplHeight(), eVmsImageType.VMS_IMAGE_TYPE_BMP.getValue(), units[ii].getBitmapId());
+                }
+                else {
+                    //formObjDto = new VmsFormObjBitmapId(objSize, blinking, posX, posY, bkClr, object.getDsplWidth(), object.getDsplHeight(), eVmsImageType.VMS_IMAGE_TYPE_BMP.getValue(), units[ii].getBitmapId());
+                    formObjDto = new VmsFormObjBitmap(objSize, blinking, posX, posY, bkClr, formObj.getDsplWidth(), formObj.getDsplHeight(), eVmsImageType.VMS_IMAGE_TYPE_BMP.getValue(), formObj.getImageData());
+                }
+                formObjDto.calSize();
+                formDto.addObject(formObjDto);
+            }
+            formDto.calObjCount();
+        }
+        formData.calFormCount();
+
+        VmsReqDownloadForm downloadForm = new VmsReqDownloadForm(null/*this*/, formData);
+        return sendData(downloadForm, 1);
+    }
+
+    /**
+     * 자동 및 고정 스케쥴인 경우 폼정보 하나를 하나의 패킷으로 전송한다.
+     * @return
+     */
+    public boolean downloadAutoFixForm() {
+        // Download Form  (패킷하나에 하나의 폼 정보를 다운로드한다.)
+        ApplicationConfig config = (ApplicationConfig)AppUtils.getBean(ApplicationConfig.class);
+        int formCnt = this.downloadData.getMaxSchedule();
+        if (formCnt <= 0) {
+            log.info("downloadAutoFixForm: VMS {}, Download Schedule Form Count Zero. {} EA.", this.vmsCtlrNmbr, formCnt);
+            return true;
+        }
+        int downloadCnt = this.downloadData.getDownloadCnt();
+        log.info("downloadAutoFixForm: VMS {}, Schedule Form {} EA, Download Count {} EA.", this.vmsCtlrNmbr, formCnt, downloadCnt);
+        if (downloadCnt >= formCnt) {
+            // 폼정보를 모두 다운로드 했기때문에 폼파일을 다운로드 해야 한다.
+            this.downloadData.setDownloadCnt(0); // 폼이미지파일을 다운로드해야 하기때문에 다운로드 인덱스를 다시 0으로 리셋
+            return downloadFile();
+        }
+
+        // 폼아이디는 제어기가 최초에 접속했을때 한번만 내려보내기 때문에
+        // 폼아이디를 여기서 설정해 주어야 한다.
+        VmsDownloadData.VmsDownloadDataInfo[] units = this.downloadData.getUnits();
+        int formId   = units[downloadCnt].getFormNo();
+        int downloadFormCnt = 1;
+        int displaySec = 1;//units[downloadCnt].getDisplaySec();
+        int displayType = units[downloadCnt].getDisplayType();
+        int bitmapId = units[downloadCnt].getBitmapId();
+        int formIdx  = units[downloadCnt].getFormIdx();
+        VmsForm pForm = this.formManager.getItem(formIdx);
+        int objSize = 1;
+        int blinking = pForm.getVmsFormDsplMthdCd();
+        int posX = 0;
+        int posY = 0;
+        int bkClr = units[downloadCnt].getBkClr();
+
+        VmsFormDataDto formData = new VmsFormDataDto(formId, downloadFormCnt);
+        VmsFormDto formDto = formData.addForm(formId, displaySec, displayType, bkClr, objSize);
+        VmsFormObj formObjDto= new VmsFormObjBitmapId(objSize, blinking, posX, posY, bkClr, this.vmsWidth, this.vmsHeight, eVmsImageType.VMS_IMAGE_TYPE_BMP.getValue(), bitmapId);
+        formObjDto.calSize();
+        formDto.addObject(formObjDto);
+        formData.calFormCount();
+
+        this.downloadData.setDownloadCnt(downloadCnt+1);
+
+        log.info("downloadAutoFixForm: VMS {}, Schedule Form {} EA, Download Count {} EA, VmsFormId {}, FormId {}, BitmapId {}.",
+                this.vmsCtlrNmbr, formCnt, downloadCnt+1, pForm.getVmsFormId(), formId, bitmapId);
+
+//        VmsFormDataDto formData = new VmsFormDataDto(formId, downloadFormCnt);
+//        int ii = downloadCnt;
+//        VmsForm pForm = this.formManager.getItem(units[ii].getFormIdx());
+//        List<VmsFormObject> objects = pForm.getObjects();
+//        VmsFormDto formDto = formData.addForm(units[ii].getVmsFormId(), units[ii].getDisplaySec(), units[ii].getDisplayType(), units[ii].getBkClr(), objects.size());
+//        for (int jj = 0; jj < objects.size(); jj++) {
+//            VmsFormObject formObj = objects.get(jj);
+//
+//            int objSize = formObj.getObjectSize();
+//            int blinking = formObj.getBlinking();
+//            int posX = formObj.getPosX();
+//            int posY = formObj.getPosY();
+//            int bkClr = formObj.getBkColor();
+//
+//            String fileName = String.format("C:\\DRIVE_E\\ANDONG_VMS_FTP\\FORM\\%d_%d_%d-%d-%d-%d-%d.bmp", this.vmsCtlrNmbr, ii, jj, posX, posY, formObj.getDsplWidth(), formObj.getDsplHeight());
+//
+//            VmsFormObj formObjDto;
+//            if (objects.get(jj).getObjectKind() == eVmsFormObjectKind.OBJECT_TEXT) {
+//                int clrR = formObj.getFontClr().getRed();
+//                int clrG = formObj.getFontClr().getGreen();
+//                int clrB = formObj.getFontClr().getBlue();
+//                int fontNameCd = formObj.getFontNameCd();
+//                formObjDto = new VmsFormObjText(objSize, blinking, posX, posY, bkClr, clrR, clrG, clrB, formObj.getFontSize(), fontNameCd, formObj.getFontBold(), formObj.getTextData());
+//            }
+//            else if (objects.get(jj).getObjectKind() == eVmsFormObjectKind.OBJECT_BITMAP_ID) {
+//                //formObjDto = new VmsFormObjBitmapId(objSize, blinking, posX, posY, bkClr, object.getDsplWidth(), object.getDsplHeight(), eVmsImageType.VMS_IMAGE_TYPE_BMP.getValue(), units[ii].getBitmapId());
+//                ItsUtils.saveByteArrayToFile(fileName, formObj.getImageData());
+//                formObjDto = new VmsFormObjBitmap(objSize, blinking, posX, posY, bkClr, formObj.getDsplWidth(), formObj.getDsplHeight(), eVmsImageType.VMS_IMAGE_TYPE_BMP.getValue(), formObj.getImageData());
+//            }
+//            else {
+//                //formObjDto = new VmsFormObjBitmapId(objSize, blinking, posX, posY, bkClr, object.getDsplWidth(), object.getDsplHeight(), eVmsImageType.VMS_IMAGE_TYPE_BMP.getValue(), units[ii].getBitmapId());
+//                ItsUtils.saveByteArrayToFile(fileName, formObj.getImageData());
+//                formObjDto = new VmsFormObjBitmap(objSize, blinking, posX, posY, bkClr, formObj.getDsplWidth(), formObj.getDsplHeight(), eVmsImageType.VMS_IMAGE_TYPE_BMP.getValue(), formObj.getImageData());
+//            }
+//            formObjDto.calSize();
+//            formDto.addObject(formObjDto);
+//        }
+//        formDto.calObjCount();
+//        formData.calFormCount();
+
+        VmsReqDownloadForm downloadForm = new VmsReqDownloadForm(null/*this*/, formData);
+        return sendData(downloadForm, 1);
+    }
+
+    /**
+     * 폼 이미지 및 기타 폼에 표출할 심볼 이미지가 다운로드 완료가 된후에 스케쥴 정보를 표출하도록 한다.
+     * @return
+     */
+    public boolean downloadFile() {
+        int formCnt = this.downloadData.getMaxSchedule();
+        if (formCnt <= 0) {
+            log.info("downloadFile: VMS {}, Download Schedule Form Count Zero. {} EA.", this.vmsCtlrNmbr, formCnt);
+            return true;
+        }
+
+        int downloadCnt = this.downloadData.getDownloadCnt();
+        log.info("downloadFile: VMS {}, Schedule Form {} EA, Download Count {} EA.", this.vmsCtlrNmbr, formCnt, downloadCnt);
+        if (downloadCnt >= formCnt) {
+            // 폼파일이(폼이미지파일) 모두 다운로드 되었으므로 스케쥴 정보를 다운로드 한다.
+            return downloadFormSchedule();  // Display Schedule Form
+        }
+
+        this.downloadFormId = 0;
+        ApplicationConfig config = (ApplicationConfig)AppUtils.getBean(ApplicationConfig.class);
+        VmsDownloadData.VmsDownloadDataInfo[] units = this.downloadData.getUnits();
+        for (int ii = downloadCnt; ii < formCnt; ii++) {
+            this.downloadData.setDownloadCnt(downloadCnt+1);
+
+            int vmsFormId = units[ii].getVmsFormId();
+            int formId    = units[ii].getFormNo();
+            int bitmapId  = units[ii].getBitmapId();
+            int formIdx   = units[ii].getFormIdx();
+            VmsForm pForm = this.formManager.getItem(formIdx);
+
+            if (pForm.getVmsFormTypeCd() == eVmsFormType.eFormTp_hongbo.getValue()) {
+                // 홈보폼인 경우 다운로드 폼 ID를 저장해 놓는다.
+                this.downloadFormId = vmsFormId;
+            }
+
+            if (config.isCheckNewForm() && !units[ii].isDownload()) {
+                // 이미 다운로드 했기 때문에 다시 다운로드 하지 않는다.
+                log.info("downloadFile: VMS {}, IDX {}, VmsFormId {}, FormId {}, BitmapId {}, formIdx {}, DownloadFormID: {}, already download...",
+                        this.vmsCtlrNmbr, ii, vmsFormId, formId, bitmapId, formIdx, this.downloadFormId);
+                this.downloadFormId = 0;
+                continue;
+            }
+
+            log.info("downloadFile: VMS {}, Idx {}, VmsFormId {}, FormId {}, BitmapId {}, formIdx {}, DownloadFormID: {}",
+                    this.vmsCtlrNmbr, ii, pForm.getVmsFormId(), formId, bitmapId, formIdx, this.downloadFormId);
+
+            String fileName = String.format("BID%04d.BMP", bitmapId);
+            eVmsFileSaveLocation saveLoc = eVmsFileSaveLocation.LOC_DOWNLOAD_PROG_IMAGE;
+
+            VmsReqDataDownload dataDownload = new VmsReqDataDownload(null/*this*/, saveLoc, fileName, pForm.getImageData());
+            return sendData(dataDownload, 1);
+        }
+
+        // 폼이미지 정보가 모두 다운로드 되었으므로 스케쥴 정보를 다운로드 한다.
+        return downloadFormSchedule();  // Display Schedule Form
+    }
+
+    /**
+     * 제어기에 표출할 폼의 스케쥴 정보를 다운로드 한다.
+     * @return
+     */
+    public boolean downloadFormSchedule() {
+        // 도로공사 표준에 최대 10개의 스케쥴을 사용하도록 되어 있음.
+        int maxSchedule = VmsConstants.VMS_MIN_DOWNLOAD_FORMS;
+        int formCnt = this.downloadData.getMaxSchedule();
+        if (formCnt <= 0) {
+            log.info("downloadScheduleForm: VMS {}, Download Schedule Form Count Zero. {} EA.", this.vmsCtlrNmbr, formCnt);
+            return true;
+        }
+
+        short[] formId = new short[maxSchedule];
+        byte[] dispSec = new byte[maxSchedule];
+        for (int ii = 0; ii < maxSchedule; ii++) {
+            formId[ii] = 0;
+            dispSec[ii] = 0;
+        }
+
+        log.info("downloadFormSchedule: VMS {}, Schedule {} EA, Default Schedule {}.", this.vmsCtlrNmbr, formCnt, this.downloadData.isDefault());
+        if (this.downloadData.isDefault()) {
+            formId[0] = (short)VmsConstants.DEFAULT_FORM_ID;
+            dispSec[0] = 4;
+            log.info("downloadFormSchedule: VMS {}, Schedule {} EA, Default Schedule {}.", this.vmsCtlrNmbr, formCnt, this.downloadData.isDefault());
+        }
+        else {
+            for (int ii = 0; ii < formCnt && ii < maxSchedule; ii++) {
+                formId[ii] = (short) this.downloadData.getUnits()[ii].getFormNo();
+                dispSec[ii] = (byte)(this.downloadData.getUnits()[ii].getDisplaySec() & 0xFF);
+                log.info("downloadFormSchedule: VMS {}, Schedule {} EA, Idx {}, FormId {}, DisplayTm {}.", this.vmsCtlrNmbr, formCnt, ii+1, formId[ii], dispSec[ii]);
+            }
+        }
+
+        VmsReqDownloadFormSchedule downloadFormSchedule = new VmsReqDownloadFormSchedule(null/*this*/, formId, dispSec);
+        return sendData(downloadFormSchedule, 1);
+    }
+
+    /**
+     * 스케쥴을 표출하도록 Blank 명령을 전송한다.
+     * @return
+     */
+    public boolean downloadBlank() {
+        log.info("downloadBlank: VMS {}.", this.vmsCtlrNmbr);
+        VmsReqBlank reqBlank = new VmsReqBlank(null);//this);
+        return sendData(reqBlank, 1);
+    }
+
+    /**
+     * 제어기로 심벌라이브러리를 다운로드한다.
+     * @return
+     */
+    public boolean downloadSymbLib() {
+        this.dnldSymbLibNmbr = 0;
+        if (this.reqDnldSymbMap.size() == 0) {
+            return false;
+        }
+
+        VmsScheduleSymbDto dnldSymb = null;
+        for (Map.Entry<Integer, VmsScheduleSymbDto> e : this.reqDnldSymbMap.entrySet()) {
+            dnldSymb = e.getValue();
+            break;
+        }
+
+        if (dnldSymb != null) {
+            this.dnldSymbLibNmbr = dnldSymb.getDnldSymbLibNmbr();
+            String fileName = String.format("BID%04d.BMP", this.dnldSymbLibNmbr);
+            eVmsFileSaveLocation saveLoc = eVmsFileSaveLocation.LOC_DOWNLOAD_PROG_IMAGE;
+
+            VmsReqDataDownload dataDownload = new VmsReqDataDownload(null/*this*/, saveLoc, fileName, dnldSymb.getImageData());
+            sendData(dataDownload, 1);
+            return true;
+        }
+        return false;
+    }
+/*
+    private int   powerCtrlMode;  // 전원제어 모드                1 Byte  0x00 : 꺼짐, 0x01 : 켜짐,
+    private int   fanRunMode;     // Fan 동작모드                 1 Byte  0x00 : 꺼짐, 0x01 : 켜짐, 0x02 : 자동, 0x09: Unknown
+    private int   fanRunTemp;     // Fan 의 동작개시온도          1 Byte  온도( 0x00 ~0x03f )
+    private int   heaterRunMode;  // Heater 의 동작모드           1 Byte  0x00 : 꺼짐, 0x01 : 켜짐, 0x02 : 자동, 0x09: Unknown
+    private int   heaterRunTemp;  // Heater 의 동작개시온도       1 Byte  온도(0x00 ~ 0x3f )
+    private int   brightMode; // 화면의 밝기 - 휘도 모드, 0x00:주간, 0x01:야간, 0x02:Auto, 0x03:수동
+    private int   brightCurr; // 화면의 밝기 - 현재 휘도값, 0~100
+    private int   brightWeek; // 화면의 밝기 - 주간 휘도값, 0~100
+    private int   brightNght; // 화면의 밝기 - 야간 휘도값, 0~100
+    private int   blinkTime;      // 깜빡이는 시간주기            1 Byte  문자 비트맵의 깜빡이는 시간주기 0x00 ~ 0x1e( 0.1 ~3.0 )
+    private short scnTurnTime;    // 디폴트 시나리오로 전환시간   2 Byte  디폴트 시나리오로 전환될 때까지 기다리는 시간, 단위 : 초
+    private int   modlErrRate;    // 장애 모듈비율(%)             1 Byte  에러난 픽셀의 백분율 (0~100: 초기값:10%)
+*/
+    public void updateParameter(int powerCtrlMode, int fanRunMode, int fanRunTemp, int heaterRunMode, int heaterRunTemp,
+                                int brightMode, int brightCurr, int brightWeek, int brightNght, int blinkTime, short scnTurnTime, int modlErrRate) {
+        boolean isDifferent = false;
+
+        if (powerCtrlMode != this.panlPwerMode) {
+            isDifferent = true;
+            this.panlPwerMode = powerCtrlMode;
+        }
+        if (fanRunMode != this.fanMode) {
+            isDifferent = true;
+            this.fanMode = fanRunMode;
+        }
+        if (fanRunTemp != this.fanRunTmpr) {
+            isDifferent = true;
+            this.fanRunTmpr = fanRunTemp;
+        }
+        if (heaterRunMode != this.hetrMode) {
+            isDifferent = true;
+            this.hetrMode = heaterRunMode;
+        }
+        if (heaterRunTemp != this.hetrRunTmpr) {
+            isDifferent = true;
+            this.hetrRunTmpr = heaterRunTemp;
+        }
+
+        if (brightMode != this.brghMode) {
+            isDifferent = true;
+            this.brghMode = brightMode;
+        }
+        if (brightCurr != this.brghCurrStep) {
+            isDifferent = true;
+            this.brghCurrStep = brightCurr;
+        }
+        if (brightWeek != this.brghWeekStep) {
+            isDifferent = true;
+            this.brghWeekStep = brightWeek;
+        }
+        if (brightNght != this.brghNghtStep) {
+            isDifferent = true;
+            this.brghNghtStep = brightNght;
+        }
+
+        if (scnTurnTime != this.defPhseChngCycl) {
+            isDifferent = true;
+            this.defPhseChngCycl = (int)scnTurnTime;
+        }
+        if (modlErrRate != this.modlErrRate) {
+            isDifferent = true;
+            this.modlErrRate = modlErrRate;
+        }
+
+        if (isDifferent) {
+            DbmsDataProcess dbmsDataProcess = (DbmsDataProcess) AppUtils.getBean(DbmsDataProcess.class);
+            dbmsDataProcess.add(new DbmsData(DbmsDataType.DBMS_DATA_CTLR_PARAMETER, false, toParamEntity()));
+        }
+    }
+
+    public VmsCtlrParam toParamEntity() {
+        return VmsCtlrParam.builder()
+                .vmsCtlrNmbr(this.vmsCtlrNmbr)
+                .panlPwerMode(this.panlPwerMode)
+                .fanMode(this.fanMode)
+                .fanRunTmpr(this.fanRunTmpr)
+                .hetrMode(this.hetrMode)
+                .hetrRunTmpr(this.hetrRunTmpr)
+                .brghMode(this.brghMode)
+                .brghCurrStep(this.brghCurrStep)
+                .brghWeekStep(this.brghWeekStep)
+                .brghNghtStep(this.brghNghtStep)
+                .modlErrRate(this.modlErrRate)
+                .cmncFailRate(this.cmncFailRate)
+                .build();
+    }
+
+}
+

+ 1 - 1
src/main/java/com/its/vms/ui/SubUI.form

@@ -371,7 +371,7 @@
                     </constraints>
                     <properties>
                       <font name="Malgun Gothic" size="12" style="0"/>
-                      <text value="Button"/>
+                      <text value="TEST"/>
                     </properties>
                   </component>
                 </children>

+ 11 - 6
src/main/java/com/its/vms/ui/SubUI.java

@@ -77,10 +77,16 @@ public abstract class SubUI {
         taLog.setFont(d2font);
 
         txtPort.setVisible(false);
-        btnReserved.setVisible(false);
         SpinnerModel value = new SpinnerNumberModel(0, 0, 100, 1);
         spControl.setModel(value);
 
+        btnReserved.setVisible(true);
+        btnReserved.addActionListener(new ActionListener() {
+            @Override
+            public void actionPerformed(ActionEvent e) {
+                selObj.addRequestData(new TcpServerSendData(eVmsOpCode.OP_VMS_DISPLAY_DEFAULT_FORM, null));
+            }
+        });
         btnLogClear.addActionListener(new ActionListener() {
             @Override
             public void actionPerformed(ActionEvent e) {
@@ -151,6 +157,7 @@ public abstract class SubUI {
                 JOptionPane.showMessageDialog(getRootPanel(), message, title, JOptionPane.YES_OPTION);
             }
         });
+
     }
 
     public void statusControl(int controlType) {
@@ -273,16 +280,14 @@ public abstract class SubUI {
                     fan = "중지";
                 } else if (stts.getFanSttsCd().equals("PAS1")) {
                     fan = "가동";
-                }
-                else {
+                } else {
                     fan = "-?-";
                 }
                 if (stts.getHetrSttsCd().equals("HTS0")) {
                     heater = "중지";
                 } else if (stts.getHetrSttsCd().equals("HTS1")) {
                     heater = "가동";
-                }
-                else {
+                } else {
                     heater = "-?-";
                 }
                 temper = String.valueOf(stts.getCboxTmpr());
@@ -501,7 +506,7 @@ public abstract class SubUI {
         btnReserved = new JButton();
         Font btnReservedFont = this.$$$getFont$$$("Malgun Gothic", Font.PLAIN, 12, btnReserved.getFont());
         if (btnReservedFont != null) btnReserved.setFont(btnReservedFont);
-        btnReserved.setText("Button");
+        btnReserved.setText("TEST");
         panel1.add(btnReserved, new GridConstraints(0, 9, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
         final JPanel panel3 = new JPanel();
         panel3.setLayout(new GridLayoutManager(2, 1, new Insets(0, 4, 0, 4), -1, -1));

+ 12 - 2
src/main/java/com/its/vms/xnettcp/vms/VmsTcpCommServerInitializer.java

@@ -5,13 +5,16 @@ import com.its.vms.config.CommunicationConfig;
 import com.its.vms.dto.TbVmsCtlrDto;
 import com.its.vms.process.DbmsDataProcess;
 import com.its.vms.service.AppRepositoryService;
+import com.its.vms.xnettcp.vms.codec.TcpServerByteBufMessageDecoder;
 import com.its.vms.xnettcp.vms.codec.VmsTcpServerDleStuffingDecoder;
 import com.its.vms.xnettcp.vms.codec.VmsTcpServerEncoder;
 import com.its.vms.xnettcp.vms.handler.VmsServerIdleStateHandler;
 import com.its.vms.xnettcp.vms.handler.VmsServerPacketInboundHandler;
+import com.its.vms.xnettcp.vms.protocol.enums.eVmsProtocolVersion;
 import io.netty.channel.Channel;
 import io.netty.channel.ChannelInitializer;
 import io.netty.channel.ChannelPipeline;
+import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
 import io.netty.handler.timeout.IdleStateHandler;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
@@ -26,6 +29,7 @@ public class VmsTcpCommServerInitializer extends ChannelInitializer<Channel> {
     private final DbmsDataProcess dbmsDataProcess;
     private final VmsServerPacketInboundHandler vmsServerPacketInboundHandler;
     private final VmsTcpServerEncoder vmsTcpServerEncoder;
+    private final TcpServerByteBufMessageDecoder tcpServerByteBufMessageDecoder;
     private final AppRepositoryService repoService;
 
     @Override
@@ -48,8 +52,14 @@ public class VmsTcpCommServerInitializer extends ChannelInitializer<Channel> {
             //pipeline.addLast(new LoggingHandler(LogLevel.INFO));
             pipeline.addLast("vmsTcpIdleStateHandler", tcpIdleStateHandler);
             pipeline.addLast("vmsServerIdleStateHandler", new VmsServerIdleStateHandler(obj, this.dbmsDataProcess, this.config));   // packet idle state handler, event handler
-            if (obj.getProtocolVer() == 0) {
-                pipeline.addLast("vmsServerDecoder", new VmsTcpServerDleStuffingDecoder(this.config, this.repoService, obj));  // Decoding handler
+            if (obj.getProtocolVer() == eVmsProtocolVersion.PROTOCOL_ANDONG.getValue()) {
+                // CONTROLLER KIND(0 1), ADDRESS(2 3, 4 5), FRAME SEQUENCE NO(6 7), OP CODE(8), DATA LENGTH(9 10 11 12), DATA(13 ...)
+                int lengthFieldOffset = 9;
+                int lengthFieldLength = 4;
+                int lengthAdjustment = 0;
+                int initialBytesToStrip = 0;
+                pipeline.addLast("vmsServerDecoder", new LengthFieldBasedFrameDecoder(Short.MAX_VALUE, lengthFieldOffset, lengthFieldLength, lengthAdjustment, initialBytesToStrip));  // Decoding handler
+                //pipeline.addLast("vmsServerPacketDecoder", this.tcpServerByteBufMessageDecoder);
             }
             else {
                 pipeline.addLast("vmsServerDecoder", new VmsTcpServerDleStuffingDecoder(this.config, this.repoService, obj));  // Decoding handler

+ 3 - 0
src/main/java/com/its/vms/xnettcp/vms/VmsTcpCommServerService.java

@@ -5,6 +5,7 @@ import com.its.app.utils.OS;
 import com.its.vms.config.CommunicationConfig;
 import com.its.vms.process.DbmsDataProcess;
 import com.its.vms.service.AppRepositoryService;
+import com.its.vms.xnettcp.vms.codec.TcpServerByteBufMessageDecoder;
 import com.its.vms.xnettcp.vms.codec.VmsTcpServerEncoder;
 import com.its.vms.xnettcp.vms.handler.VmsServerPacketInboundHandler;
 import io.netty.bootstrap.ServerBootstrap;
@@ -25,6 +26,7 @@ public class VmsTcpCommServerService {
     private final VmsTcpServerEncoder vmsTcpServerEncoder;
     private final VmsServerPacketInboundHandler vmsServerPacketInboundHandler;
     private final DbmsDataProcess dbmsDataProcess;
+    private final TcpServerByteBufMessageDecoder tcpServerByteBufMessageDecoder;
     private final AppRepositoryService repoService;
 
     private EventLoopGroup acceptGroups = null;
@@ -107,6 +109,7 @@ public class VmsTcpCommServerService {
                 this.dbmsDataProcess,
                 this.vmsServerPacketInboundHandler,
                 this.vmsTcpServerEncoder,
+                this.tcpServerByteBufMessageDecoder,
                 this.repoService
         );
         serverBootstrap.childHandler(vmsTcpCommServerInitializer);

+ 60 - 0
src/main/java/com/its/vms/xnettcp/vms/codec/TcpServerByteBufMessageDecoder.java

@@ -0,0 +1,60 @@
+package com.its.vms.xnettcp.vms.codec;
+
+import com.its.app.utils.NettyUtils;
+import com.its.vms.dto.TbVmsCtlrDto;
+import com.its.vms.service.AppRepositoryService;
+import com.its.vms.xnettcp.vms.protocol.impl.VmsResFramePacket;
+import io.netty.buffer.ByteBuf;
+import io.netty.channel.ChannelHandler;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.handler.codec.MessageToMessageDecoder;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+
+@Slf4j
+@Component
+@RequiredArgsConstructor
+@ChannelHandler.Sharable
+public class TcpServerByteBufMessageDecoder extends MessageToMessageDecoder<ByteBuf> {
+
+    private final AppRepositoryService appRepositoryService;
+
+    @Override
+    protected void decode(ChannelHandlerContext ctx, ByteBuf byteBuf, List<Object> list) throws Exception {
+        try {
+            if (byteBuf == null) {
+                log.error("Receive: Packet frame packet error. length field data error");
+                ctx.close();
+                return;
+            }
+
+            // CONTROLLER KIND(0 1), ADDRESS(2 3, 4 5), FRAME SEQUENCE NO(6 7), OP CODE(8), DATA LENGTH(9 10 11 12), DATA(13 ...)
+            final int readableBytes = byteBuf.readableBytes();
+            if (readableBytes < 13) {
+                log.error("Receive: Packet readableBytes too small: {}, required min size: {}, will be closed.", readableBytes, 13);
+                ctx.close();
+                return;
+            }
+
+
+            String ipAddress = NettyUtils.getRemoteIpAddress(ctx.channel());
+            TbVmsCtlrDto vmsObj = this.appRepositoryService.getIpAddrMap(ipAddress);
+            if (vmsObj == null) {
+                log.error("Receive: Packet {} Bytes, But Unknown IpAddress {}, will be closed.", readableBytes, ipAddress);
+                ctx.close();
+                return;
+            }
+            byte[] packets = new byte[readableBytes];
+            byteBuf.readBytes(packets);
+            VmsResFramePacket framePacket = new VmsResFramePacket(vmsObj, packets, packets.length);
+            list.add(framePacket);
+        }
+        catch (Exception e) {
+            log.error("TcpServerByteBufMessageDecoder.decode: Exception: {}.", e.getMessage());
+        }
+    }
+
+}

+ 33 - 3
src/main/java/com/its/vms/xnettcp/vms/handler/VmsServerPacketInboundHandler.java

@@ -1,9 +1,12 @@
 package com.its.vms.xnettcp.vms.handler;
 
 import com.its.app.utils.NettyUtils;
+import com.its.vms.dto.TbVmsCtlrDto;
+import com.its.vms.service.AppRepositoryService;
 import com.its.vms.xnettcp.vms.process.TcpServerRecvData;
 import com.its.vms.xnettcp.vms.process.TcpServerRecvDataProcess;
 import com.its.vms.xnettcp.vms.protocol.impl.VmsResFramePacket;
+import io.netty.buffer.ByteBuf;
 import io.netty.channel.ChannelHandler;
 import io.netty.channel.ChannelHandlerContext;
 import io.netty.channel.ChannelInboundHandlerAdapter;
@@ -18,16 +21,43 @@ import org.springframework.stereotype.Component;
 public class VmsServerPacketInboundHandler extends ChannelInboundHandlerAdapter {
 
     private final TcpServerRecvDataProcess tcpServerRecvDataProcess;
+    private final AppRepositoryService appRepositoryService;
 
     @Override
     public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
-        if (!(msg instanceof VmsResFramePacket)) {
-            String ipAddress = NettyUtils.getRemoteIpAddress(ctx.channel());
+
+        String ipAddress = NettyUtils.getRemoteIpAddress(ctx.channel());
+
+        if (!(msg instanceof VmsResFramePacket) && !(msg instanceof ByteBuf)) {
             log.error("[{}] | VmsServerPacketInboundHandler: Received Data is not VmsServerPacketInboundHandler Object", ipAddress);
+            ctx.close();
             return;
         }
 
-        VmsResFramePacket framePacket = (VmsResFramePacket)msg;
+        VmsResFramePacket framePacket;
+        if (msg instanceof VmsResFramePacket) {
+            framePacket = (VmsResFramePacket) msg;
+        }
+        else {
+            ByteBuf byteBuf = (ByteBuf)msg;
+            final int readableBytes = byteBuf.readableBytes();
+            if (readableBytes < 13) {
+                log.error("[{}] | VmsServerPacketInboundHandler: Received Data readableBytes too small: {}, required min size: {}, will be closed",
+                        ipAddress, readableBytes, 13);
+                ctx.close();
+                return;
+            }
+
+            TbVmsCtlrDto vmsObj = this.appRepositoryService.getIpAddrMap(ipAddress);
+            if (vmsObj == null) {
+                log.error("Receive: Packet {} Bytes, But Unknown IpAddress {}, will be closed.", readableBytes, ipAddress);
+                ctx.close();
+                return;
+            }
+            byte[] packets = new byte[readableBytes];
+            byteBuf.readBytes(packets);
+           framePacket = new VmsResFramePacket(vmsObj, packets, packets.length);
+        }
         this.tcpServerRecvDataProcess.add(new TcpServerRecvData(TcpServerRecvData.DATA_TYPE_RES_PACKET, framePacket.getVmsObj(), ctx, framePacket));
     }
 

+ 4 - 2
src/main/java/com/its/vms/xnettcp/vms/protocol/impl/VmsReqDownloadForm.java

@@ -46,9 +46,11 @@ public class VmsReqDownloadForm extends VmsReqFramePacket {
         bodySize += 4;  // 다운로드 폼 헤더 크기
         for (int ii = 0; ii < formData.getFormCnt(); ii++) {
             bodySize += 6;  // 폼데이터 헤더 크기
-            for (int jj = 0; jj < formData.getFormList().get(ii).getObjCnt(); jj++) {
+            VmsFormDto formDto = formData.getFormList().get(ii);
+            for (int jj = 0; jj < formDto.getObjCnt(); jj++) {
                 bodySize += 9;  // 오브젝트 데이터 헤더 크기
-                bodySize += formData.getFormList().get(ii).getObjList().get(jj).getObjSize(); // 오브젝트 데이터 크기
+                VmsFormObj formObj = formDto.getObjList().get(jj);
+                bodySize += formObj.getObjSize(); // 오브젝트 데이터 크기
             }
         }