소스 검색

[WallPadAPI, WallPadConfig]
1. 5.29 소스 기준으로 업데이트

[WallPadDevService]
1. 5.29 소스 기준으로 업데이트
2. 2443분기일 경우, 일괄제어 조명 추가, 2443일 경우 일괄제어 조명에서 디바이스 정보 찾는것 하지 않음

jglee 3 년 전
부모
커밋
1c2ea1ef85
38개의 변경된 파일23431개의 추가작업 그리고 22184개의 파일을 삭제
  1. 235 7
      WallPadAPI/src/main/java/com/artncore/WallPadDataMgr/WallpadDeviceSet.java
  2. 76 23
      WallPadAPI/src/main/java/com/artncore/WallPadDataMgr/WallpadStatusData.java
  3. 151 5
      WallPadAPI/src/main/java/com/artncore/WallPadDataMgr/wallpaddbmgr.java
  4. 8 1
      WallPadAPI/src/main/java/com/artncore/commons/define.java
  5. 1 0
      WallPadAPI/src/main/java/com/artncore/wallpadapi/CooktopAPI.java
  6. 60 0
      WallPadAPI/src/main/java/com/artncore/wallpadapi/SdbAPI.java
  7. 59 0
      WallPadAPI/src/main/java/com/artncore/wallpadapi/Sdb_LivingRoomLightAPI.java
  8. 8 4
      WallPadAPI/src/main/java/com/artncore/wallpadapi/WallPadAPI.java
  9. 9 2
      WallPadConfig/src/main/AndroidManifest.xml
  10. 4 2
      WallPadConfig/src/main/java/kr/co/icontrols/v40ioctl/V40IF.java
  11. 4 2
      WallPadConfig/src/main/java/kr/co/icontrols/v40ioctl/V40IOInterface.java
  12. 4 2
      WallPadConfig/src/main/java/kr/co/icontrols/v40ioctl/V40IOInterface2.java
  13. 2 0
      WallPadConfig/src/main/java/kr/co/icontrols/wallpadconfig/declare/ID.java
  14. 15 2
      WallPadConfig/src/main/java/kr/co/icontrols/wallpadconfig/screen/ConfigMoningCallMainScreen.java
  15. 106 5
      WallPadConfig/src/main/java/kr/co/icontrols/wallpadconfig/screen/ConfigSettingMainScreen.java
  16. 26 26
      WallPadDevService/src/main/AndroidManifest.xml
  17. 196 174
      WallPadDevService/src/main/java/com/artncore/devicectr/WallPadInterface.java
  18. 241 239
      WallPadDevService/src/main/java/com/artncore/wallpaddevservice/DataBaseLoader.java
  19. 238 238
      WallPadDevService/src/main/java/com/artncore/wallpaddevservice/DeviceInitChecker.java
  20. 120 23
      WallPadDevService/src/main/java/com/artncore/wallpaddevservice/ServiceMain.java
  21. 4 209
      WallPadDevService/src/main/java/com/artncore/wallpaddevservice/driver/AirQualitySensor_Controller.java
  22. 611 600
      WallPadDevService/src/main/java/com/artncore/wallpaddevservice/driver/AllLightHDC_Controller.java
  23. 94 16
      WallPadDevService/src/main/java/com/artncore/wallpaddevservice/driver/CookTopFinder_Controller.java
  24. 4 3
      WallPadDevService/src/main/java/com/artncore/wallpaddevservice/driver/Cooktop_Controller.java
  25. 1762 1762
      WallPadDevService/src/main/java/com/artncore/wallpaddevservice/driver/DeviceManager.java
  26. 1779 1767
      WallPadDevService/src/main/java/com/artncore/wallpaddevservice/driver/DriverInterOpAPI.java
  27. 1203 1204
      WallPadDevService/src/main/java/com/artncore/wallpaddevservice/driver/GasValve_Controller.java
  28. 553 555
      WallPadDevService/src/main/java/com/artncore/wallpaddevservice/driver/HeatingFinder_Controller.java
  29. 1696 1697
      WallPadDevService/src/main/java/com/artncore/wallpaddevservice/driver/HeatingV1_Controller.java
  30. 3537 3538
      WallPadDevService/src/main/java/com/artncore/wallpaddevservice/driver/HeatingV2_Controller.java
  31. 2739 2739
      WallPadDevService/src/main/java/com/artncore/wallpaddevservice/driver/MultiSwitch_Controller.java
  32. 337 81
      WallPadDevService/src/main/java/com/artncore/wallpaddevservice/driver/Sdb_Controller.java
  33. 39 6
      WallPadDevService/src/main/java/com/artncore/wallpaddevservice/driver/Sdb_LivingRoomLight_Controller.java
  34. 3772 3720
      WallPadDevService/src/main/java/com/artncore/wallpaddevservice/driver/SmartKeyRfDoor_Controller.java
  35. 3704 3528
      WallPadDevService/src/main/java/com/artncore/wallpaddevservice/driver/SmartSwitchPol_Controller.java
  36. 26 0
      WallPadDevService/src/main/java/kr/co/icontrols/v40ioctl/V40IF.java
  37. 4 2
      WallPadDevService/src/main/java/kr/co/icontrols/v40ioctl/V40IOInterface.java
  38. 4 2
      WallPadDevService/src/main/java/kr/co/icontrols/v40ioctl/V40IOInterface2.java

+ 235 - 7
WallPadAPI/src/main/java/com/artncore/WallPadDataMgr/WallpadDeviceSet.java

@@ -142,7 +142,8 @@ public class WallpadDeviceSet extends wallpaddbmgr {
 			else if (mModelType == Version.MODEL_TYPE.IHN_D101 || mModelType == Version.MODEL_TYPE.IHN_D101_I
 			else if (mModelType == Version.MODEL_TYPE.IHN_D101 || mModelType == Version.MODEL_TYPE.IHN_D101_I
 					|| mModelType == Version.MODEL_TYPE.IHN_D101K || mModelType == Version.MODEL_TYPE.IHN_D101K_I
 					|| mModelType == Version.MODEL_TYPE.IHN_D101K || mModelType == Version.MODEL_TYPE.IHN_D101K_I
 					|| mModelType == Version.MODEL_TYPE.IHN_1010GL || mModelType == Version.MODEL_TYPE.IHN_1010GL_I
 					|| mModelType == Version.MODEL_TYPE.IHN_1010GL || mModelType == Version.MODEL_TYPE.IHN_1010GL_I
-					|| mModelType == Version.MODEL_TYPE.IHN_1010GL_I_2443ALT || mModelType == Version.MODEL_TYPE.IHN_1010GL_I_6410ALT)
+					|| mModelType == Version.MODEL_TYPE.IHN_1010GL_I_2443ALT || mModelType == Version.MODEL_TYPE.IHN_1010GL_I_6410ALT
+					|| mModelType == Version.MODEL_TYPE.IHN_D101_I_OCF)
 			{
 			{
 				if (GetData[1].indexOf("현산향일체형조명기본형") > 0) returnData[1] = LIGHT_TYPE_HDC_INTLIGHT_NORMAL;
 				if (GetData[1].indexOf("현산향일체형조명기본형") > 0) returnData[1] = LIGHT_TYPE_HDC_INTLIGHT_NORMAL;
 				else if (GetData[1].indexOf("현산향일체형조명일괄소등병합형_멀티스위치") > 0) returnData[1] = LIGHT_TYPE_HDC_INTLIGHT_ADD_BATCHLIGHT_MULTISWITCH;
 				else if (GetData[1].indexOf("현산향일체형조명일괄소등병합형_멀티스위치") > 0) returnData[1] = LIGHT_TYPE_HDC_INTLIGHT_ADD_BATCHLIGHT_MULTISWITCH;
@@ -213,7 +214,7 @@ public class WallpadDeviceSet extends wallpaddbmgr {
 			}
 			}
 			else {
 			else {
 				if (Version.getModelType() == Version.MODEL_TYPE.IHN_1010GL || Version.getModelType() == Version.MODEL_TYPE.IHN_1010GL_I
 				if (Version.getModelType() == Version.MODEL_TYPE.IHN_1010GL || Version.getModelType() == Version.MODEL_TYPE.IHN_1010GL_I
-						|| Version.getModelType() == Version.MODEL_TYPE.IHN_1010GL_I_2443ALT || Version.getModelType() == Version.MODEL_TYPE.IHN_1010GL_I_6410ALT)
+						|| mModelType == Version.MODEL_TYPE.IHN_1010GL_I_2443ALT || mModelType == Version.MODEL_TYPE.IHN_1010GL_I_6410ALT)
 					strSettingValue = "1(3:" + define.DEVICE_ID_LIGHT + "(" + define.DEVICE_ENABLE + ")종류(" + strLightingControllerType + ")";
 					strSettingValue = "1(3:" + define.DEVICE_ID_LIGHT + "(" + define.DEVICE_ENABLE + ")종류(" + strLightingControllerType + ")";
 				else strSettingValue = "1(1:" + define.DEVICE_ID_LIGHT + "(" + define.DEVICE_ENABLE + ")종류(" + strLightingControllerType + ")";
 				else strSettingValue = "1(1:" + define.DEVICE_ID_LIGHT + "(" + define.DEVICE_ENABLE + ")종류(" + strLightingControllerType + ")";
 			}
 			}
@@ -262,8 +263,9 @@ public class WallpadDeviceSet extends wallpaddbmgr {
 		if (mModelType == Version.MODEL_TYPE.IHN_D101 || mModelType == Version.MODEL_TYPE.IHN_D101_I
 		if (mModelType == Version.MODEL_TYPE.IHN_D101 || mModelType == Version.MODEL_TYPE.IHN_D101_I
 				|| mModelType == Version.MODEL_TYPE.IHN_D101K || mModelType == Version.MODEL_TYPE.IHN_D101K_I
 				|| mModelType == Version.MODEL_TYPE.IHN_D101K || mModelType == Version.MODEL_TYPE.IHN_D101K_I
 				|| mModelType == Version.MODEL_TYPE.IHN_1010GL || mModelType == Version.MODEL_TYPE.IHN_1010GL_I
 				|| mModelType == Version.MODEL_TYPE.IHN_1010GL || mModelType == Version.MODEL_TYPE.IHN_1010GL_I
+				|| mModelType == Version.MODEL_TYPE.IHN_1010GL_I_2443ALT || mModelType == Version.MODEL_TYPE.IHN_1010GL_I_6410ALT
 				|| mModelType == Version.MODEL_TYPE.IHN_1020GL
 				|| mModelType == Version.MODEL_TYPE.IHN_1020GL
-				|| mModelType == Version.MODEL_TYPE.IHN_1010GL_I_2443ALT || mModelType == Version.MODEL_TYPE.IHN_1010GL_I_6410ALT)
+				|| mModelType == Version.MODEL_TYPE.IHN_D101_I_OCF)
 		{
 		{
 			returnData[0] = 1;
 			returnData[0] = 1;
 			returnData[1] = BATCH_TYPE_HDC_LCD_SMART;
 			returnData[1] = BATCH_TYPE_HDC_LCD_SMART;
@@ -291,8 +293,9 @@ public class WallpadDeviceSet extends wallpaddbmgr {
 			if (mModelType == Version.MODEL_TYPE.IHN_D101 || mModelType == Version.MODEL_TYPE.IHN_D101_I
 			if (mModelType == Version.MODEL_TYPE.IHN_D101 || mModelType == Version.MODEL_TYPE.IHN_D101_I
 					|| mModelType == Version.MODEL_TYPE.IHN_D101K || mModelType == Version.MODEL_TYPE.IHN_D101K_I
 					|| mModelType == Version.MODEL_TYPE.IHN_D101K || mModelType == Version.MODEL_TYPE.IHN_D101K_I
 					|| mModelType == Version.MODEL_TYPE.IHN_1010GL || mModelType == Version.MODEL_TYPE.IHN_1010GL_I
 					|| mModelType == Version.MODEL_TYPE.IHN_1010GL || mModelType == Version.MODEL_TYPE.IHN_1010GL_I
+					|| mModelType == Version.MODEL_TYPE.IHN_1010GL_I_2443ALT || mModelType == Version.MODEL_TYPE.IHN_1010GL_I_6410ALT
 					|| mModelType == Version.MODEL_TYPE.IHN_1020GL
 					|| mModelType == Version.MODEL_TYPE.IHN_1020GL
-					|| mModelType == Version.MODEL_TYPE.IHN_1010GL_I_2443ALT || mModelType == Version.MODEL_TYPE.IHN_1010GL_I_6410ALT)
+					|| mModelType == Version.MODEL_TYPE.IHN_D101_I_OCF)
 			{
 			{
 				if (GetData[1].indexOf("현산향스마트스위치") > 0) returnData[1] = BATCH_TYPE_HDC_OLD_SMART;
 				if (GetData[1].indexOf("현산향스마트스위치") > 0) returnData[1] = BATCH_TYPE_HDC_OLD_SMART;
 				else if (GetData[1].indexOf("현산향LCD스마트스위치") > 0) returnData[1] = BATCH_TYPE_HDC_LCD_SMART;
 				else if (GetData[1].indexOf("현산향LCD스마트스위치") > 0) returnData[1] = BATCH_TYPE_HDC_LCD_SMART;
@@ -1070,7 +1073,8 @@ public class WallpadDeviceSet extends wallpaddbmgr {
 					UpdateSettingData("subdev_list", "분전반", 0, "1(1:"+"분전반" + "(" + "사용안함" + ")종류(" + "사용안함" + ")");
 					UpdateSettingData("subdev_list", "분전반", 0, "1(1:"+"분전반" + "(" + "사용안함" + ")종류(" + "사용안함" + ")");
 				}
 				}
 				else if (mModelType == Version.MODEL_TYPE.IHN_D101 || mModelType == Version.MODEL_TYPE.IHN_D101_I
 				else if (mModelType == Version.MODEL_TYPE.IHN_D101 || mModelType == Version.MODEL_TYPE.IHN_D101_I
-						|| mModelType == Version.MODEL_TYPE.IHN_D101K || mModelType == Version.MODEL_TYPE.IHN_D101K_I) {
+						|| mModelType == Version.MODEL_TYPE.IHN_D101K || mModelType == Version.MODEL_TYPE.IHN_D101K_I
+						|| mModelType == Version.MODEL_TYPE.IHN_D101_I_OCF) {
 					UpdateSettingData("subdev_list", "분전반", 0, "1(1:" + "분전반" + "(" + "사용함" + ")종류(" + "스마트분전반" + ")");
 					UpdateSettingData("subdev_list", "분전반", 0, "1(1:" + "분전반" + "(" + "사용함" + ")종류(" + "스마트분전반" + ")");
 				}
 				}
 				else {
 				else {
@@ -1301,6 +1305,37 @@ public class WallpadDeviceSet extends wallpaddbmgr {
 		}
 		}
 	}
 	}
 
 
+	public int Get_Thermo_Info()
+	{
+		String[] GetData = GetSettingData("온도조절기");
+
+		int returnData = 1;
+		try
+		{
+			if (GetData == null) return returnData;
+
+			if (GetData[1].indexOf("사용함") > 0) returnData = 1;
+			else
+			{
+				returnData = 0;
+				return returnData;
+			}
+
+			return returnData;
+		}
+		catch (RuntimeException re) {
+			LogUtil.errorLogInfo("", TAG, re);
+			returnData = 1;
+			return  returnData;
+		}
+		catch (Exception e) {
+			//e.printStackTrace();
+			LogUtil.errorLogInfo("", TAG, e);
+			returnData = 1;
+			return  returnData;
+		}
+	}
+
 	public static final int SET_IN_MOTION        = 0x01;
 	public static final int SET_IN_MOTION        = 0x01;
 	public static final int SET_OUT_MOTION       = 0x02;
 	public static final int SET_OUT_MOTION       = 0x02;
 	public static final int SET_OUT_TO_IN_MOTION = 0x04;
 	public static final int SET_OUT_TO_IN_MOTION = 0x04;
@@ -3223,7 +3258,8 @@ public class WallpadDeviceSet extends wallpaddbmgr {
 				else if (mModelType == Version.MODEL_TYPE.IHN_D101 || mModelType == Version.MODEL_TYPE.IHN_D101_I
 				else if (mModelType == Version.MODEL_TYPE.IHN_D101 || mModelType == Version.MODEL_TYPE.IHN_D101_I
 						|| mModelType == Version.MODEL_TYPE.IHN_D101K || mModelType == Version.MODEL_TYPE.IHN_D101K_I
 						|| mModelType == Version.MODEL_TYPE.IHN_D101K || mModelType == Version.MODEL_TYPE.IHN_D101K_I
 						|| mModelType == Version.MODEL_TYPE.IHN_1010GL || mModelType == Version.MODEL_TYPE.IHN_1010GL_I
 						|| mModelType == Version.MODEL_TYPE.IHN_1010GL || mModelType == Version.MODEL_TYPE.IHN_1010GL_I
-						|| mModelType == Version.MODEL_TYPE.IHN_1010GL_I_2443ALT || mModelType == Version.MODEL_TYPE.IHN_1010GL_I_6410ALT)
+						|| mModelType == Version.MODEL_TYPE.IHN_1010GL_I_2443ALT || mModelType == Version.MODEL_TYPE.IHN_1010GL_I_6410ALT
+						|| mModelType == Version.MODEL_TYPE.IHN_D101_I_OCF)
 				{
 				{
 					// IGW300 설정
 					// IGW300 설정
 					UpdateSettingData("subdev_list"
 					UpdateSettingData("subdev_list"
@@ -4544,7 +4580,7 @@ public class WallpadDeviceSet extends wallpaddbmgr {
             LogUtil.errorLogInfo("", TAG, re);
             LogUtil.errorLogInfo("", TAG, re);
 			return false;
 			return false;
         } catch (Exception e) {
         } catch (Exception e) {
-			Log.e(TAG, "[Exception] setEscapeLadderDownSend(int nValue)");
+			Log.e(TAG, "[Exception] Set_KakaoShow(boolean value)");
 			LogUtil.errorLogInfo("", TAG, e);
 			LogUtil.errorLogInfo("", TAG, e);
 			return false;
 			return false;
 		}
 		}
@@ -4641,4 +4677,196 @@ public class WallpadDeviceSet extends wallpaddbmgr {
 		}
 		}
 	}
 	}
 
 
+	public static final int KITCHEN_EM_BATCH_CTRL  			= 140; // 일괄제어
+	public static final int KITCHEN_EM_ORDER_CTRL  			= 141; // 순차제어
+	public static final int KITCHEN_EM_ORDER_CTRL_RESET  	= 142; // 순차제어 최초적용: 초기화 진행 (초기화 후 순차제어로 변경)
+
+	/**
+	 * 각실EM 제어 옵션 설정정보 가져오기
+	 * @return int 타입 - 140(일괄제어), 141(순차제어), 142(순차제어 & 각실EM 초기화 필요: 초기화 후, 141로 변경필요)
+	 */
+	public int getSDB_EM_Light_Option() {
+		String[] GetData = GetSettingData("각실EM제어옵션");
+		try {
+			if (GetData != null) {
+				String devInfo = GetData[1];
+				devInfo = devInfo.replace('(', '_');
+				devInfo = devInfo.replace(':', '_');
+				devInfo = devInfo.replace(')', '_');
+
+				String[] parseData = devInfo.split("_");
+
+				//[0] - 기기번호
+				//[1] - 회로수
+				//[2] - 기기이름
+				//[3] - 사용유무 (사용함 or 사용안함)------------> 사용할 정보
+				//[4] - 명칭 (종류)
+				//[5] - 명칭에 대한 정보 ----------------------> 사용할 정보, ','로 구분됨
+				if (parseData[3].equals("사용함") == true) {
+					String TempData = parseData[5];
+					if (TempData != null) {
+						if (TempData.equals("일괄제어")) {
+							Log.d(TAG, "[getSDB_EM_Light_Option] 각실EM 제어 옵션: 일괄제어");
+							return KITCHEN_EM_BATCH_CTRL;
+						}
+						else if (TempData.equals("순차제어")) {
+							Log.d(TAG, "[getSDB_EM_Light_Option] 각실EM 제어 옵션: 순차제어");
+							return KITCHEN_EM_ORDER_CTRL;
+						}
+						else if (TempData.equals("순차제어초기화")) {
+							Log.d(TAG, "[getSDB_EM_Light_Option] 각실EM 제어 옵션: 순차제어 & 초기화");
+							return KITCHEN_EM_ORDER_CTRL_RESET;
+						}
+						else {
+							Log.d(TAG, "[getSDB_EM_Light_Option] 각실EM 제어 옵션: 미정의");
+						}
+					}
+				}
+			}
+		} catch (RuntimeException re) {
+			LogUtil.errorLogInfo("", TAG, re);
+		} catch (Exception e) {
+			Log.e(TAG, "[Exception] getSDB_EM_Light_Option()");
+			LogUtil.errorLogInfo("", TAG, e);
+		}
+		return KITCHEN_EM_ORDER_CTRL_RESET;
+	}
+
+	public boolean setSDB_EM_Light_Option(int nValue) {
+		try {
+			if (nValue < KITCHEN_EM_BATCH_CTRL || KITCHEN_EM_ORDER_CTRL_RESET < nValue) {
+				Log.w(TAG, "[setSDB_EM_Light_Option] nValue is out of range!! -> " + nValue);
+				return false;
+			}
+
+			String strSettingValue = "";
+
+			if (nValue == KITCHEN_EM_BATCH_CTRL) {
+				// 외부 연동사가 월패드 구독안함
+				strSettingValue = "1(1:" + define.DEVICE_ID_SDBEM_LIGHT_OPTION + "(" + define.DEVICE_ENABLE + ")종류(일괄제어))";
+			}
+			else if (nValue == KITCHEN_EM_ORDER_CTRL) {
+				strSettingValue = "1(1:" + define.DEVICE_ID_SDBEM_LIGHT_OPTION + "(" + define.DEVICE_ENABLE + ")종류(순차제어))";
+			}
+			else if (nValue == KITCHEN_EM_ORDER_CTRL_RESET) {
+				strSettingValue = "1(1:" + define.DEVICE_ID_SDBEM_LIGHT_OPTION + "(" + define.DEVICE_ENABLE + ")종류(순차제어초기화))";
+			}
+
+			Log.i(TAG, "[setSDB_EM_Light_Option] strSettingValue: " + strSettingValue);
+
+			UpdateSettingData("subdev_list", define.DEVICE_ID_SDBEM_LIGHT_OPTION, 0, strSettingValue);
+
+			return true;
+		} catch (RuntimeException re) {
+			LogUtil.errorLogInfo("", TAG, re);
+			return false;
+		} catch (Exception e) {
+			Log.e(TAG, "[Exception] setSDB_EM_Light_Option(int nValue)");
+			LogUtil.errorLogInfo("", TAG, e);
+			return false;
+		}
+	}
+
+
+	/**
+	 * HDC Linker 사용여부 및 HDC Linker(월패드 구독) 항목 설정
+	 * @param Linkers HDC Linker 목록 (예. SKT_KT_KAKAO -> 구독하는 항목만 표기하며, null이면 구독 없음. 배열로 연동사 구분.)
+	 * @return 성공 시 true 값 반환, 실패 시 false값 반환
+	 */
+	public boolean setHDCLinker(String[] Linkers) {
+		try {
+			String linkers = "none";
+			if (Linkers == null) {
+				Log.w(TAG, "[setHDCLinker] Linkers is null!!");
+				linkers = "none";
+			}
+			else {
+				Log.i(TAG, "[setHDCLinker] Linkers [" + Linkers.length + "]");
+				for (int i = 0; i < Linkers.length; i++) {
+					if (i == 0) linkers = Linkers[i];
+					else linkers += "_" + Linkers[i];
+				}
+			}
+
+			String strSettingValue = "사용";
+
+			if (linkers == "none") {
+				// 외부 연동사가 월패드 구독안함
+				strSettingValue = "1(1:" + define.DEVICE_ID_HDCLINKER + "(" + define.DEVICE_DISABLE + "))";
+			}
+			else {
+				// 외부 연동사가 월패드 구독함
+				strSettingValue = "1(1:" + define.DEVICE_ID_HDCLINKER + "(" + define.DEVICE_ENABLE + ")종류(" + linkers + "))";
+			}
+
+			Log.i(TAG, "[setHDCLinker] strSettingValue: " + strSettingValue);
+
+			UpdateSettingData("subdev_list", define.DEVICE_ID_HDCLINKER, 0, strSettingValue);
+
+			return true;
+		} catch (RuntimeException re) {
+			LogUtil.errorLogInfo("", TAG, re);
+			return false;
+		} catch (Exception e) {
+			Log.e(TAG, "[Exception] setHDCLinker(String strLinkers)");
+			LogUtil.errorLogInfo("", TAG, e);
+			return false;
+		}
+	}
+
+	/**
+	 * HDC Linker(월패드 구독) 사용여부 확인
+	 * @return true: 사용함, false: 사용안함
+	 */
+	public boolean getHDCLinkerUsage() {
+		boolean bResult = false;
+		try {
+			String[] data = GetSettingData(define.DEVICE_ID_HDCLINKER);
+			if (data == null) bResult = false;   // 사용안함
+			else {
+				if (data[1].indexOf("사용함") > 0) bResult = true;
+			}
+		} catch (NullPointerException e) {
+			LogUtil.errorLogInfo("", TAG, e);
+		}
+		return bResult;
+	}
+
+	/**
+	 * HDC Linker(월패드 구독) 목록 확인 (외부 연동사(이통사/포탈) 목록 확인)
+	 * @return
+	 */
+	public String[] getHDCLinker() {
+		String[] returnData = null;
+		try {
+			String[] data = GetSettingData(define.DEVICE_ID_HDCLINKER);
+			if (data == null) return null;   // 사용안함
+
+			for (int i = 0; i < data.length; i++) Log.e(TAG, "[getHDCLinker] data[" + i + "] = " + data[i]);
+
+			if (data[1].indexOf("사용함") > 0) {
+				String[] strLinkers = data[1].split("종류\\(");
+				strLinkers = strLinkers[1].split("\\)");
+				if (strLinkers[0] != null) {
+					Log.i(TAG, "[getHDCLinker] strLinkers[0] = " + strLinkers[0]);
+					returnData = strLinkers[0].split("_");
+				}
+				else {
+					if (setHDCLinker(null)) {
+						String strSettingValue = "1(1:" + define.DEVICE_ID_HDCLINKER + "(" + define.DEVICE_DISABLE + "))";
+						UpdateSettingData("subdev_list", define.DEVICE_ID_HDCLINKER, 0, strSettingValue);
+						returnData = null;
+					}
+				}
+			}
+		} catch (NullPointerException e) {
+			LogUtil.errorLogInfo("", TAG, e);
+		}
+
+		return returnData;
+	}
+
+
+
+
 }
 }

+ 76 - 23
WallPadAPI/src/main/java/com/artncore/WallPadDataMgr/WallpadStatusData.java

@@ -1022,6 +1022,10 @@ public class WallpadStatusData extends wallpaddbmgr {
 	public static final String MAIN_GUI_SELECT = "MAIN_GUI_SELECT";
 	public static final String MAIN_GUI_SELECT = "MAIN_GUI_SELECT";
 	public static final String MAIN_GUI_SELECT_DEFAULT = "BASIC";
 	public static final String MAIN_GUI_SELECT_DEFAULT = "BASIC";
 
 
+	//무선도어락 문열림 대기시간
+	public static final String DOORLOCK_OPENDELAY_VALUE = "DOORLOCK_OPENDELAY_VALUE";
+	public static final String DOORLOCK_OPENDELAY_VALUE_DEFAULT = "3";
+
 	// 거실조명 모드제어 설정값 (Preset)
 	// 거실조명 모드제어 설정값 (Preset)
     // "조명1전원:디밍:색온도/조명2전원:디밍:색온도 ~ 조명8전원:디밍:색온도"
     // "조명1전원:디밍:색온도/조명2전원:디밍:색온도 ~ 조명8전원:디밍:색온도"
     // 그룹제어시에는 조명1의 값만 사용한다. (조명전원 : on/off/none(don't care), 디밍/색온도 : 1 ~ 10, 미설정시 0)
     // 그룹제어시에는 조명1의 값만 사용한다. (조명전원 : on/off/none(don't care), 디밍/색온도 : 1 ~ 10, 미설정시 0)
@@ -6477,38 +6481,87 @@ public class WallpadStatusData extends wallpaddbmgr {
 		UpdateWallPADData(CAMERA_ENCODING_ERROR, String.valueOf(bError));
 		UpdateWallPADData(CAMERA_ENCODING_ERROR, String.valueOf(bError));
 	}
 	}
 
 
-	public boolean GetMetroUXEditDefaultSet() {
+
+	public static final String METRO_UX_EDIT_DEFAULT_SET = "METRO_UX_EDIT_DEFAULT_SET";
+
+	// 메트로 메인화면 UX 즐겨찾기 편집 기능이 추가됨
+	// 최초 설정 여부 파악
+	public boolean GetMetroUXEditDefaultSet()
+	{
 		try {
 		try {
-			String strUse = this.GetWallPADData("METRO_UX_EDIT_DEFAULT_SET");
-			Log.d("WallpadStatusData", "[GetMetroUXEditDefaultSet] strUse [" + strUse + "]");
-			if (strUse == null) {
-				return true;
-			} else {
+			String strUse = GetWallPADData(METRO_UX_EDIT_DEFAULT_SET);
+			Log.d(TAG, "[GetMetroUXEditDefaultSet] strUse [" + strUse + "]");
+			if (strUse == null) return true; // 기본값: true
+			else {
 				int ret = Integer.parseInt(strUse);
 				int ret = Integer.parseInt(strUse);
-				return ret == 1;
+				return (ret == ENALBLE) ? true : false;
 			}
 			}
-		} catch (RuntimeException var3) {
-			LogUtil.errorLogInfo("", "WallpadStatusData", var3);
+		}
+		catch (RuntimeException re) {
+			LogUtil.errorLogInfo("", TAG, re);
 			return true;
 			return true;
-		} catch (Exception var4) {
-			LogUtil.errorLogInfo("", "WallpadStatusData", var4);
+		}
+		catch (Exception e)
+		{
+			//e.printStackTrace();
+			LogUtil.errorLogInfo("", TAG, e);
+			// 기본값 사용
 			return true;
 			return true;
 		}
 		}
 	}
 	}
 
 
-	public void SetMetroUXEditDefaultSet(boolean Use) {
-		try {
-			Log.d("WallpadStatusData", "[SetMetroUXEditDefaultSet] Use [" + Use + "]");
-			if (Use) {
-				this.UpdateWallPADData("METRO_UX_EDIT_DEFAULT_SET", String.valueOf(1));
-			} else {
-				this.UpdateWallPADData("METRO_UX_EDIT_DEFAULT_SET", String.valueOf(0));
-			}
-		} catch (RuntimeException var3) {
-			LogUtil.errorLogInfo("", "WallpadStatusData", var3);
-		} catch (Exception var4) {
-			LogUtil.errorLogInfo("", "WallpadStatusData", var4);
+	public void SetMetroUXEditDefaultSet( boolean Use )
+	{
+		try
+		{
+			Log.d(TAG, "[SetMetroUXEditDefaultSet] Use [" + Use + "]");
+			if( Use == true )UpdateWallPADData(METRO_UX_EDIT_DEFAULT_SET, String.valueOf(ENALBLE));
+			else UpdateWallPADData(METRO_UX_EDIT_DEFAULT_SET, String.valueOf(DISABEL));
+		}
+		catch (RuntimeException re) {
+			LogUtil.errorLogInfo("", TAG, re);
+		}
+		catch (Exception e)
+		{
+			//e.printStackTrace();
+			LogUtil.errorLogInfo("", TAG, e);
 		}
 		}
+	}
 
 
+	/**
+	 * 도어락 문열림 대기시간 설정값 확인
+	 * @return DOORLOCK_OPEN_WAIT_TIME (3/5/10초)
+	 */
+	public int Get_DoorOpen_WaitTime()
+	{
+		try
+		{
+			String ret = GetWallPADData(DOORLOCK_OPENDELAY_VALUE);
+			Log.d(TAG, "[Get_DoorOpen_WaitTime] ret [" + ret + "]");
+			return Integer.parseInt(ret);
+		}
+		catch (RuntimeException re) {
+			LogUtil.errorLogInfo("", TAG, re);
+			return Integer.parseInt(DOORLOCK_OPENDELAY_VALUE_DEFAULT); // DB 값 접근 에러 발생시 초기값 설정
+		}
+		catch (Exception e )
+		{
+			LogUtil.errorLogInfo("", TAG, e);//e.printStackTrace();
+			return Integer.parseInt(DOORLOCK_OPENDELAY_VALUE_DEFAULT); // DB 값 접근 에러 발생시 초기값 설정
+		}
+	}
+
+	public void Set_DoorOpen_WaitTime(int value) {
+		try
+		{
+			UpdateWallPADData(DOORLOCK_OPENDELAY_VALUE, String.valueOf(value) );
+		}
+		catch (RuntimeException re) {
+			LogUtil.errorLogInfo("", TAG, re);
+		}
+		catch (Exception e )
+		{
+			LogUtil.errorLogInfo("", TAG, e);//e.printStackTrace();
+		}
 	}
 	}
 }
 }

+ 151 - 5
WallPadAPI/src/main/java/com/artncore/WallPadDataMgr/wallpaddbmgr.java

@@ -432,6 +432,73 @@ public class wallpaddbmgr {
             {"1", "1", define.DEVICE_ID_DISTRIBUTION_KIND, define.DEVICE_DISABLE, "종류(사용안함)"},
             {"1", "1", define.DEVICE_ID_DISTRIBUTION_KIND, define.DEVICE_DISABLE, "종류(사용안함)"},
     };
     };
 
 
+
+    // 첫번째 - 기기개수(기본 1로 입력), 두번째 - 회로수(방개수 등), 세번째 - 디바이스 이름, 네번째 - 사용여부, 다섯번째 - 기타정보
+    private static String[][] iHN1010GL_I_2443ALT_DevicesSettingInitData = new String[][] {
+
+            {"1", "1", define.DEVICE_ID_SENSOR, define.DEVICE_ENABLE, "외부동체사용(사용함)내부동체사용(사용함)외부동체를내부동체로사용(사용안함))"},
+            {"1", "1", define.DEVICE_ID_SUBPHONE_BAUDRATE, define.DEVICE_ENABLE, "종류(1200)"},
+            {"1", "1", define.DEVICE_ID_GAS, define.DEVICE_ENABLE, ""},
+            {"1", "1", define.DEVICE_ID_DOORLOCK, define.DEVICE_ENABLE, "종류(유선)"},
+            {"1", "4", define.DEVICE_ID_THERMO, define.DEVICE_ENABLE, ""},
+            {"1", "3", define.DEVICE_ID_LIGHT, define.DEVICE_ENABLE, "종류(현산향일체형조명기본형)"},
+            {"1", "1", define.DEVICE_ID_BATCHLIGHT, define.DEVICE_ENABLE, "종류(현산향LCD스마트스위치)L1설정(3)L2설정(4)"}, // 확인필요!!!
+            {"1", "1", define.DEVICE_ID_DOORCAM, define.DEVICE_ENABLE, "종류(기본)"},
+            {"1", "5", define.DEVICE_ID_REMOTE_METER, define.DEVICE_ENABLE, "EMS(사용함)요금테이블(사용안함)"},
+            {"1", "1", define.DEVICE_ID_ELEVATOR, define.DEVICE_ENABLE, "종류(기본)"},
+            ///////////////////////////
+
+            {"1", "1", define.DEVICE_ID_VENTIL, define.DEVICE_DISABLE, ""},
+            {"1", "1", define.DEVICE_ID_ENERGY_DEVICES, define.DEVICE_DISABLE, ""},
+            {"1", "1", define.DEVICE_ID_CCTV, define.DEVICE_DISABLE, ""},
+            {"1", "1", define.DEVICE_ID_ENERGY_MODULE, define.DEVICE_DISABLE, ""},
+            {"1", "1", define.DEVICE_ID_EMERGENGY_LEDDER, define.DEVICE_DISABLE, ""},
+            {"1", "1", define.DEVICE_ID_MOOD_LIGHT, define.DEVICE_DISABLE, "종류(하단등)"}, //17.11.02 사용안함으로 변경(현정배CJ 요청)
+            {"1", "1", define.DEVICE_ID_ELECTRIC_CAR, define.DEVICE_DISABLE, "IP(10.0.1.1:10000)"},
+            {"1", "1", define.DEVICE_ID_PARKING, define.DEVICE_DISABLE, "종류(아이콘트롤스)IP(10.0.1.10:10000)"},
+            {"1", "1", define.DEVICE_ID_ENERGY_SERVER_CONNECT, define.DEVICE_DISABLE, "IP(10.0.1.1:10000)검침일사용자설정(사용안함)"},
+            {"1", "1", define.DEVICE_ID_DISTRIBUTION_KIND, define.DEVICE_DISABLE, "종류(사용안함)"},
+            {"1", "1", define.DEVICE_ID_REMOTECON, define.DEVICE_DISABLE, ""},
+            {"1", "1", define.DEVICE_ID_IDLE_POWER_SAVING_SWITCH, define.DEVICE_DISABLE, "종류( 기본 )"}
+
+//
+
+
+            ////////////////////////////////////////////////////
+
+    };
+
+    // 첫번째 - 기기개수(기본 1로 입력), 두번째 - 회로수(방개수 등), 세번째 - 디바이스 이름, 네번째 - 사용여부, 다섯번째 - 기타정보
+    private static String[][] iHN1010GL_I_6410ALT_DevicesSettingInitData = new String[][] {
+
+            {"1", "1", define.DEVICE_ID_GAS, define.DEVICE_ENABLE, ""},
+            {"1", "1", define.DEVICE_ID_DOORLOCK, define.DEVICE_ENABLE, "종류(무선)"},
+            {"1", "4", define.DEVICE_ID_THERMO, define.DEVICE_ENABLE, ""},
+            {"1", "3", define.DEVICE_ID_LIGHT, define.DEVICE_ENABLE, "종류(현산향일체형조명일괄소등병합형_멀티스위치)"},
+            {"1", "5", define.DEVICE_ID_REALTIMEMETER, define.DEVICE_ENABLE, ""},
+            {"1", "1", define.DEVICE_ID_BATCHLIGHT, define.DEVICE_ENABLE, "종류(현산향LCD스마트스위치)L1설정(3)L2설정(4)"},
+            {"1", "1", define.DEVICE_ID_REMOTECON, define.DEVICE_ENABLE, ""},
+            {"1", "1", define.DEVICE_ID_DOORCAM, define.DEVICE_ENABLE, "종류(기본)"},
+            {"1", "1", define.DEVICE_ID_VENTIL, define.DEVICE_DISABLE, "종류(기본)"},
+
+            {"1", "1", define.DEVICE_ID_ENERGY_DEVICES, define.DEVICE_ENABLE, ""},
+            {"1", "1", define.DEVICE_ID_IDLE_POWER_SAVING_SWITCH, define.DEVICE_ENABLE, ""},
+            {"1", "1", define.DEVICE_ID_ENERGY_MODULE, define.DEVICE_DISABLE, ""},
+            {"1", "5", define.DEVICE_ID_REMOTE_METER, define.DEVICE_ENABLE, "EMS(사용함)요금테이블(사용안함)"},
+
+            {"1", "1", define.DEVICE_ID_EMERGENGY_LEDDER, define.DEVICE_DISABLE, ""},
+
+            {"1", "1", define.DEVICE_ID_MOOD_LIGHT, define.DEVICE_DISABLE, "종류(하단등)"}, //17.11.02 사용안함으로 변경(현정배CJ 요청)
+
+            {"1", "1", define.DEVICE_ID_PARKING, define.DEVICE_DISABLE, "종류(아이콘트롤스)IP(10.0.1.10:10000)"},
+            {"1", "1", define.DEVICE_ID_ELECTRIC_CAR, define.DEVICE_DISABLE, "IP(10.0.1.1:10000)"},
+            {"1", "1", define.DEVICE_ID_ENERGY_SERVER_CONNECT, define.DEVICE_DISABLE, "IP(10.0.1.1:10000)검침일사용자설정(사용안함)"},
+
+            {"1", "1", define.DEVICE_ID_BLE_SMARTKEY, define.DEVICE_ENABLE, ""},
+            {"1", "1", define.DEVICE_ID_ESCAPELADDER_DOWN_SEND, define.DEVICE_ENABLE, "종류(윗집)"},
+            {"1", "1", define.DEVICE_ID_DISTRIBUTION_KIND, define.DEVICE_DISABLE, "종류(사용안함)"},
+    };
+
     // 첫번째 - 기기개수(기본 1로 입력), 두번째 - 회로수(방개수 등), 세번째 - 디바이스 이름, 네번째 - 사용여부, 다섯번째 - 기타정보
     // 첫번째 - 기기개수(기본 1로 입력), 두번째 - 회로수(방개수 등), 세번째 - 디바이스 이름, 네번째 - 사용여부, 다섯번째 - 기타정보
     private static String[][] iHN1020B_A_DevicesSettingInitData = new String[][] {
     private static String[][] iHN1020B_A_DevicesSettingInitData = new String[][] {
 
 
@@ -833,6 +900,8 @@ public class wallpaddbmgr {
         insertWallPADDB(WallpadStatusData.CALLFUNCTION_VISITORPIC_USE, WallpadStatusData.CALLFUNCTION_VISITORPIC_USE_DEFAULT);
         insertWallPADDB(WallpadStatusData.CALLFUNCTION_VISITORPIC_USE, WallpadStatusData.CALLFUNCTION_VISITORPIC_USE_DEFAULT);
 
 
         insertWallPADDB(WallpadStatusData.CAMERA_ENCODING_ERROR, WallpadStatusData.CAMERA_ENCODING_ERROR_DEFAULT);
         insertWallPADDB(WallpadStatusData.CAMERA_ENCODING_ERROR, WallpadStatusData.CAMERA_ENCODING_ERROR_DEFAULT);
+        insertWallPADDB(WallpadStatusData.METRO_UX_EDIT_DEFAULT_SET, String.valueOf(WallpadStatusData.ENALBLE));
+        insertWallPADDB(WallpadStatusData.DOORLOCK_OPENDELAY_VALUE, WallpadStatusData.DOORLOCK_OPENDELAY_VALUE_DEFAULT);
     }
     }
 
 
     private String InsertDefaultData(String name) {
     private String InsertDefaultData(String name) {
@@ -1078,6 +1147,10 @@ public class wallpaddbmgr {
             insertWallPADDB(WallpadStatusData.GUARD_RELEASE_PW_INPUT, "1");
             insertWallPADDB(WallpadStatusData.GUARD_RELEASE_PW_INPUT, "1");
             ret_data =  "1";
             ret_data =  "1";
         }
         }
+        else if (name.equals(WallpadStatusData.METRO_UX_EDIT_DEFAULT_SET)) {
+            insertWallPADDB(WallpadStatusData.METRO_UX_EDIT_DEFAULT_SET, "1");
+            ret_data =  "1";
+        }
         else if (name.equals(WallpadStatusData.GUARD_SENSOR_CHECK)) {
         else if (name.equals(WallpadStatusData.GUARD_SENSOR_CHECK)) {
             insertWallPADDB(WallpadStatusData.GUARD_SENSOR_CHECK, "1");
             insertWallPADDB(WallpadStatusData.GUARD_SENSOR_CHECK, "1");
             ret_data =  "1";
             ret_data =  "1";
@@ -1551,6 +1624,11 @@ public class wallpaddbmgr {
             insertWallPADDB(WallpadStatusData.CAMERA_ENCODING_ERROR, WallpadStatusData.CAMERA_ENCODING_ERROR_DEFAULT);
             insertWallPADDB(WallpadStatusData.CAMERA_ENCODING_ERROR, WallpadStatusData.CAMERA_ENCODING_ERROR_DEFAULT);
             ret_data = WallpadStatusData.CAMERA_ENCODING_ERROR_DEFAULT;
             ret_data = WallpadStatusData.CAMERA_ENCODING_ERROR_DEFAULT;
         }
         }
+        else if(name.equals(WallpadStatusData.DOORLOCK_OPENDELAY_VALUE))
+        {
+            insertWallPADDB(WallpadStatusData.DOORLOCK_OPENDELAY_VALUE, WallpadStatusData.DOORLOCK_OPENDELAY_VALUE_DEFAULT);
+            ret_data = WallpadStatusData.DOORLOCK_OPENDELAY_VALUE_DEFAULT;
+        }
         return ret_data;
         return ret_data;
     }
     }
 
 
@@ -1984,7 +2062,8 @@ public class wallpaddbmgr {
             }
             }
         }
         }
         else if (mModelType == Version.MODEL_TYPE.IHN_D101 || mModelType == Version.MODEL_TYPE.IHN_D101_I
         else if (mModelType == Version.MODEL_TYPE.IHN_D101 || mModelType == Version.MODEL_TYPE.IHN_D101_I
-                || mModelType == Version.MODEL_TYPE.IHN_D101K || mModelType == Version.MODEL_TYPE.IHN_D101K_I)
+                || mModelType == Version.MODEL_TYPE.IHN_D101K || mModelType == Version.MODEL_TYPE.IHN_D101K_I
+                || mModelType == Version.MODEL_TYPE.IHN_D101_I_OCF)
         {
         {
             for (int i = 0; i < iHND101_DevicesSettingInitData.length; i++) {
             for (int i = 0; i < iHND101_DevicesSettingInitData.length; i++) {
                 Log.d(TAG, mModelType+"_DevicesSettingInitData! "+i);
                 Log.d(TAG, mModelType+"_DevicesSettingInitData! "+i);
@@ -2044,8 +2123,7 @@ public class wallpaddbmgr {
                 );
                 );
             }
             }
         }
         }
-        else if (mModelType == Version.MODEL_TYPE.IHN_1010GL || mModelType == Version.MODEL_TYPE.IHN_1010GL_I
-                || mModelType == Version.MODEL_TYPE.IHN_1010GL_I_2443ALT || mModelType == Version.MODEL_TYPE.IHN_1010GL_I_6410ALT) {
+        else if (mModelType == Version.MODEL_TYPE.IHN_1010GL || mModelType == Version.MODEL_TYPE.IHN_1010GL_I) {
             for (int i = 0; i < iHN1010GL_DevicesSettingInitData.length; i++) {
             for (int i = 0; i < iHN1010GL_DevicesSettingInitData.length; i++) {
                 Log.d(TAG, mModelType+"_DevicesSettingInitData! "+i);
                 Log.d(TAG, mModelType+"_DevicesSettingInitData! "+i);
                 InsertinitDeviceData("subdev_list"
                 InsertinitDeviceData("subdev_list"
@@ -2064,6 +2142,44 @@ public class wallpaddbmgr {
                 );
                 );
             }
             }
         }
         }
+        else if (mModelType == Version.MODEL_TYPE.IHN_1010GL_I_2443ALT) {
+            for (int i = 0; i < iHN1010GL_I_2443ALT_DevicesSettingInitData.length; i++) {
+                Log.d(TAG, mModelType+"_DevicesSettingInitData! "+i);
+                InsertinitDeviceData("subdev_list"
+                        , iHN1010GL_I_2443ALT_DevicesSettingInitData[i][2]
+                        , 0
+                        , iHN1010GL_I_2443ALT_DevicesSettingInitData[i][0]+
+                                "("
+                                + iHN1010GL_I_2443ALT_DevicesSettingInitData[i][1]+
+                                ":"
+                                + iHN1010GL_I_2443ALT_DevicesSettingInitData[i][2]+
+                                "("+
+                                iHN1010GL_I_2443ALT_DevicesSettingInitData[i][3]+
+                                ")"+
+                                iHN1010GL_I_2443ALT_DevicesSettingInitData[i][4]+
+                                ")"
+                );
+            }
+        }
+        else if (mModelType == Version.MODEL_TYPE.IHN_1010GL_I_6410ALT) {
+            for (int i = 0; i < iHN1010GL_I_6410ALT_DevicesSettingInitData.length; i++) {
+                Log.d(TAG, mModelType+"_DevicesSettingInitData! "+i);
+                InsertinitDeviceData("subdev_list"
+                        , iHN1010GL_I_6410ALT_DevicesSettingInitData[i][2]
+                        , 0
+                        , iHN1010GL_I_6410ALT_DevicesSettingInitData[i][0]+
+                                "("
+                                + iHN1010GL_I_6410ALT_DevicesSettingInitData[i][1]+
+                                ":"
+                                + iHN1010GL_I_6410ALT_DevicesSettingInitData[i][2]+
+                                "("+
+                                iHN1010GL_I_6410ALT_DevicesSettingInitData[i][3]+
+                                ")"+
+                                iHN1010GL_I_6410ALT_DevicesSettingInitData[i][4]+
+                                ")"
+                );
+            }
+        }
         else if (mModelType == Version.MODEL_TYPE.IHN_1030_I) {
         else if (mModelType == Version.MODEL_TYPE.IHN_1030_I) {
             for (int i = 0; i < iHN1030_DevicesSettingInitData.length; i++) {
             for (int i = 0; i < iHN1030_DevicesSettingInitData.length; i++) {
                 Log.d(TAG, mModelType+"_DevicesSettingInitData! "+i);
                 Log.d(TAG, mModelType+"_DevicesSettingInitData! "+i);
@@ -2418,7 +2534,8 @@ public class wallpaddbmgr {
      * **/
      * **/
     public void initWidgetData() {
     public void initWidgetData() {
         if (mModelType == Version.MODEL_TYPE.IHN_D101 || mModelType == Version.MODEL_TYPE.IHN_D101_I
         if (mModelType == Version.MODEL_TYPE.IHN_D101 || mModelType == Version.MODEL_TYPE.IHN_D101_I
-                || mModelType == Version.MODEL_TYPE.IHN_D101K || mModelType == Version.MODEL_TYPE.IHN_D101K_I) {
+                || mModelType == Version.MODEL_TYPE.IHN_D101K || mModelType == Version.MODEL_TYPE.IHN_D101K_I
+                || mModelType == Version.MODEL_TYPE.IHN_D101_I_OCF) {
             InsertinitWidgetData(0, define.ICONS.MENUS.MAIN_ELEVATOR.getID());
             InsertinitWidgetData(0, define.ICONS.MENUS.MAIN_ELEVATOR.getID());
             InsertinitWidgetData(1, define.ICONS.MENUS.TALK_FRONT.getID());
             InsertinitWidgetData(1, define.ICONS.MENUS.TALK_FRONT.getID());
             InsertinitWidgetData(2, define.ICONS.MENUS.TALK_GUARD.getID());
             InsertinitWidgetData(2, define.ICONS.MENUS.TALK_GUARD.getID());
@@ -2426,7 +2543,7 @@ public class wallpaddbmgr {
             InsertinitWidgetData(4, define.ICONS.MENUS.CTRL_HEATING.getID());
             InsertinitWidgetData(4, define.ICONS.MENUS.CTRL_HEATING.getID());
             InsertinitWidgetData(5, define.ICONS.MENUS.CTRL_VENT.getID());
             InsertinitWidgetData(5, define.ICONS.MENUS.CTRL_VENT.getID());
             InsertinitWidgetData(6, define.ICONS.MENUS.ENERGY_SMARTPANEL.getID());
             InsertinitWidgetData(6, define.ICONS.MENUS.ENERGY_SMARTPANEL.getID());
-            InsertinitWidgetData(7, define.ICONS.MENUS.ADD_NOTICE.getID());
+            InsertinitWidgetData(47, define.ICONS.MENUS.ADD_NOTICE.getID());
             InsertinitWidgetData(8, define.ICONS.MENUS.ADD_MEMO.getID());
             InsertinitWidgetData(8, define.ICONS.MENUS.ADD_MEMO.getID());
             InsertinitWidgetData(9, define.ICONS.MENUS.SECURITY_SETARMED.getID());
             InsertinitWidgetData(9, define.ICONS.MENUS.SECURITY_SETARMED.getID());
             InsertinitWidgetData(10, define.ICONS.MENUS.ADD_CCTV.getID());
             InsertinitWidgetData(10, define.ICONS.MENUS.ADD_CCTV.getID());
@@ -2445,6 +2562,34 @@ public class wallpaddbmgr {
             InsertinitWidgetData(9, define.ICONS.MENUS.CTRL_GAS.getID());   // 가스밸브
             InsertinitWidgetData(9, define.ICONS.MENUS.CTRL_GAS.getID());   // 가스밸브
             InsertinitWidgetData(10, define.ICONS.MENUS.ADD_NOTICE.getID());   // 공지사항
             InsertinitWidgetData(10, define.ICONS.MENUS.ADD_NOTICE.getID());   // 공지사항
         }
         }
+        else if (mModelType == Version.MODEL_TYPE.IHN_1010GL_I_2443ALT) {
+            InsertinitWidgetData(0, define.ICONS.MENUS.MAIN_ELEVATOR.getID());
+            InsertinitWidgetData(1, define.ICONS.MENUS.TALK_FRONT.getID());
+            InsertinitWidgetData(2, define.ICONS.MENUS.TALK_GUARD.getID());
+            InsertinitWidgetData(3, define.ICONS.MENUS.CTRL_LIGHT.getID());
+            InsertinitWidgetData(4, define.ICONS.MENUS.CTRL_HEATING.getID());
+            InsertinitWidgetData(5, define.ICONS.MENUS.CTRL_DOORLOCK.getID());
+            InsertinitWidgetData(6, define.ICONS.MENUS.ADD_NOTICE.getID());
+            InsertinitWidgetData(7, define.ICONS.MENUS.ADD_MEMO.getID());
+            InsertinitWidgetData(8, define.ICONS.MENUS.SECURITY_SETARMED.getID());
+            InsertinitWidgetData(9, define.ICONS.MENUS.SETTING_MORNINGCALL.getID());
+            InsertinitWidgetData(10, define.ICONS.MENUS.SETTING_CLREANSCREEN.getID());
+            InsertinitWidgetData(11, define.ICONS.MENUS.SETTING_CONFIG.getID());
+
+        }
+        else if (mModelType == Version.MODEL_TYPE.IHN_1010GL_I_6410ALT) {
+            InsertinitWidgetData(0, define.ICONS.MENUS.MAIN_CALRENDAR.getID());   // 달력/시계
+            InsertinitWidgetData(1, define.ICONS.MENUS.MAIN_ELEVATOR.getID());   // 엘리베이터
+            InsertinitWidgetData(2, define.ICONS.MENUS.TALK_GUARD.getID());   // 경비통화
+            InsertinitWidgetData(3, define.ICONS.MENUS.ENERGY_REMOTEMETER.getID());   // 원격검침
+            InsertinitWidgetData(4, define.ICONS.MENUS.MAIN_WEATHER.getID());   // 날씨
+            InsertinitWidgetData(5, define.ICONS.MENUS.CTRL_HEATING.getID());   // 난방
+            InsertinitWidgetData(6, define.ICONS.MENUS.SECURITY_SETARMED.getID());   // 방범
+            InsertinitWidgetData(7, define.ICONS.MENUS.SETTING_CONFIG.getID());   // 설정
+            InsertinitWidgetData(8, define.ICONS.MENUS.CTRL_LIGHT.getID());   // 조명
+            InsertinitWidgetData(9, define.ICONS.MENUS.CTRL_GAS.getID());   // 가스밸브
+            InsertinitWidgetData(10, define.ICONS.MENUS.ADD_NOTICE.getID());   // 공지사항
+        }
         else {
         else {
             /**
             /**
              * IHN-1010(-I), IHN-1010GL(-I), IHN-1030(-I), IHN-1040(-I), IHN-1050(-I), IHN-1050DW-I, IHN-T1010(-I), IHN-1020B-I, IHN-1303-I
              * IHN-1010(-I), IHN-1010GL(-I), IHN-1030(-I), IHN-1040(-I), IHN-1050(-I), IHN-1050DW-I, IHN-T1010(-I), IHN-1020B-I, IHN-1303-I
@@ -3490,6 +3635,7 @@ public class wallpaddbmgr {
                         case API_Menu.SubMenuCtrl.HDC_EachLamp:
                         case API_Menu.SubMenuCtrl.HDC_EachLamp:
                         case API_Menu.SubMenuCtrl.OutSide_livingLamp:
                         case API_Menu.SubMenuCtrl.OutSide_livingLamp:
                         case API_Menu.SubMenuCtrl.OutSide_EachLamp:
                         case API_Menu.SubMenuCtrl.OutSide_EachLamp:
+                        case API_Menu.SubMenuCtrl.HDCLivingNEach_Lamp:
                             values.put("name", API_Menu.SubMenuCtrl.Name_Lamp);
                             values.put("name", API_Menu.SubMenuCtrl.Name_Lamp);
                             if(wdb!=null)
                             if(wdb!=null)
                                 wdb.insert(MenuTBL, null, values);
                                 wdb.insert(MenuTBL, null, values);

+ 8 - 1
WallPadAPI/src/main/java/com/artncore/commons/define.java

@@ -4,7 +4,7 @@ import android.os.Environment;
 
 
 public class define {
 public class define {
 	/** WallPadAPI Version 을 정의합니다. */
 	/** WallPadAPI Version 을 정의합니다. */
-	public static final String WALLPADAPI_VERSION = "2021.05.28.01";
+	public static final String WALLPADAPI_VERSION = "2021.05.29.01";
 	///////////////////////////////////////////////////////////////////////
 	///////////////////////////////////////////////////////////////////////
 	// WallPadDevService 의 각 드라이버와 통신을 위한 드라이버 이름을 정의합니다.
 	// WallPadDevService 의 각 드라이버와 통신을 위한 드라이버 이름을 정의합니다.
 	///////////////////////////////////////////////////////////////////////
 	///////////////////////////////////////////////////////////////////////
@@ -689,6 +689,8 @@ public class define {
 	public static final String DEVICE_ID_PSTN_CALL                = "국선";
 	public static final String DEVICE_ID_PSTN_CALL                = "국선";
 	public static final String DEVICE_ID_CALLHISTOTY              = "통화내역";
 	public static final String DEVICE_ID_CALLHISTOTY              = "통화내역";
 	public static final String DEVICE_ID_VISITORPIC               = "방문자사진";
 	public static final String DEVICE_ID_VISITORPIC               = "방문자사진";
+	public static final String DEVICE_ID_CCTV           = "CCTV";
+	public static final String DEVICE_ID_ELEVATOR       = "엘리베이터";
 
 
 	/**
 	/**
 	 * 카카오홈 사용 여부 이름
 	 * 카카오홈 사용 여부 이름
@@ -704,6 +706,7 @@ public class define {
 	public static final String DEVICE_ID_SMARTIOTCAM_FLIP = "스마트현관카메라좌우반전";
 	public static final String DEVICE_ID_SMARTIOTCAM_FLIP = "스마트현관카메라좌우반전";
 	public static final String DEVICE_ID_CONSTRUCTION_SPECIAL_FUNC = "건설사특화기능";
 	public static final String DEVICE_ID_CONSTRUCTION_SPECIAL_FUNC = "건설사특화기능";
 	public static final String DEVICE_ID_MAIN_GUI_CTRL_USE = "제어기능";
 	public static final String DEVICE_ID_MAIN_GUI_CTRL_USE = "제어기능";
+	public static final String DEVICE_ID_DOOROPEN_WAIT_TIME = "문열림대기시간";
 
 
 	public static final String DEVICE_ENABLE  = "사용함";
 	public static final String DEVICE_ENABLE  = "사용함";
 	public static final String DEVICE_DISABLE = "사용안함";
 	public static final String DEVICE_DISABLE = "사용안함";
@@ -711,6 +714,10 @@ public class define {
 	public static final String DEVICE_ID_UPPER = "윗집";
 	public static final String DEVICE_ID_UPPER = "윗집";
 	public static final String DEVICE_ID_BELOW = "아랫집";
 	public static final String DEVICE_ID_BELOW = "아랫집";
 
 
+	public static final String DEVICE_ID_HDCLINKER  = "HDCLINKER";   // 외부연동사(이통사/포털) 연동여부 및 연동사 구분
+
+	public static final String DEVICE_ID_SDBEM_LIGHT_OPTION  = "각실EM제어옵션";   // 각실EM제어 옵션
+
 	public define()
 	public define()
 	{
 	{
 	}
 	}

+ 1 - 0
WallPadAPI/src/main/java/com/artncore/wallpadapi/CooktopAPI.java

@@ -292,6 +292,7 @@ public class CooktopAPI extends WallPadDevAPI {
      */
      */
     public int setUnitCircuitClose(byte Index, byte circuitIndex) {
     public int setUnitCircuitClose(byte Index, byte circuitIndex) {
         // 1. Parameter Check
         // 1. Parameter Check
+        Log.w(TAG, "[setUnitCircuitClose] DeviceID is " + Index + ", cir ID" +  circuitIndex);
         if (data.DeviceCnt <= 0) {
         if (data.DeviceCnt <= 0) {
             Log.w(TAG, "[setUnitCircuitClose] DeviceCnt is '0'  Not Yet !!!");
             Log.w(TAG, "[setUnitCircuitClose] DeviceCnt is '0'  Not Yet !!!");
             return -1;
             return -1;

+ 60 - 0
WallPadAPI/src/main/java/com/artncore/wallpadapi/SdbAPI.java

@@ -223,6 +223,16 @@ public class SdbAPI extends WallPadDevAPI
         }
         }
     }
     }
 
 
+    /** 조명 ON/OFF 상태 */
+    public static class LIGHT_ONOFF {
+        /** ON */
+        public static byte ON = (byte) 0x01;
+        /** OFF */
+        public static byte OFF = (byte) 0x02;
+        /** OFF */
+        public static byte DONTCARE = (byte) 0xFF;
+    }
+
     /** 기기 데이터 */
     /** 기기 데이터 */
     public Data data;
     public Data data;
 
 
@@ -1185,6 +1195,44 @@ public class SdbAPI extends WallPadDevAPI
         return SendNReadCMD_int(define.APICMD_SINKCTRL, "SetLight", EmIndex, LightIndex, (OnOff)?1:0, Dimming, Color);
         return SendNReadCMD_int(define.APICMD_SINKCTRL, "SetLight", EmIndex, LightIndex, (OnOff)?1:0, Dimming, Color);
     }
     }
 
 
+    /**
+     * 조명을 제어한다. 조명상태 제어에 don't care 기능 추가
+     *
+     * @param EmIndex    - (byte) 제어할 에너지미터 인덱스 (define.DEVICE_ALL_OR_NOTHING 는 허용하지 않음)
+     * @param LightIndex - (byte) 제어할 조명 인덱스 (0~3, define.DEVICE_ALL_OR_NOTHING:전체)
+     * @param OnOff      - (byte) 0x01 : On, 0x02 : Off, 0xFF : don't care
+     * @param Dimming    - (byte) 제어할 조명 밝기 단계 (1, 2, 3 ... 10 : 10단계)
+     * @param Color      - (byte) 제어할 조명 색상 단계 (1, 2, 3 ... 10 : 10단계)
+     *
+     * @return (int) - >=0 : 성공, <0 : 실패
+     */
+    public int SetLight2(byte EmIndex, byte LightIndex, byte OnOff, byte Dimming, byte Color) {
+        // 1. Parameter Check
+        int ret = IndexRangeCheck(EmIndex, LightIndex, define.DEVICE_ALL_OR_NOTHING);
+        if (ret < 0) {
+            Log.w(TAG, "[SetLight2] IndexRangeCheck Error (ret:" + ret + ")");
+            return ret;
+        }
+
+        if (!LightPowerRangeCheck(OnOff)) {
+            Log.w(TAG, "[SetLight] Param : Power Out Of Range !!! (OnOff:" + OnOff + ")");
+            return APIErrorCode.INVALIDPARAMETER;
+        }
+
+        if (!DimmingNColorRangeCheck(Dimming)) {
+            Log.w(TAG, "[SetLight2] Param : Dimming Out Of Range !!! (Dimming:" + Dimming + ")");
+            return APIErrorCode.INVALIDPARAMETER;
+        }
+
+        if (!DimmingNColorRangeCheck(Color)) {
+            Log.w(TAG, "[SetLight2] Param : Color Out Of Range !!! (Color:" + Color + ")");
+            return APIErrorCode.INVALIDPARAMETER;
+        }
+
+        // 2. Send
+        return SendNReadCMD_int(define.APICMD_SINKCTRL, "SetLight2", EmIndex, LightIndex, OnOff, Dimming, Color);
+    }
+
     /**
     /**
      * 조명을 ON/OFF 제어한다.
      * 조명을 ON/OFF 제어한다.
      *
      *
@@ -1643,6 +1691,18 @@ public class SdbAPI extends WallPadDevAPI
         return  APIErrorCode.C_SUCCESS;
         return  APIErrorCode.C_SUCCESS;
     }
     }
 
 
+    /**
+     * 조명 제어상태 범위를 체크한다.
+     *
+     * @param OnOff - (byte) 체크할 단계
+     *
+     * @return (boolean) ture:정상 , false:범위이탈
+     */
+    private boolean LightPowerRangeCheck(byte OnOff) {
+        if ((OnOff < LIGHT_ONOFF.ON || LIGHT_ONOFF.OFF < OnOff) && (OnOff != define.DEVICE_ALL_OR_NOTHING)) return false;
+        return true;
+    }
+
     /**
     /**
      * 밝기, 색상의 단계 범위를 체크한다.
      * 밝기, 색상의 단계 범위를 체크한다.
      *
      *

+ 59 - 0
WallPadAPI/src/main/java/com/artncore/wallpadapi/Sdb_LivingRoomLightAPI.java

@@ -33,6 +33,16 @@ public class Sdb_LivingRoomLightAPI extends WallPadDevAPI {
     /** 기기 데이터 */
     /** 기기 데이터 */
     public Sdb_DataClasses.LivingEnergyMeterClass data;
     public Sdb_DataClasses.LivingEnergyMeterClass data;
 
 
+    /** 조명 ON/OFF 상태 */
+    public static class LIGHT_ONOFF {
+        /** ON */
+        public static byte ON = (byte) 0x01;
+        /** OFF */
+        public static byte OFF = (byte) 0x02;
+        /** OFF */
+        public static byte DONTCARE = (byte) 0xFF;
+    }
+
     /** 거실 조명 모드 */
     /** 거실 조명 모드 */
     public static class LIGHT_MODE {
     public static class LIGHT_MODE {
         /** 특정 모드가 아님 */
         /** 특정 모드가 아님 */
@@ -350,6 +360,42 @@ public class Sdb_LivingRoomLightAPI extends WallPadDevAPI {
         return SendNReadCMD_int(define.APICMD_SINKCTRL, "SetLight", LightIndex, (OnOff)?1:0, Dimming, Color, 0);
         return SendNReadCMD_int(define.APICMD_SINKCTRL, "SetLight", LightIndex, (OnOff)?1:0, Dimming, Color, 0);
     }
     }
 
 
+    /**
+     * 조명을 제어한다. 조명상태 제어에 don't care 기능 추가
+     *
+     * @param LightIndex - (byte) 제어할 조명 인덱스 (0~3, defien.DEVICE_ALL_OR_NOTHING:전체)
+     * @param OnOff      - (byte) 0x01 : On, 0x02 : Off, 0xFF : don't care
+     * @param Dimming    - (byte) 제어할 조명 밝기 단계 (1, 2, 3 ... 10 : 10단계)
+     * @param Color      - (byte) 제어할 조명 색상 단계 (1, 2, 3 ... 10 : 10단계)
+     *
+     * @return (int) - >=0 : 성공, <0 : 실패
+     */
+    public int SetLight2(byte LightIndex, byte OnOff, byte Dimming, byte Color) {
+        // 1. Parameter Check
+        if (!LightIndexRangeCheck(LightIndex)) {
+            Log.w(TAG, "[SetLight2] LightIndexRangeCheck Error");
+            return APIErrorCode.INVALIDPARAMETER;
+        }
+
+        if (!LightPowerRangeCheck(OnOff)) {
+            Log.w(TAG, "[SetLight2] Param : Power Out Of Range !!! (OnOff:" + OnOff + ")");
+            return APIErrorCode.INVALIDPARAMETER;
+        }
+
+        if (!DimmingNColorRangeCheck(Dimming)) {
+            Log.w(TAG, "[SetLight2] Param : Dimming Out Of Range !!! (Dimming:" + Dimming + ")");
+            return APIErrorCode.INVALIDPARAMETER;
+        }
+
+        if (!DimmingNColorRangeCheck(Color)) {
+            Log.w(TAG, "[SetLight2] Param : Color Out Of Range !!! (Color:" + Color + ")");
+            return APIErrorCode.INVALIDPARAMETER;
+        }
+
+        // 2. Send
+        return SendNReadCMD_int(define.APICMD_SINKCTRL, "SetLight2", LightIndex, OnOff, Dimming, Color, 0);
+    }
+
     /**
     /**
      * 조명을 ON/OFF 제어한다.
      * 조명을 ON/OFF 제어한다.
      *
      *
@@ -759,4 +805,17 @@ public class Sdb_LivingRoomLightAPI extends WallPadDevAPI {
         }
         }
         return true;
         return true;
     }
     }
+
+    /**
+     * 조명 제어상태 범위를 체크한다.
+     *
+     * @param OnOff - (byte) 체크할 단계
+     *
+     * @return (boolean) ture:정상 , false:범위이탈
+     */
+    private boolean LightPowerRangeCheck(byte OnOff) {
+        if ((OnOff < LIGHT_ONOFF.ON || LIGHT_ONOFF.OFF < OnOff) && (OnOff != define.DEVICE_ALL_OR_NOTHING)) return false;
+        return true;
+    }
+
 }
 }

+ 8 - 4
WallPadAPI/src/main/java/com/artncore/wallpadapi/WallPadAPI.java

@@ -164,7 +164,8 @@ public class WallPadAPI {
     public int SetBatchSwitchStatus(boolean onoff) {
     public int SetBatchSwitchStatus(boolean onoff) {
         try {
         try {
             if (mModelType == Version.MODEL_TYPE.IHN_D101 || mModelType == Version.MODEL_TYPE.IHN_D101_I
             if (mModelType == Version.MODEL_TYPE.IHN_D101 || mModelType == Version.MODEL_TYPE.IHN_D101_I
-                    || mModelType == Version.MODEL_TYPE.IHN_D101K || mModelType == Version.MODEL_TYPE.IHN_D101K_I)
+                    || mModelType == Version.MODEL_TYPE.IHN_D101K || mModelType == Version.MODEL_TYPE.IHN_D101K_I
+                    || mModelType == Version.MODEL_TYPE.IHN_D101_I_OCF)
             {
             {
                 // DC 분전반 사용 (DC 조명)
                 // DC 분전반 사용 (DC 조명)
                 WallpadDeviceSet wds = new WallpadDeviceSet(mContext);
                 WallpadDeviceSet wds = new WallpadDeviceSet(mContext);
@@ -253,7 +254,8 @@ public class WallPadAPI {
         int ret = -100;
         int ret = -100;
         try {
         try {
             if (mModelType == Version.MODEL_TYPE.IHN_D101 || mModelType == Version.MODEL_TYPE.IHN_D101_I
             if (mModelType == Version.MODEL_TYPE.IHN_D101 || mModelType == Version.MODEL_TYPE.IHN_D101_I
-                    || mModelType == Version.MODEL_TYPE.IHN_D101K || mModelType == Version.MODEL_TYPE.IHN_D101K_I)
+                    || mModelType == Version.MODEL_TYPE.IHN_D101K || mModelType == Version.MODEL_TYPE.IHN_D101K_I
+                    || mModelType == Version.MODEL_TYPE.IHN_D101_I_OCF)
             {
             {
                 WallpadDeviceSet wds = new WallpadDeviceSet(mContext);
                 WallpadDeviceSet wds = new WallpadDeviceSet(mContext);
                 int nDPType = wds.Get_DistributionPannelType_Info();
                 int nDPType = wds.Get_DistributionPannelType_Info();
@@ -442,7 +444,8 @@ public class WallPadAPI {
                 else if (mModelType == Version.MODEL_TYPE.IHN_D101 || mModelType == Version.MODEL_TYPE.IHN_D101_I
                 else if (mModelType == Version.MODEL_TYPE.IHN_D101 || mModelType == Version.MODEL_TYPE.IHN_D101_I
                         || mModelType == Version.MODEL_TYPE.IHN_D101K || mModelType == Version.MODEL_TYPE.IHN_D101K_I
                         || mModelType == Version.MODEL_TYPE.IHN_D101K || mModelType == Version.MODEL_TYPE.IHN_D101K_I
                         || mModelType == Version.MODEL_TYPE.IHN_1010GL || mModelType == Version.MODEL_TYPE.IHN_1010GL_I
                         || mModelType == Version.MODEL_TYPE.IHN_1010GL || mModelType == Version.MODEL_TYPE.IHN_1010GL_I
-                        || mModelType == Version.MODEL_TYPE.IHN_1010GL_I_2443ALT || mModelType == Version.MODEL_TYPE.IHN_1010GL_I_6410ALT)
+                        || mModelType == Version.MODEL_TYPE.IHN_1010GL_I_2443ALT || mModelType == Version.MODEL_TYPE.IHN_1010GL_I_6410ALT
+                        || mModelType == Version.MODEL_TYPE.IHN_D101_I_OCF)
                 {
                 {
                     IGW300API iGW300API = null;
                     IGW300API iGW300API = null;
                     iGW300API = Get_IGW300Controller();
                     iGW300API = Get_IGW300Controller();
@@ -555,7 +558,8 @@ public class WallPadAPI {
                 else if (mModelType == Version.MODEL_TYPE.IHN_D101 || mModelType == Version.MODEL_TYPE.IHN_D101_I
                 else if (mModelType == Version.MODEL_TYPE.IHN_D101 || mModelType == Version.MODEL_TYPE.IHN_D101_I
                         || mModelType == Version.MODEL_TYPE.IHN_D101K || mModelType == Version.MODEL_TYPE.IHN_D101K_I
                         || mModelType == Version.MODEL_TYPE.IHN_D101K || mModelType == Version.MODEL_TYPE.IHN_D101K_I
                         || mModelType == Version.MODEL_TYPE.IHN_1010GL || mModelType == Version.MODEL_TYPE.IHN_1010GL_I
                         || mModelType == Version.MODEL_TYPE.IHN_1010GL || mModelType == Version.MODEL_TYPE.IHN_1010GL_I
-                        || mModelType == Version.MODEL_TYPE.IHN_1010GL_I_2443ALT || mModelType == Version.MODEL_TYPE.IHN_1010GL_I_6410ALT)
+                        || mModelType == Version.MODEL_TYPE.IHN_1010GL_I_2443ALT || mModelType == Version.MODEL_TYPE.IHN_1010GL_I_6410ALT
+                        || mModelType == Version.MODEL_TYPE.IHN_D101_I_OCF)
                 {
                 {
                     IGW300API iGW300API = null;
                     IGW300API iGW300API = null;
                     iGW300API = Get_IGW300Controller();
                     iGW300API = Get_IGW300Controller();

+ 9 - 2
WallPadConfig/src/main/AndroidManifest.xml

@@ -1,14 +1,21 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="kr.co.icontrols.wallpadconfig"
     package="kr.co.icontrols.wallpadconfig"
     android:versionCode="01"
     android:versionCode="01"
-    android:versionName="2021.05.28.01">
+    android:versionName="2021.05.29.01">
 
 
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
+    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
     <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
     <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
-	<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
     <uses-permission android:name="android.permission.WRITE_SETTINGS"/>
     <uses-permission android:name="android.permission.WRITE_SETTINGS"/>
     <uses-permission android:name="android.permission.RECORD_AUDIO" />
     <uses-permission android:name="android.permission.RECORD_AUDIO" />
 	<uses-permission android:name="android.permission.WAKE_LOCK" />
 	<uses-permission android:name="android.permission.WAKE_LOCK" />
 	<uses-permission android:name="android.permission.INTERNET"/>
 	<uses-permission android:name="android.permission.INTERNET"/>
+
+    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
+    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
+    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
+    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
+    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
     
     
     <application
     <application
         android:allowBackup="true"
         android:allowBackup="true"

+ 4 - 2
WallPadConfig/src/main/java/kr/co/icontrols/v40ioctl/V40IF.java

@@ -414,7 +414,8 @@ public class V40IF {
     public void Emergency_Type_Set() {
     public void Emergency_Type_Set() {
         WpdInterfaceOpen();
         WpdInterfaceOpen();
         if (Version.getModelType() == Version.MODEL_TYPE.IHN_D101 || Version.getModelType() == Version.MODEL_TYPE.IHN_D101_I
         if (Version.getModelType() == Version.MODEL_TYPE.IHN_D101 || Version.getModelType() == Version.MODEL_TYPE.IHN_D101_I
-                || Version.getModelType() == Version.MODEL_TYPE.IHN_D101K || Version.getModelType() == Version.MODEL_TYPE.IHN_D101K_I) {
+                || Version.getModelType() == Version.MODEL_TYPE.IHN_D101K || Version.getModelType() == Version.MODEL_TYPE.IHN_D101K_I
+                || Version.getModelType() == Version.MODEL_TYPE.IHN_D101_I_OCF) {
             Log.d(TAG, "[Emergency_Type_Set] V40 - D101 mode");
             Log.d(TAG, "[Emergency_Type_Set] V40 - D101 mode");
 
 
             WpdInterfaceControl(IOCTL_EMR_TYPE, 0);
             WpdInterfaceControl(IOCTL_EMR_TYPE, 0);
@@ -440,7 +441,8 @@ public class V40IF {
         WpdInterfaceControl(IOCTL_LEDNEMR_ONOFF, 0);
         WpdInterfaceControl(IOCTL_LEDNEMR_ONOFF, 0);
 
 
         if (Version.getModelType() != Version.MODEL_TYPE.IHN_D101 && Version.getModelType() != Version.MODEL_TYPE.IHN_D101_I
         if (Version.getModelType() != Version.MODEL_TYPE.IHN_D101 && Version.getModelType() != Version.MODEL_TYPE.IHN_D101_I
-                && Version.getModelType() != Version.MODEL_TYPE.IHN_D101K && Version.getModelType() != Version.MODEL_TYPE.IHN_D101K_I) {
+                && Version.getModelType() != Version.MODEL_TYPE.IHN_D101K && Version.getModelType() != Version.MODEL_TYPE.IHN_D101K_I
+                && Version.getModelType() != Version.MODEL_TYPE.IHN_D101_I_OCF) {
             WpdInterfaceControl(IOCTL_EMR_OFF, 0);
             WpdInterfaceControl(IOCTL_EMR_OFF, 0);
         }
         }
         WpdInterfaceClose();
         WpdInterfaceClose();

+ 4 - 2
WallPadConfig/src/main/java/kr/co/icontrols/v40ioctl/V40IOInterface.java

@@ -69,7 +69,8 @@ public class V40IOInterface {
 	public void Emergency_Type_Set() {
 	public void Emergency_Type_Set() {
 		WpdInterfaceOpen();
 		WpdInterfaceOpen();
 		if (Version.getModelType() == Version.MODEL_TYPE.IHN_D101 || Version.getModelType() == Version.MODEL_TYPE.IHN_D101_I
 		if (Version.getModelType() == Version.MODEL_TYPE.IHN_D101 || Version.getModelType() == Version.MODEL_TYPE.IHN_D101_I
-				|| Version.getModelType() == Version.MODEL_TYPE.IHN_D101K || Version.getModelType() == Version.MODEL_TYPE.IHN_D101K_I) {
+				|| Version.getModelType() == Version.MODEL_TYPE.IHN_D101K || Version.getModelType() == Version.MODEL_TYPE.IHN_D101K_I
+				|| Version.getModelType() == Version.MODEL_TYPE.IHN_D101_I_OCF) {
 			Log.d(TAG, "[Emergency_Type_Set] V40 - D101 mode");
 			Log.d(TAG, "[Emergency_Type_Set] V40 - D101 mode");
 
 
 			WpdInterfaceControl(IOCTL_EMR_TYPE, 0);
 			WpdInterfaceControl(IOCTL_EMR_TYPE, 0);
@@ -95,7 +96,8 @@ public class V40IOInterface {
 		WpdInterfaceControl(IOCTL_LEDNEMR_ONOFF, 0);
 		WpdInterfaceControl(IOCTL_LEDNEMR_ONOFF, 0);
 
 
 		if (Version.getModelType() != Version.MODEL_TYPE.IHN_D101 && Version.getModelType() != Version.MODEL_TYPE.IHN_D101_I
 		if (Version.getModelType() != Version.MODEL_TYPE.IHN_D101 && Version.getModelType() != Version.MODEL_TYPE.IHN_D101_I
-				&& Version.getModelType() != Version.MODEL_TYPE.IHN_D101K && Version.getModelType() != Version.MODEL_TYPE.IHN_D101K_I) {
+				&& Version.getModelType() != Version.MODEL_TYPE.IHN_D101K && Version.getModelType() != Version.MODEL_TYPE.IHN_D101K_I
+				&& Version.getModelType() != Version.MODEL_TYPE.IHN_D101_I_OCF) {
 			WpdInterfaceControl(IOCTL_EMR_OFF, 0);
 			WpdInterfaceControl(IOCTL_EMR_OFF, 0);
 		}
 		}
 		WpdInterfaceClose();
 		WpdInterfaceClose();

+ 4 - 2
WallPadConfig/src/main/java/kr/co/icontrols/v40ioctl/V40IOInterface2.java

@@ -239,7 +239,8 @@ public class V40IOInterface2 {
 	public void Emergency_Type_Set() {
 	public void Emergency_Type_Set() {
 		WpdInterfaceOpen();
 		WpdInterfaceOpen();
 		if (Version.getModelType() == Version.MODEL_TYPE.IHN_D101 || Version.getModelType() == Version.MODEL_TYPE.IHN_D101_I
 		if (Version.getModelType() == Version.MODEL_TYPE.IHN_D101 || Version.getModelType() == Version.MODEL_TYPE.IHN_D101_I
-				|| Version.getModelType() == Version.MODEL_TYPE.IHN_D101K || Version.getModelType() == Version.MODEL_TYPE.IHN_D101K_I) {
+				|| Version.getModelType() == Version.MODEL_TYPE.IHN_D101K || Version.getModelType() == Version.MODEL_TYPE.IHN_D101K_I
+				|| Version.getModelType() == Version.MODEL_TYPE.IHN_D101_I_OCF) {
 			Log.d(TAG, "[Emergency_Type_Set] V40 - D101 mode");
 			Log.d(TAG, "[Emergency_Type_Set] V40 - D101 mode");
 
 
 			WpdInterfaceControl(IOCTL_EMR_TYPE, 0);
 			WpdInterfaceControl(IOCTL_EMR_TYPE, 0);
@@ -265,7 +266,8 @@ public class V40IOInterface2 {
 		WpdInterfaceControl(IOCTL_LEDNEMR_ONOFF, 0);
 		WpdInterfaceControl(IOCTL_LEDNEMR_ONOFF, 0);
 
 
 		if (Version.getModelType() != Version.MODEL_TYPE.IHN_D101 && Version.getModelType() != Version.MODEL_TYPE.IHN_D101_I
 		if (Version.getModelType() != Version.MODEL_TYPE.IHN_D101 && Version.getModelType() != Version.MODEL_TYPE.IHN_D101_I
-				&& Version.getModelType() != Version.MODEL_TYPE.IHN_D101K && Version.getModelType() != Version.MODEL_TYPE.IHN_D101K_I) {
+				&& Version.getModelType() != Version.MODEL_TYPE.IHN_D101K && Version.getModelType() != Version.MODEL_TYPE.IHN_D101K_I
+				&& Version.getModelType() != Version.MODEL_TYPE.IHN_D101_I_OCF) {
 			WpdInterfaceControl(IOCTL_EMR_OFF, 0);
 			WpdInterfaceControl(IOCTL_EMR_OFF, 0);
 		}
 		}
 		WpdInterfaceClose();
 		WpdInterfaceClose();

+ 2 - 0
WallPadConfig/src/main/java/kr/co/icontrols/wallpadconfig/declare/ID.java

@@ -220,6 +220,8 @@ public final class ID
             public final static int EASYMODE_CHECKBOX_NOTUSE   = BASE + 283;
             public final static int EASYMODE_CHECKBOX_NOTUSE   = BASE + 283;
             public final static int CALL_SOUND_CHECKBOX_USE 		= BASE + 284;
             public final static int CALL_SOUND_CHECKBOX_USE 		= BASE + 284;
             public final static int CALL_SOUND_CHECKBOX_NOTUSE 		= BASE + 285;
             public final static int CALL_SOUND_CHECKBOX_NOTUSE 		= BASE + 285;
+            public final static int OPENDELAY_LEFT = BASE + 286;
+            public final static int OPENDELAY_RIGHT = BASE + 287;
 
 
         }
         }
         public static final class text
         public static final class text

+ 15 - 2
WallPadConfig/src/main/java/kr/co/icontrols/wallpadconfig/screen/ConfigMoningCallMainScreen.java

@@ -1,5 +1,6 @@
 package kr.co.icontrols.wallpadconfig.screen;
 package kr.co.icontrols.wallpadconfig.screen;
 
 
+import com.artncore.WallPadDataMgr.WallpadDeviceSet;
 import com.artncore.WallPadDataMgr.WallpadStatusData;
 import com.artncore.WallPadDataMgr.WallpadStatusData;
 import com.artncore.wallpadapi.WallPadAPI;
 import com.artncore.wallpadapi.WallPadAPI;
 
 
@@ -159,9 +160,16 @@ public class ConfigMoningCallMainScreen extends WpadScreen {
 
 
 		int Pass = 0;
 		int Pass = 0;
 		int itemCount = 5;
 		int itemCount = 5;
-
+		WallpadDeviceSet devSet = new WallpadDeviceSet(this.getContext());
 		if (Version.getModelType() == Version.MODEL_TYPE.IHN_750) itemCount = 3;
 		if (Version.getModelType() == Version.MODEL_TYPE.IHN_750) itemCount = 3;
+		int[] VentiInfo = devSet.Get_Ventil_Info();
+		if (VentiInfo[0] == 0) {
+			//환기끄기
+			mItemListText = new String[]{"모닝콜 울림", "시간설정", "벨소리선택", "조명연동"};
+			itemCount = 4;
+		}
 
 
+		devSet.closeDB();
 		for (int i = 0; i < itemCount; i++) {
 		for (int i = 0; i < itemCount; i++) {
 
 
 			if (i > 0)
 			if (i > 0)
@@ -187,7 +195,12 @@ public class ConfigMoningCallMainScreen extends WpadScreen {
 
 
 		if (Version.getModelType() != Version.MODEL_TYPE.IHN_750) {
 		if (Version.getModelType() != Version.MODEL_TYPE.IHN_750) {
 			SelItem[4] = new SelectItemComponent(context, layout, Common.ImgPosion.GetX(596), Common.ImgPosion.GetY(131 + 90 * 4), MoningCallMainID.button.LEFT_05, MoningCallMainID.button.RIGHT_05, LampLink, mLampIdx);
 			SelItem[4] = new SelectItemComponent(context, layout, Common.ImgPosion.GetX(596), Common.ImgPosion.GetY(131 + 90 * 4), MoningCallMainID.button.LEFT_05, MoningCallMainID.button.RIGHT_05, LampLink, mLampIdx);
-			SelItem[5] = new SelectItemComponent(context, layout, Common.ImgPosion.GetX(596), Common.ImgPosion.GetY(131 + 90 * 5), MoningCallMainID.button.LEFT_06, MoningCallMainID.button.RIGHT_06, ChangeAirLink, mChangeAirIdx);
+			if (VentiInfo[0] == 1) {
+				//환기끄기
+				SelItem[5] = new SelectItemComponent(context, layout, Common.ImgPosion.GetX(596), Common.ImgPosion.GetY(131 + 90 * 5), MoningCallMainID.button.LEFT_06, MoningCallMainID.button.RIGHT_06, ChangeAirLink, mChangeAirIdx);
+
+			}
+
 		}
 		}
 
 
 		Log.d(TAG, "[END - Screen] --------------------------------------------");
 		Log.d(TAG, "[END - Screen] --------------------------------------------");

+ 106 - 5
WallPadConfig/src/main/java/kr/co/icontrols/wallpadconfig/screen/ConfigSettingMainScreen.java

@@ -91,7 +91,7 @@ public class ConfigSettingMainScreen extends WpadScreen {
 	public final String TXT_BAND_LOCATION = "밴드위치알림";
 	public final String TXT_BAND_LOCATION = "밴드위치알림";
 	public final String TXT_WEB_CTR_PWD = "웹 제어 비밀번호";
 	public final String TXT_WEB_CTR_PWD = "웹 제어 비밀번호";
 	public final String TXT_EASYMODE = "간편모드설정";
 	public final String TXT_EASYMODE = "간편모드설정";
-
+	public final String TXT_OPEN_DELAY = "문열림대기시간 설정";
 
 
 	ArrayList<Integer> sensorRoomIdxArr = new ArrayList<Integer>();
 	ArrayList<Integer> sensorRoomIdxArr = new ArrayList<Integer>();
 	ArrayList<String> sensorRoomNameArr = new ArrayList<String>();
 	ArrayList<String> sensorRoomNameArr = new ArrayList<String>();
@@ -224,6 +224,8 @@ public class ConfigSettingMainScreen extends WpadScreen {
 	private final int MAX_SLEEP_TIME = 180;   // 슬립모드 최대시간 (시간단위 : 초)
 	private final int MAX_SLEEP_TIME = 180;   // 슬립모드 최대시간 (시간단위 : 초)
 	private final int MIN_SLEEP_TIME = 30;   // 슬립모드 최소시간 (시간단위 : 초)
 	private final int MIN_SLEEP_TIME = 30;   // 슬립모드 최소시간 (시간단위 : 초)
 	private final int MAX_CLOSESENSOR_LEVEL = 5;
 	private final int MAX_CLOSESENSOR_LEVEL = 5;
+	private final int MAX_OPENDELAY_LEVEL = 2;
+	private int [] DoorLock_OpenDelayTime = { 3, 5, 10 };
 
 
 	private int mVolumeLevel = 1;
 	private int mVolumeLevel = 1;
 	private int mLcdLevel = 4;
 	private int mLcdLevel = 4;
@@ -245,6 +247,7 @@ public class ConfigSettingMainScreen extends WpadScreen {
 	private boolean mEnergyControllerComm = false;
 	private boolean mEnergyControllerComm = false;
 	private boolean mBandLocAlarm = false;
 	private boolean mBandLocAlarm = false;
 	private boolean mEasyModeUse = false;
 	private boolean mEasyModeUse = false;
+	private int mOpenDelayTime = 0; //  index
 
 
 	private int EmListIndex = 0;
 	private int EmListIndex = 0;
 
 
@@ -290,6 +293,10 @@ public class ConfigSettingMainScreen extends WpadScreen {
 			mButtonLightLevel = wd.GetLEDButtonBrightnessLevel();
 			mButtonLightLevel = wd.GetLEDButtonBrightnessLevel();
 			mARSControl = wd.GetArsControl();
 			mARSControl = wd.GetArsControl();
 			mRemoteControl = wd.GetRemoteControl();
 			mRemoteControl = wd.GetRemoteControl();
+			for (int i = 0; i <= MAX_OPENDELAY_LEVEL; i++) {
+				if (DoorLock_OpenDelayTime[i] == wd.Get_DoorOpen_WaitTime())
+					mOpenDelayTime = i;
+			}
 			wd.closeDB();
 			wd.closeDB();
 
 
 			WallpadDeviceSet wpddevset = new WallpadDeviceSet(this.getContext());
 			WallpadDeviceSet wpddevset = new WallpadDeviceSet(this.getContext());
@@ -312,7 +319,7 @@ public class ConfigSettingMainScreen extends WpadScreen {
 				mSite_DongtanLakeIPARK = true;
 				mSite_DongtanLakeIPARK = true;
 			}*/
 			}*/
 
 
-			Log.d(TAG, "[initInfo] mButtonLightLevel [" + mButtonLightLevel + "], mARSControl [" + mARSControl + "], mRemoteControl [" + mRemoteControl + "]");
+			Log.d(TAG, "[initInfo] mButtonLightLevel [" + mButtonLightLevel + "], mARSControl [" + mARSControl + "], mRemoteControl [" + mRemoteControl + "], mOpenDelayTime [" + mOpenDelayTime + "]");
 
 
 			for (int i = 0; i < MAX_LCD_LEVEL; i++) {
 			for (int i = 0; i < MAX_LCD_LEVEL; i++) {
 				if (LCD_BrightnessValue[i] == getBrightness) {
 				if (LCD_BrightnessValue[i] == getBrightness) {
@@ -336,7 +343,8 @@ public class ConfigSettingMainScreen extends WpadScreen {
 			}
 			}
 
 
 			if (Version.getModelType() == Version.MODEL_TYPE.IHN_D101 || Version.getModelType() == Version.MODEL_TYPE.IHN_D101_I
 			if (Version.getModelType() == Version.MODEL_TYPE.IHN_D101 || Version.getModelType() == Version.MODEL_TYPE.IHN_D101_I
-					|| Version.getModelType() == Version.MODEL_TYPE.IHN_D101K || Version.getModelType() == Version.MODEL_TYPE.IHN_D101K_I)
+					|| Version.getModelType() == Version.MODEL_TYPE.IHN_D101K || Version.getModelType() == Version.MODEL_TYPE.IHN_D101K_I
+					|| Version.getModelType() == Version.MODEL_TYPE.IHN_D101_I_OCF)
 			{
 			{
 				//TXT_CLOSE_SENSOR
 				//TXT_CLOSE_SENSOR
 				data = new SetKind( TYPE_L_R_ARROW , ConfingSettingMainID.button.CLOSESENSOR_LEFT , ConfingSettingMainID.button.CLOSESENSOR_RIGHT , TXT_CLOSE_SENSOR );
 				data = new SetKind( TYPE_L_R_ARROW , ConfingSettingMainID.button.CLOSESENSOR_LEFT , ConfingSettingMainID.button.CLOSESENSOR_RIGHT , TXT_CLOSE_SENSOR );
@@ -437,7 +445,8 @@ public class ConfigSettingMainScreen extends WpadScreen {
 			}
 			}
 
 
 			if ((Version.getModelType() == Version.MODEL_TYPE.IHN_D101 || Version.getModelType() == Version.MODEL_TYPE.IHN_D101_I
 			if ((Version.getModelType() == Version.MODEL_TYPE.IHN_D101 || Version.getModelType() == Version.MODEL_TYPE.IHN_D101_I
-					|| Version.getModelType() == Version.MODEL_TYPE.IHN_D101K || Version.getModelType() == Version.MODEL_TYPE.IHN_D101K_I)
+					|| Version.getModelType() == Version.MODEL_TYPE.IHN_D101K || Version.getModelType() == Version.MODEL_TYPE.IHN_D101K_I
+					|| Version.getModelType() == Version.MODEL_TYPE.IHN_D101_I_OCF)
 					&& (nDistributionPanelType == Version.DISTRIBUTION_MODEL.SMART_DIST))
 					&& (nDistributionPanelType == Version.DISTRIBUTION_MODEL.SMART_DIST))
 			{
 			{
 				WallpadDeviceSet wds = new WallpadDeviceSet(getContext());
 				WallpadDeviceSet wds = new WallpadDeviceSet(getContext());
@@ -476,6 +485,14 @@ public class ConfigSettingMainScreen extends WpadScreen {
 				//data = new SetKind( TYPE_BUTTON , ConfingSettingMainID.button.REMOCON_REG , 0 , TXT_REMOCON_REG );
 				//data = new SetKind( TYPE_BUTTON , ConfingSettingMainID.button.REMOCON_REG , 0 , TXT_REMOCON_REG );
 				//SettingData.add(data);
 				//SettingData.add(data);
 			}
 			}
+
+			boolean bDoorLockOpenDelay = (getDoorLockOpenDelayUse() > 0) ? true : false;
+			if (bDoorLockOpenDelay) {
+				data = new SetKind(TYPE_L_R_ARROW , ConfingSettingMainID.button.OPENDELAY_LEFT , ConfingSettingMainID.button.OPENDELAY_RIGHT , TXT_OPEN_DELAY);
+				SettingData.add(data);
+				setting_manual_str += "OPEN_DELAY:" + SettingData.size() + "/";
+			}
+
 			m_CurPage = 1;
 			m_CurPage = 1;
 			Log.d(TAG, "List Count = " + SettingData.size());
 			Log.d(TAG, "List Count = " + SettingData.size());
 
 
@@ -816,6 +833,10 @@ public class ConfigSettingMainScreen extends WpadScreen {
 					DrawEasyMode(mEasyModeUse, false);
 					DrawEasyMode(mEasyModeUse, false);
 				}
 				}
 
 
+				if (SettingData.get(i).m_TxtTitle.equals(TXT_OPEN_DELAY)) {
+					DrawDoorLockOpenDelay(mOpenDelayTime);
+				}
+
 				lineIdx++;
 				lineIdx++;
 				arrayIdx++;
 				arrayIdx++;
 			}
 			}
@@ -884,7 +905,8 @@ public class ConfigSettingMainScreen extends WpadScreen {
 			mIntLightCheckHandler.sendEmptyMessage(0);
 			mIntLightCheckHandler.sendEmptyMessage(0);
 		}
 		}
 		else if (Version.getModelType() == Version.MODEL_TYPE.IHN_D101 || Version.getModelType() == Version.MODEL_TYPE.IHN_D101_I
 		else if (Version.getModelType() == Version.MODEL_TYPE.IHN_D101 || Version.getModelType() == Version.MODEL_TYPE.IHN_D101_I
-				|| Version.getModelType() == Version.MODEL_TYPE.IHN_D101K || Version.getModelType() == Version.MODEL_TYPE.IHN_D101K_I)
+				|| Version.getModelType() == Version.MODEL_TYPE.IHN_D101K || Version.getModelType() == Version.MODEL_TYPE.IHN_D101K_I
+				|| Version.getModelType() == Version.MODEL_TYPE.IHN_D101_I_OCF)
 		{
 		{
 			mSensorLightCheckHandler.sendEmptyMessage(0);
 			mSensorLightCheckHandler.sendEmptyMessage(0);
 		}
 		}
@@ -1539,6 +1561,12 @@ public class ConfigSettingMainScreen extends WpadScreen {
 					Sound().Play(SND.effect.TOUCH_UNLATCHED);
 					Sound().Play(SND.effect.TOUCH_UNLATCHED);
 				}
 				}
 			}
 			}
+			else if (TargetId == ConfingSettingMainID.button.OPENDELAY_LEFT) {
+				ChangeOpenDelayLevel(false);
+			}
+			else if (TargetId == ConfingSettingMainID.button.OPENDELAY_RIGHT) {
+				ChangeOpenDelayLevel(true);
+			}
 			/*else
 			/*else
 			{
 			{
 				if(true)
 				if(true)
@@ -2405,6 +2433,53 @@ public class ConfigSettingMainScreen extends WpadScreen {
 		}
 		}
 	}
 	}
 
 
+	private void ChangeOpenDelayLevel( boolean Up ) {
+		if (Up == true) {
+			if (mOpenDelayTime != MAX_OPENDELAY_LEVEL) Sound().Play(SND.effect.TOUCH_LATCHED);
+
+			mOpenDelayTime++;
+			if (mOpenDelayTime >= MAX_OPENDELAY_LEVEL) mOpenDelayTime = MAX_OPENDELAY_LEVEL;
+		}
+		else {
+			if (mOpenDelayTime != 0) Sound().Play(SND.effect.TOUCH_LATCHED);
+
+			mOpenDelayTime--;
+			if (mOpenDelayTime <= 0) mOpenDelayTime = 0;
+		}
+		DrawDoorLockOpenDelay(mOpenDelayTime);
+
+		// DB Save
+		if (mOpenDelayTime >= 0 &&  mOpenDelayTime <= MAX_OPENDELAY_LEVEL) {
+			WallpadStatusData wd = new WallpadStatusData(this.getContext());
+			wd.Set_DoorOpen_WaitTime(DoorLock_OpenDelayTime[mOpenDelayTime]);
+		}
+	}
+
+	private void DrawDoorLockOpenDelay(int level) {
+		try {
+			Log.d(TAG, "[DrawDoorLockOpenDelay] level [" + level + "], DelayTime [" + DoorLock_OpenDelayTime[level] + "]");
+			int idx = getViewIdx(TXT_OPEN_DELAY);
+			textValue[idx].setText(DoorLock_OpenDelayTime[level] + "초");
+
+			if (level == MAX_OPENDELAY_LEVEL) {
+				Btn_Right[idx].setButtonRearImage();
+			}
+			else if (level == 0) {
+				Btn_Left[idx].setButtonRearImage();
+			}
+			else {
+				Btn_Right[idx].setButtonFrontImage();
+				Btn_Left[idx].setButtonFrontImage();
+			}
+		} catch (RuntimeException re) {
+			LogUtil.errorLogInfo("", TAG, re);
+		} catch (Exception e) {
+			Log.e(TAG,"[Exception] DrawDoorLockOpenDelay(int level)");
+			//e.printStackTrace();
+			LogUtil.errorLogInfo("", TAG, e);
+		}
+	}
+
 	/**
 	/**
 	 * 무선리모콘 사용유무 확인
 	 * 무선리모콘 사용유무 확인
 	 *
 	 *
@@ -2435,4 +2510,30 @@ public class ConfigSettingMainScreen extends WpadScreen {
             LogUtil.errorLogInfo("", TAG, e);
             LogUtil.errorLogInfo("", TAG, e);
 		}
 		}
 	}
 	}
+
+	/**
+	 * 무선 도어락 문열림 대기모드 사용여부
+	 *
+	 * @return (int) - >0 : 무선 도어락 문열림 대기모드 사용, <0 : 실패 또는 미사용
+	 */
+	private int getDoorLockOpenDelayUse() {
+		// 1. get DB
+		WallpadDeviceSet devset = new WallpadDeviceSet(super.getContext());
+		int Doorinfo = devset.GetDeviceSetted("무선도어락문열림대기모드");
+		devset.closeDB();
+
+		// 2. Check
+		if (Doorinfo == WallpadDeviceSet.DEV_DATA_ENABLE) {
+			return 1;
+		}
+		else if (Doorinfo == WallpadDeviceSet.DEV_DATA_DISABLE) {
+			return -1;
+		}
+		else if (Doorinfo == WallpadDeviceSet.DEV_DATA_NONE) {
+			return -2;
+		}
+		else {
+			return -3;
+		}
+	}
 }
 }

+ 26 - 26
WallPadDevService/src/main/AndroidManifest.xml

@@ -1,26 +1,26 @@
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.artncore.deviceservice"
-    android:versionCode="1"
-    android:versionName="2021.05.28.01">
-
-    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
-    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
-    <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
-	<uses-permission android:name="android.permission.CALL_PHONE"/>
-	<uses-permission android:name="android.permission.INTERNET"/>	
-	<uses-permission android:name="com.artncore.apps.ic_wallpad.call.dao.CallHistoryProvider.Permission.READ" />
-    <uses-permission android:name="com.artncore.apps.ic_wallpad.call.dao.CallHistoryProvider.Permission.WRITE" />
-    
-    <application
-        android:allowBackup="true"
-        android:icon="@mipmap/ic_launcher"
-        android:label="@string/app_name"        
-        android:theme="@style/AppTheme" >
-        <service android:name="com.artncore.wallpaddevservice.ServiceMain">
-            <intent-filter>
-    			<action android:name="wallpaddevservice.ServiceMain" />    		    		                             
-			</intent-filter>
-        </service>
-    </application>
-
-</manifest>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.artncore.deviceservice"
+    android:versionCode="1"
+    android:versionName="2021.05.29.01">
+
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
+    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
+    <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
+	<uses-permission android:name="android.permission.CALL_PHONE"/>
+	<uses-permission android:name="android.permission.INTERNET"/>	
+	<uses-permission android:name="com.artncore.apps.ic_wallpad.call.dao.CallHistoryProvider.Permission.READ" />
+    <uses-permission android:name="com.artncore.apps.ic_wallpad.call.dao.CallHistoryProvider.Permission.WRITE" />
+    
+    <application
+        android:allowBackup="true"
+        android:icon="@mipmap/ic_launcher"
+        android:label="@string/app_name"        
+        android:theme="@style/AppTheme" >
+        <service android:name="com.artncore.wallpaddevservice.ServiceMain">
+            <intent-filter>
+    			<action android:name="wallpaddevservice.ServiceMain" />    		    		                             
+			</intent-filter>
+        </service>
+    </application>
+
+</manifest>

+ 196 - 174
WallPadDevService/src/main/java/com/artncore/devicectr/WallPadInterface.java

@@ -1,174 +1,196 @@
-package com.artncore.devicectr;
-
-import android.util.Log;
-
-import java.nio.channels.OverlappingFileLockException;
-import com.util.LogUtil;
-import kr.co.icontrols.v40ioctl.V40IF;
-import kr.co.icontrols.wallpadsupport.Version;
-
-public class WallPadInterface {
-
-	String TAG = "WallPadInterface";
-
-	public static final int EVT_RING = 220;     // PSTN Incomingcall 상태 전달
-	public static final int BTN_EMR  = 221;     //FRONT 비상 버튼 입력 상태 전달
-	public static final int BTN_CALL = 222;     //FRONT 통화 버튼 입력 상태 전달
-	public static final int BTN_OPEN = 223;     //FRONT OPEN 버튼 입력 상태 전달
-	public static final int BTN_DOOR = 224;     //현관폰 벨 버튼 입력 상태 전달
-	public static final int BTN_DOOR_IHN1010 = 268;     //현관폰 벨 버튼 입력 상태 전달 (IHN-1010)
-	public static final int EVT_EMR  = 225;     //비상 센서 입력 상태 전달
-	public static final int EVT_MAG0 = 226;     //센서 마그네틱 0 입력 상태 전달
-	public static final int EVT_MAG1 = 227;     //센서 마그네틱 1 입력 상태 전달
-	public static final int EVT_EXIT = 228;     //센서 피난사다리 입력 상태 전달
-	public static final int EVT_MOTIN = 229;    //센서 동체감지기-내부 입력 상태 전달
-	public static final int EVT_MOTOUT = 230;   //센서 동체감지기-외부 입력 상태 전달
-	public static final int EVT_RING_END = 231; // PSTN Incomingcall 종료 상태 전달 (본 이벤트는 본인이 전화를 받아서 EVT_RING 가 종료된 경우 호출되지않습니다.)
-
-	public static final int AUDIO_MODE_NORMAL           = 0;
-	public static final int AUDIO_MODE_IN_CALL          = 2;
-	public static final int AUDIO_MODE_IN_COMMUNICATION = 3;
-	public static final int AUDIO_MODE_IN_CALL_PSTN     = 4; // PSTN 로 WallPad 와 통화시
-	public static final int AUDIO_MODE_SUBPHONE         = 5; // MoIP로 WallPad 와 SubPhone 통화시
-	public static final int AUDIO_MODE_PSTN_SUBPHONE    = 6; // PSTN 로 SubPhone 과 통화시
-	public static final int AUDIO_MODE_DOOR_SUBPHONE    = 7; // 현관폰 과 SubPhone 통화시
-	public static final int AUDIO_MODE_IN_MIC_PSTN      = 8; // PSTN 로 WallPad 와 통화시 MIC On
-	public static final int AUDIO_MODE_IN_ARS_PSTN      = 9; // PSTN 로 WallPad 와 통화시 ARS 모드로
-	public static final int AUDIO_MODE_IN_VOICE_DOOR    = 10; // WallPad와 현관폰 통화시 음성출력 모드로
-
-	public static final int IOCTL_DOOR_DINGDONG         = 0xFF01;   // 현관폰 벨제어
-	public static final int IOCTL_BTNEMR_LEDONOFF       = 0xFF02;   // 비상버튼 LED
-	public static final int IOCTL_BTNCALL_LEDONOFF      = 0xFF03;   // 통화버튼 LED
-	public static final int IOCTL_BTNOPEN_LEDONOFF      = 0xFF04;   // 문열림 LED
-	public static final int IOCTL_SUBTOUCH_POWERONOFF   = 0xFF05;   // 터치 버튼 on/off
-	public static final int IOCTL_VIDEOOUT_DOORONOFF    = 0xFF06;   // 서브폰 영상 제어
-	public static final int IOCTL_CAMERA_POWERONOFF     = 0xFF07;   // 카메라 on/off
-
-	public static final int IOCTL_SUBPHONE_MUTEONOFF    = 0xFF08;   //현관,서브폰 Audio Mute
-	public static final int IOCTL_DOOR_LOCK_OPEN_REGIS  = 0xFF09;   //Door Lock Open/Regis
-	public static final int IOCTL_RFREMOCON_RESET       = 0xFF0A;   //RF Remocon on/off
-	public static final int IOCTL_DOOR_POWERONOFF       = 0xFF0B;   //현관폰 Power on/off
-	public static final int IOCTL_FRONTHOME_LEDONOFF    = 0xFF0C;   //Front LED
-	public static final int IOCTL_FRONTEMR_LEDONOFF     = 0xFF0D;   //Front LED
-	public static final int IOCTL_BTNEMR_LED_TRIGGER    = 0xFF0E;   //비상 버튼 LED 트리거 제어
-
-	public static final int IOCTL_VIDEOINPUT_DOORCAMERA = 0xFE01;   //영상 입력 제어
-	public static final int IOCTL_MIC_GAIN_SET          = 0xFD01;   //Mic Gain 설정
-	public static final int IOCTL_MIC_GAIN_GET          = 0xFD02;   //Mic Gain 읽기
-	public static final int IOCTL_MIC_RECORD_GAIN_SET   = 0xFD03;   //Mic Record Gain 설정
-	public static final int IOCTL_MIC_RECORD_GAIN_GET   = 0xFD04;   //Mic Record Gain 읽기
-	public static final int IOCTL_MIC_BOOST_GAIN_SET    = 0xFD05;   //Mic Boost Gain 설정
-	public static final int IOCTL_MIC_BOOST_GAIN_GET    = 0xFD06;   //Mic Boost Gain 읽기
-	public static final int IOCTL_MIC_LINE1_GAIN_SET    = 0xFD07;   //Mic Line1 Gain 설정
-	public static final int IOCTL_MIC_LINE1_GAIN_GET    = 0xFD08;   //Mic Line1 Gain 읽기
-	public static final int IOCTL_SPK_EQ_GAIN_SET       = 0xFD09;   //Speaker EQ Gain 설정
-	public static final int IOCTL_SPK_EQ_GAIN_GET       = 0xFD0A;   //Speaker EQ Gain 읽기
-	public static final int IOCTL_MIC_DSP_MAX_GAIN_SET  = 0xFD0B;   //Mic dsp max Gain 설정
-	public static final int IOCTL_MIC_DSP_MAX_GAIN_GET  = 0xFD0C;   //Mic dsp max Gain 읽기
-	public static final int IOCTL_MONOOUT_SUB_GAIN_SET  = 0xFD0D;   //Mono out subphone Gain 설정
-	public static final int IOCTL_MONOOUT_SUB_GAIN_GET  = 0xFD0E;   //Mono out subphone Gain 읽기
-	public static final int IOCTL_MOOD_BACKLIGHT_SET    = 0xFC01;   //무드 등 Backlight 제어
-	public static final int IOCTL_ETHERNET_MAC_SET      = 0xFB01;
-
-	public static final int IOCTL_DOOR_DETECTIME_SET           = 0xFA01;   //DoorPhone Detection Time
-	public static final int IOCTL_SENSOR_MAG0_DETECTIME_SET    = 0xFA02;   //Sensor Magnetic0 Detection Time
-	public static final int IOCTL_SENSOR_MAG1_DETECTIME_SET    = 0xFA03;   //Sensor Magnetic1 Detection Time
-	public static final int IOCTL_SENSOR_EXIT_DETECTIME_SET    = 0xFA04;   //Sensor Exit Detection Time
-	public static final int IOCTL_SENSOR_MOTIN_DETECTIME_SET   = 0xFA05;   //Sensor Motion In Detection Time
-	public static final int IOCTL_SENSOR_MOTOUT_DETECTIME_SET  = 0xFA06;   //Sensor Motion Out Detection Time
-	public static final int IOCTL_SENSOR_EMR_DETECTIME_SET     = 0xFA07;   //Sensor Emergency Detection Time
-
-	public static final int IOCTL_CAMERA_BRIGHTNESS_SET        = 0xF901;   //Camera Brightness Set
-	public static final int IOCTL_CAMERA_CONTRAST_SET          = 0xF902;   //Camera Contrast Set
-
-	public static final int IOCTL_SENSOR_MAG0_STATE            = 0xF801;   //Sensor Magnetic0 State
-	public static final int IOCTL_SENSOR_MAG1_STATE            = 0xF802;   //Sensor Magnetic1 State
-	public static final int IOCTL_SENSOR_EXIT_STATE            = 0xF803;   //Sensor Exit State
-	public static final int IOCTL_SENSOR_MOTIN_STATE           = 0xF804;   //Sensor Motion In State
-	public static final int IOCTL_SENSOR_MOTOUT_STATE          = 0xF805;   //Sensor Motion Out State
-	public static final int IOCTL_SENSOR_EMR_STATE             = 0xF806;   //Sensor Emergency State
-
-	public static final int IOCTL_KEY_ONOFF_SET                = 0xF701;   //SideKey On/Off Control
-	public static final int IOCTL_KEY_ONOFF_GET                = 0xF702;   //SideKey On/Off 상태 읽기
-
-	public WallPadInterface() {
-		// TODO Auto-generated constructor stub
-	}
-	static {
-		System.loadLibrary("wpddevctr");
-	}
-
-	public void MacSet(String macstr)
-	{
-		WpdInterfaceOpen();
-		SetMacAddr(IOCTL_ETHERNET_MAC_SET, macstr);
-		WpdInterfaceClose();
-	}
-	public int DoControl(int cmd, int arg)
-	{
-		WpdInterfaceOpen();
-		int ctr = WpdInterfaceControl( cmd, arg);
-		WpdInterfaceClose();
-
-		return ctr;
-	}
-
-	public void DoorLockControl(boolean ctr) {
-		try {
-			// A40 - 월패드
-			if (Version.getPlatformType() == Version.PLATFORM_TYPE.A40i) {
-				Log.i(TAG, "[DoorLockControl] ctr [" + ctr + "]");
-				V40IF mV40IF = new V40IF();
-				mV40IF.DoorLockControl(ctr);
-			}
-			else {
-				WpdInterfaceOpen();
-				WpdInterfaceControl(IOCTL_DOOR_LOCK_OPEN_REGIS, (ctr)?1:0);
-				WpdInterfaceClose();
-			}
-		} catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-        } catch (Exception e) {
-			Log.e(TAG, "[Exception] DoorLockControl(boolean ctr)");
-			//e.printStackTrace();
-            LogUtil.errorLogInfo("", TAG, e);
-		}
-	}
-
-	public int cameraPowerControll(boolean onOff) {
-		int bOnOff = 0;
-
-		if (onOff == true) {
-			bOnOff = 1;
-		}
-		else {
-			bOnOff = 0;
-		}
-
-		int ret = -1;
-
-		if (Version.getPlatformType() == Version.PLATFORM_TYPE.A40i && !Version.getGatewayUsage()) {
-			// A40 - 월패드
-			V40IF mV40IF = new V40IF();
-			if (mV40IF.WpdInterfaceOpen() != -1) {
-				ret = mV40IF.WpdInterfaceControl(IOCTL_DOOR_POWERONOFF, bOnOff);
-				mV40IF.WpdInterfaceClose();
-			}
-		}
-		else {
-			// 현산향
-			Log.i(TAG, "[cameraPowerControll] onoff : " + onOff);
-			if (WpdInterfaceOpen() != -1) {
-				ret = WpdInterfaceControl(IOCTL_DOOR_POWERONOFF, bOnOff);
-
-				WpdInterfaceClose();
-			}
-		}
-		return ret;
-	}
-
-	public native int WpdInterfaceOpen();
-	public native int WpdInterfaceClose();
-	public native int WpdInterfaceControl(int cmd, int arg);
-	public native int SetMacAddr(int cmd, String macstr);
-}
+package com.artncore.devicectr;
+
+import android.util.Log;
+
+import java.nio.channels.OverlappingFileLockException;
+import com.util.LogUtil;
+import kr.co.icontrols.v40ioctl.V40IF;
+import kr.co.icontrols.wallpadsupport.Version;
+
+public class WallPadInterface {
+
+	String TAG = "WallPadInterface";
+
+	public static final int EVT_RING = 220;     // PSTN Incomingcall 상태 전달
+	public static final int BTN_EMR  = 221;     //FRONT 비상 버튼 입력 상태 전달
+	public static final int BTN_CALL = 222;     //FRONT 통화 버튼 입력 상태 전달
+	public static final int BTN_OPEN = 223;     //FRONT OPEN 버튼 입력 상태 전달
+	public static final int BTN_DOOR = 224;     //현관폰 벨 버튼 입력 상태 전달
+	public static final int BTN_DOOR_IHN1010 = 268;     //현관폰 벨 버튼 입력 상태 전달 (IHN-1010)
+	public static final int EVT_EMR  = 225;     //비상 센서 입력 상태 전달
+	public static final int EVT_MAG0 = 226;     //센서 마그네틱 0 입력 상태 전달
+	public static final int EVT_MAG1 = 227;     //센서 마그네틱 1 입력 상태 전달
+	public static final int EVT_EXIT = 228;     //센서 피난사다리 입력 상태 전달
+	public static final int EVT_MOTIN = 229;    //센서 동체감지기-내부 입력 상태 전달
+	public static final int EVT_MOTOUT = 230;   //센서 동체감지기-외부 입력 상태 전달
+	public static final int EVT_RING_END = 231; // PSTN Incomingcall 종료 상태 전달 (본 이벤트는 본인이 전화를 받아서 EVT_RING 가 종료된 경우 호출되지않습니다.)
+
+	public static final int AUDIO_MODE_NORMAL           = 0;
+	public static final int AUDIO_MODE_IN_CALL          = 2;
+	public static final int AUDIO_MODE_IN_COMMUNICATION = 3;
+	public static final int AUDIO_MODE_IN_CALL_PSTN     = 4; // PSTN 로 WallPad 와 통화시
+	public static final int AUDIO_MODE_SUBPHONE         = 5; // MoIP로 WallPad 와 SubPhone 통화시
+	public static final int AUDIO_MODE_PSTN_SUBPHONE    = 6; // PSTN 로 SubPhone 과 통화시
+	public static final int AUDIO_MODE_DOOR_SUBPHONE    = 7; // 현관폰 과 SubPhone 통화시
+	public static final int AUDIO_MODE_IN_MIC_PSTN      = 8; // PSTN 로 WallPad 와 통화시 MIC On
+	public static final int AUDIO_MODE_IN_ARS_PSTN      = 9; // PSTN 로 WallPad 와 통화시 ARS 모드로
+	public static final int AUDIO_MODE_IN_VOICE_DOOR    = 10; // WallPad와 현관폰 통화시 음성출력 모드로
+
+	public static final int IOCTL_DOOR_DINGDONG         = 0xFF01;   // 현관폰 벨제어
+	public static final int IOCTL_BTNEMR_LEDONOFF       = 0xFF02;   // 비상버튼 LED
+	public static final int IOCTL_BTNCALL_LEDONOFF      = 0xFF03;   // 통화버튼 LED
+	public static final int IOCTL_BTNOPEN_LEDONOFF      = 0xFF04;   // 문열림 LED
+	public static final int IOCTL_SUBTOUCH_POWERONOFF   = 0xFF05;   // 터치 버튼 on/off
+	public static final int IOCTL_VIDEOOUT_DOORONOFF    = 0xFF06;   // 서브폰 영상 제어
+	public static final int IOCTL_CAMERA_POWERONOFF     = 0xFF07;   // 카메라 on/off
+
+	public static final int IOCTL_SUBPHONE_MUTEONOFF    = 0xFF08;   //현관,서브폰 Audio Mute
+	public static final int IOCTL_DOOR_LOCK_OPEN_REGIS  = 0xFF09;   //Door Lock Open/Regis
+	public static final int IOCTL_RFREMOCON_RESET       = 0xFF0A;   //RF Remocon on/off
+	public static final int IOCTL_DOOR_POWERONOFF       = 0xFF0B;   //현관폰 Power on/off
+	public static final int IOCTL_FRONTHOME_LEDONOFF    = 0xFF0C;   //Front LED
+	public static final int IOCTL_FRONTEMR_LEDONOFF     = 0xFF0D;   //Front LED
+	public static final int IOCTL_BTNEMR_LED_TRIGGER    = 0xFF0E;   //비상 버튼 LED 트리거 제어
+
+	public static final int IOCTL_VIDEOINPUT_DOORCAMERA = 0xFE01;   //영상 입력 제어
+	public static final int IOCTL_MIC_GAIN_SET          = 0xFD01;   //Mic Gain 설정
+	public static final int IOCTL_MIC_GAIN_GET          = 0xFD02;   //Mic Gain 읽기
+	public static final int IOCTL_MIC_RECORD_GAIN_SET   = 0xFD03;   //Mic Record Gain 설정
+	public static final int IOCTL_MIC_RECORD_GAIN_GET   = 0xFD04;   //Mic Record Gain 읽기
+	public static final int IOCTL_MIC_BOOST_GAIN_SET    = 0xFD05;   //Mic Boost Gain 설정
+	public static final int IOCTL_MIC_BOOST_GAIN_GET    = 0xFD06;   //Mic Boost Gain 읽기
+	public static final int IOCTL_MIC_LINE1_GAIN_SET    = 0xFD07;   //Mic Line1 Gain 설정
+	public static final int IOCTL_MIC_LINE1_GAIN_GET    = 0xFD08;   //Mic Line1 Gain 읽기
+	public static final int IOCTL_SPK_EQ_GAIN_SET       = 0xFD09;   //Speaker EQ Gain 설정
+	public static final int IOCTL_SPK_EQ_GAIN_GET       = 0xFD0A;   //Speaker EQ Gain 읽기
+	public static final int IOCTL_MIC_DSP_MAX_GAIN_SET  = 0xFD0B;   //Mic dsp max Gain 설정
+	public static final int IOCTL_MIC_DSP_MAX_GAIN_GET  = 0xFD0C;   //Mic dsp max Gain 읽기
+	public static final int IOCTL_MONOOUT_SUB_GAIN_SET  = 0xFD0D;   //Mono out subphone Gain 설정
+	public static final int IOCTL_MONOOUT_SUB_GAIN_GET  = 0xFD0E;   //Mono out subphone Gain 읽기
+	public static final int IOCTL_MOOD_BACKLIGHT_SET    = 0xFC01;   //무드 등 Backlight 제어
+	public static final int IOCTL_ETHERNET_MAC_SET      = 0xFB01;
+
+	public static final int IOCTL_DOOR_DETECTIME_SET           = 0xFA01;   //DoorPhone Detection Time
+	public static final int IOCTL_SENSOR_MAG0_DETECTIME_SET    = 0xFA02;   //Sensor Magnetic0 Detection Time
+	public static final int IOCTL_SENSOR_MAG1_DETECTIME_SET    = 0xFA03;   //Sensor Magnetic1 Detection Time
+	public static final int IOCTL_SENSOR_EXIT_DETECTIME_SET    = 0xFA04;   //Sensor Exit Detection Time
+	public static final int IOCTL_SENSOR_MOTIN_DETECTIME_SET   = 0xFA05;   //Sensor Motion In Detection Time
+	public static final int IOCTL_SENSOR_MOTOUT_DETECTIME_SET  = 0xFA06;   //Sensor Motion Out Detection Time
+	public static final int IOCTL_SENSOR_EMR_DETECTIME_SET     = 0xFA07;   //Sensor Emergency Detection Time
+
+	public static final int IOCTL_CAMERA_BRIGHTNESS_SET        = 0xF901;   //Camera Brightness Set
+	public static final int IOCTL_CAMERA_CONTRAST_SET          = 0xF902;   //Camera Contrast Set
+
+	public static final int IOCTL_SENSOR_MAG0_STATE            = 0xF801;   //Sensor Magnetic0 State
+	public static final int IOCTL_SENSOR_MAG1_STATE            = 0xF802;   //Sensor Magnetic1 State
+	public static final int IOCTL_SENSOR_EXIT_STATE            = 0xF803;   //Sensor Exit State
+	public static final int IOCTL_SENSOR_MOTIN_STATE           = 0xF804;   //Sensor Motion In State
+	public static final int IOCTL_SENSOR_MOTOUT_STATE          = 0xF805;   //Sensor Motion Out State
+	public static final int IOCTL_SENSOR_EMR_STATE             = 0xF806;   //Sensor Emergency State
+
+	public static final int IOCTL_KEY_ONOFF_SET                = 0xF701;   //SideKey On/Off Control
+	public static final int IOCTL_KEY_ONOFF_GET                = 0xF702;   //SideKey On/Off 상태 읽기
+
+	public WallPadInterface() {
+		// TODO Auto-generated constructor stub
+	}
+	static {
+		System.loadLibrary("wpddevctr");
+	}
+
+	public void MacSet(String macstr)
+	{
+		WpdInterfaceOpen();
+		SetMacAddr(IOCTL_ETHERNET_MAC_SET, macstr);
+		WpdInterfaceClose();
+	}
+	public int DoControl(int cmd, int arg)
+	{
+		WpdInterfaceOpen();
+		int ctr = WpdInterfaceControl( cmd, arg);
+		WpdInterfaceClose();
+
+		return ctr;
+	}
+
+	public void DoorLockControl(boolean ctr) {
+		try {
+			// A40 - 월패드
+			if (Version.getPlatformType() == Version.PLATFORM_TYPE.A40i) {
+				Log.i(TAG, "[DoorLockControl] ctr [" + ctr + "]");
+				V40IF mV40IF = new V40IF();
+				mV40IF.DoorLockControl(ctr);
+			}
+			else {
+				WpdInterfaceOpen();
+				WpdInterfaceControl(IOCTL_DOOR_LOCK_OPEN_REGIS, (ctr)?1:0);
+				WpdInterfaceClose();
+			}
+		} catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+        } catch (Exception e) {
+			Log.e(TAG, "[Exception] DoorLockControl(boolean ctr)");
+			//e.printStackTrace();
+            LogUtil.errorLogInfo("", TAG, e);
+		}
+	}
+
+	/**
+	 * 삼성SDS 도어락 연동 기능 추가
+	 *  기존소스에도 있지만, 검증할 시간이 부족하여, 임시로 따로 구분하여 구현함 (jeff, 2021.04.09)
+	 * @param nValue 0: 등록, 1: 문열림, 2: 문열림 대기 미설정, 3: 문열림 대기 3초, 4: 문열리 대기 5초, 5: 문열림 대기 10초
+	 */
+	public boolean ctrlDoorlockOpenStandbyMode(int nValue) {
+		try {
+			// A40 - 월패드
+			if (Version.getPlatformType() == Version.PLATFORM_TYPE.A40i) {
+				Log.i(TAG, "[ctrlDoorlockOpenStandbyMode] nValue [" + nValue + "]");
+				V40IF mV40IF = new V40IF();
+				mV40IF.ctrlDoorlockOpenStandbyMode(nValue);
+			}
+		} catch (RuntimeException re) {
+			LogUtil.errorLogInfo("", TAG, re);
+		} catch (Exception e) {
+			//e.printStackTrace();
+			LogUtil.errorLogInfo("", TAG, e);
+		}
+		return true;
+	}
+
+	public int cameraPowerControll(boolean onOff) {
+		int bOnOff = 0;
+
+		if (onOff == true) {
+			bOnOff = 1;
+		}
+		else {
+			bOnOff = 0;
+		}
+
+		int ret = -1;
+
+		if (Version.getPlatformType() == Version.PLATFORM_TYPE.A40i && !Version.getGatewayUsage()) {
+			// A40 - 월패드
+			V40IF mV40IF = new V40IF();
+			if (mV40IF.WpdInterfaceOpen() != -1) {
+				ret = mV40IF.WpdInterfaceControl(IOCTL_DOOR_POWERONOFF, bOnOff);
+				mV40IF.WpdInterfaceClose();
+			}
+		}
+		else {
+			// 현산향
+			Log.i(TAG, "[cameraPowerControll] onoff : " + onOff);
+			if (WpdInterfaceOpen() != -1) {
+				ret = WpdInterfaceControl(IOCTL_DOOR_POWERONOFF, bOnOff);
+
+				WpdInterfaceClose();
+			}
+		}
+		return ret;
+	}
+
+	public native int WpdInterfaceOpen();
+	public native int WpdInterfaceClose();
+	public native int WpdInterfaceControl(int cmd, int arg);
+	public native int SetMacAddr(int cmd, String macstr);
+}

+ 241 - 239
WallPadDevService/src/main/java/com/artncore/wallpaddevservice/DataBaseLoader.java

@@ -1,239 +1,241 @@
-package com.artncore.wallpaddevservice;
-
-import com.artncore.WallPadDataMgr.WallpadDeviceSet;
-
-import android.content.Context;
-import android.util.Log;
-
-import kr.co.icontrols.wallpadsupport.Version;
-import com.util.LogUtil;
-
-import static com.artncore.WallPadDataMgr.WallpadDeviceSet.DOORLOCK_TYPE_RF;
-
-/**
- * 디바이스 서비스 상에서 빈번히 사용되며, 부팅후 변경되지않는 데이터를<br>
- * 로딩하여 사용하는 클래스 이다.
- */
-public class DataBaseLoader {
-    private final static String TAG = "DataBaseLoader";
-
-    private final boolean DEBUG_LOG_ON = true;
-    private void DebugLogOutput(String s) { if(DEBUG_LOG_ON) Log.d(TAG, s); }
-
-    private Context mContext;
-
-    public class Data {
-        public class WallpadDeviceSet {
-            public int [] Get_Light_info;
-            public int [] Get_BatchSW_Info;
-            public int [] Heating_FixRoomCount; //[광주 무등산 임대세대 전용 기능]
-            public boolean Get_ZeroEnergyHouse; //[제로에너지하우스 사용여부]
-            public boolean Get_BLE_SmartKey;    //[BLE스마트키 사용여부]
-            public boolean Get_GasValve_Debug;  //[가스벨브 디버깅 기능 사용여부]
-            public boolean Get_Ctr_Sequence_Limit;  //[통신 시퀀스 제한(0~127) 사용여부]
-            public boolean Get_GasDetect_5time;		//[가스센서감지5회]
-            public boolean Get_IntegratedSwitchInfo; //[통합스위치 사용여부] (시간 동기화 때문에 추가함)
-            public int [] Get_DoorLock_Info;
-            public String Get_Site_Code;
-
-            public WallpadDeviceSet() {
-                Get_Light_info = new int [] {1, 11, 6};
-                Get_BatchSW_Info = new int [] {1, 22, 2, 3};
-                Heating_FixRoomCount = new int [] {0, 0};
-                Get_ZeroEnergyHouse = false;
-                Get_BLE_SmartKey = false;
-                Get_GasValve_Debug = false;
-                Get_Ctr_Sequence_Limit = false;
-                Get_GasDetect_5time = false;
-                Get_IntegratedSwitchInfo = false;
-                Get_DoorLock_Info = new int[] {1, DOORLOCK_TYPE_RF};
-                Get_Site_Code = null;
-            }
-        }
-
-        public WallpadDeviceSet wallpadDeviceSet;
-
-        public Data()
-        {
-            wallpadDeviceSet = new WallpadDeviceSet();
-        }
-    }
-    public Data data;
-
-    /** 생성자 */
-    @SuppressWarnings("static-access")
-    public DataBaseLoader(Context context) {
-        // 1. Param Check
-        if (context == null) {
-            Log.e(TAG, "[Create] Param - context is null !!!");
-            return;
-        }
-        mContext = context;
-
-        data = new Data();
-
-        // 2. Load
-        int [] Temp;
-        /////////////////////////////////////////////////////////////////////
-        //     2.1. WallpadDeviceSet
-        /////////////////////////////////////////////////////////////////////
-        WallpadDeviceSet wallpadDeviceSet = new WallpadDeviceSet(mContext);
-
-        //         2.1.1. Get_Light_info
-        Temp = wallpadDeviceSet.Get_Light_info();
-        if (Temp != null) data.wallpadDeviceSet.Get_Light_info = Temp;
-
-        //         2.1.2. Get_BatchSW_Info
-        Temp = wallpadDeviceSet.Get_BatchSW_Info();
-        for (int a = 0; a < Temp.length; a++) {
-            Log.i(TAG, "Init Batch[" + a + "] = " + Temp[a]);
-        }
-
-        if(Temp != null) data.wallpadDeviceSet.Get_BatchSW_Info = Temp;
-
-        // 제주도 초기 업데이트 위해서 임시 추가
-        /*if(Version.getModelType() == Version.MODEL_TYPE.IHN_D101)
-        {
-            try
-            {
-                Log.i(TAG, "[DatabaseLoader] Batch D101 ~~~");
-                if(data.wallpadDeviceSet.Get_BatchSW_Info[0] == 0 || data.wallpadDeviceSet.Get_BatchSW_Info[0] == 1)
-                {
-                    Log.i(TAG, "[DatabaseLoader] Batch Use ~~~");
-
-                    if(data.wallpadDeviceSet.Get_BatchSW_Info[1] == WallpadDeviceSet.BATCH_TYPE_SMART ||
-                        data.wallpadDeviceSet.Get_BatchSW_Info[1] == WallpadDeviceSet.BATCH_TYPE_HDC_LCD_SMART  )
-                    {
-                        Log.i(TAG, "[DatabaseLoader] Batch Change ~~~");
-
-                        wallpadDeviceSet.UpdateSettingData("subdev_list"
-                                , "스마트스위치&일괄소등"
-                                , 0
-                                , "1(1:스마트스위치&일괄소등(사용함)종류(현산향LCD스마트스위치)L1설정(2)L2설정(3))"
-                        );
-                    }
-
-                    Temp = wallpadDeviceSet.Get_BatchSW_Info();
-                    for(int a = 0; a < Temp.length; a++)
-                    {
-                        Log.i(TAG, "Change Batch[" + a + "] = " + Temp[a]);
-                    }
-                    if(Temp != null) data.wallpadDeviceSet.Get_BatchSW_Info = Temp;
-                }
-            }
-            catch(Exception e)
-            {
-                e.printStackTrace();
-            }
-        }*/
-
-        //         2.1.3. 제로에너지하우스 사용여부 체크, 사용 시 에너지미터 적용됨
-        boolean tempResult = wallpadDeviceSet.GetZeroEnergyHouseInfo();
-        if (tempResult == true) {
-            data.wallpadDeviceSet.Get_Light_info[0] = 1;
-            data.wallpadDeviceSet.Get_Light_info[1] = wallpadDeviceSet.LIGHT_TYPE_ZEROENERGY_ENERGYMETER;
-            data.wallpadDeviceSet.Get_Light_info[2] = 2;
-            data.wallpadDeviceSet.Get_ZeroEnergyHouse = true;
-        }
-
-        //          2.1.4. 난방 방 개수 고정 기능 사용 여부
-        int [] TempFixRoomNum = wallpadDeviceSet.Get_Temper_FixRoomNumber();
-        if (TempFixRoomNum != null) data.wallpadDeviceSet.Heating_FixRoomCount = TempFixRoomNum;
-
-        //          2.1.5. BLE스마트키 사용여부 가져오기
-        int[] DoorCamKind = wallpadDeviceSet.Get_RFDoorCAM_Info(); // 현관카메라 종류 파악
-        if ((DoorCamKind[0] == 0)) {
-            data.wallpadDeviceSet.Get_BLE_SmartKey = false;
-        }
-        else if ((DoorCamKind[0] == 1)) {
-            // 스마트키 현관카메라 사용
-            if ((DoorCamKind[1] != WallpadDeviceSet.DOORTYPE_SMARTKEY) && (DoorCamKind[1] != WallpadDeviceSet.DOORTYPE_SMARTKEY_EXTERNAL) && (DoorCamKind[1] != WallpadDeviceSet.DOORTYPE_IOT_SMART)) {
-                data.wallpadDeviceSet.Get_BLE_SmartKey = false;
-            }
-            else {
-                data.wallpadDeviceSet.Get_BLE_SmartKey = wallpadDeviceSet.GetBLESmartKeyUSE();
-            }
-        }
-
-        //          2.1.6. 가스벨브 디버깅 기능 사용여부 가져오기
-        int Gasinfo = wallpadDeviceSet.GetDeviceSetted("가스벨브디버깅");
-        if (Gasinfo == WallpadDeviceSet.DEV_DATA_ENABLE) {
-            data.wallpadDeviceSet.Get_GasValve_Debug = true;
-        }
-
-        data.wallpadDeviceSet.Get_Ctr_Sequence_Limit = wallpadDeviceSet.GetCtrSequenceLimit();
-
-        data.wallpadDeviceSet.Get_GasDetect_5time = wallpadDeviceSet.GetGasDetect5Time();
-
-        //          2.1.11 통합스위치 설정 가져오기
-        boolean tempResult3 = wallpadDeviceSet.Get_Integrated_Switch_Info();
-        if (tempResult3 == true) {
-            data.wallpadDeviceSet.Get_IntegratedSwitchInfo = true;
-        }
-        Log.i(TAG, "[Create] Get_IntegratedSwitchInfo :" + data.wallpadDeviceSet.Get_IntegratedSwitchInfo);
-
-        //          2.1.12 도어락 타입 설정 가져오기
-        data.wallpadDeviceSet.Get_DoorLock_Info = wallpadDeviceSet.Get_DoorLock_Info();
-
-        //		   2.1.13  사이트코드 가져오기
-        String[] tempSite = null;
-        tempSite = wallpadDeviceSet.GetSettingData("site_code");
-        if ((tempSite != null) && tempSite.length > 1) {
-            data.wallpadDeviceSet.Get_Site_Code = tempSite[1];
-        }
-
-        if ((data.wallpadDeviceSet.Get_Site_Code == null) || (data.wallpadDeviceSet.Get_Site_Code.length() == 0)) {
-            Log.i(TAG, "[Create] Get_Site_Code - default value setted ~~~");
-            data.wallpadDeviceSet.Get_Site_Code = "12345678";
-        }
-
-        /////////////////////////////////////////////////////////////////////
-        wallpadDeviceSet.closeDB();
-
-        DebugLogOutput("Create !!!");
-    }
-
-
-    /**
-     * DB 제어기기 설정정보 읽기
-     *
-     * @param wallpadDeviceSet wallpadDeviceSet변수 (초기화 한것)
-     * @param StringData 사용함/사용안함 읽을 설정값
-     * **/
-    public boolean Get_GetSettingData(WallpadDeviceSet wallpadDeviceSet, String StringData)
-    {
-        String[] GetData;
-        boolean returnData = false;
-
-        if(wallpadDeviceSet == null)
-        {
-            return false;
-        }
-
-        GetData = wallpadDeviceSet.GetSettingData(StringData);
-
-        try
-        {
-            if (GetData == null) return returnData;
-
-            if (GetData[1].indexOf("사용함") > 0) returnData = true;
-            else
-            {
-                returnData = false;
-            }
-
-            return returnData;
-        }
-        catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-            returnData = false;
-            return returnData;
-        }
-        catch (Exception e) {
-            //e.printStackTrace();
-            LogUtil.errorLogInfo("", TAG, e);
-            returnData = false;
-            return returnData;
-        }
-    }
-}
+package com.artncore.wallpaddevservice;
+
+import com.artncore.WallPadDataMgr.WallpadDeviceSet;
+
+import android.content.Context;
+import android.util.Log;
+
+import kr.co.icontrols.wallpadsupport.Version;
+import com.util.LogUtil;
+
+import static com.artncore.WallPadDataMgr.WallpadDeviceSet.DOORLOCK_TYPE_RF;
+
+/**
+ * 디바이스 서비스 상에서 빈번히 사용되며, 부팅후 변경되지않는 데이터를<br>
+ * 로딩하여 사용하는 클래스 이다.
+ */
+public class DataBaseLoader {
+    private final static String TAG = "DataBaseLoader";
+
+    private final boolean DEBUG_LOG_ON = true;
+    private void DebugLogOutput(String s) { if(DEBUG_LOG_ON) Log.d(TAG, s); }
+
+    private Context mContext;
+
+    public class Data {
+        public class WallpadDeviceSet {
+            public int [] Get_Light_info;
+            public int [] Get_BatchSW_Info;
+            public int [] Heating_FixRoomCount; //[광주 무등산 임대세대 전용 기능]
+            public boolean Get_ZeroEnergyHouse; //[제로에너지하우스 사용여부]
+            public boolean Get_BLE_SmartKey;    //[BLE스마트키 사용여부]
+            public boolean Get_GasValve_Debug;  //[가스벨브 디버깅 기능 사용여부]
+            public boolean Get_Ctr_Sequence_Limit;  //[통신 시퀀스 제한(0~127) 사용여부]
+            public boolean Get_GasDetect_5time;		//[가스센서감지5회]
+            public boolean Get_IntegratedSwitchInfo; //[통합스위치 사용여부] (시간 동기화 때문에 추가함)
+            public int [] Get_DoorLock_Info;
+            public String Get_Site_Code;
+
+            public WallpadDeviceSet() {
+                Get_Light_info = new int [] {1, 11, 6};
+                Get_BatchSW_Info = new int [] {1, 22, 2, 3};
+                Heating_FixRoomCount = new int [] {0, 0};
+                Get_ZeroEnergyHouse = false;
+                Get_BLE_SmartKey = false;
+                Get_GasValve_Debug = false;
+                Get_Ctr_Sequence_Limit = false;
+                Get_GasDetect_5time = false;
+                Get_IntegratedSwitchInfo = false;
+                Get_DoorLock_Info = new int[] {1, DOORLOCK_TYPE_RF};
+                Get_Site_Code = null;
+            }
+        }
+
+        public WallpadDeviceSet wallpadDeviceSet;
+
+        public Data()
+        {
+            wallpadDeviceSet = new WallpadDeviceSet();
+        }
+    }
+    public Data data;
+
+    /** 생성자 */
+    @SuppressWarnings("static-access")
+    public DataBaseLoader(Context context) {
+        // 1. Param Check
+        if (context == null) {
+            Log.e(TAG, "[Create] Param - context is null !!!");
+            return;
+        }
+        mContext = context;
+
+        data = new Data();
+
+        // 2. Load
+        int [] Temp;
+        /////////////////////////////////////////////////////////////////////
+        //     2.1. WallpadDeviceSet
+        /////////////////////////////////////////////////////////////////////
+        WallpadDeviceSet wallpadDeviceSet = new WallpadDeviceSet(mContext);
+
+        //         2.1.1. Get_Light_info
+        Temp = wallpadDeviceSet.Get_Light_info();
+        if (Temp != null) data.wallpadDeviceSet.Get_Light_info = Temp;
+
+        //         2.1.2. Get_BatchSW_Info
+        Temp = wallpadDeviceSet.Get_BatchSW_Info();
+        for (int a = 0; a < Temp.length; a++) {
+            Log.i(TAG, "Init Batch[" + a + "] = " + Temp[a]);
+        }
+
+        if(Temp != null) data.wallpadDeviceSet.Get_BatchSW_Info = Temp;
+
+        // 제주도 초기 업데이트 위해서 임시 추가
+        /*if(Version.getModelType() == Version.MODEL_TYPE.IHN_D101)
+        {
+            try
+            {
+                Log.i(TAG, "[DatabaseLoader] Batch D101 ~~~");
+                if(data.wallpadDeviceSet.Get_BatchSW_Info[0] == 0 || data.wallpadDeviceSet.Get_BatchSW_Info[0] == 1)
+                {
+                    Log.i(TAG, "[DatabaseLoader] Batch Use ~~~");
+
+                    if(data.wallpadDeviceSet.Get_BatchSW_Info[1] == WallpadDeviceSet.BATCH_TYPE_SMART ||
+                        data.wallpadDeviceSet.Get_BatchSW_Info[1] == WallpadDeviceSet.BATCH_TYPE_HDC_LCD_SMART  )
+                    {
+                        Log.i(TAG, "[DatabaseLoader] Batch Change ~~~");
+
+                        wallpadDeviceSet.UpdateSettingData("subdev_list"
+                                , "스마트스위치&일괄소등"
+                                , 0
+                                , "1(1:스마트스위치&일괄소등(사용함)종류(현산향LCD스마트스위치)L1설정(2)L2설정(3))"
+                        );
+                    }
+
+                    Temp = wallpadDeviceSet.Get_BatchSW_Info();
+                    for(int a = 0; a < Temp.length; a++)
+                    {
+                        Log.i(TAG, "Change Batch[" + a + "] = " + Temp[a]);
+                    }
+                    if(Temp != null) data.wallpadDeviceSet.Get_BatchSW_Info = Temp;
+                }
+            }
+            catch(Exception e)
+            {
+                e.printStackTrace();
+            }
+        }*/
+
+        //         2.1.3. 제로에너지하우스 사용여부 체크, 사용 시 에너지미터 적용됨
+        boolean tempResult = wallpadDeviceSet.GetZeroEnergyHouseInfo();
+        if (tempResult == true) {
+            data.wallpadDeviceSet.Get_Light_info[0] = 1;
+            data.wallpadDeviceSet.Get_Light_info[1] = wallpadDeviceSet.LIGHT_TYPE_ZEROENERGY_ENERGYMETER;
+            data.wallpadDeviceSet.Get_Light_info[2] = 2;
+            data.wallpadDeviceSet.Get_ZeroEnergyHouse = true;
+        }
+
+        //          2.1.4. 난방 방 개수 고정 기능 사용 여부
+        int [] TempFixRoomNum = wallpadDeviceSet.Get_Temper_FixRoomNumber();
+        if (TempFixRoomNum != null) data.wallpadDeviceSet.Heating_FixRoomCount = TempFixRoomNum;
+
+        //          2.1.5. BLE스마트키 사용여부 가져오기
+        int[] DoorCamKind = wallpadDeviceSet.Get_RFDoorCAM_Info(); // 현관카메라 종류 파악
+        if ((DoorCamKind[0] == 0)) {
+            data.wallpadDeviceSet.Get_BLE_SmartKey = false;
+        }
+        else if ((DoorCamKind[0] == 1)) {
+            // 스마트키 현관카메라 사용
+            Log.d(TAG, "[DataBaseLoader] DoorCamKind [" + DoorCamKind[1] + "]");
+            if ((DoorCamKind[1] != WallpadDeviceSet.DOORTYPE_SMARTKEY) && (DoorCamKind[1] != WallpadDeviceSet.DOORTYPE_SMARTKEY_EXTERNAL) && (DoorCamKind[1] != WallpadDeviceSet.DOORTYPE_IOT_SMART)) {
+                data.wallpadDeviceSet.Get_BLE_SmartKey = false;
+            }
+            else {
+                data.wallpadDeviceSet.Get_BLE_SmartKey = wallpadDeviceSet.GetBLESmartKeyUSE();
+            }
+            Log.d(TAG, "[DataBaseLoader] Get_BLE_SmartKey [" + data.wallpadDeviceSet.Get_BLE_SmartKey + "]");
+        }
+
+        //          2.1.6. 가스벨브 디버깅 기능 사용여부 가져오기
+        int Gasinfo = wallpadDeviceSet.GetDeviceSetted("가스벨브디버깅");
+        if (Gasinfo == WallpadDeviceSet.DEV_DATA_ENABLE) {
+            data.wallpadDeviceSet.Get_GasValve_Debug = true;
+        }
+
+        data.wallpadDeviceSet.Get_Ctr_Sequence_Limit = wallpadDeviceSet.GetCtrSequenceLimit();
+
+        data.wallpadDeviceSet.Get_GasDetect_5time = wallpadDeviceSet.GetGasDetect5Time();
+
+        //          2.1.11 통합스위치 설정 가져오기
+        boolean tempResult3 = wallpadDeviceSet.Get_Integrated_Switch_Info();
+        if (tempResult3 == true) {
+            data.wallpadDeviceSet.Get_IntegratedSwitchInfo = true;
+        }
+        Log.i(TAG, "[Create] Get_IntegratedSwitchInfo :" + data.wallpadDeviceSet.Get_IntegratedSwitchInfo);
+
+        //          2.1.12 도어락 타입 설정 가져오기
+        data.wallpadDeviceSet.Get_DoorLock_Info = wallpadDeviceSet.Get_DoorLock_Info();
+
+        //		   2.1.13  사이트코드 가져오기
+        String[] tempSite = null;
+        tempSite = wallpadDeviceSet.GetSettingData("site_code");
+        if ((tempSite != null) && tempSite.length > 1) {
+            data.wallpadDeviceSet.Get_Site_Code = tempSite[1];
+        }
+
+        if ((data.wallpadDeviceSet.Get_Site_Code == null) || (data.wallpadDeviceSet.Get_Site_Code.length() == 0)) {
+            Log.i(TAG, "[Create] Get_Site_Code - default value setted ~~~");
+            data.wallpadDeviceSet.Get_Site_Code = "12345678";
+        }
+
+        /////////////////////////////////////////////////////////////////////
+        wallpadDeviceSet.closeDB();
+
+        DebugLogOutput("Create !!!");
+    }
+
+
+    /**
+     * DB 제어기기 설정정보 읽기
+     *
+     * @param wallpadDeviceSet wallpadDeviceSet변수 (초기화 한것)
+     * @param StringData 사용함/사용안함 읽을 설정값
+     * **/
+    public boolean Get_GetSettingData(WallpadDeviceSet wallpadDeviceSet, String StringData)
+    {
+        String[] GetData;
+        boolean returnData = false;
+
+        if(wallpadDeviceSet == null)
+        {
+            return false;
+        }
+
+        GetData = wallpadDeviceSet.GetSettingData(StringData);
+
+        try
+        {
+            if (GetData == null) return returnData;
+
+            if (GetData[1].indexOf("사용함") > 0) returnData = true;
+            else
+            {
+                returnData = false;
+            }
+
+            return returnData;
+        }
+        catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+            returnData = false;
+            return returnData;
+        }
+        catch (Exception e) {
+            //e.printStackTrace();
+            LogUtil.errorLogInfo("", TAG, e);
+            returnData = false;
+            return returnData;
+        }
+    }
+}

+ 238 - 238
WallPadDevService/src/main/java/com/artncore/wallpaddevservice/DeviceInitChecker.java

@@ -1,238 +1,238 @@
-package com.artncore.wallpaddevservice;
-
-import java.util.LinkedList;
-
-import com.artncore.commons.define;
-
-import android.content.Intent;
-import android.os.CountDownTimer;
-import android.util.Log;
-
-/**
- * 디바이스 드라이버의 초기화 과정이 모두 완료되었는지<br>
- * 체크 및 알람을 하는 클래스 이다.
- */
-public class DeviceInitChecker
-{
-	private final static String TAG = "DeviceInitChecker";
-
-	private final boolean DEBUG_LOG_ON = true;
-	private void DebugLogOutput(String s) { if(DEBUG_LOG_ON) Log.d(TAG, s); }
-
-	private LinkedList<String> mQueue;
-
-	private boolean mAddEnd;
-
-	private boolean mSendInitBR;
-
-	private CountDownTimer mTimeOut = null;
-
-	private final long TIMEOUT_MINUTE = 2;
-
-	public DeviceInitChecker()
-	{
-		mQueue = new LinkedList<String>();
-		mQueue.clear();
-
-		mSendInitBR = false;
-		mAddEnd = false;
-
-		DebugLogOutput("Create !!!");
-	}
-
-	/**
-	 * 등록이 완료되었을시 호출한다.
-	 * 본 메소드를 호출한 이후 {@link DeviceInitChecker#Add(String)} 를 통하여 등록이 불가하다.
-	 */
-	public void SetAddEnd()
-	{
-		DebugLogOutput("[SetAddEnd]");
-		mAddEnd = true;
-
-		PrintDeviceList();
-
-		CheckInitCompletion();
-
-		if(!mSendInitBR)
-		{
-			CreateTimeOut();
-		}
-	}
-
-	/**
-	 * 초기화를 체크할 드라이버를 등록한다.
-	 *
-	 * @param DeviceName - (String) 등록할 디바이스 이름
-	 *
-	 * @return (int) - >=0 : 성공, <0 : 실패
-	 */
-	public int Add(String DeviceName)
-	{
-		DebugLogOutput("[Add] " + DeviceName);
-
-		if(mAddEnd)
-		{
-			Log.w(TAG, "[Add] mAddEnd is true !!!");
-			return -1;
-		}
-		if(FindDeviceName(DeviceName) >= 0)
-		{
-			Log.w(TAG, "[Add] FindDeviceName Result OK Error");
-			return -2;
-		}
-
-		mQueue.add(DeviceName);
-
-		return 0;
-	}
-
-	/**
-	 * 초기화를 체크할 드라이버를 리스트에서 제거 한다.<br>
-	 * 제거는 초기화 과정을 완료하였을시 호출하며, 본 메소드에서는<br>
-	 * 리스트가 비었는지를 체크하여, 모두 완료되었을시 BR 을 송신한다.
-	 *
-	 * @param DeviceName - (String) 삭제할 디바이스 이름
-	 *
-	 * @return (int) - >=0 : 성공, <0 : 실패
-	 */
-	public int Remove(String DeviceName)
-	{
-		DebugLogOutput("[Remove] " + DeviceName);
-
-		int location = FindDeviceName(DeviceName);
-		if(location < 0)
-		{
-			Log.w(TAG, "[Remove] FindDeviceName Result OK Error (ret:" + location + ", DeviceName:" + DeviceName + ")");
-			return location;
-		}
-
-		mQueue.remove(location);
-
-		CheckInitCompletion();
-
-		return 0;
-	}
-
-	/**
-	 * 같은 이름으로 등록되었는지 체크한다.
-	 *
-	 * @param DeviceName - (String) 확인할 디바이스 이름
-	 *
-	 * @return (int) 0 >= : 있음 , 0 < : 없음
-	 */
-	private int FindDeviceName(String DeviceName)
-	{
-		if(mQueue.isEmpty()) return -1;
-
-		for(int i=0 ; i<mQueue.size() ; i++)
-		{
-			String getName = mQueue.get(i);
-			if(DeviceName.equals(getName))
-				return i;
-		}
-
-		return -2;
-	}
-
-	/**
-	 * 체크 초기화 완료
-	 */
-	private void CheckInitCompletion()
-	{
-		if(!mSendInitBR && mAddEnd)
-		{
-			if(mQueue.isEmpty())
-			{
-				SendBR();
-			}
-		}
-	}
-
-	/**
-	 * 초기화 완료  BR을 송신한다.
-	 */
-	private void SendBR()
-	{
-		mSendInitBR = true;
-		Intent notiIntent = new Intent();
-		notiIntent.setAction(define.NOTIFY_ACNAME);
-		notiIntent.putExtra(define.NOTIBR_KIND, define.NOTIFY_DEVICE_INIT_COMPLETION);
-		ServiceMain.svcContext.sendBroadcast(notiIntent);
-
-		CancelTimeOut();
-
-		Log.i(TAG, " ");
-		Log.i(TAG, "++++++++++++++++++++++++++++++++++++++");
-		Log.i(TAG, "++++++++++++++++++++++++++++++++++++++");
-		Log.i(TAG, "NOTIFY_DEVICE_INIT_COMPLETION !!!");
-		Log.i(TAG, "++++++++++++++++++++++++++++++++++++++");
-		Log.i(TAG, "++++++++++++++++++++++++++++++++++++++");
-		Log.i(TAG, " ");
-	}
-
-	/**
-	 * 등록된 리스트를 LOG 출력한다.
-	 */
-	private void PrintDeviceList()
-	{
-		Log.i(TAG, "\r\n------------------------------");
-		Log.i(TAG, "Print Init Check Device List");
-		Log.i(TAG, "------------------------------");
-		if(mQueue.isEmpty())
-		{
-			Log.i(TAG, "isEmpty !!!");
-		}
-		else
-		{
-			for(int i=0 ; i<mQueue.size() ; i++)
-			{
-				String getName = mQueue.get(i);
-				Log.i(TAG, (int)(i+1) + ". "+ getName);
-			}
-		}
-		Log.i(TAG, "------------------------------\r\n");
-	}
-
-	/**
-	 * TimeOut 을 생성한다.<br>
-	 * 지정된 시간이후 SendBR을 무조건 송신한다.
-	 */
-	private void CreateTimeOut()
-	{
-		if(mTimeOut != null) mTimeOut.cancel();
-		mTimeOut = new CountDownTimer( (long)(TIMEOUT_MINUTE * (1000 * 60)), 1000)
-		{
-			@Override
-			public void onFinish()
-			{
-				Log.d(TAG, "[CreateTimeOut] - onFinish !!!");
-
-				SendBR();
-			}
-
-			@Override
-			public void onTick(long arg0) {
-				long RemainingTime = (long)(arg0/1000);
-				if(RemainingTime <= 10)
-				{
-					Log.d(TAG, "[CreateTimeOut] - onTick (" + RemainingTime + " sec)");
-				}
-			}
-		};
-
-		mTimeOut.cancel();
-		mTimeOut.start();
-	}
-
-	/**
-	 * TimeOut 을 중지한다.
-	 */
-	private void CancelTimeOut()
-	{
-		if(mTimeOut != null)
-		{
-			mTimeOut.cancel();
-			mTimeOut = null;
-		}
-	}
-}
+package com.artncore.wallpaddevservice;
+
+import java.util.LinkedList;
+
+import com.artncore.commons.define;
+
+import android.content.Intent;
+import android.os.CountDownTimer;
+import android.util.Log;
+
+/**
+ * 디바이스 드라이버의 초기화 과정이 모두 완료되었는지<br>
+ * 체크 및 알람을 하는 클래스 이다.
+ */
+public class DeviceInitChecker
+{
+	private final static String TAG = "DeviceInitChecker";
+
+	private final boolean DEBUG_LOG_ON = true;
+	private void DebugLogOutput(String s) { if(DEBUG_LOG_ON) Log.d(TAG, s); }
+
+	private LinkedList<String> mQueue;
+
+	private boolean mAddEnd;
+
+	private boolean mSendInitBR;
+
+	private CountDownTimer mTimeOut = null;
+
+	private final long TIMEOUT_MINUTE = 2;
+
+	public DeviceInitChecker()
+	{
+		mQueue = new LinkedList<String>();
+		mQueue.clear();
+
+		mSendInitBR = false;
+		mAddEnd = false;
+
+		DebugLogOutput("Create !!!");
+	}
+
+	/**
+	 * 등록이 완료되었을시 호출한다.
+	 * 본 메소드를 호출한 이후 {@link DeviceInitChecker#Add(String)} 를 통하여 등록이 불가하다.
+	 */
+	public void SetAddEnd()
+	{
+		DebugLogOutput("[SetAddEnd]");
+		mAddEnd = true;
+
+		PrintDeviceList();
+
+		CheckInitCompletion();
+
+		if(!mSendInitBR)
+		{
+			CreateTimeOut();
+		}
+	}
+
+	/**
+	 * 초기화를 체크할 드라이버를 등록한다.
+	 *
+	 * @param DeviceName - (String) 등록할 디바이스 이름
+	 *
+	 * @return (int) - >=0 : 성공, <0 : 실패
+	 */
+	public int Add(String DeviceName)
+	{
+		DebugLogOutput("[Add] " + DeviceName);
+
+		if(mAddEnd)
+		{
+			Log.w(TAG, "[Add] mAddEnd is true !!!");
+			return -1;
+		}
+		if(FindDeviceName(DeviceName) >= 0)
+		{
+			Log.w(TAG, "[Add] FindDeviceName Result OK Error");
+			return -2;
+		}
+
+		mQueue.add(DeviceName);
+
+		return 0;
+	}
+
+	/**
+	 * 초기화를 체크할 드라이버를 리스트에서 제거 한다.<br>
+	 * 제거는 초기화 과정을 완료하였을시 호출하며, 본 메소드에서는<br>
+	 * 리스트가 비었는지를 체크하여, 모두 완료되었을시 BR 을 송신한다.
+	 *
+	 * @param DeviceName - (String) 삭제할 디바이스 이름
+	 *
+	 * @return (int) - >=0 : 성공, <0 : 실패
+	 */
+	public int Remove(String DeviceName)
+	{
+		DebugLogOutput("[Remove] " + DeviceName);
+
+		int location = FindDeviceName(DeviceName);
+		if(location < 0)
+		{
+			Log.w(TAG, "[Remove] FindDeviceName Result OK Error (ret:" + location + ", DeviceName:" + DeviceName + ")");
+			return location;
+		}
+
+		mQueue.remove(location);
+
+		CheckInitCompletion();
+
+		return 0;
+	}
+
+	/**
+	 * 같은 이름으로 등록되었는지 체크한다.
+	 *
+	 * @param DeviceName - (String) 확인할 디바이스 이름
+	 *
+	 * @return (int) 0 >= : 있음 , 0 < : 없음
+	 */
+	private int FindDeviceName(String DeviceName)
+	{
+		if(mQueue.isEmpty()) return -1;
+
+		for(int i=0 ; i<mQueue.size() ; i++)
+		{
+			String getName = mQueue.get(i);
+			if(DeviceName.equals(getName))
+				return i;
+		}
+
+		return -2;
+	}
+
+	/**
+	 * 체크 초기화 완료
+	 */
+	private void CheckInitCompletion()
+	{
+		if(!mSendInitBR && mAddEnd)
+		{
+			if(mQueue.isEmpty())
+			{
+				SendBR();
+			}
+		}
+	}
+
+	/**
+	 * 초기화 완료  BR을 송신한다.
+	 */
+	private void SendBR()
+	{
+		mSendInitBR = true;
+		Intent notiIntent = new Intent();
+		notiIntent.setAction(define.NOTIFY_ACNAME);
+		notiIntent.putExtra(define.NOTIBR_KIND, define.NOTIFY_DEVICE_INIT_COMPLETION);
+		ServiceMain.svcContext.sendBroadcast(notiIntent);
+
+		CancelTimeOut();
+
+		Log.i(TAG, " ");
+		Log.i(TAG, "++++++++++++++++++++++++++++++++++++++");
+		Log.i(TAG, "++++++++++++++++++++++++++++++++++++++");
+		Log.i(TAG, "NOTIFY_DEVICE_INIT_COMPLETION !!!");
+		Log.i(TAG, "++++++++++++++++++++++++++++++++++++++");
+		Log.i(TAG, "++++++++++++++++++++++++++++++++++++++");
+		Log.i(TAG, " ");
+	}
+
+	/**
+	 * 등록된 리스트를 LOG 출력한다.
+	 */
+	private void PrintDeviceList()
+	{
+		Log.i(TAG, "\r\n------------------------------");
+		Log.i(TAG, "Print Init Check Device List");
+		Log.i(TAG, "------------------------------");
+		if(mQueue.isEmpty())
+		{
+			Log.i(TAG, "isEmpty !!!");
+		}
+		else
+		{
+			for(int i=0 ; i<mQueue.size() ; i++)
+			{
+				String getName = mQueue.get(i);
+				Log.i(TAG, (int)(i+1) + ". "+ getName);
+			}
+		}
+		Log.i(TAG, "------------------------------\r\n");
+	}
+
+	/**
+	 * TimeOut 을 생성한다.<br>
+	 * 지정된 시간이후 SendBR을 무조건 송신한다.
+	 */
+	private void CreateTimeOut()
+	{
+		if(mTimeOut != null) mTimeOut.cancel();
+		mTimeOut = new CountDownTimer( (long)(TIMEOUT_MINUTE * (1000 * 60)), 1000)
+		{
+			@Override
+			public void onFinish()
+			{
+				Log.d(TAG, "[CreateTimeOut] - onFinish !!!");
+
+				SendBR();
+			}
+
+			@Override
+			public void onTick(long arg0) {
+				long RemainingTime = (long)(arg0/1000);
+				if(RemainingTime <= 10)
+				{
+					Log.d(TAG, "[CreateTimeOut] - onTick (" + RemainingTime + " sec)");
+				}
+			}
+		};
+
+		mTimeOut.cancel();
+		mTimeOut.start();
+	}
+
+	/**
+	 * TimeOut 을 중지한다.
+	 */
+	private void CancelTimeOut()
+	{
+		if(mTimeOut != null)
+		{
+			mTimeOut.cancel();
+			mTimeOut = null;
+		}
+	}
+}

+ 120 - 23
WallPadDevService/src/main/java/com/artncore/wallpaddevservice/ServiceMain.java

@@ -611,7 +611,6 @@ public class ServiceMain extends Service {
 	 */
 	 */
 	class SaxHandler extends DefaultHandler {
 	class SaxHandler extends DefaultHandler {
 		public void startElement(String url, String localName, String qname, Attributes atts) {
 		public void startElement(String url, String localName, String qname, Attributes atts) {
-
 			if (localName.equals("portmap")) {
 			if (localName.equals("portmap")) {
 				Handlercnt = 1;
 				Handlercnt = 1;
 			}
 			}
@@ -709,13 +708,13 @@ public class ServiceMain extends Service {
 					///////////////////////////////////////////
 					///////////////////////////////////////////
 
 
 					// 1. Class 생성
 					// 1. Class 생성
-//					cooktopfinder_Controller = new CookTopFinder_Controller();
-//
-//					// 2. 등록
-//					RegistrationDeviceManager = cooktopfinder_Controller;
-//
-//					// 3. 초기화체크 드라이버 등록
-//					ServiceMain.deviceInitChecker.Add(attsName);
+					cooktopfinder_Controller = new CookTopFinder_Controller();
+
+					// 2. 등록
+					RegistrationDeviceManager = cooktopfinder_Controller;
+
+					// 3. 초기화체크 드라이버 등록
+					ServiceMain.deviceInitChecker.Add(attsName);
 
 
 				}
 				}
 				else if (attsName.equals("GasValve_Driver")) {
 				else if (attsName.equals("GasValve_Driver")) {
@@ -736,7 +735,7 @@ public class ServiceMain extends Service {
 					// 2. 등록
 					// 2. 등록
 					RegistrationDeviceManager = gasValve_Controller;
 					RegistrationDeviceManager = gasValve_Controller;
 
 
-					//bSetDeviceHandler = false;
+					bSetDeviceHandler = false;
 
 
 					// 3. 초기화체크 드라이버 등록
 					// 3. 초기화체크 드라이버 등록
 					ServiceMain.deviceInitChecker.Add(attsName);
 					ServiceMain.deviceInitChecker.Add(attsName);
@@ -754,7 +753,7 @@ public class ServiceMain extends Service {
 					// 2. 등록
 					// 2. 등록
 					RegistrationDeviceManager = cooktop_Controller;
 					RegistrationDeviceManager = cooktop_Controller;
 
 
-					//bSetDeviceHandler = false;
+					bSetDeviceHandler = false;
 
 
 					// 3. 초기화체크 드라이버 등록
 					// 3. 초기화체크 드라이버 등록
 					ServiceMain.deviceInitChecker.Add(attsName);
 					ServiceMain.deviceInitChecker.Add(attsName);
@@ -988,7 +987,8 @@ public class ServiceMain extends Service {
 					if (!(mModelType == Version.MODEL_TYPE.IHN_D101 || mModelType == Version.MODEL_TYPE.IHN_D101_I
 					if (!(mModelType == Version.MODEL_TYPE.IHN_D101 || mModelType == Version.MODEL_TYPE.IHN_D101_I
 							|| mModelType == Version.MODEL_TYPE.IHN_D101K || mModelType == Version.MODEL_TYPE.IHN_D101K_I
 							|| mModelType == Version.MODEL_TYPE.IHN_D101K || mModelType == Version.MODEL_TYPE.IHN_D101K_I
 							|| mModelType == Version.MODEL_TYPE.IHN_1010GL || mModelType == Version.MODEL_TYPE.IHN_1010GL_I
 							|| mModelType == Version.MODEL_TYPE.IHN_1010GL || mModelType == Version.MODEL_TYPE.IHN_1010GL_I
-							|| mModelType == Version.MODEL_TYPE.IHN_1010GL_I_2443ALT || mModelType == Version.MODEL_TYPE.IHN_1010GL_I_6410ALT)) return;
+							|| mModelType == Version.MODEL_TYPE.IHN_1010GL_I_2443ALT || mModelType == Version.MODEL_TYPE.IHN_1010GL_I_6410ALT
+							|| mModelType == Version.MODEL_TYPE.IHN_D101_I_OCF)) return;
 
 
 					// 1. Class 생성
 					// 1. Class 생성
 					iGW300_Controller = new IGW300_Controller();
 					iGW300_Controller = new IGW300_Controller();
@@ -1015,18 +1015,20 @@ public class ServiceMain extends Service {
 					// AllLightHDC_Driver
 					// AllLightHDC_Driver
 					///////////////////////////////////////////
 					///////////////////////////////////////////
 
 
+					Log.d(TAG, "-----------------ModelType : " + mModelType);
 					// 0. 로딩여부 판단
 					// 0. 로딩여부 판단
-					if(mModelType != Version.MODEL_TYPE.IHN_1020GL) return;
 					if(Get_HDCIntLightType()) return;
 					if(Get_HDCIntLightType()) return;
+					else
+					{
+						// 1. Class 생성
+						allLightHDC_Controller = new AllLightHDC_Controller();
 
 
-					// 1. Class 생성
-					allLightHDC_Controller = new AllLightHDC_Controller();
-
-					// 2. 등록
-					RegistrationDeviceManager = allLightHDC_Controller;
+						// 2. 등록
+						RegistrationDeviceManager = allLightHDC_Controller;
 
 
-					// 3. 초기화체크 드라이버 등록
-					ServiceMain.deviceInitChecker.Add(attsName);
+						// 3. 초기화체크 드라이버 등록
+						ServiceMain.deviceInitChecker.Add(attsName);
+					}
 				}
 				}
 				else if (attsName.equals("EnergyModule_Driver")) {
 				else if (attsName.equals("EnergyModule_Driver")) {
 					///////////////////////////////////////////
 					///////////////////////////////////////////
@@ -1583,6 +1585,8 @@ public class ServiceMain extends Service {
 
 
 						// COM2 - Ctrl_Module
 						// COM2 - Ctrl_Module
 						"<driver name = \"AllLightHDC_Driver\"            module =\"Ctrl_Module\"               startaddr = \"0x11\"    endaddr = \"0x11\"    option = \"null\"  />"+
 						"<driver name = \"AllLightHDC_Driver\"            module =\"Ctrl_Module\"               startaddr = \"0x11\"    endaddr = \"0x11\"    option = \"null\"  />"+
+						"<driver name = \"CookTopFinder_Driver\"               module =\"Ctrl_Module\"               startaddr = \"0x31\"    endaddr = \"0x31\"    option = \"null\"  />"+
+						"<driver name = \"CookTop_Driver\"               module =\"Ctrl_Module\"               startaddr = \"0x31\"    endaddr = \"0x31\"    option = \"null\"  />"+
 						"<driver name = \"GasValve_Driver\"               module =\"Ctrl_Module\"               startaddr = \"0x31\"    endaddr = \"0x31\"    option = \"null\"  />"+
 						"<driver name = \"GasValve_Driver\"               module =\"Ctrl_Module\"               startaddr = \"0x31\"    endaddr = \"0x31\"    option = \"null\"  />"+
 						"<driver name = \"DLock_Driver\"                  module =\"Ctrl_Module\"               startaddr = \"0x41\"    endaddr = \"0x41\"    option = \"null\"  />"+
 						"<driver name = \"DLock_Driver\"                  module =\"Ctrl_Module\"               startaddr = \"0x41\"    endaddr = \"0x41\"    option = \"null\"  />"+
 						"<driver name = \"Ventilation_Driver\"            module =\"Ctrl_Module\"               startaddr = \"0x61\"    endaddr = \"0x68\"    option = \"null\"  />"+
 						"<driver name = \"Ventilation_Driver\"            module =\"Ctrl_Module\"               startaddr = \"0x61\"    endaddr = \"0x68\"    option = \"null\"  />"+
@@ -1636,6 +1640,8 @@ public class ServiceMain extends Service {
 
 
 						// COM2 - Ctrl_Module
 						// COM2 - Ctrl_Module
 						"<driver name = \"AllLightHDC_Driver\"            module =\"Ctrl_Module\"               startaddr = \"0x11\"    endaddr = \"0x11\"    option = \"null\"  />"+
 						"<driver name = \"AllLightHDC_Driver\"            module =\"Ctrl_Module\"               startaddr = \"0x11\"    endaddr = \"0x11\"    option = \"null\"  />"+
+						"<driver name = \"CookTopFinder_Driver\"               module =\"Ctrl_Module\"               startaddr = \"0x31\"    endaddr = \"0x31\"    option = \"null\"  />"+
+						"<driver name = \"CookTop_Driver\"               module =\"Ctrl_Module\"               startaddr = \"0x31\"    endaddr = \"0x31\"    option = \"null\"  />"+
 						"<driver name = \"GasValve_Driver\"               module =\"Ctrl_Module\"               startaddr = \"0x31\"    endaddr = \"0x31\"    option = \"null\"  />"+
 						"<driver name = \"GasValve_Driver\"               module =\"Ctrl_Module\"               startaddr = \"0x31\"    endaddr = \"0x31\"    option = \"null\"  />"+
 						"<driver name = \"DLock_Driver\"                  module =\"Ctrl_Module\"               startaddr = \"0x41\"    endaddr = \"0x41\"    option = \"null\"  />"+
 						"<driver name = \"DLock_Driver\"                  module =\"Ctrl_Module\"               startaddr = \"0x41\"    endaddr = \"0x41\"    option = \"null\"  />"+
 						"<driver name = \"Ventilation_Driver\"            module =\"Ctrl_Module\"               startaddr = \"0x61\"    endaddr = \"0x68\"    option = \"null\"  />"+
 						"<driver name = \"Ventilation_Driver\"            module =\"Ctrl_Module\"               startaddr = \"0x61\"    endaddr = \"0x68\"    option = \"null\"  />"+
@@ -1694,6 +1700,8 @@ public class ServiceMain extends Service {
 						"<driver name = \"HeatingV1_Driver\"              module =\"Ctrl_Module2\"              startaddr = \"0x21\"    endaddr = \"0x21\"    option = \"null\"  />"+
 						"<driver name = \"HeatingV1_Driver\"              module =\"Ctrl_Module2\"              startaddr = \"0x21\"    endaddr = \"0x21\"    option = \"null\"  />"+
 						"<driver name = \"HeatingV2_Driver\"              module =\"Ctrl_Module2\"              startaddr = \"0x28\"    endaddr = \"0x28\"    option = \"null\"  />"+
 						"<driver name = \"HeatingV2_Driver\"              module =\"Ctrl_Module2\"              startaddr = \"0x28\"    endaddr = \"0x28\"    option = \"null\"  />"+
 						"<driver name = \"BatchLight_Driver\"             module =\"Ctrl_Module2\"              startaddr = \"0x15\"    endaddr = \"0x17\"    option = \"null\"  />"+
 						"<driver name = \"BatchLight_Driver\"             module =\"Ctrl_Module2\"              startaddr = \"0x15\"    endaddr = \"0x17\"    option = \"null\"  />"+
+						"<driver name = \"CookTopFinder_Driver\"               module =\"Ctrl_Module2\"              startaddr = \"0x31\"    endaddr = \"0x31\"    option = \"null\"  />"+
+						"<driver name = \"CookTop_Driver\"               module =\"Ctrl_Module2\"              startaddr = \"0x31\"    endaddr = \"0x31\"    option = \"null\"  />"+
 						"<driver name = \"GasValve_Driver\"               module =\"Ctrl_Module2\"              startaddr = \"0x31\"    endaddr = \"0x31\"    option = \"null\"  />"+
 						"<driver name = \"GasValve_Driver\"               module =\"Ctrl_Module2\"              startaddr = \"0x31\"    endaddr = \"0x31\"    option = \"null\"  />"+
 
 
 
 
@@ -1724,7 +1732,9 @@ public class ServiceMain extends Service {
 						//"<driver name = \"SmartRfCam_Driver\"             module =\"Special_Module\"            startaddr = \"0xA2\"    endaddr = \"0xA2\"    option = \"null\"  />"+
 						//"<driver name = \"SmartRfCam_Driver\"             module =\"Special_Module\"            startaddr = \"0xA2\"    endaddr = \"0xA2\"    option = \"null\"  />"+
 
 
 						// COM4 - Ctrl_Module2
 						// COM4 - Ctrl_Module2
-                        "<driver name = \"EnergyController_Driver\"         module =\"Ctrl_Module2\"              startaddr = \"0x51\"    endaddr = \"0x51\"    option = \"null\"  />"+
+						"<driver name = \"EnergyController_Driver\"         module =\"Ctrl_Module2\"              startaddr = \"0x51\"    endaddr = \"0x51\"    option = \"null\"  />"+
+						"<driver name = \"CookTopFinder_Driver\"                 module =\"Ctrl_Module2\"              startaddr = \"0x31\"    endaddr = \"0x31\"    option = \"null\"  />"+
+						"<driver name = \"CookTop_Driver\"                 module =\"Ctrl_Module2\"              startaddr = \"0x31\"    endaddr = \"0x31\"    option = \"null\"  />"+
 						"<driver name = \"GasValve_Driver\"                 module =\"Ctrl_Module2\"              startaddr = \"0x31\"    endaddr = \"0x31\"    option = \"null\"  />"+
 						"<driver name = \"GasValve_Driver\"                 module =\"Ctrl_Module2\"              startaddr = \"0x31\"    endaddr = \"0x31\"    option = \"null\"  />"+
 						//"<driver name = \"HeatingFinder_Driver\"          module =\"Ctrl_Module2\"              startaddr = \"0x21\"    endaddr = \"0x2F\"    option = \"null\"  />"+
 						//"<driver name = \"HeatingFinder_Driver\"          module =\"Ctrl_Module2\"              startaddr = \"0x21\"    endaddr = \"0x2F\"    option = \"null\"  />"+
 						//"<driver name = \"HeatingV1_Driver\"              module =\"Ctrl_Module2\"              startaddr = \"0x21\"    endaddr = \"0x21\"    option = \"null\"  />"+
 						//"<driver name = \"HeatingV1_Driver\"              module =\"Ctrl_Module2\"              startaddr = \"0x21\"    endaddr = \"0x21\"    option = \"null\"  />"+
@@ -1752,6 +1762,8 @@ public class ServiceMain extends Service {
 					"<driver name = \"BatchLight_Driver\"             module =\"LH_Module1\"              startaddr = \"0x15\"    endaddr = \"0x17\"    option = \"null\"  />"+
 					"<driver name = \"BatchLight_Driver\"             module =\"LH_Module1\"              startaddr = \"0x15\"    endaddr = \"0x17\"    option = \"null\"  />"+
 					"<driver name = \"MultiSwitch_Driver\"            module =\"LH_Module1\"              startaddr = \"0x51\"    endaddr = \"0x58\"    option = \"null\"  />"+
 					"<driver name = \"MultiSwitch_Driver\"            module =\"LH_Module1\"              startaddr = \"0x51\"    endaddr = \"0x58\"    option = \"null\"  />"+
 					"<driver name = \"Ventilation_Driver\"            module =\"LH_Module1\"              startaddr = \"0x61\"    endaddr = \"0x68\"    option = \"null\"  />"+
 					"<driver name = \"Ventilation_Driver\"            module =\"LH_Module1\"              startaddr = \"0x61\"    endaddr = \"0x68\"    option = \"null\"  />"+
+					"<driver name = \"CookTopFinder_Driver\"               module =\"LH_Module1\"              startaddr = \"0x31\"    endaddr = \"0x31\"    option = \"null\"  />"+
+					"<driver name = \"CookTop_Driver\"               module =\"LH_Module1\"              startaddr = \"0x31\"    endaddr = \"0x31\"    option = \"null\"  />"+
 					"<driver name = \"GasValve_Driver\"               module =\"LH_Module1\"              startaddr = \"0x31\"    endaddr = \"0x31\"    option = \"null\"  />"+
 					"<driver name = \"GasValve_Driver\"               module =\"LH_Module1\"              startaddr = \"0x31\"    endaddr = \"0x31\"    option = \"null\"  />"+
 					"<driver name = \"HeatingFinder_Driver\"          module =\"LH_Module1\"              startaddr = \"0x21\"    endaddr = \"0x2F\"    option = \"null\"  />"+
 					"<driver name = \"HeatingFinder_Driver\"          module =\"LH_Module1\"              startaddr = \"0x21\"    endaddr = \"0x2F\"    option = \"null\"  />"+
 					"<driver name = \"HeatingV1_Driver\"              module =\"LH_Module1\"              startaddr = \"0x21\"    endaddr = \"0x21\"    option = \"null\"  />"+
 					"<driver name = \"HeatingV1_Driver\"              module =\"LH_Module1\"              startaddr = \"0x21\"    endaddr = \"0x21\"    option = \"null\"  />"+
@@ -1796,7 +1808,8 @@ public class ServiceMain extends Service {
 					"</drivermap> </lookup_tables>";
 					"</drivermap> </lookup_tables>";
 		}
 		}
 		else if (mModelType == Version.MODEL_TYPE.IHN_D101 || mModelType == Version.MODEL_TYPE.IHN_D101_I
 		else if (mModelType == Version.MODEL_TYPE.IHN_D101 || mModelType == Version.MODEL_TYPE.IHN_D101_I
-				|| mModelType == Version.MODEL_TYPE.IHN_D101K || mModelType == Version.MODEL_TYPE.IHN_D101K_I)
+				|| mModelType == Version.MODEL_TYPE.IHN_D101K || mModelType == Version.MODEL_TYPE.IHN_D101K_I
+				|| mModelType == Version.MODEL_TYPE.IHN_D101_I_OCF)
 		{
 		{
 //			Log.d(TAG, "[DefaultLoadConfigFile] Get_HeatOneDevice_Use() = " + Get_HeatOneDevice_Use()); // 테스트코드
 //			Log.d(TAG, "[DefaultLoadConfigFile] Get_HeatOneDevice_Use() = " + Get_HeatOneDevice_Use()); // 테스트코드
 			// 신규 분전반 2.0 프로토콜 적용관련
 			// 신규 분전반 2.0 프로토콜 적용관련
@@ -1831,6 +1844,8 @@ public class ServiceMain extends Service {
 //					"<driver name = \"PhoneNRemotecon_Driver\"        module =\"PhoneNRemotecon_Module\"    startaddr = \"0x00\"    endaddr = \"0xFF\"    option = \"null\"  />"+
 //					"<driver name = \"PhoneNRemotecon_Driver\"        module =\"PhoneNRemotecon_Module\"    startaddr = \"0x00\"    endaddr = \"0xFF\"    option = \"null\"  />"+
 
 
 						// COM2 - Ctrl_Module
 						// COM2 - Ctrl_Module
+						"<driver name = \"CookTopFinder_Driver\"               module =\"Ctrl_Module1\"               startaddr = \"0x31\"    endaddr = \"0x31\"    option = \"null\"  />"+
+						"<driver name = \"CookTop_Driver\"               module =\"Ctrl_Module1\"               startaddr = \"0x31\"    endaddr = \"0x31\"    option = \"null\"  />"+
 						"<driver name = \"GasValve_Driver\"               module =\"Ctrl_Module1\"               startaddr = \"0x31\"    endaddr = \"0x31\"    option = \"null\"  />"+
 						"<driver name = \"GasValve_Driver\"               module =\"Ctrl_Module1\"               startaddr = \"0x31\"    endaddr = \"0x31\"    option = \"null\"  />"+
 //					"<driver name = \"ElectricRange_Controller\"      module =\"Ctrl_Module1\"               startaddr = \"0xE1\"    endaddr = \"0xE2\"    option = \"null\"  />"+
 //					"<driver name = \"ElectricRange_Controller\"      module =\"Ctrl_Module1\"               startaddr = \"0xE1\"    endaddr = \"0xE2\"    option = \"null\"  />"+
 						"<driver name = \"DLock_Driver\"                  module =\"Ctrl_Module1\"               startaddr = \"0x41\"    endaddr = \"0x41\"    option = \"null\"  />"+
 						"<driver name = \"DLock_Driver\"                  module =\"Ctrl_Module1\"               startaddr = \"0x41\"    endaddr = \"0x41\"    option = \"null\"  />"+
@@ -1885,6 +1900,8 @@ public class ServiceMain extends Service {
 //					"<driver name = \"PhoneNRemotecon_Driver\"        module =\"PhoneNRemotecon_Module\"    startaddr = \"0x00\"    endaddr = \"0xFF\"    option = \"null\"  />"+
 //					"<driver name = \"PhoneNRemotecon_Driver\"        module =\"PhoneNRemotecon_Module\"    startaddr = \"0x00\"    endaddr = \"0xFF\"    option = \"null\"  />"+
 
 
 						// COM2 - Ctrl_Module
 						// COM2 - Ctrl_Module
+						"<driver name = \"CookTopFinder_Driver\"               module =\"Ctrl_Module1\"               startaddr = \"0x31\"    endaddr = \"0x31\"    option = \"null\"  />"+
+						"<driver name = \"CookTop_Driver\"               module =\"Ctrl_Module1\"               startaddr = \"0x31\"    endaddr = \"0x31\"    option = \"null\"  />"+
 						"<driver name = \"GasValve_Driver\"               module =\"Ctrl_Module1\"               startaddr = \"0x31\"    endaddr = \"0x31\"    option = \"null\"  />"+
 						"<driver name = \"GasValve_Driver\"               module =\"Ctrl_Module1\"               startaddr = \"0x31\"    endaddr = \"0x31\"    option = \"null\"  />"+
 						"<driver name = \"ElectricRange_Controller\"      module =\"Ctrl_Module1\"               startaddr = \"0xE1\"    endaddr = \"0xE2\"    option = \"null\"  />"+
 						"<driver name = \"ElectricRange_Controller\"      module =\"Ctrl_Module1\"               startaddr = \"0xE1\"    endaddr = \"0xE2\"    option = \"null\"  />"+
 						"<driver name = \"DLock_Driver\"                  module =\"Ctrl_Module1\"               startaddr = \"0x41\"    endaddr = \"0x41\"    option = \"null\"  />"+
 						"<driver name = \"DLock_Driver\"                  module =\"Ctrl_Module1\"               startaddr = \"0x41\"    endaddr = \"0x41\"    option = \"null\"  />"+
@@ -1939,6 +1956,8 @@ public class ServiceMain extends Service {
 //					"<driver name = \"PhoneNRemotecon_Driver\"        module =\"PhoneNRemotecon_Module\"    startaddr = \"0x00\"    endaddr = \"0xFF\"    option = \"null\"  />"+
 //					"<driver name = \"PhoneNRemotecon_Driver\"        module =\"PhoneNRemotecon_Module\"    startaddr = \"0x00\"    endaddr = \"0xFF\"    option = \"null\"  />"+
 
 
 						// COM2 - Ctrl_Module
 						// COM2 - Ctrl_Module
+						"<driver name = \"CookTopFinder_Driver\"               module =\"Ctrl_Module1\"               startaddr = \"0x31\"    endaddr = \"0x31\"    option = \"null\"  />"+
+						"<driver name = \"CookTop_Driver\"               module =\"Ctrl_Module1\"               startaddr = \"0x31\"    endaddr = \"0x31\"    option = \"null\"  />"+
 						"<driver name = \"GasValve_Driver\"               module =\"Ctrl_Module1\"               startaddr = \"0x31\"    endaddr = \"0x31\"    option = \"null\"  />"+
 						"<driver name = \"GasValve_Driver\"               module =\"Ctrl_Module1\"               startaddr = \"0x31\"    endaddr = \"0x31\"    option = \"null\"  />"+
 //					"<driver name = \"ElectricRange_Controller\"      module =\"Ctrl_Module1\"               startaddr = \"0xE1\"    endaddr = \"0xE2\"    option = \"null\"  />"+
 //					"<driver name = \"ElectricRange_Controller\"      module =\"Ctrl_Module1\"               startaddr = \"0xE1\"    endaddr = \"0xE2\"    option = \"null\"  />"+
 						"<driver name = \"DLock_Driver\"                  module =\"Ctrl_Module1\"               startaddr = \"0x41\"    endaddr = \"0x41\"    option = \"null\"  />"+
 						"<driver name = \"DLock_Driver\"                  module =\"Ctrl_Module1\"               startaddr = \"0x41\"    endaddr = \"0x41\"    option = \"null\"  />"+
@@ -1976,7 +1995,7 @@ public class ServiceMain extends Service {
 			}
 			}
 		}
 		}
         else if (mModelType == Version.MODEL_TYPE.IHN_1010GL || mModelType == Version.MODEL_TYPE.IHN_1010GL_I
         else if (mModelType == Version.MODEL_TYPE.IHN_1010GL || mModelType == Version.MODEL_TYPE.IHN_1010GL_I
-				|| mModelType == Version.MODEL_TYPE.IHN_1010GL_I_2443ALT || mModelType == Version.MODEL_TYPE.IHN_1010GL_I_6410ALT) {
+				|| mModelType == Version.MODEL_TYPE.IHN_1010GL_I_6410ALT) {
 			/**
 			/**
 			 * 현산 AC배전 조명 현장용 월패드
 			 * 현산 AC배전 조명 현장용 월패드
 			 * 일괄소등병합형 거실조명릴레이 보드 + 통합스위치(멀티스위치 프로토콜 사용)
 			 * 일괄소등병합형 거실조명릴레이 보드 + 통합스위치(멀티스위치 프로토콜 사용)
@@ -1998,6 +2017,8 @@ public class ServiceMain extends Service {
 //					"<driver name = \"PhoneNRemotecon_Driver\"        module =\"PhoneNRemotecon_Module\"    startaddr = \"0x00\"    endaddr = \"0xFF\"    option = \"null\"  />"+
 //					"<driver name = \"PhoneNRemotecon_Driver\"        module =\"PhoneNRemotecon_Module\"    startaddr = \"0x00\"    endaddr = \"0xFF\"    option = \"null\"  />"+
 
 
 					// COM2 - Ctrl_Module
 					// COM2 - Ctrl_Module
+					"<driver name = \"CookTopFinder_Driver\"							module =\"Ctrl_Module\"               startaddr = \"0x31\"    endaddr = \"0x31\"    option = \"null\"  />"+
+					"<driver name = \"CookTop_Driver\"							module =\"Ctrl_Module\"               startaddr = \"0x31\"    endaddr = \"0x31\"    option = \"null\"  />"+
 					"<driver name = \"GasValve_Driver\"							module =\"Ctrl_Module\"               startaddr = \"0x31\"    endaddr = \"0x31\"    option = \"null\"  />"+
 					"<driver name = \"GasValve_Driver\"							module =\"Ctrl_Module\"               startaddr = \"0x31\"    endaddr = \"0x31\"    option = \"null\"  />"+
 //					"<driver name = \"ElectricRange_Controller\"      			module =\"Ctrl_Module\"               startaddr = \"0xE1\"    endaddr = \"0xE2\"    option = \"null\"  />"+
 //					"<driver name = \"ElectricRange_Controller\"      			module =\"Ctrl_Module\"               startaddr = \"0xE1\"    endaddr = \"0xE2\"    option = \"null\"  />"+
 					"<driver name = \"DLock_Driver\"								module =\"Ctrl_Module\"               startaddr = \"0x41\"    endaddr = \"0x41\"    option = \"null\"  />"+
 					"<driver name = \"DLock_Driver\"								module =\"Ctrl_Module\"               startaddr = \"0x41\"    endaddr = \"0x41\"    option = \"null\"  />"+
@@ -2037,6 +2058,70 @@ public class ServiceMain extends Service {
 
 
 					"</drivermap> </lookup_tables>";
 					"</drivermap> </lookup_tables>";
         }
         }
+		else if ( mModelType == Version.MODEL_TYPE.IHN_1010GL_I_2443ALT) {
+			/**
+			 * 현산 AC배전 조명 현장용 월패드
+			 * 일괄소등병합형 거실조명릴레이 보드 + 통합스위치(멀티스위치 프로토콜 사용)
+			 */
+			default_cfg = "<?xml version=\"1.0\" encoding=\"utf-8\"?>"+
+					"<lookup_tables> <portmap>" +
+					//     portmap
+//					"<comport name = \"com1\"    baudrate = \"1200\"    module =\"PhoneNRemotecon_Module\"    type = \"Event\"    timeout = \"null\"    option = \"null\"    />"+
+					"<comport name = \"com2\"    baudrate = \"9600\"			module =\"Ctrl_Module\"					type = \"Polling\"  timeout = \"100\"     option = \"null\"    />"+
+					"<comport name = \"com3\"    baudrate = \"9600\"			module =\"SmartSwitch_Module\"		type = \"Polling\"  timeout = \"100\"     option = \"null\"    />"+
+					"<comport name = \"com4\"    baudrate = \"9600\"			module =\"Energy_Module\"				type = \"Polling\"  timeout = \"100\"     option = \"null\"    />"+
+					"<comport name = \"com5\"    baudrate = \"38400\"		module =\"Dgw_Module\"					type = \"Polling\"  timeout = \"100\"     option = \"null\"    />"+
+					"<comport name = \"com6\"    baudrate = \"38400\"		module =\"IntLight_Module\"				type = \"Polling\"  timeout = \"100\"     option = \"null\"    />"+
+					"</portmap>   <drivermap> " +
+
+					//     drivermap
+
+					// COM1 - PhoneNRemotecon_Module
+//					"<driver name = \"PhoneNRemotecon_Driver\"        module =\"PhoneNRemotecon_Module\"    startaddr = \"0x00\"    endaddr = \"0xFF\"    option = \"null\"  />"+
+
+					// COM2 - Ctrl_Module
+					"<driver name = \"AllLightHDC_Driver\"            module =\"Ctrl_Module\"               startaddr = \"0x11\"    endaddr = \"0x11\"    option = \"null\"  />"+
+					"<driver name = \"CookTopFinder_Driver\"							module =\"Ctrl_Module\"               startaddr = \"0x31\"    endaddr = \"0x31\"    option = \"null\"  />"+
+					"<driver name = \"CookTop_Driver\"							module =\"Ctrl_Module\"               startaddr = \"0x31\"    endaddr = \"0x31\"    option = \"null\"  />"+
+					"<driver name = \"GasValve_Driver\"							module =\"Ctrl_Module\"               startaddr = \"0x31\"    endaddr = \"0x31\"    option = \"null\"  />"+
+//					"<driver name = \"ElectricRange_Controller\"      			module =\"Ctrl_Module\"               startaddr = \"0xE1\"    endaddr = \"0xE2\"    option = \"null\"  />"+
+					"<driver name = \"DLock_Driver\"								module =\"Ctrl_Module\"               startaddr = \"0x41\"    endaddr = \"0x41\"    option = \"null\"  />"+
+					"<driver name = \"FP_DLock_Driver\"							module =\"Ctrl_Module\"               startaddr = \"0x48\"    endaddr = \"0x48\"    option = \"null\"  />"+
+					"<driver name = \"Ventilation_Driver\"							module =\"Ctrl_Module\"               startaddr = \"0x61\"    endaddr = \"0x68\"    option = \"null\"  />"+
+					"<driver name = \"HeatingFinder_Driver\"						module =\"Ctrl_Module\"               startaddr = \"0x21\"    endaddr = \"0x2F\"    option = \"null\"  />"+
+					"<driver name = \"HeatingV1_Driver\"							module =\"Ctrl_Module\"               startaddr = \"0x21\"    endaddr = \"0x21\"    option = \"null\"  />"+
+					"<driver name = \"HeatingV2_Driver\"							module =\"Ctrl_Module\"               startaddr = \"0x28\"    endaddr = \"0x28\"    option = \"null\"  />"+
+					"<driver name = \"SensorAP_Controller\"						module =\"Ctrl_Module\"         		startaddr = \"0xB1\"    endaddr = \"0xB3\"    option = \"null\"  />"+
+					"<driver name = \"InRoomDetectSensor_Controller\"		module =\"Ctrl_Module\"         	 	startaddr = \"0xB7\"    endaddr = \"0xBE\"    option = \"null\"  />"+
+					"<driver name = \"Louver_Controller\"  						module =\"Ctrl_Module\"         	 	startaddr = \"0x91\"    endaddr = \"0x91\"    option = \"null\"  />"+
+					"<driver name = \"Curtain_LivingRoom_Driver\"  						module =\"Ctrl_Module\"         	 	startaddr = \"0x81\"    endaddr = \"0x8F\"    option = \"null\"  />"+
+					"<driver name = \"Curtain_Room_Driver\"  						module =\"Ctrl_Module\"         	 	startaddr = \"0x91\"    endaddr = \"0x9F\"    option = \"null\"  />"+
+
+					// COM3 - SmartSwitch_Module
+					"<driver name = \"SmartSwitchPol_Controller\"     			module =\"SmartSwitch_Module\"        startaddr = \"0xC1\"    endaddr = \"0xC1\"    option = \"null\"  />"+
+					"<driver name = \"SmartSwitchEvt_Controller\"     			module =\"SmartSwitch_Module\"        startaddr = \"0xC1\"    endaddr = \"0xC1\"    option = \"null\"  />"+
+					"<driver name = \"SystemAircon_Controller\"      			module =\"SmartSwitch_Module\"        startaddr = \"0x78\"    endaddr = \"0x78\"    option = \"null\"  />"+
+					"<driver name = \"SmartRfCam_Driver\"             			module =\"SmartSwitch_Module\"        startaddr = \"0xA2\"    endaddr = \"0xA2\"    option = \"null\"  />"+
+					"<driver name = \"RfDoorCam_Driver\"              			module =\"SmartSwitch_Module\"        startaddr = \"0xA1\"    endaddr = \"0xA1\"    option = \"null\"  />"+
+//					"<driver name = \"BioRecognition_Driver\"         module =\"SmartSwitch_Module\"         startaddr = \"0xA5\"    endaddr = \"0xA5\"    option = \"null\"  />"+
+//					"<driver name = \"Purity_Controller\"       	  module =\"SmartSwitch_Module\"         startaddr = \"0x65\"    endaddr = \"0x65\"    option = \"null\"  />"+
+
+					// COM4 - Energy_Module
+					"<driver name = \"CutOffConcent_Driver\"					module =\"Energy_Module\"             startaddr = \"0x41\"    endaddr = \"0x42\"    option = \"null\"  />" +
+					"<driver name = \"MultiSwitch_Driver\"            			module =\"Energy_Module\"              startaddr = \"0x51\"    endaddr = \"0x58\"    option = \"null\"  />"+
+					"<driver name = \"RealTimeMeter_Driver\"					module =\"Energy_Module\"               startaddr = \"0xD1\"    endaddr = \"0xD1\"    option = \"null\" />"+
+
+					// COM5 - Dgw_Module
+					"<driver name = \"IGW300_Controller\"             			module =\"Dgw_Module\"                startaddr = \"0x01\"    endaddr = \"0x01\"    option = \"null\"  />"+
+
+					// COM6 - IntLight_Driver
+					"<driver name = \"IntLight_Driver\"               				module =\"IntLight_Module\"           startaddr = \"0xA1\"    endaddr = \"0xA1\"    option = \"null\"  />"+
+
+					// COM7 - LivingRoom EnergyMeter
+//					"<driver name = \"Sdb_LivingRoomLight_Driver\"      module =\"Ctrl_Module2\"              startaddr = \"0x31\"    endaddr = \"0x31\"    option = \"null\"  />"+
+
+					"</drivermap> </lookup_tables>";
+		}
 		else if (mModelType == Version.MODEL_TYPE.IHN_1020B_I) {
 		else if (mModelType == Version.MODEL_TYPE.IHN_1020B_I) {
 			///////////////////////////////////////////////////////////////////////////////
 			///////////////////////////////////////////////////////////////////////////////
 			// 신규 월패드 보급형 (IHN-1020B-I)
 			// 신규 월패드 보급형 (IHN-1020B-I)
@@ -2072,6 +2157,8 @@ public class ServiceMain extends Service {
 							"<driver name = \"HeatingFinder_Driver\"          module =\"Ctrl_Module2\"              startaddr = \"0x21\"    endaddr = \"0x2F\"    option = \"null\"  />"+
 							"<driver name = \"HeatingFinder_Driver\"          module =\"Ctrl_Module2\"              startaddr = \"0x21\"    endaddr = \"0x2F\"    option = \"null\"  />"+
 							"<driver name = \"HeatingV1_Driver\"              module =\"Ctrl_Module2\"              startaddr = \"0x21\"    endaddr = \"0x21\"    option = \"null\"  />"+
 							"<driver name = \"HeatingV1_Driver\"              module =\"Ctrl_Module2\"              startaddr = \"0x21\"    endaddr = \"0x21\"    option = \"null\"  />"+
 							"<driver name = \"HeatingV2_Driver\"              module =\"Ctrl_Module2\"              startaddr = \"0x28\"    endaddr = \"0x28\"    option = \"null\"  />"+
 							"<driver name = \"HeatingV2_Driver\"              module =\"Ctrl_Module2\"              startaddr = \"0x28\"    endaddr = \"0x28\"    option = \"null\"  />"+
+							"<driver name = \"CookTopFinder_Driver\"               module =\"Ctrl_Module2\"              startaddr = \"0x31\"    endaddr = \"0x31\"    option = \"null\"  />"+
+							"<driver name = \"CookTop_Driver\"               module =\"Ctrl_Module2\"              startaddr = \"0x31\"    endaddr = \"0x31\"    option = \"null\"  />"+
 							"<driver name = \"GasValve_Driver\"               module =\"Ctrl_Module2\"              startaddr = \"0x31\"    endaddr = \"0x31\"    option = \"null\"  />"+
 							"<driver name = \"GasValve_Driver\"               module =\"Ctrl_Module2\"              startaddr = \"0x31\"    endaddr = \"0x31\"    option = \"null\"  />"+
 							"<driver name = \"Ventilation_Driver\"            module =\"Ctrl_Module2\"              startaddr = \"0x61\"    endaddr = \"0x68\"    option = \"null\"  />"+
 							"<driver name = \"Ventilation_Driver\"            module =\"Ctrl_Module2\"              startaddr = \"0x61\"    endaddr = \"0x68\"    option = \"null\"  />"+
 
 
@@ -2098,6 +2185,8 @@ public class ServiceMain extends Service {
 							//"<driver name = \"LivingEM_Driver\"                 module =\"Ctrl_Module1\"              startaddr = \"0x31\"    endaddr = \"0x31\"    option = \"null\"  />"+
 							//"<driver name = \"LivingEM_Driver\"                 module =\"Ctrl_Module1\"              startaddr = \"0x31\"    endaddr = \"0x31\"    option = \"null\"  />"+
 							"<driver name = \"BatchLight_Driver\"             module =\"Ctrl_Module1\"              startaddr = \"0x15\"    endaddr = \"0x17\"    option = \"null\"  />"+
 							"<driver name = \"BatchLight_Driver\"             module =\"Ctrl_Module1\"              startaddr = \"0x15\"    endaddr = \"0x17\"    option = \"null\"  />"+
 							"<driver name = \"Light_Driver\"                  module =\"Ctrl_Module1\"              startaddr = \"0x16\"    endaddr = \"0x16\"    option = \"null\"  />"+
 							"<driver name = \"Light_Driver\"                  module =\"Ctrl_Module1\"              startaddr = \"0x16\"    endaddr = \"0x16\"    option = \"null\"  />"+
+							"<driver name = \"CookTopFinder_Driver\"               module =\"Ctrl_Module1\"              startaddr = \"0x31\"    endaddr = \"0x31\"    option = \"null\"  />"+
+							"<driver name = \"CookTop_Driver\"               module =\"Ctrl_Module1\"              startaddr = \"0x31\"    endaddr = \"0x31\"    option = \"null\"  />"+
 							"<driver name = \"GasValve_Driver\"               module =\"Ctrl_Module1\"              startaddr = \"0x31\"    endaddr = \"0x31\"    option = \"null\"  />"+
 							"<driver name = \"GasValve_Driver\"               module =\"Ctrl_Module1\"              startaddr = \"0x31\"    endaddr = \"0x31\"    option = \"null\"  />"+
 							"<driver name = \"MultiSwitch_Driver\"            module =\"Ctrl_Module1\"              startaddr = \"0x51\"    endaddr = \"0x58\"    option = \"null\"  />"+
 							"<driver name = \"MultiSwitch_Driver\"            module =\"Ctrl_Module1\"              startaddr = \"0x51\"    endaddr = \"0x58\"    option = \"null\"  />"+
 							"<driver name = \"InterlayerNoise_controller\"    module =\"Ctrl_Module1\"              startaddr = \"0xB4\"    endaddr = \"0xB6\"    option = \"null\"  />"+
 							"<driver name = \"InterlayerNoise_controller\"    module =\"Ctrl_Module1\"              startaddr = \"0xB4\"    endaddr = \"0xB6\"    option = \"null\"  />"+
@@ -2142,6 +2231,8 @@ public class ServiceMain extends Service {
 							"<driver name = \"Light_Driver\"                  module =\"LH_Module1\"              startaddr = \"0x16\"    endaddr = \"0x16\"    option = \"null\"  />"+
 							"<driver name = \"Light_Driver\"                  module =\"LH_Module1\"              startaddr = \"0x16\"    endaddr = \"0x16\"    option = \"null\"  />"+
 							"<driver name = \"MultiSwitch_Driver\"            module =\"LH_Module1\"              startaddr = \"0x51\"    endaddr = \"0x58\"    option = \"null\"  />"+
 							"<driver name = \"MultiSwitch_Driver\"            module =\"LH_Module1\"              startaddr = \"0x51\"    endaddr = \"0x58\"    option = \"null\"  />"+
 							"<driver name = \"Ventilation_Driver\"            module =\"LH_Module1\"              startaddr = \"0x61\"    endaddr = \"0x68\"    option = \"null\"  />"+
 							"<driver name = \"Ventilation_Driver\"            module =\"LH_Module1\"              startaddr = \"0x61\"    endaddr = \"0x68\"    option = \"null\"  />"+
+							"<driver name = \"CookTopFinder_Driver\"               module =\"LH_Module1\"              startaddr = \"0x31\"    endaddr = \"0x31\"    option = \"null\"  />"+
+							"<driver name = \"CookTop_Driver\"               module =\"LH_Module1\"              startaddr = \"0x31\"    endaddr = \"0x31\"    option = \"null\"  />"+
 							"<driver name = \"GasValve_Driver\"               module =\"LH_Module1\"              startaddr = \"0x31\"    endaddr = \"0x31\"    option = \"null\"  />"+
 							"<driver name = \"GasValve_Driver\"               module =\"LH_Module1\"              startaddr = \"0x31\"    endaddr = \"0x31\"    option = \"null\"  />"+
 							"<driver name = \"HeatingFinder_Driver\"          module =\"LH_Module1\"              startaddr = \"0x21\"    endaddr = \"0x2F\"    option = \"null\"  />"+
 							"<driver name = \"HeatingFinder_Driver\"          module =\"LH_Module1\"              startaddr = \"0x21\"    endaddr = \"0x2F\"    option = \"null\"  />"+
 							"<driver name = \"HeatingV1_Driver\"              module =\"LH_Module1\"              startaddr = \"0x21\"    endaddr = \"0x21\"    option = \"null\"  />"+
 							"<driver name = \"HeatingV1_Driver\"              module =\"LH_Module1\"              startaddr = \"0x21\"    endaddr = \"0x21\"    option = \"null\"  />"+
@@ -2178,6 +2269,8 @@ public class ServiceMain extends Service {
 
 
 							// COM3 - Ctrl_Module2
 							// COM3 - Ctrl_Module2
 							// "<driver name = \"EnergyController_Driver\"         module =\"Ctrl_Module2\"              startaddr = \"0x51\"    endaddr = \"0x51\"    option = \"null\"  />"+
 							// "<driver name = \"EnergyController_Driver\"         module =\"Ctrl_Module2\"              startaddr = \"0x51\"    endaddr = \"0x51\"    option = \"null\"  />"+
+							"<driver name = \"CookTopFinder_Driver\"               module =\"Ctrl_Module2\"              startaddr = \"0x31\"    endaddr = \"0x31\"    option = \"null\"  />"+
+							"<driver name = \"CookTop_Driver\"               module =\"Ctrl_Module2\"              startaddr = \"0x31\"    endaddr = \"0x31\"    option = \"null\"  />"+
 							"<driver name = \"GasValve_Driver\"               module =\"Ctrl_Module2\"              startaddr = \"0x31\"    endaddr = \"0x31\"    option = \"null\"  />"+
 							"<driver name = \"GasValve_Driver\"               module =\"Ctrl_Module2\"              startaddr = \"0x31\"    endaddr = \"0x31\"    option = \"null\"  />"+
 							"<driver name = \"HeatingFinder_Driver\"          module =\"Ctrl_Module2\"              startaddr = \"0x21\"    endaddr = \"0x2F\"    option = \"null\"  />"+
 							"<driver name = \"HeatingFinder_Driver\"          module =\"Ctrl_Module2\"              startaddr = \"0x21\"    endaddr = \"0x2F\"    option = \"null\"  />"+
 							"<driver name = \"HeatingV1_Driver\"              module =\"Ctrl_Module2\"              startaddr = \"0x21\"    endaddr = \"0x21\"    option = \"null\"  />"+
 							"<driver name = \"HeatingV1_Driver\"              module =\"Ctrl_Module2\"              startaddr = \"0x21\"    endaddr = \"0x21\"    option = \"null\"  />"+
@@ -2265,6 +2358,8 @@ public class ServiceMain extends Service {
 						"<driver name = \"BatchLight_Driver\"             module =\"Ctrl_Module2\"              startaddr = \"0x15\"    endaddr = \"0x17\"    option = \"null\"  />"+
 						"<driver name = \"BatchLight_Driver\"             module =\"Ctrl_Module2\"              startaddr = \"0x15\"    endaddr = \"0x17\"    option = \"null\"  />"+
 						"<driver name = \"Light_Driver\"                  module =\"Ctrl_Module2\"              startaddr = \"0x16\"    endaddr = \"0x16\"    option = \"null\"  />"+
 						"<driver name = \"Light_Driver\"                  module =\"Ctrl_Module2\"              startaddr = \"0x16\"    endaddr = \"0x16\"    option = \"null\"  />"+
 						"<driver name = \"MultiSwitch_Driver\"            module =\"Ctrl_Module2\"              startaddr = \"0x51\"    endaddr = \"0x58\"    option = \"null\"  />"+
 						"<driver name = \"MultiSwitch_Driver\"            module =\"Ctrl_Module2\"              startaddr = \"0x51\"    endaddr = \"0x58\"    option = \"null\"  />"+
+						"<driver name = \"CookTopFinder_Driver\"               module =\"Ctrl_Module2\"              startaddr = \"0x31\"    endaddr = \"0x31\"    option = \"null\"  />"+
+						"<driver name = \"CookTop_Driver\"               module =\"Ctrl_Module2\"              startaddr = \"0x31\"    endaddr = \"0x31\"    option = \"null\"  />"+
 						"<driver name = \"GasValve_Driver\"               module =\"Ctrl_Module2\"              startaddr = \"0x31\"    endaddr = \"0x31\"    option = \"null\"  />"+
 						"<driver name = \"GasValve_Driver\"               module =\"Ctrl_Module2\"              startaddr = \"0x31\"    endaddr = \"0x31\"    option = \"null\"  />"+
 						"<driver name = \"HeatingFinder_Driver\"          module =\"Ctrl_Module2\"              startaddr = \"0x21\"    endaddr = \"0x2F\"    option = \"null\"  />"+
 						"<driver name = \"HeatingFinder_Driver\"          module =\"Ctrl_Module2\"              startaddr = \"0x21\"    endaddr = \"0x2F\"    option = \"null\"  />"+
 						"<driver name = \"HeatingV1_Driver\"              module =\"Ctrl_Module2\"              startaddr = \"0x21\"    endaddr = \"0x21\"    option = \"null\"  />"+
 						"<driver name = \"HeatingV1_Driver\"              module =\"Ctrl_Module2\"              startaddr = \"0x21\"    endaddr = \"0x21\"    option = \"null\"  />"+
@@ -2296,6 +2391,8 @@ public class ServiceMain extends Service {
 						// COM3 - Ctrl_Module2
 						// COM3 - Ctrl_Module2
 						"<driver name = \"Light_Driver\"                  module =\"Ctrl_Module2\"              startaddr = \"0x16\"    endaddr = \"0x16\"    option = \"null\"  />"+
 						"<driver name = \"Light_Driver\"                  module =\"Ctrl_Module2\"              startaddr = \"0x16\"    endaddr = \"0x16\"    option = \"null\"  />"+
 						"<driver name = \"BatchLight_Driver\"             module =\"Ctrl_Module2\"              startaddr = \"0x15\"    endaddr = \"0x17\"    option = \"null\"  />"+
 						"<driver name = \"BatchLight_Driver\"             module =\"Ctrl_Module2\"              startaddr = \"0x15\"    endaddr = \"0x17\"    option = \"null\"  />"+
+						"<driver name = \"CookTopFinder_Driver\"               module =\"Ctrl_Module2\"              startaddr = \"0x31\"    endaddr = \"0x31\"    option = \"null\"  />"+
+						"<driver name = \"CookTop_Driver\"               module =\"Ctrl_Module2\"              startaddr = \"0x31\"    endaddr = \"0x31\"    option = \"null\"  />"+
 						"<driver name = \"GasValve_Driver\"               module =\"Ctrl_Module2\"              startaddr = \"0x31\"    endaddr = \"0x31\"    option = \"null\"  />"+
 						"<driver name = \"GasValve_Driver\"               module =\"Ctrl_Module2\"              startaddr = \"0x31\"    endaddr = \"0x31\"    option = \"null\"  />"+
 						"<driver name = \"MultiSwitch_Driver\"            module =\"Ctrl_Module2\"              startaddr = \"0x51\"    endaddr = \"0x58\"    option = \"null\"  />"+
 						"<driver name = \"MultiSwitch_Driver\"            module =\"Ctrl_Module2\"              startaddr = \"0x51\"    endaddr = \"0x58\"    option = \"null\"  />"+
 						"<driver name = \"Ventilation_Driver\"            module =\"Ctrl_Module2\"              startaddr = \"0x61\"    endaddr = \"0x68\"    option = \"null\"  />"+
 						"<driver name = \"Ventilation_Driver\"            module =\"Ctrl_Module2\"              startaddr = \"0x61\"    endaddr = \"0x68\"    option = \"null\"  />"+
@@ -2664,7 +2761,7 @@ public class ServiceMain extends Service {
 					CMDHmem.cmd = cmd;
 					CMDHmem.cmd = cmd;
 					CMDHmem.Setted = true;
 					CMDHmem.Setted = true;
 					CMDHmem.StrArg = data;
 					CMDHmem.StrArg = data;
-					Message AIDLmsg = devmgr.DevHandler.obtainMessage();
+					Message AIDLmsg = devmgr.DevHandler.obtainMessage(); //여기서 안됨
 					AIDLmsg.what = CommonDefine.DEVCTR_REQDEVCTR;
 					AIDLmsg.what = CommonDefine.DEVCTR_REQDEVCTR;
 					AIDLmsg.obj = CMDHmem;
 					AIDLmsg.obj = CMDHmem;
 					devmgr.DevHandler.sendMessage(AIDLmsg);
 					devmgr.DevHandler.sendMessage(AIDLmsg);

+ 4 - 209
WallPadDevService/src/main/java/com/artncore/wallpaddevservice/driver/AirQualitySensor_Controller.java

@@ -46,11 +46,6 @@ public class AirQualitySensor_Controller extends DeviceManager {
 	private byte TARGET_LEDBRIGHTNESS = CMDList.LEDBrightness.Level_02;   // LED 밝기 상태 (기본설정은 가장 밝게)
 	private byte TARGET_LEDBRIGHTNESS = CMDList.LEDBrightness.Level_02;   // LED 밝기 상태 (기본설정은 가장 밝게)
 	private byte TARGET_FANMODE = CMDList.FanMode.Repeat;   // 팬 동작 모드 (기본설정은 반복)
 	private byte TARGET_FANMODE = CMDList.FanMode.Repeat;   // 팬 동작 모드 (기본설정은 반복)
 
 
-	/**
-	 * 현재 상태 정보
-	 */
-	private STATUS curStatus;
-
 	/** 기기정보 */
 	/** 기기정보 */
 	public class Info {
 	public class Info {
 		/** 기능 지원 여부 */
 		/** 기능 지원 여부 */
@@ -179,15 +174,6 @@ public class AirQualitySensor_Controller extends DeviceManager {
 		public byte hLevelPM1p0;
 		public byte hLevelPM1p0;
 		public byte hLevelCO2;
 		public byte hLevelCO2;
 
 
-		//변화를 체크하기 위한 정보
-		public boolean bisChangePM10 = false; //정보 입력된면 -> 1
-		public boolean bisChangePM2p5 = false;//정보 입력된면 -> 2
-		public boolean bisChangePM1p0 = false;//정보 입력된면 -> 4
-		public boolean bisChangeCO2 = false;//정보 입력된면 -> 8
-
-		public int iChangedTypeCount = 0;
-
-
 		public STATUS() {
 		public STATUS() {
 			bPMSensorStatus = false; // 최초에 정상으로 로딩. 문제가 있을시 true 됨
 			bPMSensorStatus = false; // 최초에 정상으로 로딩. 문제가 있을시 true 됨
 			bCO2SensorStatus = false;
 			bCO2SensorStatus = false;
@@ -373,17 +359,6 @@ public class AirQualitySensor_Controller extends DeviceManager {
 	}
 	}
 
 
 
 
-	/**
-	 * 현재 공기질 정보 상태를 가져온다.
-	 * @return
-	 */
-	public STATUS getCurStatus()
-	{
-		STATUS temp_curStatus = curStatus;
-		return temp_curStatus;
-	}
-
-
 
 
 	///////////////////////////////////////////////////////////////////////////////////////////////
 	///////////////////////////////////////////////////////////////////////////////////////////////
 	// Polling
 	// Polling
@@ -478,11 +453,7 @@ public class AirQualitySensor_Controller extends DeviceManager {
 
 
 				byte CurrentAddress = mDriver.Polling.CurrentAddress;
 				byte CurrentAddress = mDriver.Polling.CurrentAddress;
 				if (mDriver.info[CurrentAddress].Install) {
 				if (mDriver.info[CurrentAddress].Install) {
-					//현재 받아온 정보를 가지고 있음 여기에 다 있음
 					STATUS recvStatus = Send_GetAirQuality(CurrentAddress); // 평상시 폴링 (11커맨드)
 					STATUS recvStatus = Send_GetAirQuality(CurrentAddress); // 평상시 폴링 (11커맨드)
-					//현재 상태 정보를 저장
-					curStatus = CheckStatusWithPrevious(curStatus, recvStatus);
-
 					if (recvStatus != null) {
 					if (recvStatus != null) {
 						UpdateVariables(CurrentAddress, recvStatus, false);
 						UpdateVariables(CurrentAddress, recvStatus, false);
 					}
 					}
@@ -520,182 +491,6 @@ public class AirQualitySensor_Controller extends DeviceManager {
 		}
 		}
 	}
 	}
 
 
-
-	/**
-	 * 스마트스위치용 Level로 변하기 위한 모듈
-	 * @param step PM10 스텝
-	 * @param curLevel PM 변환전 레벨
-	 * @return PM 변환 후, 레벨
-	 */
-	public byte LevelConverter_PM10(byte step, byte curLevel) {
-		byte converted_Level = 0;
-		if (step == 4) {
-			// 4단계
-			converted_Level = (byte) (curLevel - AIRLevel.LEVEL4.PM10.GOOD + 1);
-
-		}
-		else if (step == 8) {
-			// 8단계
-			converted_Level = (byte) (curLevel - AIRLevel.LEVEL8.PM10.BEST + 1);
-		}
-		return converted_Level; // 기본 : 보통
-	}
-
-	/**
-	 * 스마트스위치용 Level로 변하기 위한 모듈
-	 * @param step PM2.5, PM1.0 스텝
-	 * @param curLevel PM2.5, PM1.0 변환전 레벨
-	 * @return PM2.5, PM1.0 변환 후, 레벨
-	 */
-	public byte LevelConverter_PM2p5(byte step, byte curLevel) {
-		byte converted_Level = 0;
-		if (step == 4) {
-			// 4단계
-			converted_Level = (byte) (curLevel - AIRLevel.LEVEL4.PM2_5.GOOD + 1);
-
-		}
-		else if (step == 8) {
-			// 8단계
-			converted_Level = (byte) (curLevel - AIRLevel.LEVEL8.PM2_5.BEST + 1);
-		}
-		return converted_Level; // 기본 : 보통
-	}
-
-	/**
-	 * 스마트스위치용 Level로 변하기 위한 모듈
-	 * @param step CO2 스텝
-	 * @param curLevel CO2 변환전 레벨
-	 * @return CO2 변환 후, 레벨
-	 */
-	public byte LevelConverter_CO2(byte step, byte curLevel) {
-		byte converted_Level = 0;
-		if (step == 4) {
-			// 4단계
-			converted_Level = (byte) (curLevel - AIRLevel.LEVEL4.CO2.GOOD + 1);
-
-		}
-		else if (step == 8) {
-			// 8단계
-			converted_Level = (byte) (curLevel - AIRLevel.LEVEL8.CO2.BEST + 1);
-		}
-		return converted_Level; // 기본 : 보통
-	}
-
-	
-	/**
-	 * 현재 공기질 변화 정보를 체크
-	 * 스마트스위치에서 사용하기 위한 함수
-	 * @param cur_Status 현재 정보
-	 * @param prev_Status 이전 정보
-	 */
-	public STATUS CheckStatusWithPrevious(STATUS prev_Status, STATUS cur_Status)
-	{
-		STATUS temp_status = cur_Status;
-		cur_Status.bisChangePM10 = false; //정보 입력된면 -> 1
-		cur_Status.bisChangePM2p5 = false;//정보 입력된면 -> 2
-		cur_Status.bisChangePM1p0 = false;//정보 입력된면 -> 4
-		cur_Status.bisChangeCO2 = false;//정보 입력된면 -> 8
-
-		cur_Status.iChangedTypeCount = 0;
-
-		//미세먼지 단계 비교(PM10)
-		if(prev_Status.hLevelPM10!=cur_Status.hLevelPM10)
-		{
-			temp_status.bisChangePM10 = true;
-			temp_status.iChangedTypeCount++;
-		}
-		//초미세먼지 단계 비교(PM2.5)
-		if(prev_Status.hLevelPM2p5!=cur_Status.hLevelPM2p5)
-		{
-			temp_status.bisChangePM2p5 = true;
-			temp_status.iChangedTypeCount++;
-		}
-		//극초미세먼지 단계 비교(PM1.0)
-		if(prev_Status.hLevelPM1p0!=cur_Status.hLevelPM1p0)
-		{
-			temp_status.bisChangePM1p0 = true;
-			temp_status.iChangedTypeCount++;
-		}
-		//이산화탄소 단계 비교(CO2)
-		if(prev_Status.hLevelCO2!=cur_Status.hLevelCO2)
-		{
-			temp_status.bisChangeCO2 = true;
-			temp_status.iChangedTypeCount++;
-		}
-
-		return temp_status;
-	}
-
-
-	/**
-	 * 스마트스위치에서 사용하기 위한 데이터값 생성
-	 * @param cur_Status
-	 * @return
-	 */
-	public byte[] MakeAirQualityInfo_For_SmartSwitch(STATUS cur_Status)
-	{
-		//공기질 정보 종류 만들기
-		int index = 0;
-		byte TotalType = 0;
-		byte[] return_Array = new byte[cur_Status.iChangedTypeCount*3 + 2];//(공기질 정보 + 공기질 상태 단계 종류
-
-		index = 2;
-		if(cur_Status.bisChangePM10)
-		{
-			TotalType = (byte) (TotalType | 1);
-			//미세먼지 PM10 단계
-			//단계정보 수정
-			byte level = LevelConverter_PM10(cur_Status.hAirQualityStep, cur_Status.hLevelPM10);
-			return_Array[index++] = level;
-			//미세먼지 PM10 (상위)
-			return_Array[index++] = cur_Status.hValuePM10DecimalParent;
-			//미세먼지 PM10 (하위)
-			return_Array[index++] = cur_Status.hValuePM10DecimalSub;
-		}
-		//초미세먼지 단계 비교(PM2.5)
-		if(cur_Status.bisChangePM2p5)
-		{
-			TotalType = (byte) (TotalType | 2);
-			//초미세먼지 PM10 단계
-			byte level = LevelConverter_PM2p5(cur_Status.hAirQualityStep, cur_Status.hLevelPM2p5);
-			return_Array[index++] = level;
-			//초미세먼지 PM10 (상위)
-			return_Array[index++] = cur_Status.hValuePM2p5DecimalParent;
-			//초미세먼지 PM10 (하위)
-			return_Array[index++] = cur_Status.hValuePM2p5DecimalSub;
-		}
-		//극초미세먼지 단계 비교(PM1.0)
-		if(cur_Status.bisChangePM1p0)
-		{
-			TotalType = (byte) (TotalType | 4);
-			//극초미세먼지 PM10 단계
-			byte level = LevelConverter_PM2p5(cur_Status.hAirQualityStep, cur_Status.hLevelPM1p0);
-			return_Array[index++] = level;
-			//극초미세먼지 PM10 (상위)
-			return_Array[index++] = cur_Status.hValuePM1p0DecimalParent;
-			//극초미세먼지 PM10 (하위)
-			return_Array[index++] = cur_Status.hValuePM1p0DecimalSub;
-		}
-		//이산화탄소 단계 비교(CO2)
-		if(cur_Status.bisChangeCO2)
-		{
-			TotalType = (byte) (TotalType | 8);
-			//이산화탄소 PM10 단계
-			byte level = LevelConverter_CO2(cur_Status.hAirQualityStep, cur_Status.hLevelCO2);
-			return_Array[index++] = level;
-			//이산화탄소 PM10 (상위)
-			return_Array[index++] = cur_Status.hValueCO2DecimalParent;
-			//이산화탄소 PM10 (하위)
-			return_Array[index++] = cur_Status.hValueCO2DecimalSub;
-		}
-
-		index = 0;
-		return_Array[index++] = TotalType;
-		return_Array[index++] = (byte) cur_Status.iChangedTypeCount;
-
-		return return_Array;
-	}
-
 	@Override
 	@Override
 	public String NoSinkCtrl(String StrArg) {
 	public String NoSinkCtrl(String StrArg) {
 		DeviceLog("[NoSinkCtrl] Start");
 		DeviceLog("[NoSinkCtrl] Start");
@@ -939,12 +734,12 @@ public class AirQualitySensor_Controller extends DeviceManager {
 
 
 			// 센서 팬 상태 관리
 			// 센서 팬 상태 관리
 			if (mDriver.Status[nID].bAutoFanCtrl) {
 			if (mDriver.Status[nID].bAutoFanCtrl) {
-				if (7 < nHour && nHour < 22) {
-					// 08:00 ~ 21:59 (반복)
-					TARGET_FANMODE = CMDList.FanMode.Repeat;
+				if (0 <= nMin && nMin < 5) {
+					// 매 시간 정각부터 4분(총 5분)
+					TARGET_FANMODE = CMDList.FanMode.Always;
 				}
 				}
 				else {
 				else {
-					// 22:00 ~ 07:59 (꺼짐)
+					// 매 시간 5분 ~ 59분(총 55분)
 					TARGET_FANMODE = CMDList.FanMode.Off;
 					TARGET_FANMODE = CMDList.FanMode.Off;
 				}
 				}
 			}
 			}

+ 611 - 600
WallPadDevService/src/main/java/com/artncore/wallpaddevservice/driver/AllLightHDC_Controller.java

@@ -1,600 +1,611 @@
-/*
- * Copyright (C) 2015 Android WallPad Project
- *
- * FileName  : AllLightHDC_Controller.java
- * Project   : Android WallPad Project
- * Company   : HDC I-CONTROLS ( www.icontrols.co.kr )
- * Author    : Kang Sang Ho  , lairu@icontrols.co.kr
- */
-
-package com.artncore.wallpaddevservice.driver;
-
-import android.annotation.SuppressLint;
-import android.util.Log;
-
-import com.artncore.commons.APIErrorCode;
-import com.artncore.commons.define;
-import com.artncore.wallpaddevservice.ServiceMain;
-import com.util.LogUtil;
-
-
-/**
- * 일괄소등 제어기 (현산:제일전기) 의 드라이버 모듈이다.
- */
-@SuppressLint("HandlerLeak")
-public class AllLightHDC_Controller extends DeviceManager
-{
-    private final static String TAG = "AllLightHDC_Controller";
-
-    private final byte DEVICE_ADDRESS  = (byte) 0x11;
-
-    /** 초기 기기 검색 횟수  */
-    private final int MAX_SEARCH_COUNT   = 3;
-
-    private static boolean AllLightStatus = false;
-
-    /**
-     * 일괄소등 상태를 반환한다.
-     *
-     * @return (boolean) true : 일괄소등해제 , false : 일괄소등
-     */
-    public static boolean GetAllLightStatus() { return AllLightStatus; }
-
-    public class Status
-    {
-        boolean OnOff;          // true  : ON  ( 조명ON  , 일괄소등해제 )
-        // false : OFF ( 조명 OFF , 일괄소등상태 )
-        public Status()
-        {
-            OnOff = false;      // 조명OFF 일괄소등상태
-        }
-    }
-
-    public class Info
-    {
-        byte FwVer_Year;
-        byte FwVer_Month;
-        byte ProtocolVer_Main;
-        byte ProtocolVer_Sub;
-        public Info()
-        {
-            FwVer_Year = 0x00;
-            FwVer_Month = 0x00;
-            ProtocolVer_Main = 0x00;
-            ProtocolVer_Sub = 0x00;
-        }
-
-        public String ToDebugString()
-        {
-            String retStr =
-                    "==========================\r\n" +
-                            "Info\r\n" +
-                            "==========================\r\n" +
-                            "FwVer       : " + (int)(2000 + FwVer_Year) + "/" + FwVer_Month + "\r\n" +
-                            "ProtocolVer : V" + ProtocolVer_Main + "." + ProtocolVer_Sub + "\r\n" +
-                            "==========================\r\n";
-            return retStr;
-        }
-    }
-
-    public class Driver
-    {
-        private PollingList Polling;
-
-        private Status status;
-
-        public Driver()
-        {
-            Polling = new PollingList();
-            status  = new Status();
-        }
-
-        /** Polling 관련 */
-        private class PollingList
-        {
-            private final class STATUS
-            {
-                /** 초기화 과정 */
-                public final static byte First = 0;
-                /** 초기화 타임아웃 */
-                public final static byte FirstTimeOut = 1;
-                /** 평상시 */
-                public final static byte Normal = 2;
-            }
-
-            public byte Status;
-            public int SearchTryCount;
-
-            private PollingList()
-            {
-                Status = STATUS.First;
-                SearchTryCount = 0;
-            }
-        }
-    }
-
-    private Driver mDriver = null;
-
-
-    /**
-     * 생성자
-     */
-    public AllLightHDC_Controller()
-    {
-        /** 로그 초기상태 */
-        log_sw = false;
-
-        /** 통신성공률 변수 초기화 */
-        super.CommDataGeneration(1);
-
-        /** 드라이버 내부 변수 초기화 */
-        mDriver = new Driver();
-    }
-
-    @Override
-    public void DeviceLog(String msg)
-    {
-        if (!log_sw) return;
-        Log.d(TAG, msg);
-    }
-
-    /**
-     * 로딩후 처음 폴링 시퀀스
-     */
-    @Override
-    protected void do_boot()
-    {
-    }
-
-    ///////////////////////////////////////////////////////////////////////////////////////////////
-    // Polling
-    ///////////////////////////////////////////////////////////////////////////////////////////////
-    /**
-     * do_ctr : 폴링스케쥴러
-     */
-    @Override
-    protected void do_ctr()
-    {
-        DeviceLog("Polling ");
-
-        /* [[ First & FirstTimeOut ]]
-         * 초기 디바이스정보  검색 */
-        if( (mDriver.Polling.Status == Driver.PollingList.STATUS.First) ||
-                (mDriver.Polling.Status == Driver.PollingList.STATUS.FirstTimeOut) )
-        {
-            if(mDriver.Polling.Status == Driver.PollingList.STATUS.First)
-            {
-                if(mDriver.Polling.SearchTryCount++ > MAX_SEARCH_COUNT)
-                {
-                    mDriver.Polling.Status = Driver.PollingList.STATUS.FirstTimeOut;
-
-                    Log.i(TAG, "--------------------------------------------------");
-                    Log.i(TAG, "SearchDevice Fail... FirstTimeOut ");
-                    Log.i(TAG, "--------------------------------------------------");
-
-                    ServiceMain.deviceInitChecker.Remove(super.DeviceName);
-                }
-            }
-
-            Info info = Send_GetVerInfo();
-            if(info != null)
-            {
-                mDriver.Polling.Status = Driver.PollingList.STATUS.Normal;
-                Log.i(TAG, info.ToDebugString());
-
-                ServiceMain.deviceInitChecker.Remove(super.DeviceName);
-            }
-        }
-        /* [[ Normal ]]
-         * 평상시 */
-        else if(mDriver.Polling.Status == Driver.PollingList.STATUS.Normal)
-        {
-            Status status = Send_GetLightStatus();
-            if(status != null)
-            {
-                UpdateVariables(status);
-            }
-        }
-        /*
-         * 예외처리 */
-        else
-        {
-            mDriver = new Driver();
-        }
-    }
-
-    ///////////////////////////////////////////////////////////////////////////////////////////////
-    // Ctrl
-    ///////////////////////////////////////////////////////////////////////////////////////////////
-    /**
-     * NoSink 제어
-     *
-     * @param StrArg
-     *
-     * @return
-     */
-    public String NoSinkCtrl(String StrArg)
-    {
-        DeviceLog("[NoSinkCtrl] Start");
-
-        // 1. 디바이스 초기화시 에러리턴
-        if( (mDriver.Polling.Status == Driver.PollingList.STATUS.First) ||
-                (mDriver.Polling.Status == Driver.PollingList.STATUS.FirstTimeOut) )
-        {
-            Log.w(TAG, "[NoSinkCtrl] - Not Yet !!!");
-            return "FAIL;" + APIErrorCode.DEVICEISNOTREADY;
-        }
-
-        CtrDevFormat ctrDevFormat = GetCtrDevParamParsing(StrArg, 5);
-        if(ctrDevFormat.ret != APIErrorCode.C_SUCCESS)
-        {
-            Log.w(TAG, "[NoSinkCtrl] GetCtrDevParamParsing Error (ret:" + ctrDevFormat.ret + ")");
-            return "FAIL;" + APIErrorCode.DEFAULT_PARSING_ERR;
-        }
-
-        //////////////////////////////////////////////////////////
-        // Refresh : 데이터 갱신 (No Sink)
-        //////////////////////////////////////////////////////////
-        if(ctrDevFormat.CmdStr!=null && ctrDevFormat.CmdStr.equals("Refresh"))
-        {
-            return RefreshResult();
-        }
-
-        return "FAIL;" + APIErrorCode.UNKNOWNCOMMAND;
-    }
-
-    /**
-     * do_ctrEmm : 싱크 제어
-     */
-    @Override
-    @SuppressLint("DefaultLocale")
-    protected String do_ctrEmm(DeviceCtrSHMem SHMem)
-    {
-        DeviceLog("[do_ctrEmm] Start");
-        DeviceLog("cmd    : " + SHMem.cmd);
-        DeviceLog("StrArg : " + SHMem.StrArg);
-
-        // 1. 디바이스 초기화시 에러리턴
-        if( (mDriver.Polling.Status == Driver.PollingList.STATUS.First) ||
-                (mDriver.Polling.Status == Driver.PollingList.STATUS.FirstTimeOut) )
-        {
-            Log.w(TAG, "[do_ctrEmm] - Not Yet !!!");
-            return SHMem.retVal = "FAIL;" + APIErrorCode.DEVICEISNOTREADY;
-        }
-
-        CtrDevFormat ctrDevFormat = GetCtrDevParamParsing(SHMem.StrArg, 5);
-        if(ctrDevFormat.ret != APIErrorCode.C_SUCCESS)
-        {
-            Log.w(TAG, "[do_ctrEmm] GetCtrDevParamParsing Error (ret:" + ctrDevFormat.ret + ")");
-            return SHMem.retVal = "FAIL;" + APIErrorCode.DEFAULT_PARSING_ERR;
-        }
-
-        //////////////////////////////////////////////////////////
-        // Refresh : 데이터 갱신 (Sink)
-        //////////////////////////////////////////////////////////
-        if(ctrDevFormat.CmdStr!=null)
-        {
-            if(ctrDevFormat.CmdStr.equals("Refresh"))
-            {
-                Status status = Send_GetLightStatus();
-                if(status == null)
-                    return SHMem.retVal = "FAIL;" + APIErrorCode.DEVICEISNORESPONSE;
-
-                UpdateVariables(status);
-                return SHMem.retVal = RefreshResult();
-            }
-            else if(ctrDevFormat.CmdStr.equals("AllLightControl"))
-            {
-                // 1. Param Check
-                byte ParamOnOff   = ctrDevFormat.param[0];
-
-                // 2. Make Packet Data
-                boolean OnOff = false;
-                if(ParamOnOff != 0x00) OnOff = true;
-
-                // 3. Doing
-                Status status = Send_SetLightOnOff(OnOff);
-                if(status == null)
-                    return SHMem.retVal = "FAIL;" + APIErrorCode.DEVICEISNORESPONSE;
-
-                UpdateVariables(status);
-
-                return SHMem.retVal = "SUCCESS";
-            }
-        }
-
-
-        return SHMem.retVal = "UNKNOWNCMD";
-    }
-
-
-    ///////////////////////////////////////////////////////////////////////////////////////////////
-    // RefreshResult
-    ///////////////////////////////////////////////////////////////////////////////////////////////
-    /**
-     * Refresh 에 대한 응답포멧 정의
-     *
-     * @return (String) "SUCCESS; ..." 성공 , "FAIL; ... " 실패
-     */
-    private String RefreshResult()
-    {
-        String result = null;
-
-        DeviceLog("RefreshResult call : ");
-
-        // 1. Check Polling Status
-        if( (mDriver.Polling.Status == Driver.PollingList.STATUS.First) ||
-                (mDriver.Polling.Status == Driver.PollingList.STATUS.FirstTimeOut) )
-        {
-            result = "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
-            return result;
-        }
-
-        // 2. Param Range Check
-
-        // 3. Make Return String Format
-        try
-        {
-            if(mDriver == null)                   return "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
-            if(mDriver.status == null)            return "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
-
-            /*
-             * [Format]
-             *
-             * SUCCESS       - (String) 성공
-             *
-             * OnOff         - (boolean) 일괄소등 상태
-             */
-            result = APIErrorCode.SUCCESS + ";";
-
-            result += mDriver.status.OnOff + ";";
-        }
-        catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-            result = "FAIL;"+APIErrorCode.EXCEPTION;
-        }
-        catch (Exception e) {
-            Log.e(TAG, "[Exception Error] RefreshResult");
-            //e.printStackTrace();
-            LogUtil.errorLogInfo("", TAG, e);
-            result = "FAIL;"+APIErrorCode.EXCEPTION;
-        }
-        DeviceLog(" RefreshResult return : "+result);
-
-        return result;
-    }
-
-    ///////////////////////////////////////////////////////////////////////////////////////////////
-    // Protocol Command Send Func
-    ///////////////////////////////////////////////////////////////////////////////////////////////
-    /**
-     * 조명제어기 상태값 요청
-     *
-     * @return (Status) null - Error , Not null - OK
-     */
-    private Status Send_GetLightStatus()
-    {
-        DeviceLog("[Send_GetLightStatus] Start");
-
-        // 1. In 파라미터 확인
-
-        // 2. 패킷 데이터 만들기
-        byte [] ReqData = new byte [] { 0x00, 0x00, 0x00, 0x00, 0x00 };
-
-        // 3. 데이터 전송 및 응답
-        byte [] Reply = SendNRead_Fixed( (byte)(DEVICE_ADDRESS), CMDList.Req.GetLightStatus, ReqData);
-
-        // 4. 수신데이터 파싱
-        Status status = ReplyParsing(Reply);
-        if(status == null)
-        {
-            DeviceLog("[Send_GetLightStatus] Reply is null");
-            AddDoCount(false);
-            return null;
-        }
-        AddDoCount(true);
-
-        return status;
-    }
-
-    /**
-     * 조명제어기 점등/소등 요청
-     *
-     * @param  OnOff - (boolean) true : 일괄소등해제 , false : 일괄소등
-     *
-     * @return (Status) null - Error , Not null - OK
-     */
-    private Status Send_SetLightOnOff(boolean OnOff)
-    {
-        DeviceLog("[Send_SetLightOnOff] Start");
-
-        // 1. In 파라미터 확인
-
-        // 2. 패킷 데이터 만들기
-        byte D2 = 0x00;
-        if(OnOff) D2 = 0x01;
-        byte [] ReqData = new byte [] { (byte)0xFF, D2, 0x00, 0x00, 0x00 };
-
-        // 3. 데이터 전송 및 응답
-        byte [] Reply = SendNRead_Fixed( (byte)(DEVICE_ADDRESS), CMDList.Req.SetLightOnOff, ReqData);
-
-        // 4. 수신데이터 파싱
-        Status status = ReplyParsing(Reply);
-        if(status == null)
-        {
-            DeviceLog("[Send_SetLightOnOff] Reply is null");
-            AddDoCount(false);
-            return null;
-        }
-        AddDoCount(true);
-
-        return status;
-    }
-
-    /**
-     * 응답 Parsing
-     *
-     * @param Reply     - (byte []) 응답 데이터
-     *
-     * @return (Status) null - Error , Not null - OK
-     */
-    private Status ReplyParsing(byte [] Reply)
-    {
-        // 1. 수신데이터 파싱
-        //     1.1. Default Check
-        if(Reply == null)
-        {
-            DeviceLog("[ReplyParsing] Reply is null");
-            return null;
-        }
-
-        int index = 0;
-        //          - D1 : 커맨드 수신 체크
-        if(Reply[index++] != (byte)0x80)
-        {
-            Log.w(TAG, "[ReplyParsing] Reply.length  fail ... " + Reply.length);
-            return null;
-        }
-
-        // 2. Data return
-        Status status = new Status();
-        if( (Reply[1] & BIT5) == 0x00 )
-        {
-            // 일괄소등 해제 (조명켜짐)
-            status.OnOff = true;
-        }
-        else
-        {
-            // 일괄소등 (조명꺼짐)
-            status.OnOff = false;
-        }
-
-        return status;
-    }
-
-    /**
-     * 버전정보 요청 (프로토콜 V2.2 추가사항 : 2013/04/15)
-     *
-     * @return (Status) null - Error , Not null - OK
-     */
-    private Info Send_GetVerInfo()
-    {
-        DeviceLog("[Send_GetVerInfo] Start");
-
-        // 1. In 파라미터 확인
-
-        // 2. 패킷 데이터 만들기
-        byte [] ReqData = new byte [] { 0x00, 0x00, 0x00, 0x00, 0x00 };
-
-        // 3. 데이터 전송 및 응답
-        byte [] Reply = SendNRead_Fixed( (byte)(DEVICE_ADDRESS), CMDList.Req.GetVerInfo, ReqData);
-
-        // 4. 수신데이터 파싱
-        //     4.1. Default Check
-        if(Reply == null)
-        {
-            DeviceLog("[Send_GetVerInfo] Reply is null");
-            AddDoCount(false);
-            return null;
-        }
-
-        int index = 0;
-        byte data = 0x00;
-        //          - D1 : 커맨드 수신 체크
-        data = Reply[index++];
-        if(data != (byte)0x80)
-        {
-            Log.w(TAG, "[Send_GetVerInfo] Reply D1 fail ... D1:" + String.format("0x%02X", data));
-            AddDoCount(false);
-            return null;
-        }
-        //          - D2 : 펌웨어 Build Date (Year)
-        index++;
-
-        //          - D3 : 펌웨어 Build Date (Month)
-        data = Reply[index++];
-        if((data < 1) || (data > 12))
-        {
-            Log.w(TAG, "[Send_GetVerInfo] Reply D3 fail ... D3:" + data);
-            AddDoCount(false);
-            return null;
-        }
-
-        // 5. Data return
-        index = 1;
-        Info info = new Info();
-        info.FwVer_Year = Reply[index++];
-        info.FwVer_Month = Reply[index++];
-        info.ProtocolVer_Main = Reply[index++];
-        info.ProtocolVer_Sub = Reply[index++];
-
-        AddDoCount(true);
-
-        return info;
-    }
-
-    ///////////////////////////////////////////////////////////////////////////////////////////////
-    // CMDList
-    ///////////////////////////////////////////////////////////////////////////////////////////////
-    /**
-     * 명령어 리스트
-     */
-    public static class CMDList
-    {
-        public static final class Req
-        {
-            /////////////////////////////////////////////////////////
-            // Board
-            /////////////////////////////////////////////////////////
-            /** 조명제어기 상태값 요청 */
-            public final static byte GetLightStatus    = 0x00;
-
-            /** 조명제어기 점등/소등 요청 */
-            public final static byte SetLightOnOff     = 0x02;
-
-            /** 버전정보 요청 (프로토콜 V2.2 추가사항 : 2013/04/15) */
-            public final static byte GetVerInfo        = 0x21;
-        }
-    }
-
-    ///////////////////////////////////////////////////////////////////////////////////////////////
-    // UpdateVariables
-    ///////////////////////////////////////////////////////////////////////////////////////////////
-    /**
-     * XXXX 데이터를 업데이트 한다.
-     *
-     * @param XXXXData - (XXXXData) 업데이트할 XXXX 데이터
-     *
-     * @return (boolean) 데이터 변경여부 (true:변경 , false:미변경)
-     */
-    private boolean UpdateVariables(Status status)
-    {
-        boolean bChanged = false;
-        if(mDriver.status.OnOff != status.OnOff)
-        {
-            mDriver.status.OnOff = status.OnOff;
-            bChanged = true;
-        }
-        AllLightStatus = status.OnOff;
-
-        if(bChanged)
-        {
-            StatusChanged();
-
-            int kind = 0;
-            if(AllLightStatus)
-            {
-                kind = define.NOTIFY_ALL_LIGHT_ON;
-                Log.i(TAG, "SendNotifyKindBR(NOTIFY_ALL_LIGHT_ON)");
-            }
-            else
-            {
-                kind = define.NOTIFY_ALL_LIGHT_OFF;
-                Log.i(TAG, "SendNotifyKindBR(NOTIFY_ALL_LIGHT_OFF)");
-            }
-            SendNotifyKindBR(kind);
-        }
-
-        return true;
-    }
-}
+/*
+ * Copyright (C) 2015 Android WallPad Project
+ *
+ * FileName  : AllLightHDC_Controller.java
+ * Project   : Android WallPad Project
+ * Company   : HDC I-CONTROLS ( www.icontrols.co.kr )
+ * Author    : Kang Sang Ho  , lairu@icontrols.co.kr
+ */
+
+package com.artncore.wallpaddevservice.driver;
+
+import android.annotation.SuppressLint;
+import android.util.Log;
+
+import com.artncore.commons.APIErrorCode;
+import com.artncore.commons.define;
+import com.artncore.wallpaddevservice.ServiceMain;
+import com.util.LogUtil;
+
+import kr.co.icontrols.wallpadsupport.Version;
+
+
+/**
+ * 일괄소등 제어기 (현산:제일전기) 의 드라이버 모듈이다.
+ */
+@SuppressLint("HandlerLeak")
+public class AllLightHDC_Controller extends DeviceManager
+{
+    private final static String TAG = "AllLightHDC_Controller";
+
+    private final byte DEVICE_ADDRESS  = (byte) 0x11;
+
+    /** 초기 기기 검색 횟수  */
+    private final int MAX_SEARCH_COUNT   = 3;
+
+    private static boolean AllLightStatus = false;
+
+    /**
+     * 일괄소등 상태를 반환한다.
+     *
+     * @return (boolean) true : 일괄소등해제 , false : 일괄소등
+     */
+    public static boolean GetAllLightStatus() { return AllLightStatus; }
+
+    public class Status
+    {
+        boolean OnOff;          // true  : ON  ( 조명ON  , 일괄소등해제 )
+        // false : OFF ( 조명 OFF , 일괄소등상태 )
+        public Status()
+        {
+            OnOff = false;      // 조명OFF 일괄소등상태
+        }
+    }
+
+    public class Info
+    {
+        byte FwVer_Year;
+        byte FwVer_Month;
+        byte ProtocolVer_Main;
+        byte ProtocolVer_Sub;
+        public Info()
+        {
+            FwVer_Year = 0x00;
+            FwVer_Month = 0x00;
+            ProtocolVer_Main = 0x00;
+            ProtocolVer_Sub = 0x00;
+        }
+
+        public String ToDebugString()
+        {
+            String retStr =
+                    "==========================\r\n" +
+                            "Info\r\n" +
+                            "==========================\r\n" +
+                            "FwVer       : " + (int)(2000 + FwVer_Year) + "/" + FwVer_Month + "\r\n" +
+                            "ProtocolVer : V" + ProtocolVer_Main + "." + ProtocolVer_Sub + "\r\n" +
+                            "==========================\r\n";
+            return retStr;
+        }
+    }
+
+    public class Driver
+    {
+        private PollingList Polling;
+
+        private Status status;
+
+        public Driver()
+        {
+            Polling = new PollingList();
+            status  = new Status();
+        }
+
+        /** Polling 관련 */
+        private class PollingList
+        {
+            private final class STATUS
+            {
+                /** 초기화 과정 */
+                public final static byte First = 0;
+                /** 초기화 타임아웃 */
+                public final static byte FirstTimeOut = 1;
+                /** 평상시 */
+                public final static byte Normal = 2;
+            }
+
+            public byte Status;
+            public int SearchTryCount;
+
+            private PollingList()
+            {
+                Status = STATUS.First;
+                SearchTryCount = 0;
+            }
+        }
+    }
+
+    private Driver mDriver = null;
+
+
+    /**
+     * 생성자
+     */
+    public AllLightHDC_Controller()
+    {
+        /** 로그 초기상태 */
+        log_sw = false;
+
+        /** 통신성공률 변수 초기화 */
+        super.CommDataGeneration(1);
+
+        /** 드라이버 내부 변수 초기화 */
+        mDriver = new Driver();
+    }
+
+    @Override
+    public void DeviceLog(String msg)
+    {
+        if (!log_sw) return;
+        Log.d(TAG, msg);
+    }
+
+    /**
+     * 로딩후 처음 폴링 시퀀스
+     */
+    @Override
+    protected void do_boot()
+    {
+    }
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    // Polling
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+     * do_ctr : 폴링스케쥴러
+     */
+    @Override
+    protected void do_ctr()
+    {
+        DeviceLog("Polling ");
+
+        /* [[ First & FirstTimeOut ]]
+         * 초기 디바이스정보  검색 */
+        if( (mDriver.Polling.Status == Driver.PollingList.STATUS.First) ||
+                (mDriver.Polling.Status == Driver.PollingList.STATUS.FirstTimeOut) )
+        {
+            if(mDriver.Polling.Status == Driver.PollingList.STATUS.First)
+            {
+                if(mDriver.Polling.SearchTryCount++ > MAX_SEARCH_COUNT)
+                {
+                    mDriver.Polling.Status = Driver.PollingList.STATUS.FirstTimeOut;
+
+                    Log.i(TAG, "--------------------------------------------------");
+                    Log.i(TAG, "SearchDevice Fail... FirstTimeOut ");
+                    Log.i(TAG, "--------------------------------------------------");
+
+                    ServiceMain.deviceInitChecker.Remove(super.DeviceName);
+                }
+            }
+
+            if (Version.getModelType() == Version.MODEL_TYPE.IHN_1010GL_I_2443ALT) {
+                Log.i(TAG, "--------------------------------------------------");
+                Log.i(TAG, "Send_GetVerInfo() pass!! -> model : IHN-1010-I-2443ALT!!");
+                Log.i(TAG, "--------------------------------------------------");
+                mDriver.Polling.Status = Driver.PollingList.STATUS.Normal;
+                ServiceMain.deviceInitChecker.Remove(super.DeviceName);
+            }
+            else {
+                Info info = Send_GetVerInfo();
+                if(info != null)
+                {
+                    mDriver.Polling.Status = Driver.PollingList.STATUS.Normal;
+                    Log.i(TAG, info.ToDebugString());
+
+                    ServiceMain.deviceInitChecker.Remove(super.DeviceName);
+                }
+            }
+        }
+        /* [[ Normal ]]
+         * 평상시 */
+        else if(mDriver.Polling.Status == Driver.PollingList.STATUS.Normal)
+        {
+            Status status = Send_GetLightStatus();
+            if(status != null)
+            {
+                UpdateVariables(status);
+            }
+        }
+        /*
+         * 예외처리 */
+        else
+        {
+            mDriver = new Driver();
+        }
+    }
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    // Ctrl
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+     * NoSink 제어
+     *
+     * @param StrArg
+     *
+     * @return
+     */
+    public String NoSinkCtrl(String StrArg)
+    {
+        DeviceLog("[NoSinkCtrl] Start");
+
+        // 1. 디바이스 초기화시 에러리턴
+        if( (mDriver.Polling.Status == Driver.PollingList.STATUS.First) ||
+                (mDriver.Polling.Status == Driver.PollingList.STATUS.FirstTimeOut) )
+        {
+            Log.w(TAG, "[NoSinkCtrl] - Not Yet !!!");
+            return "FAIL;" + APIErrorCode.DEVICEISNOTREADY;
+        }
+
+        CtrDevFormat ctrDevFormat = GetCtrDevParamParsing(StrArg, 5);
+        if(ctrDevFormat.ret != APIErrorCode.C_SUCCESS)
+        {
+            Log.w(TAG, "[NoSinkCtrl] GetCtrDevParamParsing Error (ret:" + ctrDevFormat.ret + ")");
+            return "FAIL;" + APIErrorCode.DEFAULT_PARSING_ERR;
+        }
+
+        //////////////////////////////////////////////////////////
+        // Refresh : 데이터 갱신 (No Sink)
+        //////////////////////////////////////////////////////////
+        if(ctrDevFormat.CmdStr!=null && ctrDevFormat.CmdStr.equals("Refresh"))
+        {
+            return RefreshResult();
+        }
+
+        return "FAIL;" + APIErrorCode.UNKNOWNCOMMAND;
+    }
+
+    /**
+     * do_ctrEmm : 싱크 제어
+     */
+    @Override
+    @SuppressLint("DefaultLocale")
+    protected String do_ctrEmm(DeviceCtrSHMem SHMem)
+    {
+        DeviceLog("[do_ctrEmm] Start");
+        DeviceLog("cmd    : " + SHMem.cmd);
+        DeviceLog("StrArg : " + SHMem.StrArg);
+
+        // 1. 디바이스 초기화시 에러리턴
+        if( (mDriver.Polling.Status == Driver.PollingList.STATUS.First) ||
+                (mDriver.Polling.Status == Driver.PollingList.STATUS.FirstTimeOut) )
+        {
+            Log.w(TAG, "[do_ctrEmm] - Not Yet !!!");
+            return SHMem.retVal = "FAIL;" + APIErrorCode.DEVICEISNOTREADY;
+        }
+
+        CtrDevFormat ctrDevFormat = GetCtrDevParamParsing(SHMem.StrArg, 5);
+        if(ctrDevFormat.ret != APIErrorCode.C_SUCCESS)
+        {
+            Log.w(TAG, "[do_ctrEmm] GetCtrDevParamParsing Error (ret:" + ctrDevFormat.ret + ")");
+            return SHMem.retVal = "FAIL;" + APIErrorCode.DEFAULT_PARSING_ERR;
+        }
+
+        //////////////////////////////////////////////////////////
+        // Refresh : 데이터 갱신 (Sink)
+        //////////////////////////////////////////////////////////
+        if(ctrDevFormat.CmdStr!=null)
+        {
+            if(ctrDevFormat.CmdStr.equals("Refresh"))
+            {
+                Status status = Send_GetLightStatus();
+                if(status == null)
+                    return SHMem.retVal = "FAIL;" + APIErrorCode.DEVICEISNORESPONSE;
+
+                UpdateVariables(status);
+                return SHMem.retVal = RefreshResult();
+            }
+            else if(ctrDevFormat.CmdStr.equals("AllLightControl"))
+            {
+                // 1. Param Check
+                byte ParamOnOff   = ctrDevFormat.param[0];
+
+                // 2. Make Packet Data
+                boolean OnOff = false;
+                if(ParamOnOff != 0x00) OnOff = true;
+
+                // 3. Doing
+                Status status = Send_SetLightOnOff(OnOff);
+                if(status == null)
+                    return SHMem.retVal = "FAIL;" + APIErrorCode.DEVICEISNORESPONSE;
+
+                UpdateVariables(status);
+
+                return SHMem.retVal = "SUCCESS";
+            }
+        }
+
+
+        return SHMem.retVal = "UNKNOWNCMD";
+    }
+
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    // RefreshResult
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+     * Refresh 에 대한 응답포멧 정의
+     *
+     * @return (String) "SUCCESS; ..." 성공 , "FAIL; ... " 실패
+     */
+    private String RefreshResult()
+    {
+        String result = null;
+
+        DeviceLog("RefreshResult call : ");
+
+        // 1. Check Polling Status
+        if( (mDriver.Polling.Status == Driver.PollingList.STATUS.First) ||
+                (mDriver.Polling.Status == Driver.PollingList.STATUS.FirstTimeOut) )
+        {
+            result = "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
+            return result;
+        }
+
+        // 2. Param Range Check
+
+        // 3. Make Return String Format
+        try
+        {
+            if(mDriver == null)                   return "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
+            if(mDriver.status == null)            return "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
+
+            /*
+             * [Format]
+             *
+             * SUCCESS       - (String) 성공
+             *
+             * OnOff         - (boolean) 일괄소등 상태
+             */
+            result = APIErrorCode.SUCCESS + ";";
+
+            result += mDriver.status.OnOff + ";";
+        }
+        catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+            result = "FAIL;"+APIErrorCode.EXCEPTION;
+        }
+        catch (Exception e) {
+            Log.e(TAG, "[Exception Error] RefreshResult");
+            //e.printStackTrace();
+            LogUtil.errorLogInfo("", TAG, e);
+            result = "FAIL;"+APIErrorCode.EXCEPTION;
+        }
+        DeviceLog(" RefreshResult return : "+result);
+
+        return result;
+    }
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    // Protocol Command Send Func
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+     * 조명제어기 상태값 요청
+     *
+     * @return (Status) null - Error , Not null - OK
+     */
+    private Status Send_GetLightStatus()
+    {
+        DeviceLog("[Send_GetLightStatus] Start");
+
+        // 1. In 파라미터 확인
+
+        // 2. 패킷 데이터 만들기
+        byte [] ReqData = new byte [] { 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+        // 3. 데이터 전송 및 응답
+        byte [] Reply = SendNRead_Fixed( (byte)(DEVICE_ADDRESS), CMDList.Req.GetLightStatus, ReqData);
+
+        // 4. 수신데이터 파싱
+        Status status = ReplyParsing(Reply);
+        if(status == null)
+        {
+            DeviceLog("[Send_GetLightStatus] Reply is null");
+            AddDoCount(false);
+            return null;
+        }
+        AddDoCount(true);
+
+        return status;
+    }
+
+    /**
+     * 조명제어기 점등/소등 요청
+     *
+     * @param  OnOff - (boolean) true : 일괄소등해제 , false : 일괄소등
+     *
+     * @return (Status) null - Error , Not null - OK
+     */
+    private Status Send_SetLightOnOff(boolean OnOff)
+    {
+        DeviceLog("[Send_SetLightOnOff] Start");
+
+        // 1. In 파라미터 확인
+
+        // 2. 패킷 데이터 만들기
+        byte D2 = 0x00;
+        if(OnOff) D2 = 0x01;
+        byte [] ReqData = new byte [] { (byte)0xFF, D2, 0x00, 0x00, 0x00 };
+
+        // 3. 데이터 전송 및 응답
+        byte [] Reply = SendNRead_Fixed( (byte)(DEVICE_ADDRESS), CMDList.Req.SetLightOnOff, ReqData);
+
+        // 4. 수신데이터 파싱
+        Status status = ReplyParsing(Reply);
+        if(status == null)
+        {
+            DeviceLog("[Send_SetLightOnOff] Reply is null");
+            AddDoCount(false);
+            return null;
+        }
+        AddDoCount(true);
+
+        return status;
+    }
+
+    /**
+     * 응답 Parsing
+     *
+     * @param Reply     - (byte []) 응답 데이터
+     *
+     * @return (Status) null - Error , Not null - OK
+     */
+    private Status ReplyParsing(byte [] Reply)
+    {
+        // 1. 수신데이터 파싱
+        //     1.1. Default Check
+        if(Reply == null)
+        {
+            DeviceLog("[ReplyParsing] Reply is null");
+            return null;
+        }
+
+        int index = 0;
+        //          - D1 : 커맨드 수신 체크
+        if(Reply[index++] != (byte)0x80)
+        {
+            Log.w(TAG, "[ReplyParsing] Reply.length  fail ... " + Reply.length);
+            return null;
+        }
+
+        // 2. Data return
+        Status status = new Status();
+        if( (Reply[1] & BIT5) == 0x00 )
+        {
+            // 일괄소등 해제 (조명켜짐)
+            status.OnOff = true;
+        }
+        else
+        {
+            // 일괄소등 (조명꺼짐)
+            status.OnOff = false;
+        }
+
+        return status;
+    }
+
+    /**
+     * 버전정보 요청 (프로토콜 V2.2 추가사항 : 2013/04/15)
+     *
+     * @return (Status) null - Error , Not null - OK
+     */
+    private Info Send_GetVerInfo()
+    {
+        DeviceLog("[Send_GetVerInfo] Start");
+
+        // 1. In 파라미터 확인
+
+        // 2. 패킷 데이터 만들기
+        byte [] ReqData = new byte [] { 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+        // 3. 데이터 전송 및 응답
+        byte [] Reply = SendNRead_Fixed( (byte)(DEVICE_ADDRESS), CMDList.Req.GetVerInfo, ReqData);
+
+        // 4. 수신데이터 파싱
+        //     4.1. Default Check
+        if(Reply == null)
+        {
+            DeviceLog("[Send_GetVerInfo] Reply is null");
+            AddDoCount(false);
+            return null;
+        }
+
+        int index = 0;
+        byte data = 0x00;
+        //          - D1 : 커맨드 수신 체크
+        data = Reply[index++];
+        if(data != (byte)0x80)
+        {
+            Log.w(TAG, "[Send_GetVerInfo] Reply D1 fail ... D1:" + String.format("0x%02X", data));
+            AddDoCount(false);
+            return null;
+        }
+        //          - D2 : 펌웨어 Build Date (Year)
+        index++;
+
+        //          - D3 : 펌웨어 Build Date (Month)
+        data = Reply[index++];
+        if((data < 1) || (data > 12))
+        {
+            Log.w(TAG, "[Send_GetVerInfo] Reply D3 fail ... D3:" + data);
+            AddDoCount(false);
+            return null;
+        }
+
+        // 5. Data return
+        index = 1;
+        Info info = new Info();
+        info.FwVer_Year = Reply[index++];
+        info.FwVer_Month = Reply[index++];
+        info.ProtocolVer_Main = Reply[index++];
+        info.ProtocolVer_Sub = Reply[index++];
+
+        AddDoCount(true);
+
+        return info;
+    }
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    // CMDList
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+     * 명령어 리스트
+     */
+    public static class CMDList
+    {
+        public static final class Req
+        {
+            /////////////////////////////////////////////////////////
+            // Board
+            /////////////////////////////////////////////////////////
+            /** 조명제어기 상태값 요청 */
+            public final static byte GetLightStatus    = 0x00;
+
+            /** 조명제어기 점등/소등 요청 */
+            public final static byte SetLightOnOff     = 0x02;
+
+            /** 버전정보 요청 (프로토콜 V2.2 추가사항 : 2013/04/15) */
+            public final static byte GetVerInfo        = 0x21;
+        }
+    }
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    // UpdateVariables
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+     * XXXX 데이터를 업데이트 한다.
+     *
+     * @param XXXXData - (XXXXData) 업데이트할 XXXX 데이터
+     *
+     * @return (boolean) 데이터 변경여부 (true:변경 , false:미변경)
+     */
+    private boolean UpdateVariables(Status status)
+    {
+        boolean bChanged = false;
+        if(mDriver.status.OnOff != status.OnOff)
+        {
+            mDriver.status.OnOff = status.OnOff;
+            bChanged = true;
+        }
+        AllLightStatus = status.OnOff;
+
+        if(bChanged)
+        {
+            StatusChanged();
+
+            int kind = 0;
+            if(AllLightStatus)
+            {
+                kind = define.NOTIFY_ALL_LIGHT_ON;
+                Log.i(TAG, "SendNotifyKindBR(NOTIFY_ALL_LIGHT_ON)");
+            }
+            else
+            {
+                kind = define.NOTIFY_ALL_LIGHT_OFF;
+                Log.i(TAG, "SendNotifyKindBR(NOTIFY_ALL_LIGHT_OFF)");
+            }
+            SendNotifyKindBR(kind);
+        }
+
+        return true;
+    }
+}

+ 94 - 16
WallPadDevService/src/main/java/com/artncore/wallpaddevservice/driver/CookTopFinder_Controller.java

@@ -13,6 +13,7 @@ import android.annotation.SuppressLint;
 import android.os.Message;
 import android.os.Message;
 import android.util.Log;
 import android.util.Log;
 
 
+import com.artncore.WallPadDataMgr.WallpadDevStatus;
 import com.artncore.commons.APIErrorCode;
 import com.artncore.commons.APIErrorCode;
 import com.artncore.commons.define;
 import com.artncore.commons.define;
 import com.artncore.wallpaddevservice.CommonDefine;
 import com.artncore.wallpaddevservice.CommonDefine;
@@ -190,11 +191,13 @@ public class CookTopFinder_Controller extends DeviceManager
 
 
             if (!mDriver.Polling.Find_V1) {
             if (!mDriver.Polling.Find_V1) {
                 if (mDriver.Polling.GasReplyCount >= MAX_FIND_COUNT) {
                 if (mDriver.Polling.GasReplyCount >= MAX_FIND_COUNT) {
+                    ServiceMain.deviceInitChecker.Remove(ServiceMain.cooktop_Controller.DeviceName);
                     LoadingDriver(define.DRIVERID_GAS);
                     LoadingDriver(define.DRIVERID_GAS);
                     mDriver.Polling.SetStatus(CookTopFinder_Controller.Driver.PollingList.STATUS.Normal);
                     mDriver.Polling.SetStatus(CookTopFinder_Controller.Driver.PollingList.STATUS.Normal);
                     return;
                     return;
                 }
                 }
                 else if (mDriver.Polling.CookTopReplyCount >= MAX_FIND_COUNT) {
                 else if (mDriver.Polling.CookTopReplyCount >= MAX_FIND_COUNT) {
+                    ServiceMain.deviceInitChecker.Remove(ServiceMain.gasValve_Controller.DeviceName);
                     LoadingDriver(define.DRIVERID_COOKTOP);
                     LoadingDriver(define.DRIVERID_COOKTOP);
                     mDriver.Polling.SetStatus(CookTopFinder_Controller.Driver.PollingList.STATUS.Normal);
                     mDriver.Polling.SetStatus(CookTopFinder_Controller.Driver.PollingList.STATUS.Normal);
                     return;
                     return;
@@ -340,33 +343,108 @@ public class CookTopFinder_Controller extends DeviceManager
     @SuppressLint("LongLogTag")
     @SuppressLint("LongLogTag")
     private boolean Send_GasReplyCheck()
     private boolean Send_GasReplyCheck()
     {
     {
-        DeviceLog("[Send_GasReplyCheck] Start");
+//        DeviceLog("[Send_GasReplyCheck] Start");
+//
+//        // 1. In 파라미터 확인
+//
+//        // 2. 패킷 데이터 만들기
+//        //byte [] ReqData = new byte [] { (byte)0xFF };
+//
+//        // 3. 데이터 전송 및 응답
+//        byte [] ReqData = new byte [] { 0x00, 0x00, 0x00, 0x00, 0x00 };
+//        byte [] Reply = SendNRead_Fixed( (byte)(DEVICE_ADDRESS_GAS), GasValve_Controller.CMDList.Req.GetStatus, ReqData);
+//        //byte [] Reply = SendNRead_Variable( (byte)(DEVICE_ADDRESS_GAS), CMDList.GAS.Req.GetStatus, ReqData);
+//
+//        // 4. 수신데이터 파싱
+//        //     4.1. Default Check
+//        if(Reply == null)
+//        {
+//            DeviceLog("[Send_GasReplyCheck] Reply is null");
+//            return false;
+//        }
+//        if( (Reply.length != 5))
+//        {
+//            // 길이 체크
+//            // 가스 (GasValue_Controller 체크)
+//            Log.w(TAG, "[Send_GasReplyCheck] Reply.length  fail ... " + Reply.length);
+//            return false;
+//        }
+//        return true;
+
+
+        byte MaxDeviceID = 0;
+        boolean result = false;
+        for(byte DeviceIdx = 0 ; DeviceIdx<2 ; DeviceIdx++)
+        {
+            result = Send_GetStatus(DeviceIdx);
+            if(result)
+            {
+                break;
+            }
+            else
+            {
+                Log.i(TAG, "SearchDevice     DeviceNum = " + (byte)(DeviceIdx+1) + "      Fail...");
+            }
+            Sleep(1000);
+        }
+
+        return result;
+    }
+
+
+    private void Send_DummyPacket()
+    {
+        if(!USE_DUMMY_PACKET) return;
+
+        byte [] ReqPaket = new byte[] {0x02, (byte)0xFF, 0x00, Get_Sequence(), 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+        WritePacket(ReqPaket, true);
+
+        Sleep(100);
+    }
+
+    private final boolean USE_DUMMY_PACKET = false;
+
+    private boolean Send_GetStatus(byte DeviceIdx)
+    {
+        boolean result = false;
+        DeviceLog("[Send_GetStatus] Start");
+        Send_DummyPacket();
 
 
-        // 1. In 파라미터 확인
 
 
         // 2. 패킷 데이터 만들기
         // 2. 패킷 데이터 만들기
-        //byte [] ReqData = new byte [] { (byte)0xFF };
+        byte [] ReqData = new byte [] { 0x00, 0x00, 0x00, 0x00, 0x00 };
 
 
         // 3. 데이터 전송 및 응답
         // 3. 데이터 전송 및 응답
-        byte [] ReqData = new byte [] { 0x00, 0x00, 0x00, 0x00, 0x00 };
-        byte [] Reply = SendNRead_Fixed( (byte)(DEVICE_ADDRESS_GAS), GasValve_Controller.CMDList.Req.GetStatus, ReqData);
-        //byte [] Reply = SendNRead_Variable( (byte)(DEVICE_ADDRESS_GAS), CMDList.GAS.Req.GetStatus, ReqData);
+        byte [] Reply = null;
+        byte [] TempReply = null;
+        if(ServiceMain.dataBaseLoader.data.wallpadDeviceSet.Get_GasValve_Debug)
+        {
+            // a. All Data 임시 저장
+            TempReply = SendNRead_Fixed_ReturnAllPacket( (byte)(DEVICE_ADDRESS_GAS + DeviceIdx), GasValve_Controller.CMDList.Req.GetStatus, ReqData);
+            if(TempReply!=null)
+            {
+                result = true;
+            }
+            else
+            {
+                result = false;
+            }
+        }
+        else
+        {
+            Reply = SendNRead_Fixed( (byte)(DEVICE_ADDRESS_GAS + DeviceIdx), GasValve_Controller.CMDList.Req.GetStatus, ReqData);
+        }
 
 
-        // 4. 수신데이터 파싱
-        //     4.1. Default Check
         if(Reply == null)
         if(Reply == null)
         {
         {
-            DeviceLog("[Send_GasReplyCheck] Reply is null");
-            return false;
+            result = false;
         }
         }
-        if( (Reply.length != 5))
+        else
         {
         {
-            // 길이 체크
-            // 가스 (GasValue_Controller 체크)
-            Log.w(TAG, "[Send_GasReplyCheck] Reply.length  fail ... " + Reply.length);
-            return false;
+            result = true;
         }
         }
-        return true;
+
+        return result;
     }
     }
 
 
     /**
     /**

+ 4 - 3
WallPadDevService/src/main/java/com/artncore/wallpaddevservice/driver/Cooktop_Controller.java

@@ -448,7 +448,7 @@ public class Cooktop_Controller extends DeviceManager {
                             return SHMem.retVal = APIErrorCode.FAILSTR + ";" + APIErrorCode.INVALIDPARAMETER;
                             return SHMem.retVal = APIErrorCode.FAILSTR + ";" + APIErrorCode.INVALIDPARAMETER;
                         }
                         }
                         else {
                         else {
-                            if (circuitIdx >= mDriver.Device[Index].info.hCircuitCnt) {
+                            if (circuitIdx > mDriver.Device[Index].info.hCircuitCnt) {
                                 Log.w(TAG, "[do_ctrEmm -> setUnitCircuitClose] Param : CircuitIdx - Out Of Range #2 !!! (CircuitIdx:" + circuitIdx + ")");
                                 Log.w(TAG, "[do_ctrEmm -> setUnitCircuitClose] Param : CircuitIdx - Out Of Range #2 !!! (CircuitIdx:" + circuitIdx + ")");
                                 return SHMem.retVal = APIErrorCode.FAILSTR + ";" + APIErrorCode.INVALIDPARAMETER;
                                 return SHMem.retVal = APIErrorCode.FAILSTR + ";" + APIErrorCode.INVALIDPARAMETER;
                             }
                             }
@@ -985,7 +985,8 @@ public class Cooktop_Controller extends DeviceManager {
             }
             }
 
 
             // 2. 패킷 데이터 만들기
             // 2. 패킷 데이터 만들기
-            byte[] ReqData = { (byte) circuitId, (byte) status };
+            byte id = (byte) (circuitId + 1);
+            byte[] ReqData = { (byte) id, (byte) status };
 
 
             // 3. 데이터 전송 및 응답
             // 3. 데이터 전송 및 응답
             byte[] Reply = SendNRead_Variable((byte) (DEVICE_ADDRESS + deviceIdx), CMDList.Req.SetUnitCircuitStatus, ReqData);
             byte[] Reply = SendNRead_Variable((byte) (DEVICE_ADDRESS + deviceIdx), CMDList.Req.SetUnitCircuitStatus, ReqData);
@@ -1094,7 +1095,7 @@ public class Cooktop_Controller extends DeviceManager {
             //     1.2. Details Data Check
             //     1.2. Details Data Check
             //          - D1 : 제어기 ID
             //          - D1 : 제어기 ID
             data = Reply[index++];
             data = Reply[index++];
-            if (circuitId != data) {
+            if ((circuitId+1) != data) {
                 Log.w(TAG, "[parsingReply_UnitCircuitCommon] D1 (circuitId) : Circuit is not match!! Req ID [" + ToByteString(circuitId) + ", Rep ID [" + ToByteString(data) + "]");
                 Log.w(TAG, "[parsingReply_UnitCircuitCommon] D1 (circuitId) : Circuit is not match!! Req ID [" + ToByteString(circuitId) + ", Rep ID [" + ToByteString(data) + "]");
                 return null;
                 return null;
             }
             }

+ 1762 - 1762
WallPadDevService/src/main/java/com/artncore/wallpaddevservice/driver/DeviceManager.java

@@ -1,1762 +1,1762 @@
-package com.artncore.wallpaddevservice.driver;
-
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.util.ArrayList;
-import java.util.List;
-
-import com.artncore.commons.APIErrorCode;
-import com.artncore.commons.define;
-import com.artncore.wallpaddevservice.CommonDefine;
-import com.artncore.wallpaddevservice.SerialHandler;
-import com.artncore.wallpaddevservice.ServiceMain;
-import com.artncore.wallpaddevservice.SerialHandler.SERIAL_PORT_TYPE;
-
-import android.annotation.SuppressLint;
-import android.content.Intent;
-import android.os.CountDownTimer;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.util.Log;
-import android_serialport_api.SerialPort;
-import android_serialport_api.SerialPort_LH;
-import com.util.LogUtil;
-@SuppressLint("HandlerLeak")
-public class DeviceManager extends Thread
-{
-	private final String TAG = "DeviceManager";
-	private String getTAG() { return TAG + ":" + DeviceName; }
-
-	public final byte BIT0 = define.BIT0;
-	public final byte BIT1 = define.BIT1;
-	public final byte BIT2 = define.BIT2;
-	public final byte BIT3 = define.BIT3;
-	public final byte BIT4 = define.BIT4;
-	public final byte BIT5 = define.BIT5;
-	public final byte BIT6 = define.BIT6;
-	public final byte BIT7 = define.BIT7;
-
-	public final byte [] BIT_ARRAY = new byte [] { BIT0, BIT1, BIT2, BIT3, BIT4, BIT5, BIT6, BIT7 };
-
-	public final byte STX = 0x02;
-
-	public final long TIME_SEC = 1000;
-
-	public final long TIME_MINUTE = (long) (TIME_SEC * 60);
-
-	private final int MAX_TOTAL_COUNT  = 100000000;
-	private final int MAX_RECENT_COUNT = 100;
-
-	DeviceCtrSHMem 		SHMem;
-	SerialHandler  		PortHandler;
-	Handler  			MainHandler;
-	public int			startAddr;
-	public int			endAddr;
-	public Handler      DevHandler;
-	public int          DevID;
-
-	private boolean             bCommCNTGeneration = false;
-	public boolean getCommCNTGeneration() { return bCommCNTGeneration; }
-	int[]				TotalCommSuccCNT;
-	int[]				TotalCommFailCNT;
-	int[]				RecentCommSuccCNT;
-	int[]				RecentCommFailCNT;
-	byte[][]            recentdata;
-	byte[]              WriteLocation;
-
-	boolean             LogByteBuffOutput = true;
-
-	public String		DeviceName = null;
-	public String       ModuleName = null;
-	/**
-	 * 0 : 제어기기류 (normal type) <br>
-	 * 1 : 게이트웨이 <br>
-	 * 2 : 에너지제품군 <br>
-	 * 3 : 스마트스위치 <br>
-	 */
-	int                 ReadFormatType = 0;
-	public boolean 		log_sw;
-	public int          DevStatus;
-
-	private long        ReadTimeOut = 200;
-
-	public boolean      Doing = false;
-
-	public boolean      SerialLog = false;
-
-	//for test or business sample
-	static boolean 		virtualmode = true;
-	SerialPort          mSerialPort = null;
-	SerialPort_LH       mSerialPort_LH = null;
-	private int mSerialPortType = SERIAL_PORT_TYPE.Normal;
-
-	byte   sequencenum=0;
-	int    devSleepTime = 150;
-
-	private byte [] ReadBuffer = new byte[64 * 4 * 2];
-	private byte [] DecBuffer = new byte[64 * 4];
-
-	List<DeviceCtrSHMem> DevSHMem = new ArrayList<DeviceCtrSHMem>();
-	List<String> ChangedBRList = new ArrayList<String>();
-
-	String LogAuther;
-	int    LogDriverID;
-
-	/**
-	 * 생성자
-	 */
-	public DeviceManager()
-	{
-	}
-
-	// =================================================================================================
-	// [[ 통신성공률 ]] region
-	// =================================================================================================
-	/**
-	 * 통신성공률 관련 변수를 생성 및 초기화 한다.
-	 *
-	 * @param DeviceCount - (int) 디바이스 개수
-	 *
-	 * @return (boolean) 성공여부  true:성공,  false:실패
-	 */
-	public boolean CommDataGeneration(int DeviceCount)
-	{
-		if(DeviceCount <= 0)
-		{
-			Log.w(getTAG(), "[CommDataGeneration] Param : DeviceCount  Out Of Range !!!(DeviceCount:" + DeviceCount + ")");
-			return false;
-		}
-
-		TotalCommSuccCNT  = new int[DeviceCount];
-		TotalCommFailCNT  = new int[DeviceCount];
-		RecentCommSuccCNT = new int[DeviceCount];
-		RecentCommFailCNT = new int[DeviceCount];
-		recentdata = new byte[DeviceCount][MAX_RECENT_COUNT];
-		WriteLocation = new byte[DeviceCount];
-
-		bCommCNTGeneration = true;
-		return true;
-	}
-
-	/**
-	 * 통신성공률을 업데이트 한다.
-	 *
-	 * @param devIndex - (int) 기기 인덱스 (1개 일 경우 : 0)
-	 * @param Success - (boolean) 성공유무  true:성공,  false:실패
-	 */
-	protected void AddDoCount(int devIndex, boolean Success)
-	{
-		if(!bCommCNTGeneration)
-		{
-			Log.w(getTAG(), "[AddDoCount]" + "bCommCNTGeneration flase !!!");
-			return;
-		}
-		try
-		{
-			if(devIndex >= TotalCommSuccCNT.length)
-			{
-				Log.w(getTAG(), "[AddDoCount]" + "Param : devIndex  Out Of Range !!!(devIndex:" + devIndex + ", length:" + TotalCommSuccCNT.length + ")");
-				return;
-			}
-			byte ret = Success?(byte)1:(byte)2;
-			if (recentdata[devIndex][WriteLocation[devIndex]]!=0)
-			{
-				if (recentdata[devIndex][WriteLocation[devIndex]] == 1)
-					RecentCommSuccCNT[devIndex]--;
-				else
-					RecentCommFailCNT[devIndex]--;
-			}
-			recentdata[devIndex][WriteLocation[devIndex]] = ret;
-			WriteLocation[devIndex]++;
-			if (WriteLocation[devIndex] >= MAX_RECENT_COUNT) WriteLocation[devIndex] = 0;
-
-			if (Success)
-			{
-				TotalCommSuccCNT[devIndex]++;
-				RecentCommSuccCNT[devIndex]++;
-			}
-			else
-			{
-				TotalCommFailCNT[devIndex]++;
-				RecentCommFailCNT[devIndex]++;
-			}
-
-			int TotalCount = (int)(TotalCommSuccCNT[devIndex]+TotalCommFailCNT[devIndex]);
-			if(TotalCount >= MAX_TOTAL_COUNT)
-			{
-				TotalCommSuccCNT[devIndex]  = 0;
-				RecentCommFailCNT[devIndex] = 0;
-			}
-		}
-		catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-        }
-		catch (Exception e) {
-			Log.e(getTAG(), "[AddDoCount]" + "Exception Error");
-			//e.printStackTrace();
-            LogUtil.errorLogInfo("", TAG, e);
-		}
-	}
-
-	/**
-	 * 통신성공률을 업데이트 한다. <br>
-	 * 기기가 드라이버에 1개 일경우에 사용한다.
-	 *
-	 * @param Success - (boolean) 성공유무  true:성공,  false:실패
-	 */
-	protected void AddDoCount(boolean Success)
-	{
-		AddDoCount(0, Success);
-	}
-
-	/**
-	 * 통신 성공률 데이터를 String 데이터로 추출한다.
-	 *
-	 * @param DevIndex - (int) 디바이스 인덱스
-	 *
-	 * @return (String) - "SUCCESS; ..." 성공 , "FAIL; ... " 실패
-	 */
-	public String GetTransactionReport(int DevIndex)
-	{
-		if(!bCommCNTGeneration)
-		{
-			Log.w(getTAG(), "[GetTransactionReport] bCommCNTGeneration false !!!");
-			return GetFailResult(APIErrorCode.DEVICEISNOTREADY);
-		}
-
-		try
-		{
-			if (DevIndex >= TotalCommSuccCNT.length) return GetFailResult(APIErrorCode.INVALIDPARAMETER);
-
-			String Retval = APIErrorCode.SUCCESS +
-					define.DEVCTR_CMD_SPLITER+TotalCommSuccCNT[DevIndex]  +
-					define.DEVCTR_CMD_SPLITER+TotalCommFailCNT[DevIndex]  +
-					define.DEVCTR_CMD_SPLITER+RecentCommSuccCNT[DevIndex] +
-					define.DEVCTR_CMD_SPLITER+RecentCommFailCNT[DevIndex] +
-					define.DEVCTR_CMD_SPLITER+MAX_RECENT_COUNT;
-
-			int startidx = WriteLocation[DevIndex]-1;
-			if (startidx < 0) startidx = MAX_RECENT_COUNT-1;
-			for (int i = 0; i< MAX_RECENT_COUNT; i++)
-			{
-				Retval+=(define.DEVCTR_CMD_SPLITER+recentdata[DevIndex][startidx]);
-				startidx--;
-				if (startidx < 0) startidx = MAX_RECENT_COUNT-1;
-			}
-
-			return Retval;
-		}
-		catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-			return GetFailResult(APIErrorCode.EXCEPTION);
-        }
-		catch (Exception e) {
-			Log.e(getTAG(), "[Exception Error] GetTransactionReport");
-			//e.printStackTrace();
-            LogUtil.errorLogInfo("", TAG, e);
-			return GetFailResult(APIErrorCode.EXCEPTION);
-		}
-	}
-
-
-	// =================================================================================================
-	// [[ 상태변경 알림 Broadcast ]] region
-	// =================================================================================================
-	/**
-	 * 상태 변경을 알린다.<br>
-	 * 등록된 ChangedBRList 만큼 전송한다.
-	 */
-	protected void StatusChanged()
-	{
-		synchronized(ChangedBRList)
-		{
-			if (!ChangedBRList.isEmpty())
-			{
-				for(int i=0;i< ChangedBRList.size();i++)
-				{
-					Intent intent = new Intent();
-					intent.setAction(ChangedBRList.get(i));
-					DeviceLog("StatusChanged BR Send "+ChangedBRList.get(i));
-					ServiceMain.svcContext.sendBroadcast(intent);
-				}
-			}
-		}
-	}
-
-	/**
-	 * 상태 변경을 알리며, 추가로 1 byte 데이터를 전송한다.<br>
-	 * 등록된 ChangedBRList 만큼 전송한다.
-	 *
-	 * @param status - (byte) 전송할 데이터
-	 */
-	protected void StatusChanged(byte status) {
-		synchronized(ChangedBRList) {
-			if (!ChangedBRList.isEmpty()) {
-
-				for (int i = 0; i < ChangedBRList.size(); i++) {
-					Intent intent = new Intent();
-					intent.setAction(ChangedBRList.get(i));
-					intent.putExtra("STATUS", status);
-					DeviceLog("StatusChanged BR Send " + ChangedBRList.get(i) + ":" + String.format("0x%02X", status));
-					ServiceMain.svcContext.sendBroadcast(intent);
-				}
-			}
-		}
-	}
-
-	/**
-	 * 상태 변경시 알릴 Action Name 을 등록한다.
-	 *
-	 * @param Acname - (String) 등록할 Action Name
-	 */
-	public void AddBR(String Acname)
-	{
-		if (Acname != null)
-		{
-			synchronized(ChangedBRList)
-			{
-				int limit = ChangedBRList.size();
-
-				if (limit > 0)
-				{
-					int i;
-					for (i=0;i<limit;i++)
-						if (Acname.equalsIgnoreCase(ChangedBRList.get(i)))
-							break;
-					if (i==limit)
-					{
-						ChangedBRList.add(Acname);
-
-					}
-
-				}
-				else
-					ChangedBRList.add(Acname);
-			}
-		}
-	}
-
-	/**
-	 * 상태 변경시 알릴 Action Name 을 삭제한다.
-	 *
-	 * @param ACname - (String) 삭제할 Action Name
-	 */
-	public void RemoveBR(String ACname)
-	{
-		if(ACname == null)
-		{
-			Log.w(getTAG(), "[RemoveBR] Param:ACname is null !!!");
-			return;
-		}
-		if(ChangedBRList == null)
-		{
-			Log.w(getTAG(), "[RemoveBR] ChangedBRList is null !!!");
-			return;
-		}
-
-		synchronized(ChangedBRList)
-		{
-			if (ACname.equals("null"))
-				ChangedBRList.clear();
-			else
-			{
-				DeviceLog("Remove BR " + ACname);
-				ChangedBRList.remove(ACname);
-			}
-		}
-	}
-
-	/**
-	 * WALLPAD_NOTIFY 의 ActionName 으로 전달될 Broadcast 를 송신한다.
-	 *
-	 * @param kind - (int) 종류 (WallPadAPI -> define.java -> NOTIFY_xxxxxx 로 명명된 값을 넣는다)
-	 */
-	protected void SendNotifyKindBR(int kind)
-	{
-		Intent notiIntent = new Intent();
-		notiIntent.setAction(define.NOTIFY_ACNAME);
-		notiIntent.putExtra(define.NOTIBR_KIND, kind);
-		ServiceMain.svcContext.sendBroadcast(notiIntent);
-	}
-
-	/**
-	 * 엘리베이터 호출 요청을 한다.
-	 *
-	 * @param Up - (boolean) true : 상향호출,  false : 하향호출
-	 */
-	protected void ElevatorCall(boolean Up)
-	{
-		SendNotifyKindBR((Up==true)?define.NOTIFY_DEVICE_ELE_CALL_UP:define.NOTIFY_DEVICE_ELE_CALL_DOWN);
-	}
-
-	// =================================================================================================
-	// [[ 설정 ]] region
-	// =================================================================================================
-	/**
-	 * 디바이스ID를 설정한다.
-	 *
-	 * @param devID - (int) 설정할 ID
-	 */
-	public void Set_DevID(int devID)
-	{
-		DevID=devID;
-	}
-
-	/**
-	 * 디바이스 이름을 설정한다.
-	 *
-	 * @param devname - (String) 설정할 이름
-	 */
-	public void Set_DevName(String devname)
-	{
-		DeviceName=devname;
-	}
-
-	/**
-	 * 사용하는 모듈이름을 설정한다.
-	 *
-	 * @param modulename - (String) 설정할 모듈이름
-	 */
-	public void Set_ModuleName(String modulename)
-	{
-		ModuleName = modulename;
-
-		if(ModuleName.equals("Dgw_Module"))              ReadFormatType = 1;
-		else if(ModuleName.equals("Energy_Module"))      ReadFormatType = 2;
-		else if(ModuleName.equals("SmartSwitch_Module")) ReadFormatType = 3;
-		else if(ModuleName.equals("Special_Module"))
-		{
-			if(DeviceName.equals("SmartSwitchPol_Controller")) ReadFormatType = 3;
-		}
-		else ReadFormatType = 0;
-	}
-
-	/**
-	 * ServiceMain 의 Handler 를 설정한다.
-	 *
-	 * @param mainhandler - (Handler) 설정할 Handler
-	 */
-	public void setMainHandler(Handler mainhandler)
-	{
-		MainHandler = mainhandler;
-	}
-
-	/**
-	 * SerialHandler 를 설정한다.
-	 *
-	 * @param portHandler - (SerialHandler) 설정할 SerialHandler
-	 */
-	public void set_handler(SerialHandler portHandler)
-	{
-		PortHandler = portHandler;
-	}
-
-	/**
-	 * 시퀀스넘버를 가져온다. (업데이트포함)
-	 *
-	 * @return - (Byte) 업데이트된 시퀀스넘버
-	 */
-	public Byte Get_Sequence()
-	{
-		if (sequencenum != 127)
-			sequencenum+=1;
-		else
-			sequencenum = -128;
-		return sequencenum;
-	}
-
-	/**
-	 * 실패code 를 String 으로 반환한다.
-	 *
-	 * @param code - (int) 실패code
-	 *
-	 * @return (String)
-	 */
-	public static String GetFailResult(int code)
-	{
-		String retStr = APIErrorCode.FAILSTR+";"+code;
-		return retStr;
-	}
-
-	/**
-	 * 디바이스 로그 출력
-	 *
-	 * @param msg - (String) 출력할 메시지
-	 */
-	public void DeviceLog(String msg)
-	{
-		if (!log_sw) return;
-		//Log.i(DeviceName, APIErrorCode.GetLogPrefix()+msg);
-	}
-
-
-	// =================================================================================================
-	// [[ Packet Write & Read ]] region
-	// =================================================================================================
-	/**
-	 * 시리얼포트로 패킷을 전송한다.
-	 *
-	 * @param Packet - (byte []) 전송할 패킷
-	 * @param Delete_ReadBuffer - (boolean) 수신버퍼 삭제 여부 (true:삭제, false:미삭제) 본 옵션은 485모드 일경우 true , 232일 경우 false 설정 한다.
-	 *
-	 * @return (int) - >=0 : 성공, <0 : 실패
-	 */
-	public int WritePacket(byte[] Packet, boolean Delete_ReadBuffer)
-	{
-		// 1. Param Check
-		if(Packet == null) return -1;
-
-		// 2. 송신전 있을수 있는 수신 데이터를 삭제한다.
-		if(Delete_ReadBuffer)
-		{
-			try
-			{
-				InputStream mInputStream = mSerialPort.getInputStream();
-				if (mInputStream != null)
-				{
-					int ReadSize = mInputStream.available();
-					if(ReadSize > 0)
-					{
-						Log.d(getTAG(), "[WritePacket] Dummy Data Clear !!!(ReadSize:" + ReadSize + ")");
-						mInputStream.read(new byte [ReadSize], 0, ReadSize);
-					}
-				}
-			}
-			catch (RuntimeException re) {
-				LogUtil.errorLogInfo("", TAG, re);
-				return -100;
-			}
-			catch (Exception e) {
-				Log.e(getTAG(), "[WriteCMD] IOException Error #1");
-				return -100;
-			}
-		}
-
-		// 3. 데이터 송신
-		try
-		{
-			OutputStream mOutputStream = mSerialPort.getOutputStream();
-			mOutputStream.write(Packet);
-
-			if(SerialLog)
-				Log.d(DeviceName, "Write - " + ToByteString(Packet, Packet.length));
-		}
-		catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-			return -101;
-        }
-		catch (Exception e) {
-			Log.e(getTAG(), "[WriteCMD] IOException Error #2");
-			return -101;
-		}
-
-		return 0;
-	}
-
-	/**
-	 * 수신 TimeOut 시간을 설정한다.
-	 *
-	 * @param setTime - (long) 설정할 시간 (범위 : 10 이상)
-	 */
-	public void setReadTimeOut(long setTime)
-	{
-		if(setTime <= 0 || setTime < 10)
-		{
-			Log.w(getTAG(), "[" + DeviceName + ":setReadTimeOut]" + "Param : setTime Out Of Range !!! (setTime:" + setTime + ")");
-			return;
-		}
-
-		ReadTimeOut = setTime;
-	}
-
-	/**
-	 * 시리얼포트로 패킷을 수신 하고, 기본 패킷 구조를 Parsing 리턴 한다.
-	 *
-	 * @param nAddress       - (byte) 응답받을 Adress
-	 * @param nPaketTypeFixed - (boolean) 패킷타입 (true:고정10Byte, false:가변패킷)
-	 *
-	 * @return (byte []) null - Error , Not null - OK
-	 */
-	public byte [] ReadPacket(byte nAddress, boolean nPaketTypeFixed)
-	{
-		// 1. mInputStream Get
-		InputStream mInputStream = mSerialPort.getInputStream();
-		if (mInputStream == null)
-		{
-			Log.w(getTAG(), "[" + DeviceName + "]" + " ReadCMD - mInputStream is null !!!");
-			return null;
-		}
-
-		// 2. 사용 변수 설정
-		int ReadSize = 0;
-		int DecIndex = 0;
-		byte Data = 0x00;
-		int ExpectedLength = 0;
-
-		long StartTime = 0;
-		long Term = 0;
-		int MinWaitTime = 0;
-		int  TimeOutCount = 0;
-
-		// 3. Doing
-		StartTime = System.currentTimeMillis();
-		MinWaitTime = (int)(ReadTimeOut/2);
-		while(true)
-		{
-			try
-			{
-				// 3.1. TimeOut Check
-				Term = Math.abs(StartTime - System.currentTimeMillis());
-				TimeOutCount++;
-				if (Term > ReadTimeOut)
-				{
-					if(TimeOutCount >= MinWaitTime)
-					{
-						DeviceLog("ReadCMD - TimeOut#1 (ReadTimeOut:" + ReadTimeOut + "ms)");
-
-						if(SerialLog)
-							Log.i(TAG, "[" + DeviceName + "]" + " TimeOut - (StartTime:" + StartTime + ", ReadTimeOut:" + ReadTimeOut + ", Term:" + Term + ", TimeOutCount:" + TimeOutCount);
-						break;
-					}
-				}
-				if(TimeOutCount > (int)(ReadTimeOut*2))
-				{
-					Log.w(getTAG(), "[" + DeviceName + "]" + " ReadCMD - TimeOut#2 (TimeOut:" + TimeOutCount + ", ReadTimeOut:" + ReadTimeOut + ")");
-					break;
-				}
-
-				// 3.2. Read Size
-				ReadSize = mInputStream.available();
-				if(ReadSize > 0)
-				{
-					if(ReadSize <= ReadBuffer.length)
-					{
-						// 3.3. Read Buffer
-						mInputStream.read(ReadBuffer, 0, ReadSize);
-
-						//if(SerialLog)
-							//Log.d(DeviceName, "Read " + ToByteString(ReadBuffer, ReadSize));
-						//Log.i(DeviceName, "Read " + ToByteString(ReadBuffer, ReadSize));
-
-						// 3.4. Parsing
-						for(int i=0 ; i<ReadSize ; i++)
-						{
-							Data = ReadBuffer[i];
-
-							// STX
-							if(DecIndex == 0)
-							{
-								if(Data == STX) DecBuffer[DecIndex++] = Data;
-								else DecIndex = 0;
-							}
-
-							// ID
-							else if(DecIndex == 1)
-							{
-								if(Data == nAddress) DecBuffer[DecIndex++] = Data;
-								else DecIndex = 0;
-							}
-
-							// 가변 : LEN
-							// 고정 : CMD
-							else if(DecIndex == 2)
-							{
-								if(nPaketTypeFixed)
-								{
-									// 고정 10Byte
-									DecBuffer[DecIndex++] = Data;
-									ExpectedLength = 10;
-								}
-								else
-								{
-									// 가변
-									ExpectedLength = getInt((byte)Data);
-									if(ExpectedLength <= DecBuffer.length)
-									{
-										DecBuffer[DecIndex++] = Data;
-									}
-									else
-									{
-										DecIndex = 0;
-									}
-								}
-							}
-							else if(DecIndex < (ExpectedLength-1))
-							{
-								DecBuffer[DecIndex++] = Data;
-							}
-							else if(DecIndex == (ExpectedLength-1))
-							{
-								if(Data == Check_Byte(DecBuffer, DecIndex))
-								{
-									DecBuffer[DecIndex++] = Data;
-									byte [] RetBuffer = new byte [DecIndex];
-									for(int y=0 ; y<DecIndex ; y++) RetBuffer[y] = DecBuffer[y];
-
-									if(SerialLog)
-									    Log.d(DeviceName, "Read - " + ToByteString(RetBuffer, DecIndex));
-
-									return RetBuffer;
-								}
-								else DecIndex = 0;
-							}
-							else DecIndex = 0;
-						}
-					}
-					else
-					{
-						Log.d(getTAG(), "[ReadPacket] Dummy Data Clear !!!(ReadSize:" + ReadSize + ")");
-						mInputStream.read(new byte [ReadSize], 0, ReadSize);
-					}
-				}
-			}
-			catch (RuntimeException re) {
-				LogUtil.errorLogInfo("", TAG, re);
-				return null;
-			}
-			catch (Exception e) {
-				Log.e(getTAG(), "[" + DeviceName + "]" + " ReadCMD - Exception Error");
-				//e.printStackTrace();
-            	LogUtil.errorLogInfo("", TAG, e);
-				return null;
-			}
-
-			Sleep(1);
-		}
-
-		return null;
-	}
-
-	/**
-	 * 시리얼포트로 패킷을 전송하고 <br>
-	 * 수신힌, 기본 패킷 구조를 Parsing 리턴 한다.
-	 *
-	 * @param WriteData      - (byte []) 전송할 패킷
-	 * @param nAddress       - (byte) 응답받을 Adress
-	 * @param nPaketTypeFixed - (boolean) 패킷타입 (true:고정10Byte, false:가변패킷)
-	 *
-	 * @return (byte []) null - Error , Not null - OK
-	 */
-	public byte [] WriteNReadPacket(byte[] WriteData, byte nAddress, boolean nPaketTypeFixed)
-	{
-		if(mSerialPortType == SERIAL_PORT_TYPE.Normal)
-		{
-			// 1. WritePacket
-			int ret = WritePacket(WriteData, true);
-			if(ret < 0)
-			{
-				Log.w(getTAG(), "[WriteNReadPacket] WritePacket Error - " + ret);
-				return null;
-			}
-
-			// 3. ReadPacket
-			return ReadPacket(nAddress, nPaketTypeFixed);
-		}
-		else if(mSerialPortType == SERIAL_PORT_TYPE.LHGateWay)
-		{
-			// 1. writeNread
-			byte [] readBuffer = mSerialPort_LH.writeNread(WriteData, (int)ReadTimeOut);
-
-			// 2. read Check
-			if(readBuffer == null) return null;
-			if(nPaketTypeFixed)
-			{
-				// 고정 10 Byte
-				if(readBuffer.length != 10) return null;
-				if(readBuffer[0] != STX) return null;
-				if(readBuffer[1] != nAddress) return null;
-				if(readBuffer[readBuffer.length-1] != Check_Byte(readBuffer, readBuffer.length-1)) return null;
-				return readBuffer;
-			}
-			else
-			{
-				// 가변 패킷
-				if(readBuffer.length < 6) return null;
-				if(readBuffer[0] != STX) return null;
-				if(readBuffer[1] != nAddress) return null;
-				if(readBuffer.length != (int)readBuffer[2]) return null;
-				if(readBuffer[readBuffer.length-1] != Check_Byte(readBuffer, readBuffer.length-1)) return null;
-				return readBuffer;
-			}
-		}
-		else
-		{
-			return null;
-		}
-	}
-
-	// =================================================================================================
-	// [[ Thread run ]] region
-	// =================================================================================================
-	/**
-	 * run
-	 */
-	public void run()
-	{
-		Looper.prepare();
-		DevHandler = new Handler()
-		{
-			public void handleMessage(Message msg)
-			{
-				//int myid = android.os.Process.myTid();
-
-				switch(msg.what)
-				{
-					case CommonDefine.DEVCTR_LOGONOFF:
-						break;
-
-					case CommonDefine.DEVCTR_REQDEVCTR:
-						SHMem = (DeviceCtrSHMem) msg.obj;
-						if (SHMem.Setted)
-						{
-							DevSHMem.add(SHMem);
-							Message Nmsg = obtainMessage();
-							Nmsg.what = CommonDefine.DEVCTR_CTRREQ;
-							Nmsg.arg1  = DevID;
-
-							PortHandler.lhandler.sendMessage(Nmsg);
-						}
-						break;
-
-					case CommonDefine.DEVCTR_SETCTR:
-						mSerialPortType = (int) msg.arg2;
-						if(mSerialPortType == SERIAL_PORT_TYPE.Normal)
-						{
-							mSerialPort = (SerialPort)msg.obj;
-						}
-						else if(mSerialPortType == SERIAL_PORT_TYPE.LHGateWay)
-						{
-							mSerialPort_LH = (SerialPort_LH)msg.obj;
-						}
-						sequencenum = (byte)msg.arg1;
-						Doing = true;
-
-						////////////////////////////////////////////////////////////////////////////////
-						// Process polling job
-						////////////////////////////////////////////////////////////////////////////////
-						if (DevStatus == 0)
-						{
-							try
-							{
-								do_boot();
-							}
-							catch (RuntimeException re) {
-								LogUtil.errorLogInfo("", TAG, re);
-							}
-							catch (Exception e) {
-								Log.e(getTAG(), "[do_boot] [ExceptionError]");
-								//e.printStackTrace();
-            					LogUtil.errorLogInfo("", TAG, e);
-							}
-							DevStatus=1;
-						}
-						else
-						{
-							try
-							{
-								do_ctr();
-							}
-							catch (RuntimeException re) {
-								LogUtil.errorLogInfo("", TAG, re);
-							}
-							catch (Exception e) {
-								Log.e(getTAG(), "[do_ctr] [ExceptionError]");
-								//e.printStackTrace();
-            					LogUtil.errorLogInfo("", TAG, e);
-							}
-						}
-						////////////////////////////////////////////////////////////////////////////////
-						// End Polling Job
-						////////////////////////////////////////////////////////////////////////////////
-
-
-						if (hasMessages(CommonDefine.DEVCTR_REQDEVCTR))
-						{
-							Message Nmsg = obtainMessage();
-							Nmsg.what = CommonDefine.DEVCTR_CTRREQ;
-							PortHandler.lhandler.sendMessage(Nmsg);
-						}
-						msg = new Message();
-						msg.what = CommonDefine.DEVCTR_ENDTR;
-						msg.arg1 = sequencenum;
-
-						PortHandler.lhandler.sendMessage(msg);
-						break;
-
-					case CommonDefine.DEVCTR_SETCTREMM:
-						mSerialPortType = (int) msg.arg2;
-						if(mSerialPortType == SERIAL_PORT_TYPE.Normal)
-						{
-							mSerialPort = (SerialPort)msg.obj;
-						}
-						else if(mSerialPortType == SERIAL_PORT_TYPE.LHGateWay)
-						{
-							mSerialPort_LH = (SerialPort_LH)msg.obj;
-						}
-
-						if (DevSHMem.size() > 0)
-						{
-							SHMem = DevSHMem.get(0);
-							sequencenum = (byte)msg.arg1;
-							synchronized(SHMem)
-							{
-								DevSHMem.remove(0);
-								SHMem.retVal = "test by heatvalve"+SHMem.cmd;
-								if (SHMem.Setted)
-								{
-									SHMem.retVal = "SUCCESS";
-									if (SHMem.cmd.equals("REGBRAC"))
-									{
-										if (SHMem.StrArg != null)
-										{
-											int limit = ChangedBRList.size();
-											if (limit > 0)
-											{
-												int i;
-												for (i=0;i<limit;i++)
-													if (SHMem.StrArg.equalsIgnoreCase(ChangedBRList.get(i)))
-														break;
-												if (i==limit)
-												{
-													ChangedBRList.add(SHMem.StrArg);
-												}
-											}
-
-											ChangedBRList.add(SHMem.StrArg);
-										}
-										SHMem.retVal = "SUCCESS";
-									}
-									else if (SHMem.cmd.equals("UNREGBRAC"))
-									{
-										if (SHMem.StrArg.equals("null"))
-											ChangedBRList.clear();
-										else
-										{
-											ChangedBRList.remove(SHMem.StrArg);
-										}
-									}
-									else if (SHMem.cmd.equals("LOGONOFF"))
-									{
-										log_sw = !log_sw;
-									}
-									else if (SHMem.cmd.equals("VIRTUAL"))
-									{
-										virtualmode = !virtualmode;
-									}
-									else
-									{
-										try
-										{
-											do_ctrEmm(SHMem);
-										}
-										catch (RuntimeException re) {
-											LogUtil.errorLogInfo("", TAG, re);
-										}
-										catch (Exception e) {
-											Log.e(getTAG(), "[do_ctrEmm] [ExceptionError]");
-											//e.printStackTrace();
-            								LogUtil.errorLogInfo("", TAG, e);
-										}
-									}
-
-									SHMem.notify();
-								}
-							}
-						}
-						msg = new Message();
-						msg.what = CommonDefine.DEVCTR_ENDTR;
-						msg.arg1 = sequencenum;
-
-						PortHandler.lhandler.sendMessage(msg);
-						break;
-
-					case CommonDefine.DEVCTR_CMDQFULL:
-						synchronized(SHMem)
-						{
-							SHMem.Setted = false;
-							SHMem.retVal = "QUEUE FULL";
-							SHMem.notify();
-						}
-						break;
-
-					case CommonDefine.DEVCTR_REQRETENDTR:
-						msg = new Message();
-						msg.arg1 = sequencenum;
-						msg.what = CommonDefine.DEVCTR_ENDTR;
-
-						PortHandler.lhandler.sendMessage(msg);
-						break;
-
-					case CommonDefine.DEVCTR_SETVIRTUAL:
-						virtualmode = (msg.what==1)?true:false;
-						break;
-
-					default:
-						break;
-				}
-
-				Sleep(devSleepTime);
-			}
-		};
-		Looper.loop();
-	}
-
-	// =================================================================================================
-	// [[ 드라이버 구현부 ]] region
-	// =================================================================================================
-	/**
-	 * 로딩후 최초 1회 호출됨
-	 */
-	protected void do_boot()
-	{
-	}
-
-	/**
-	 * Sink 가 필요없는 명령어 처리
-	 *
-	 * @param StrArg - (String) 명령어
-	 *
-	 * @return (String) 결과
-	 */
-	public String NoSinkCtrl(String StrArg)
-	{
-		return null;
-	}
-
-	/**
-	 * Sink 가 필요한 명령어 처리 (통신결과응답 등)
-	 *
-	 * @param SHMem - (DeviceCtrSHMem)
-	 *
-	 * @return (String) 결과
-	 */
-	protected String do_ctrEmm(DeviceCtrSHMem SHMem)
-	{
-		return null;
-	}
-
-	/**
-	 * 폴링
-	 */
-	protected void do_ctr()
-	{
-	}
-
-	// =================================================================================================
-	// [[ Packet SEND & READ 공통부분 ]] region
-	// =================================================================================================
-	/**
-	 * 명령어를 요청하고 응답을 리턴받는다. (고정 10byte 용)
-	 *
-	 * @param ReqCMD  - (byte) 요청할 명령어
-	 * @param ReqData - (byte []) 요청 데이터
-	 *
-	 * @return (byte []) 응답 데이터 - null 일경우 Error
-	 */
-	public byte [] SendNRead_Fixed(byte Address, byte ReqCMD, byte [] ReqData)
-	{
-		// 1. Make Packet
-		byte [] ReqPaket = MakeFixedPacket(Address, ReqCMD, ReqData);
-		if(ReqPaket == null)
-		{
-			Log.w(getTAG(), "[" + DeviceName + ":SendNRead_Fixed] MakeFixedPacket return null !!!");
-			return null;
-		}
-
-		// 2. WriteNRead Packet
-		byte [] RspPacket = WriteNReadPacket(ReqPaket, Address, true);
-
-		// 3. Check ReadPacekt
-		boolean RspCmdCheck = true;
-		int ret = CheckFixedPacket(ReqPaket, RspPacket, (byte) 0x00, RspCmdCheck, true);
-		if(ret < 0) return null;
-
-		// 4. data 추출
-		int dataLen = RspPacket.length - 5;
-		if(dataLen <= 0) return null;
-
-		byte [] retDataBuffer = new byte [dataLen];
-		for(int i=0 ; i<dataLen ; i++) retDataBuffer[i] = RspPacket[4+i];
-
-		return retDataBuffer;
-	}
-
-	/**
-	 * 명령어를 요청하고 응답을 리턴받는다. (고정 10byte 용이며 STX부터 CS까지 모든 패킷을 응답한다.)
-	 *
-	 * @param ReqCMD  - (byte) 요청할 명령어
-	 * @param ReqData - (byte []) 요청 데이터
-	 *
-	 * @return (byte []) 응답 데이터 - null 일경우 Error
-	 */
-	public byte [] SendNRead_Fixed_ReturnAllPacket(byte Address, byte ReqCMD, byte [] ReqData)
-	{
-		// 1. Make Packet
-		byte [] ReqPaket = MakeFixedPacket(Address, ReqCMD, ReqData);
-		if(ReqPaket == null)
-		{
-			Log.w(getTAG(), "[" + DeviceName + ":SendNRead_Fixed] MakeFixedPacket return null !!!");
-			return null;
-		}
-
-		// 2. WriteNRead Packet
-		byte [] RspPacket = WriteNReadPacket(ReqPaket, Address, true);
-
-		// 3. Check ReadPacekt
-		boolean RspCmdCheck = true;
-		int ret = CheckFixedPacket(ReqPaket, RspPacket, (byte) 0x00, RspCmdCheck, true);
-		if(ret < 0) return null;
-
-		return RspPacket;
-	}
-
-	/**
-	 * 고정패킷을 만든다.
-	 *
-	 * @param Id   - (byte) ID
-	 * @param Cmd  - (byte) 명령어
-	 * @param Data - (byte []) 데이터
-	 *
-	 * @return (byte []) 만들어진 Packet 리턴
-	 */
-	public byte [] MakeFixedPacket(byte Id, byte Cmd, byte [] Data)
-	{
-		if(Data == null)
-		{
-			return null;
-		}
-		if(Data.length != 5)
-		{
-			Log.w("DeviceManager", "[MakeFixedPacket] Data length Error - (len:" + Data.length + ")");
-			return null;
-		}
-
-		byte length = 10;
-		byte [] retBuffer = new byte [length];
-
-		int index = 0;
-		retBuffer[index++] = STX;             // STX
-		retBuffer[index++] = Id;              // ID
-		retBuffer[index++] = Cmd;             // CMD
-		retBuffer[index++] = Get_Sequence();  // SEQ
-		if(Data != null)
-		{
-			for(int i=0 ; i<Data.length ; i++) retBuffer[index++] = Data[i];       // DATA
-		}
-		retBuffer[index++] = Check_Byte(retBuffer, retBuffer.length-1);            // CS
-
-		return retBuffer;
-	}
-
-	/**
-	 * 고정패킷 응답의 기본 포멧을 체크한다.
-	 *
-	 * @param ReqPaket   - (byte []) 요청패킷
-	 * @param RspPacket  - (byte []) 응답패킷
-	 * @param ExpectRspLen - (byte) 기대하는 응답패킷 길이 (체크하지않을 경우 0x00 입력)
-	 * @param RspCmdCheck  - (boolean) 응답 명령어 체크 여부 (true : 체크, false : 미체크)
-	 * @param ErrorLogOutput - (boolean) 에러로그 출력여부 (true : 출력, false : 미출력)
-	 *
-	 * @return (int) - >=0 : 성공, <0 : 실패
-	 */
-	public int CheckFixedPacket(byte [] ReqPaket, byte [] RspPacket, byte ExpectRspLen, boolean RspCmdCheck,boolean ErrorLogOutput)
-	{
-		// 1. Default Data Check
-		if(ReqPaket == null) return -1;        // 요청패킷 null
-		if(ReqPaket.length != 10) return -2;   // 요청패킷 길이 체크
-
-		if(RspPacket == null) return -10;      // 응답패킷 null
-		if(RspPacket.length != 10) return -11; // 응답패킷 길이 체크
-
-		// 2. ID Check
-		if(ReqPaket[1] != RspPacket[1])
-		{
-			if(ErrorLogOutput) Log.e(getTAG(), "[" + DeviceName + ":CheckFixedPacket] - ID Not Match !!! - ReqPaket ID " + String.format("[0x%02X]", ReqPaket[1]) + " / RspPacket ID " + String.format("[0x%02X]", RspPacket[1]) );
-			return -20;
-		}
-
-		// 3. LEN Check
-
-		// 4. CMD Check
-		if(RspCmdCheck)
-		{
-			byte CheckCmd = (byte)(ReqPaket[2] | (byte)0x80);
-			if( CheckCmd != RspPacket[2])
-			{
-				if(ErrorLogOutput) Log.e(getTAG(), "[" + DeviceName + ":CheckFixedPacket] - CMD Not Match !!! - CheckCmd " + String.format("[0x%02X]", CheckCmd) + " / RspPacket CMD " + String.format("[0x%02X]", RspPacket[2]) );
-				return -22;
-			}
-		}
-
-		// 5. SEQ Check
-		if(ReqPaket[3] != RspPacket[3])
-		{
-			if(ErrorLogOutput) Log.e(getTAG(), "[" + DeviceName + ":CheckFixedPacket] - SEQ Not Match !!! - ReqPaket SEQ " + String.format("[0x%02X]", ReqPaket[3]) + " / RspPacket SEQ " + String.format("[0x%02X]", RspPacket[3]) );
-			return -23;
-		}
-
-		return 0;
-	}
-
-	/**
-	 * 명령어를 요청하고 응답을 리턴받는다. (가변패킷용)
-	 *
-	 * @param Address - (byte) 요청 주소
-	 * @param ReqCMD  - (byte) 요청할 명령어
-	 * @param ReqData - (byte []) 요청 데이터
-	 *
-	 * @return (byte []) 응답 데이터 - null 일경우 Error
-	 */
-	public byte [] SendNRead_Variable(byte Address, byte ReqCMD, byte [] ReqData) {
-		// 1. Make Packet
-		byte [] ReqPaket = MakeVariablePacket(Address, ReqCMD, Get_Sequence(), ReqData);
-		if (ReqPaket == null) {
-			Log.w(getTAG(), "[" + DeviceName + ":SendNRead_Variable] MakeVariablePacket return null !!!");
-			return null;
-		}
-
-		// 2. WriteNRead Packet
-		byte [] RspPacket = WriteNReadPacket(ReqPaket, Address, false);
-
-		// 3. Check ReadPacekt
-		boolean RspCmdCheck = true;
-		if ((ReadFormatType == 1) || (ReadFormatType == 3)) RspCmdCheck = false;
-		int ret = CheckVariablePacket(ReqPaket, RspPacket, (byte) 0x00, RspCmdCheck, true);
-		if (ret < 0) return null;
-
-		// 4. data 추출
-		int dataLen = RspPacket.length - 6;
-		byte [] retDataBuffer = null;
-		if (dataLen < 0) {
-			Log.w(getTAG(), "[" + DeviceName + ":SendNRead_Variable] dataLen < 0 : (dataLen:" + dataLen + ")");
-			return null;
-		}
-		else if (dataLen == 0) {
-			if (ReadFormatType == 1) {
-				if (RspPacket[3] == (byte)0x8F) retDataBuffer = new byte[] { (byte)0x8F };
-			}
-
-			if (ReadFormatType == 3) {
-				if(RspPacket[3] == (byte)0x82) retDataBuffer = new byte[] { (byte)0x82 };
-			}
-			else {
-				retDataBuffer = new byte[] { (byte)0x00 };
-			}
-		}
-		else {
-			retDataBuffer = new byte [dataLen];
-			for (int i=0 ; i<dataLen ; i++) retDataBuffer[i] = RspPacket[5+i];
-		}
-		return retDataBuffer;
-	}
-
-	/**
-	 * 가변패킷을 만든다.
-	 *
-	 * @param Id   - (byte) ID
-	 * @param Cmd  - (byte) 명령어
-	 * @param Seq  - (byte) 시퀀스
-	 * @param Data - (byte []) 데이터
-	 *
-	 * @return (byte []) 만들어진 Packet 리턴
-	 */
-	public byte [] MakeVariablePacket(byte Id, byte Cmd, byte Seq, byte [] Data)
-	{
-		byte length = 0;
-		if(Data == null) length = 6;
-		else length = (byte)(6 + Data.length);
-
-		byte [] retBuffer = new byte [length];
-
-		int index = 0;
-		retBuffer[index++] = STX;          // STX
-		retBuffer[index++] = Id;           // ID
-		retBuffer[index++] = length;       // LEN
-		retBuffer[index++] = Cmd;          // CMD
-		retBuffer[index++] = Seq;          // SEQ
-		if(Data != null)
-		{
-			for(int i=0 ; i<Data.length ; i++) retBuffer[index++] = Data[i];       // DATA
-		}
-		retBuffer[index++] = Check_Byte(retBuffer, retBuffer.length-1);            // CS
-
-		return retBuffer;
-	}
-
-	/**
-	 * 가변패킷 응답의 기본 포멧을 체크한다.
-	 *
-	 * @param ReqPaket   - (byte []) 요청패킷
-	 * @param RspPacket  - (byte []) 응답패킷
-	 * @param ExpectRspLen - (byte) 기대하는 응답패킷 길이 (체크하지않을 경우 0x00 입력)
-	 * @param RspCmdCheck  - (boolean) 응답 명령어 체크 여부 (true : 체크, false : 미체크)
-	 * @param ErrorLogOutput - (boolean) 에러로그 출력여부 (true : 출력, false : 미출력)
-	 *
-	 * @return (int) - >=0 : 성공, <0 : 실패
-	 */
-	public int CheckVariablePacket(byte [] ReqPaket, byte [] RspPacket, byte ExpectRspLen, boolean RspCmdCheck,boolean ErrorLogOutput)
-	{
-		// 1. Default Data Check
-		if(ReqPaket == null) return -1;        // 요청패킷 null
-		if(ReqPaket.length < 6) return -2;     // 요청패킷 길이 체크
-
-		if(RspPacket == null) return -10;      // 응답패킷 null
-		if(RspPacket.length < 6) return -11;   // 응답패킷 길이 체크
-
-		// 2. ID Check
-		if(ReqPaket[1] != RspPacket[1])
-		{
-			if(ErrorLogOutput) Log.e(getTAG(), "[" + DeviceName + ":CheckVariablePacket] - ID Not Match !!! - ReqPaket ID " + String.format("[0x%02X]", ReqPaket[1]) + " / RspPacket ID " + String.format("[0x%02X]", RspPacket[1]) );
-			return -20;
-		}
-
-		// 3. LEN Check
-		if(ExpectRspLen != 0)
-		{
-			if(ExpectRspLen != RspPacket[2])
-			{
-				if(ErrorLogOutput) Log.e(getTAG(), "[" + DeviceName + ":CheckVariablePacket] - LEN Not Match !!! - ExpectRspLen " + String.format("[0x%02X]", ExpectRspLen) + " / RspPacket LEN " + String.format("[0x%02X]", RspPacket[2]) );
-				return -21;
-			}
-		}
-
-		// 4. CMD Check
-		if(RspCmdCheck)
-		{
-			byte CheckCmd = (byte)(ReqPaket[3] | (byte)0x80);
-			if(CheckCmd != RspPacket[3])
-			{
-				if (ErrorLogOutput)
-					Log.e(getTAG(), "[" + DeviceName + ":CheckVariablePacket] - CMD Not Match !!! - CheckCmd " + String.format("[0x%02X]", CheckCmd) + " / RspPacket CMD " + String.format("[0x%02X]", RspPacket[3]));
-				return -22;
-			}
-		}
-
-		// 5. SEQ Check
-		if(ReqPaket[4] != RspPacket[4])
-		{
-			if(ErrorLogOutput) Log.e(getTAG(), "[" + DeviceName + ":CheckVariablePacket] - SEQ Not Match !!! - ReqPaket SEQ " + String.format("[0x%02X]", ReqPaket[4]) + " / RspPacket SEQ " + String.format("[0x%02X]", RspPacket[4]) );
-			return -23;
-		}
-
-		return 0;
-	}
-
-	/**
-	 * CheckSum 을 생성한다.
-	 *
-	 * @param target - (byte []) 대상버퍼
-	 * @param len    - (int) 패킷 길이
-	 *
-	 * @return (byte) 생성된 CheckSum
-	 */
-	protected byte Check_Byte(byte[] target, int len)
-	{
-		if(target == null) return 0x00;
-		if(target.length < len) return 0x00;
-
-		byte cbyte = STX;
-
-		for(int i=1;i<len;i++)
-		{
-			cbyte^=target[i];
-			cbyte++;
-		}
-
-		return cbyte;
-	}
-
-
-	// =================================================================================================
-	// [[ 기기제어 명령어 관련 ]] region
-	// =================================================================================================
-	/**
-	 * 기기제어 명령어 Pasing 데이터 포멧
-	 */
-	class CtrDevFormat
-	{
-		public byte [] param;
-		public String CmdStr;
-		public int ret;
-
-		public CtrDevFormat()
-		{
-			param = null;
-			CmdStr = null;
-			ret = -10000;
-		}
-	}
-
-	/**
-	 * String 으로 전달받은 기기제어 명령을 Parsing 한다.
-	 *
-	 * @param in          - (String) 명령어
-	 * @param Paramlength - (int)    기대 Param 길이
-	 *
-	 * @return (CtrDevFormat) CtrDevFormat.ret 으로 판단 ( >=0 : 성공, <0 : 실패 )
-	 */
-	public CtrDevFormat GetCtrDevParamParsing(String in, int Paramlength)
-	{
-		CtrDevFormat ctrDevFormat = new CtrDevFormat();
-
-		if(Paramlength <= 0) { ctrDevFormat.ret = -1; return ctrDevFormat; }
-		try
-		{
-			String[] datalist = in.split(":");
-			if(datalist == null) { ctrDevFormat.ret = -2; return ctrDevFormat; }
-			if(datalist.length != Paramlength+1) { ctrDevFormat.ret = -3; return ctrDevFormat; }
-
-			ctrDevFormat.CmdStr = datalist[0];
-
-			ctrDevFormat.param = new byte[Paramlength];
-			for(int i=0 ; i<Paramlength ; i++)
-			{
-				ctrDevFormat.param[i] = Byte.parseByte(datalist[1+i]);
-			}
-
-			ctrDevFormat.ret = APIErrorCode.C_SUCCESS;
-			return ctrDevFormat;
-		}
-		catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-			ctrDevFormat.ret = -100;
-        }
-		catch (Exception e) {
-			Log.e(getTAG(), "[Exception Error] GetCtrDevParamParsing#1");
-			//e.printStackTrace();
-            LogUtil.errorLogInfo("", TAG, e);
-			ctrDevFormat.ret = -100;
-		}
-		return ctrDevFormat;
-	}
-
-	/**
-	 * String 으로 전달받은 기기제어 명령을 Parsing 한다.
-	 *
-	 * @param in          - (String) 명령어
-	 *
-	 * @return (CtrDevFormat) CtrDevFormat.ret 으로 판단 ( >=0 : 성공, <0 : 실패 )
-	 */
-	public CtrDevFormat GetCtrDevParamParsing(String in)
-	{
-		CtrDevFormat ctrDevFormat = new CtrDevFormat();
-
-		try
-		{
-			String[] datalist = in.split(":");
-			if(datalist == null) { ctrDevFormat.ret = -2; return ctrDevFormat; }
-
-			ctrDevFormat.CmdStr = datalist[0];
-			int Paramlength = datalist.length-1;
-			ctrDevFormat.param = new byte[Paramlength];
-			for(int i=0 ; i<Paramlength ; i++)
-			{
-				ctrDevFormat.param[i] = Byte.parseByte(datalist[1+i]);
-			}
-
-			ctrDevFormat.ret = APIErrorCode.C_SUCCESS;
-			return ctrDevFormat;
-		}
-		catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-			ctrDevFormat.ret = -100;
-        }
-		catch (Exception e) {
-			Log.e(getTAG(), "[Exception Error] GetCtrDevParamParsing#2");
-			//e.printStackTrace();
-            LogUtil.errorLogInfo("", TAG, e);
-			ctrDevFormat.ret = -100;
-		}
-		return ctrDevFormat;
-	}
-
-	// =================================================================================================
-	// [[ CountDownTimer ]] region
-	// =================================================================================================
-	/**
-	 * CountDownTimer 관련 class 를 정의한다. </br>
-	 * 생성:Create, 리셋:Reset, 삭제:Destroy 를 지원하며, </br>
-	 * 타이머 종료 및 Tick 이벤트 발생시 호출되는 메소드를 지원한다.
-	 */
-	public class CountDownTimerClass
-	{
-		String CLASS_NAME = "[" + DeviceName  +" :CountDownTimer]";
-
-		/** 타이머 */
-		private CountDownTimer mCountDownTimer;
-
-		/** 타이머 활성화 여부 */
-		private boolean mCountDownTimerEnable;
-
-		/** 생성자 */
-		public CountDownTimerClass()
-		{
-			mCountDownTimer = null;
-			mCountDownTimerEnable = false;
-		}
-
-		/**
-		 * 타이머 생성
-		 *
-		 * @param nFinishTimeSec - (int) 종료 시간
-		 *
-		 * @return (boolean) 정상 생성 여부 - true:정상, false:에러
-		 */
-		public boolean Create(int nFinishTimeSec)
-		{
-			// Param Check
-			if(nFinishTimeSec <= 0)
-			{
-				Log.e(TAG, CLASS_NAME + "Create - param : nEndTime - Out of range !!! (" + nFinishTimeSec + ")");
-				return false;
-			}
-
-			// Timer Make
-			if(mCountDownTimer != null) mCountDownTimer.cancel();
-			mCountDownTimer = new CountDownTimer( (long)(nFinishTimeSec * 1000), 1000) {
-				@Override
-				public void onFinish() {
-					finish();
-				}
-
-				@Override
-				public void onTick(long arg0) {
-					long RemainingTime = (long)(arg0/1000);
-					tick((int)RemainingTime);
-				}
-			};
-
-			mCountDownTimer.cancel();
-			mCountDownTimer.start();
-
-			mCountDownTimerEnable = true;
-			return true;
-		}
-
-		/**
-		 * 타이머 리셋
-		 *
-		 * @return (boolean) 정상 생성 여부 - true:정상, false:에러
-		 */
-		public boolean Reset()
-		{
-			if(mCountDownTimerEnable)
-			{
-				if(mCountDownTimer != null)
-				{
-					mCountDownTimer.cancel();
-					mCountDownTimer.start();
-				}
-				return true;
-			}
-			return false;
-		}
-
-		/**
-		 * 타이머 삭제
-		 *
-		 * @return (boolean) 정상 생성 여부 - true:정상, false:에러
-		 */
-		public boolean Destroy()
-		{
-			mCountDownTimerEnable = false;
-			if(mCountDownTimer != null)
-			{
-				mCountDownTimer.cancel();
-				mCountDownTimer = null;
-				return true;
-			}
-			return false;
-		}
-
-		/**
-		 * 타이머 종료시 호출된다.
-		 */
-		protected void finish()
-		{
-		}
-
-		/**
-		 * 타이머가 1초단위로 Tick 발생시 호출된다.
-		 * @param RemainingTime - (int) 잔여시간 (단위:초)
-		 */
-		protected void tick(int RemainingTime)
-		{
-		}
-	}
-
-	// =================================================================================================
-	// [[ Util ]] region
-	// =================================================================================================
-	/**
-	 * byte 를 int 로 변환한다.
-	 *
-	 * @param in - (byte) 변환할 byte 데이터
-	 *
-	 * @return (int) 변환된 int 데이터
-	 */
-	public int getInt(byte in)
-	{
-		if (in < 0) return in+256;
-		return in;
-	}
-
-	/**
-	 * 2byte 데이터를 소수점1자리 double 데이터로 변환한다.
-	 *
-	 * @param hi  - (byte) 상위 byte
-	 * @param low - (byte) 하위 byte
-	 *
-	 * @return (double) 변환된값
-	 */
-	public double Converter2ByteToDoubleP1(byte hi, byte low)
-	{
-		int Hi = getInt(hi);
-		int Low = getInt(low);
-		int iTemp = (Hi<<8) | Low;
-		double dTemp = (double)iTemp * (double)0.1;
-		return Double.parseDouble(String.format("%.1f", dTemp));
-	}
-
-	/**
-	 * 2byte 데이터를 소수점2자리 double 데이터로 변환한다.
-	 *
-	 * @param hi  - (byte) 상위 byte
-	 * @param low - (byte) 하위 byte
-	 *
-	 * @return (double) 변환된값
-	 */
-	public double Converter2ByteToDoubleP2(byte hi, byte low)
-	{
-		int Hi = getInt(hi);
-		int Low = getInt(low);
-		int iTemp = (Hi<<8) | Low;
-		double dTemp = (double)iTemp * (double)0.01;
-		return Double.parseDouble(String.format("%.01f", dTemp));
-	}
-
-	/**
-	 * 2byte 데이터를 double 데이터로 변환한다. (누적 전력값 단위 Wh 사용 시)
-	 *
-	 * @param hi  - (byte) 상위 byte
-	 * @param low - (byte) 하위 byte
-	 *
-	 * @return (double) 변환된값
-	 */
-	public double Converter2ByteToDouble_Wh(byte hi, byte low)
-	{
-		int Hi = getInt(hi);
-		int Low = getInt(low);
-		int iTemp = (Hi<<8) | Low;
-		double dTemp = (double)iTemp * (double)1;
-		return Double.parseDouble(String.format("%.1f", dTemp));
-	}
-
-	/**
-	 * 2byte 데이터를 int 데이터로 변환한다.
-	 *
-	 * @param hi  - (byte) 상위 byte
-	 * @param low - (byte) 하위 byte
-	 *
-	 * @return (int) 변환된값
-	 */
-	public int Converter2ByteToInt(byte hi, byte low)
-	{
-		int Hi = getInt(hi);
-		int Low = getInt(low);
-		return (int)((Hi<<8) | Low);
-	}
-
-	/**
-	 * 3byte 데이터를 int 데이터로 변환한다.
-	 *
-	 * @param hi  - (byte) 상위 byte
-	 * @param mid - (byte) 중간 byte
-	 * @param low - (byte) 하위 byte
-	 *
-	 * @return (int) 변환된값
-	 */
-	public int Converter3ByteToInt(byte hi, byte mid, byte low)
-	{
-		int Hi = getInt(hi);
-		int Mid = getInt(mid);
-		int Low = getInt(low);
-		return (int)((Hi<<16) | (Mid<<8) | Low);
-	}
-
-	/**
-	 * byte 배열 데이터를 String 데이터로 변환한다.
-	 *
-	 * @param in - (byte []) 출력할 byte 배열 데이터
-	 *
-	 * @return (String) 변환된 String 값
-	 */
-	public String ToByteString(byte [] in)
-	{
-		if(in == null) return "null";
-
-		String result = "Len:" + in.length + " [";
-
-		for(int i=0 ; i<in.length ; i++)
-			result += String.format("%02X ", in[i]);
-
-		result += "]";
-
-		return result;
-	}
-
-	/**
-	 * byte 배열 데이터를 Size 만큼 String 데이터로 변환한다.
-	 *
-	 * @param in - (byte []) 출력할 byte 배열 데이터
-	 * @param size - (int) 변환요청할 사이즈
-	 *
-	 * @return (String) 변환된 String 값
-	 */
-	public String ToByteString(byte [] in, int size)
-	{
-		if(in == null) return "null";
-		if(in.length < size) return "null";
-		String result = "Len:" + size + " [";
-
-		for(int i=0 ; i<size ; i++)
-			result += String.format("%02X ", in[i]);
-
-		result += "]";
-
-		return result;
-	}
-
-	/**
-	 * byte 데이터를 [HEX format] String 데이터로 변환한다.
-	 *
-	 * @param in - (byte) 변환할 byte 데이터
-	 *
-	 * @return (String) 변환된 String
-	 */
-	public String ToByteString(byte in)
-	{
-		return String.format("0x%02X", in);
-	}
-
-	/**
-	 * sleep
-	 *
-	 * @param time - sleep 할 시간 (milliseconds 단위 시간 설정)
-	 */
-	public void Sleep(long time)
-	{
-		try{Thread.sleep(time);}
-		catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-        }
-		catch (Exception e) {
-			Log.e(getTAG(), "[Exception Error] Sleep - DeviceName:" + DeviceName);
-			//e.printStackTrace();
-            LogUtil.errorLogInfo("", TAG, e);
-		}
-	}
-	// =================================================================================================
-	// =================================================================================================
-}
+package com.artncore.wallpaddevservice.driver;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import com.artncore.commons.APIErrorCode;
+import com.artncore.commons.define;
+import com.artncore.wallpaddevservice.CommonDefine;
+import com.artncore.wallpaddevservice.SerialHandler;
+import com.artncore.wallpaddevservice.ServiceMain;
+import com.artncore.wallpaddevservice.SerialHandler.SERIAL_PORT_TYPE;
+
+import android.annotation.SuppressLint;
+import android.content.Intent;
+import android.os.CountDownTimer;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.util.Log;
+import android_serialport_api.SerialPort;
+import android_serialport_api.SerialPort_LH;
+import com.util.LogUtil;
+@SuppressLint("HandlerLeak")
+public class DeviceManager extends Thread
+{
+	private final String TAG = "DeviceManager";
+	private String getTAG() { return TAG + ":" + DeviceName; }
+
+	public final byte BIT0 = define.BIT0;
+	public final byte BIT1 = define.BIT1;
+	public final byte BIT2 = define.BIT2;
+	public final byte BIT3 = define.BIT3;
+	public final byte BIT4 = define.BIT4;
+	public final byte BIT5 = define.BIT5;
+	public final byte BIT6 = define.BIT6;
+	public final byte BIT7 = define.BIT7;
+
+	public final byte [] BIT_ARRAY = new byte [] { BIT0, BIT1, BIT2, BIT3, BIT4, BIT5, BIT6, BIT7 };
+
+	public final byte STX = 0x02;
+
+	public final long TIME_SEC = 1000;
+
+	public final long TIME_MINUTE = (long) (TIME_SEC * 60);
+
+	private final int MAX_TOTAL_COUNT  = 100000000;
+	private final int MAX_RECENT_COUNT = 100;
+
+	DeviceCtrSHMem 		SHMem;
+	SerialHandler  		PortHandler;
+	Handler  			MainHandler;
+	public int			startAddr;
+	public int			endAddr;
+	public Handler      DevHandler;
+	public int          DevID;
+
+	private boolean             bCommCNTGeneration = false;
+	public boolean getCommCNTGeneration() { return bCommCNTGeneration; }
+	int[]				TotalCommSuccCNT;
+	int[]				TotalCommFailCNT;
+	int[]				RecentCommSuccCNT;
+	int[]				RecentCommFailCNT;
+	byte[][]            recentdata;
+	byte[]              WriteLocation;
+
+	boolean             LogByteBuffOutput = true;
+
+	public String		DeviceName = null;
+	public String       ModuleName = null;
+	/**
+	 * 0 : 제어기기류 (normal type) <br>
+	 * 1 : 게이트웨이 <br>
+	 * 2 : 에너지제품군 <br>
+	 * 3 : 스마트스위치 <br>
+	 */
+	int                 ReadFormatType = 0;
+	public boolean 		log_sw;
+	public int          DevStatus;
+
+	private long        ReadTimeOut = 200;
+
+	public boolean      Doing = false;
+
+	public boolean      SerialLog = true;
+
+	//for test or business sample
+	static boolean 		virtualmode = true;
+	SerialPort          mSerialPort = null;
+	SerialPort_LH       mSerialPort_LH = null;
+	private int mSerialPortType = SERIAL_PORT_TYPE.Normal;
+
+	byte   sequencenum=0;
+	int    devSleepTime = 150;
+
+	private byte [] ReadBuffer = new byte[64 * 4 * 2];
+	private byte [] DecBuffer = new byte[64 * 4];
+
+	List<DeviceCtrSHMem> DevSHMem = new ArrayList<DeviceCtrSHMem>();
+	List<String> ChangedBRList = new ArrayList<String>();
+
+	String LogAuther;
+	int    LogDriverID;
+
+	/**
+	 * 생성자
+	 */
+	public DeviceManager()
+	{
+	}
+
+	// =================================================================================================
+	// [[ 통신성공률 ]] region
+	// =================================================================================================
+	/**
+	 * 통신성공률 관련 변수를 생성 및 초기화 한다.
+	 *
+	 * @param DeviceCount - (int) 디바이스 개수
+	 *
+	 * @return (boolean) 성공여부  true:성공,  false:실패
+	 */
+	public boolean CommDataGeneration(int DeviceCount)
+	{
+		if(DeviceCount <= 0)
+		{
+			Log.w(getTAG(), "[CommDataGeneration] Param : DeviceCount  Out Of Range !!!(DeviceCount:" + DeviceCount + ")");
+			return false;
+		}
+
+		TotalCommSuccCNT  = new int[DeviceCount];
+		TotalCommFailCNT  = new int[DeviceCount];
+		RecentCommSuccCNT = new int[DeviceCount];
+		RecentCommFailCNT = new int[DeviceCount];
+		recentdata = new byte[DeviceCount][MAX_RECENT_COUNT];
+		WriteLocation = new byte[DeviceCount];
+
+		bCommCNTGeneration = true;
+		return true;
+	}
+
+	/**
+	 * 통신성공률을 업데이트 한다.
+	 *
+	 * @param devIndex - (int) 기기 인덱스 (1개 일 경우 : 0)
+	 * @param Success - (boolean) 성공유무  true:성공,  false:실패
+	 */
+	protected void AddDoCount(int devIndex, boolean Success)
+	{
+		if(!bCommCNTGeneration)
+		{
+			Log.w(getTAG(), "[AddDoCount]" + "bCommCNTGeneration flase !!!");
+			return;
+		}
+		try
+		{
+			if(devIndex >= TotalCommSuccCNT.length)
+			{
+				Log.w(getTAG(), "[AddDoCount]" + "Param : devIndex  Out Of Range !!!(devIndex:" + devIndex + ", length:" + TotalCommSuccCNT.length + ")");
+				return;
+			}
+			byte ret = Success?(byte)1:(byte)2;
+			if (recentdata[devIndex][WriteLocation[devIndex]]!=0)
+			{
+				if (recentdata[devIndex][WriteLocation[devIndex]] == 1)
+					RecentCommSuccCNT[devIndex]--;
+				else
+					RecentCommFailCNT[devIndex]--;
+			}
+			recentdata[devIndex][WriteLocation[devIndex]] = ret;
+			WriteLocation[devIndex]++;
+			if (WriteLocation[devIndex] >= MAX_RECENT_COUNT) WriteLocation[devIndex] = 0;
+
+			if (Success)
+			{
+				TotalCommSuccCNT[devIndex]++;
+				RecentCommSuccCNT[devIndex]++;
+			}
+			else
+			{
+				TotalCommFailCNT[devIndex]++;
+				RecentCommFailCNT[devIndex]++;
+			}
+
+			int TotalCount = (int)(TotalCommSuccCNT[devIndex]+TotalCommFailCNT[devIndex]);
+			if(TotalCount >= MAX_TOTAL_COUNT)
+			{
+				TotalCommSuccCNT[devIndex]  = 0;
+				RecentCommFailCNT[devIndex] = 0;
+			}
+		}
+		catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+        }
+		catch (Exception e) {
+			Log.e(getTAG(), "[AddDoCount]" + "Exception Error");
+			//e.printStackTrace();
+            LogUtil.errorLogInfo("", TAG, e);
+		}
+	}
+
+	/**
+	 * 통신성공률을 업데이트 한다. <br>
+	 * 기기가 드라이버에 1개 일경우에 사용한다.
+	 *
+	 * @param Success - (boolean) 성공유무  true:성공,  false:실패
+	 */
+	protected void AddDoCount(boolean Success)
+	{
+		AddDoCount(0, Success);
+	}
+
+	/**
+	 * 통신 성공률 데이터를 String 데이터로 추출한다.
+	 *
+	 * @param DevIndex - (int) 디바이스 인덱스
+	 *
+	 * @return (String) - "SUCCESS; ..." 성공 , "FAIL; ... " 실패
+	 */
+	public String GetTransactionReport(int DevIndex)
+	{
+		if(!bCommCNTGeneration)
+		{
+			Log.w(getTAG(), "[GetTransactionReport] bCommCNTGeneration false !!!");
+			return GetFailResult(APIErrorCode.DEVICEISNOTREADY);
+		}
+
+		try
+		{
+			if (DevIndex >= TotalCommSuccCNT.length) return GetFailResult(APIErrorCode.INVALIDPARAMETER);
+
+			String Retval = APIErrorCode.SUCCESS +
+					define.DEVCTR_CMD_SPLITER+TotalCommSuccCNT[DevIndex]  +
+					define.DEVCTR_CMD_SPLITER+TotalCommFailCNT[DevIndex]  +
+					define.DEVCTR_CMD_SPLITER+RecentCommSuccCNT[DevIndex] +
+					define.DEVCTR_CMD_SPLITER+RecentCommFailCNT[DevIndex] +
+					define.DEVCTR_CMD_SPLITER+MAX_RECENT_COUNT;
+
+			int startidx = WriteLocation[DevIndex]-1;
+			if (startidx < 0) startidx = MAX_RECENT_COUNT-1;
+			for (int i = 0; i< MAX_RECENT_COUNT; i++)
+			{
+				Retval+=(define.DEVCTR_CMD_SPLITER+recentdata[DevIndex][startidx]);
+				startidx--;
+				if (startidx < 0) startidx = MAX_RECENT_COUNT-1;
+			}
+
+			return Retval;
+		}
+		catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+			return GetFailResult(APIErrorCode.EXCEPTION);
+        }
+		catch (Exception e) {
+			Log.e(getTAG(), "[Exception Error] GetTransactionReport");
+			//e.printStackTrace();
+            LogUtil.errorLogInfo("", TAG, e);
+			return GetFailResult(APIErrorCode.EXCEPTION);
+		}
+	}
+
+
+	// =================================================================================================
+	// [[ 상태변경 알림 Broadcast ]] region
+	// =================================================================================================
+	/**
+	 * 상태 변경을 알린다.<br>
+	 * 등록된 ChangedBRList 만큼 전송한다.
+	 */
+	protected void StatusChanged()
+	{
+		synchronized(ChangedBRList)
+		{
+			if (!ChangedBRList.isEmpty())
+			{
+				for(int i=0;i< ChangedBRList.size();i++)
+				{
+					Intent intent = new Intent();
+					intent.setAction(ChangedBRList.get(i));
+					DeviceLog("StatusChanged BR Send "+ChangedBRList.get(i));
+					ServiceMain.svcContext.sendBroadcast(intent);
+				}
+			}
+		}
+	}
+
+	/**
+	 * 상태 변경을 알리며, 추가로 1 byte 데이터를 전송한다.<br>
+	 * 등록된 ChangedBRList 만큼 전송한다.
+	 *
+	 * @param status - (byte) 전송할 데이터
+	 */
+	protected void StatusChanged(byte status) {
+		synchronized(ChangedBRList) {
+			if (!ChangedBRList.isEmpty()) {
+
+				for (int i = 0; i < ChangedBRList.size(); i++) {
+					Intent intent = new Intent();
+					intent.setAction(ChangedBRList.get(i));
+					intent.putExtra("STATUS", status);
+					DeviceLog("StatusChanged BR Send " + ChangedBRList.get(i) + ":" + String.format("0x%02X", status));
+					ServiceMain.svcContext.sendBroadcast(intent);
+				}
+			}
+		}
+	}
+
+	/**
+	 * 상태 변경시 알릴 Action Name 을 등록한다.
+	 *
+	 * @param Acname - (String) 등록할 Action Name
+	 */
+	public void AddBR(String Acname)
+	{
+		if (Acname != null)
+		{
+			synchronized(ChangedBRList)
+			{
+				int limit = ChangedBRList.size();
+
+				if (limit > 0)
+				{
+					int i;
+					for (i=0;i<limit;i++)
+						if (Acname.equalsIgnoreCase(ChangedBRList.get(i)))
+							break;
+					if (i==limit)
+					{
+						ChangedBRList.add(Acname);
+
+					}
+
+				}
+				else
+					ChangedBRList.add(Acname);
+			}
+		}
+	}
+
+	/**
+	 * 상태 변경시 알릴 Action Name 을 삭제한다.
+	 *
+	 * @param ACname - (String) 삭제할 Action Name
+	 */
+	public void RemoveBR(String ACname)
+	{
+		if(ACname == null)
+		{
+			Log.w(getTAG(), "[RemoveBR] Param:ACname is null !!!");
+			return;
+		}
+		if(ChangedBRList == null)
+		{
+			Log.w(getTAG(), "[RemoveBR] ChangedBRList is null !!!");
+			return;
+		}
+
+		synchronized(ChangedBRList)
+		{
+			if (ACname.equals("null"))
+				ChangedBRList.clear();
+			else
+			{
+				DeviceLog("Remove BR " + ACname);
+				ChangedBRList.remove(ACname);
+			}
+		}
+	}
+
+	/**
+	 * WALLPAD_NOTIFY 의 ActionName 으로 전달될 Broadcast 를 송신한다.
+	 *
+	 * @param kind - (int) 종류 (WallPadAPI -> define.java -> NOTIFY_xxxxxx 로 명명된 값을 넣는다)
+	 */
+	protected void SendNotifyKindBR(int kind)
+	{
+		Intent notiIntent = new Intent();
+		notiIntent.setAction(define.NOTIFY_ACNAME);
+		notiIntent.putExtra(define.NOTIBR_KIND, kind);
+		ServiceMain.svcContext.sendBroadcast(notiIntent);
+	}
+
+	/**
+	 * 엘리베이터 호출 요청을 한다.
+	 *
+	 * @param Up - (boolean) true : 상향호출,  false : 하향호출
+	 */
+	protected void ElevatorCall(boolean Up)
+	{
+		SendNotifyKindBR((Up==true)?define.NOTIFY_DEVICE_ELE_CALL_UP:define.NOTIFY_DEVICE_ELE_CALL_DOWN);
+	}
+
+	// =================================================================================================
+	// [[ 설정 ]] region
+	// =================================================================================================
+	/**
+	 * 디바이스ID를 설정한다.
+	 *
+	 * @param devID - (int) 설정할 ID
+	 */
+	public void Set_DevID(int devID)
+	{
+		DevID=devID;
+	}
+
+	/**
+	 * 디바이스 이름을 설정한다.
+	 *
+	 * @param devname - (String) 설정할 이름
+	 */
+	public void Set_DevName(String devname)
+	{
+		DeviceName=devname;
+	}
+
+	/**
+	 * 사용하는 모듈이름을 설정한다.
+	 *
+	 * @param modulename - (String) 설정할 모듈이름
+	 */
+	public void Set_ModuleName(String modulename)
+	{
+		ModuleName = modulename;
+
+		if(ModuleName.equals("Dgw_Module"))              ReadFormatType = 1;
+		else if(ModuleName.equals("Energy_Module"))      ReadFormatType = 2;
+		else if(ModuleName.equals("SmartSwitch_Module")) ReadFormatType = 3;
+		else if(ModuleName.equals("Special_Module"))
+		{
+			if(DeviceName.equals("SmartSwitchPol_Controller")) ReadFormatType = 3;
+		}
+		else ReadFormatType = 0;
+	}
+
+	/**
+	 * ServiceMain 의 Handler 를 설정한다.
+	 *
+	 * @param mainhandler - (Handler) 설정할 Handler
+	 */
+	public void setMainHandler(Handler mainhandler)
+	{
+		MainHandler = mainhandler;
+	}
+
+	/**
+	 * SerialHandler 를 설정한다.
+	 *
+	 * @param portHandler - (SerialHandler) 설정할 SerialHandler
+	 */
+	public void set_handler(SerialHandler portHandler)
+	{
+		PortHandler = portHandler;
+	}
+
+	/**
+	 * 시퀀스넘버를 가져온다. (업데이트포함)
+	 *
+	 * @return - (Byte) 업데이트된 시퀀스넘버
+	 */
+	public Byte Get_Sequence()
+	{
+		if (sequencenum != 127)
+			sequencenum+=1;
+		else
+			sequencenum = -128;
+		return sequencenum;
+	}
+
+	/**
+	 * 실패code 를 String 으로 반환한다.
+	 *
+	 * @param code - (int) 실패code
+	 *
+	 * @return (String)
+	 */
+	public static String GetFailResult(int code)
+	{
+		String retStr = APIErrorCode.FAILSTR+";"+code;
+		return retStr;
+	}
+
+	/**
+	 * 디바이스 로그 출력
+	 *
+	 * @param msg - (String) 출력할 메시지
+	 */
+	public void DeviceLog(String msg)
+	{
+		if (!log_sw) return;
+		//Log.i(DeviceName, APIErrorCode.GetLogPrefix()+msg);
+	}
+
+
+	// =================================================================================================
+	// [[ Packet Write & Read ]] region
+	// =================================================================================================
+	/**
+	 * 시리얼포트로 패킷을 전송한다.
+	 *
+	 * @param Packet - (byte []) 전송할 패킷
+	 * @param Delete_ReadBuffer - (boolean) 수신버퍼 삭제 여부 (true:삭제, false:미삭제) 본 옵션은 485모드 일경우 true , 232일 경우 false 설정 한다.
+	 *
+	 * @return (int) - >=0 : 성공, <0 : 실패
+	 */
+	public int WritePacket(byte[] Packet, boolean Delete_ReadBuffer)
+	{
+		// 1. Param Check
+		if(Packet == null) return -1;
+
+		// 2. 송신전 있을수 있는 수신 데이터를 삭제한다.
+		if(Delete_ReadBuffer)
+		{
+			try
+			{
+				InputStream mInputStream = mSerialPort.getInputStream();
+				if (mInputStream != null)
+				{
+					int ReadSize = mInputStream.available();
+					if(ReadSize > 0)
+					{
+						Log.d(getTAG(), "[WritePacket] Dummy Data Clear !!!(ReadSize:" + ReadSize + ")");
+						mInputStream.read(new byte [ReadSize], 0, ReadSize);
+					}
+				}
+			}
+			catch (RuntimeException re) {
+				LogUtil.errorLogInfo("", TAG, re);
+				return -100;
+			}
+			catch (Exception e) {
+				Log.e(getTAG(), "[WriteCMD] IOException Error #1");
+				return -100;
+			}
+		}
+
+		// 3. 데이터 송신
+		try
+		{
+			OutputStream mOutputStream = mSerialPort.getOutputStream();
+			mOutputStream.write(Packet);
+
+			if(SerialLog)
+				Log.d(DeviceName, "Write - " + ToByteString(Packet, Packet.length));
+		}
+		catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+			return -101;
+        }
+		catch (Exception e) {
+			Log.e(getTAG(), "[WriteCMD] IOException Error #2");
+			return -101;
+		}
+
+		return 0;
+	}
+
+	/**
+	 * 수신 TimeOut 시간을 설정한다.
+	 *
+	 * @param setTime - (long) 설정할 시간 (범위 : 10 이상)
+	 */
+	public void setReadTimeOut(long setTime)
+	{
+		if(setTime <= 0 || setTime < 10)
+		{
+			Log.w(getTAG(), "[" + DeviceName + ":setReadTimeOut]" + "Param : setTime Out Of Range !!! (setTime:" + setTime + ")");
+			return;
+		}
+
+		ReadTimeOut = setTime;
+	}
+
+	/**
+	 * 시리얼포트로 패킷을 수신 하고, 기본 패킷 구조를 Parsing 리턴 한다.
+	 *
+	 * @param nAddress       - (byte) 응답받을 Adress
+	 * @param nPaketTypeFixed - (boolean) 패킷타입 (true:고정10Byte, false:가변패킷)
+	 *
+	 * @return (byte []) null - Error , Not null - OK
+	 */
+	public byte [] ReadPacket(byte nAddress, boolean nPaketTypeFixed)
+	{
+		// 1. mInputStream Get
+		InputStream mInputStream = mSerialPort.getInputStream();
+		if (mInputStream == null)
+		{
+			Log.w(getTAG(), "[" + DeviceName + "]" + " ReadCMD - mInputStream is null !!!");
+			return null;
+		}
+
+		// 2. 사용 변수 설정
+		int ReadSize = 0;
+		int DecIndex = 0;
+		byte Data = 0x00;
+		int ExpectedLength = 0;
+
+		long StartTime = 0;
+		long Term = 0;
+		int MinWaitTime = 0;
+		int  TimeOutCount = 0;
+
+		// 3. Doing
+		StartTime = System.currentTimeMillis();
+		MinWaitTime = (int)(ReadTimeOut/2);
+		while(true)
+		{
+			try
+			{
+				// 3.1. TimeOut Check
+				Term = Math.abs(StartTime - System.currentTimeMillis());
+				TimeOutCount++;
+				if (Term > ReadTimeOut)
+				{
+					if(TimeOutCount >= MinWaitTime)
+					{
+						DeviceLog("ReadCMD - TimeOut#1 (ReadTimeOut:" + ReadTimeOut + "ms)");
+
+						if(SerialLog)
+							Log.i(TAG, "[" + DeviceName + "]" + " TimeOut - (StartTime:" + StartTime + ", ReadTimeOut:" + ReadTimeOut + ", Term:" + Term + ", TimeOutCount:" + TimeOutCount);
+						break;
+					}
+				}
+				if(TimeOutCount > (int)(ReadTimeOut*2))
+				{
+					Log.w(getTAG(), "[" + DeviceName + "]" + " ReadCMD - TimeOut#2 (TimeOut:" + TimeOutCount + ", ReadTimeOut:" + ReadTimeOut + ")");
+					break;
+				}
+
+				// 3.2. Read Size
+				ReadSize = mInputStream.available();
+				if(ReadSize > 0)
+				{
+					if(ReadSize <= ReadBuffer.length)
+					{
+						// 3.3. Read Buffer
+						mInputStream.read(ReadBuffer, 0, ReadSize);
+
+						//if(SerialLog)
+							//Log.d(DeviceName, "Read " + ToByteString(ReadBuffer, ReadSize));
+						//Log.i(DeviceName, "Read " + ToByteString(ReadBuffer, ReadSize));
+
+						// 3.4. Parsing
+						for(int i=0 ; i<ReadSize ; i++)
+						{
+							Data = ReadBuffer[i];
+
+							// STX
+							if(DecIndex == 0)
+							{
+								if(Data == STX) DecBuffer[DecIndex++] = Data;
+								else DecIndex = 0;
+							}
+
+							// ID
+							else if(DecIndex == 1)
+							{
+								if(Data == nAddress) DecBuffer[DecIndex++] = Data;
+								else DecIndex = 0;
+							}
+
+							// 가변 : LEN
+							// 고정 : CMD
+							else if(DecIndex == 2)
+							{
+								if(nPaketTypeFixed)
+								{
+									// 고정 10Byte
+									DecBuffer[DecIndex++] = Data;
+									ExpectedLength = 10;
+								}
+								else
+								{
+									// 가변
+									ExpectedLength = getInt((byte)Data);
+									if(ExpectedLength <= DecBuffer.length)
+									{
+										DecBuffer[DecIndex++] = Data;
+									}
+									else
+									{
+										DecIndex = 0;
+									}
+								}
+							}
+							else if(DecIndex < (ExpectedLength-1))
+							{
+								DecBuffer[DecIndex++] = Data;
+							}
+							else if(DecIndex == (ExpectedLength-1))
+							{
+								if(Data == Check_Byte(DecBuffer, DecIndex))
+								{
+									DecBuffer[DecIndex++] = Data;
+									byte [] RetBuffer = new byte [DecIndex];
+									for(int y=0 ; y<DecIndex ; y++) RetBuffer[y] = DecBuffer[y];
+
+									if(SerialLog)
+									    Log.d(DeviceName, "Read - " + ToByteString(RetBuffer, DecIndex));
+
+									return RetBuffer;
+								}
+								else DecIndex = 0;
+							}
+							else DecIndex = 0;
+						}
+					}
+					else
+					{
+						Log.d(getTAG(), "[ReadPacket] Dummy Data Clear !!!(ReadSize:" + ReadSize + ")");
+						mInputStream.read(new byte [ReadSize], 0, ReadSize);
+					}
+				}
+			}
+			catch (RuntimeException re) {
+				LogUtil.errorLogInfo("", TAG, re);
+				return null;
+			}
+			catch (Exception e) {
+				Log.e(getTAG(), "[" + DeviceName + "]" + " ReadCMD - Exception Error");
+				//e.printStackTrace();
+            	LogUtil.errorLogInfo("", TAG, e);
+				return null;
+			}
+
+			Sleep(1);
+		}
+
+		return null;
+	}
+
+	/**
+	 * 시리얼포트로 패킷을 전송하고 <br>
+	 * 수신힌, 기본 패킷 구조를 Parsing 리턴 한다.
+	 *
+	 * @param WriteData      - (byte []) 전송할 패킷
+	 * @param nAddress       - (byte) 응답받을 Adress
+	 * @param nPaketTypeFixed - (boolean) 패킷타입 (true:고정10Byte, false:가변패킷)
+	 *
+	 * @return (byte []) null - Error , Not null - OK
+	 */
+	public byte [] WriteNReadPacket(byte[] WriteData, byte nAddress, boolean nPaketTypeFixed)
+	{
+		if(mSerialPortType == SERIAL_PORT_TYPE.Normal)
+		{
+			// 1. WritePacket
+			int ret = WritePacket(WriteData, true);
+			if(ret < 0)
+			{
+				Log.w(getTAG(), "[WriteNReadPacket] WritePacket Error - " + ret);
+				return null;
+			}
+
+			// 3. ReadPacket
+			return ReadPacket(nAddress, nPaketTypeFixed);
+		}
+		else if(mSerialPortType == SERIAL_PORT_TYPE.LHGateWay)
+		{
+			// 1. writeNread
+			byte [] readBuffer = mSerialPort_LH.writeNread(WriteData, (int)ReadTimeOut);
+
+			// 2. read Check
+			if(readBuffer == null) return null;
+			if(nPaketTypeFixed)
+			{
+				// 고정 10 Byte
+				if(readBuffer.length != 10) return null;
+				if(readBuffer[0] != STX) return null;
+				if(readBuffer[1] != nAddress) return null;
+				if(readBuffer[readBuffer.length-1] != Check_Byte(readBuffer, readBuffer.length-1)) return null;
+				return readBuffer;
+			}
+			else
+			{
+				// 가변 패킷
+				if(readBuffer.length < 6) return null;
+				if(readBuffer[0] != STX) return null;
+				if(readBuffer[1] != nAddress) return null;
+				if(readBuffer.length != (int)readBuffer[2]) return null;
+				if(readBuffer[readBuffer.length-1] != Check_Byte(readBuffer, readBuffer.length-1)) return null;
+				return readBuffer;
+			}
+		}
+		else
+		{
+			return null;
+		}
+	}
+
+	// =================================================================================================
+	// [[ Thread run ]] region
+	// =================================================================================================
+	/**
+	 * run
+	 */
+	public void run()
+	{
+		Looper.prepare();
+		DevHandler = new Handler()
+		{
+			public void handleMessage(Message msg)
+			{
+				//int myid = android.os.Process.myTid();
+
+				switch(msg.what)
+				{
+					case CommonDefine.DEVCTR_LOGONOFF:
+						break;
+
+					case CommonDefine.DEVCTR_REQDEVCTR:
+						SHMem = (DeviceCtrSHMem) msg.obj;
+						if (SHMem.Setted)
+						{
+							DevSHMem.add(SHMem);
+							Message Nmsg = obtainMessage();
+							Nmsg.what = CommonDefine.DEVCTR_CTRREQ;
+							Nmsg.arg1  = DevID;
+
+							PortHandler.lhandler.sendMessage(Nmsg);
+						}
+						break;
+
+					case CommonDefine.DEVCTR_SETCTR:
+						mSerialPortType = (int) msg.arg2;
+						if(mSerialPortType == SERIAL_PORT_TYPE.Normal)
+						{
+							mSerialPort = (SerialPort)msg.obj;
+						}
+						else if(mSerialPortType == SERIAL_PORT_TYPE.LHGateWay)
+						{
+							mSerialPort_LH = (SerialPort_LH)msg.obj;
+						}
+						sequencenum = (byte)msg.arg1;
+						Doing = true;
+
+						////////////////////////////////////////////////////////////////////////////////
+						// Process polling job
+						////////////////////////////////////////////////////////////////////////////////
+						if (DevStatus == 0)
+						{
+							try
+							{
+								do_boot();
+							}
+							catch (RuntimeException re) {
+								LogUtil.errorLogInfo("", TAG, re);
+							}
+							catch (Exception e) {
+								Log.e(getTAG(), "[do_boot] [ExceptionError]");
+								//e.printStackTrace();
+            					LogUtil.errorLogInfo("", TAG, e);
+							}
+							DevStatus=1;
+						}
+						else
+						{
+							try
+							{
+								do_ctr();
+							}
+							catch (RuntimeException re) {
+								LogUtil.errorLogInfo("", TAG, re);
+							}
+							catch (Exception e) {
+								Log.e(getTAG(), "[do_ctr] [ExceptionError]");
+								//e.printStackTrace();
+            					LogUtil.errorLogInfo("", TAG, e);
+							}
+						}
+						////////////////////////////////////////////////////////////////////////////////
+						// End Polling Job
+						////////////////////////////////////////////////////////////////////////////////
+
+
+						if (hasMessages(CommonDefine.DEVCTR_REQDEVCTR))
+						{
+							Message Nmsg = obtainMessage();
+							Nmsg.what = CommonDefine.DEVCTR_CTRREQ;
+							PortHandler.lhandler.sendMessage(Nmsg);
+						}
+						msg = new Message();
+						msg.what = CommonDefine.DEVCTR_ENDTR;
+						msg.arg1 = sequencenum;
+
+						PortHandler.lhandler.sendMessage(msg);
+						break;
+
+					case CommonDefine.DEVCTR_SETCTREMM:
+						mSerialPortType = (int) msg.arg2;
+						if(mSerialPortType == SERIAL_PORT_TYPE.Normal)
+						{
+							mSerialPort = (SerialPort)msg.obj;
+						}
+						else if(mSerialPortType == SERIAL_PORT_TYPE.LHGateWay)
+						{
+							mSerialPort_LH = (SerialPort_LH)msg.obj;
+						}
+
+						if (DevSHMem.size() > 0)
+						{
+							SHMem = DevSHMem.get(0);
+							sequencenum = (byte)msg.arg1;
+							synchronized(SHMem)
+							{
+								DevSHMem.remove(0);
+								SHMem.retVal = "test by heatvalve"+SHMem.cmd;
+								if (SHMem.Setted)
+								{
+									SHMem.retVal = "SUCCESS";
+									if (SHMem.cmd.equals("REGBRAC"))
+									{
+										if (SHMem.StrArg != null)
+										{
+											int limit = ChangedBRList.size();
+											if (limit > 0)
+											{
+												int i;
+												for (i=0;i<limit;i++)
+													if (SHMem.StrArg.equalsIgnoreCase(ChangedBRList.get(i)))
+														break;
+												if (i==limit)
+												{
+													ChangedBRList.add(SHMem.StrArg);
+												}
+											}
+
+											ChangedBRList.add(SHMem.StrArg);
+										}
+										SHMem.retVal = "SUCCESS";
+									}
+									else if (SHMem.cmd.equals("UNREGBRAC"))
+									{
+										if (SHMem.StrArg.equals("null"))
+											ChangedBRList.clear();
+										else
+										{
+											ChangedBRList.remove(SHMem.StrArg);
+										}
+									}
+									else if (SHMem.cmd.equals("LOGONOFF"))
+									{
+										log_sw = !log_sw;
+									}
+									else if (SHMem.cmd.equals("VIRTUAL"))
+									{
+										virtualmode = !virtualmode;
+									}
+									else
+									{
+										try
+										{
+											do_ctrEmm(SHMem);
+										}
+										catch (RuntimeException re) {
+											LogUtil.errorLogInfo("", TAG, re);
+										}
+										catch (Exception e) {
+											Log.e(getTAG(), "[do_ctrEmm] [ExceptionError]");
+											//e.printStackTrace();
+            								LogUtil.errorLogInfo("", TAG, e);
+										}
+									}
+
+									SHMem.notify();
+								}
+							}
+						}
+						msg = new Message();
+						msg.what = CommonDefine.DEVCTR_ENDTR;
+						msg.arg1 = sequencenum;
+
+						PortHandler.lhandler.sendMessage(msg);
+						break;
+
+					case CommonDefine.DEVCTR_CMDQFULL:
+						synchronized(SHMem)
+						{
+							SHMem.Setted = false;
+							SHMem.retVal = "QUEUE FULL";
+							SHMem.notify();
+						}
+						break;
+
+					case CommonDefine.DEVCTR_REQRETENDTR:
+						msg = new Message();
+						msg.arg1 = sequencenum;
+						msg.what = CommonDefine.DEVCTR_ENDTR;
+
+						PortHandler.lhandler.sendMessage(msg);
+						break;
+
+					case CommonDefine.DEVCTR_SETVIRTUAL:
+						virtualmode = (msg.what==1)?true:false;
+						break;
+
+					default:
+						break;
+				}
+
+				Sleep(devSleepTime);
+			}
+		};
+		Looper.loop();
+	}
+
+	// =================================================================================================
+	// [[ 드라이버 구현부 ]] region
+	// =================================================================================================
+	/**
+	 * 로딩후 최초 1회 호출됨
+	 */
+	protected void do_boot()
+	{
+	}
+
+	/**
+	 * Sink 가 필요없는 명령어 처리
+	 *
+	 * @param StrArg - (String) 명령어
+	 *
+	 * @return (String) 결과
+	 */
+	public String NoSinkCtrl(String StrArg)
+	{
+		return null;
+	}
+
+	/**
+	 * Sink 가 필요한 명령어 처리 (통신결과응답 등)
+	 *
+	 * @param SHMem - (DeviceCtrSHMem)
+	 *
+	 * @return (String) 결과
+	 */
+	protected String do_ctrEmm(DeviceCtrSHMem SHMem)
+	{
+		return null;
+	}
+
+	/**
+	 * 폴링
+	 */
+	protected void do_ctr()
+	{
+	}
+
+	// =================================================================================================
+	// [[ Packet SEND & READ 공통부분 ]] region
+	// =================================================================================================
+	/**
+	 * 명령어를 요청하고 응답을 리턴받는다. (고정 10byte 용)
+	 *
+	 * @param ReqCMD  - (byte) 요청할 명령어
+	 * @param ReqData - (byte []) 요청 데이터
+	 *
+	 * @return (byte []) 응답 데이터 - null 일경우 Error
+	 */
+	public byte [] SendNRead_Fixed(byte Address, byte ReqCMD, byte [] ReqData)
+	{
+		// 1. Make Packet
+		byte [] ReqPaket = MakeFixedPacket(Address, ReqCMD, ReqData);
+		if(ReqPaket == null)
+		{
+			Log.w(getTAG(), "[" + DeviceName + ":SendNRead_Fixed] MakeFixedPacket return null !!!");
+			return null;
+		}
+
+		// 2. WriteNRead Packet
+		byte [] RspPacket = WriteNReadPacket(ReqPaket, Address, true);
+
+		// 3. Check ReadPacekt
+		boolean RspCmdCheck = true;
+		int ret = CheckFixedPacket(ReqPaket, RspPacket, (byte) 0x00, RspCmdCheck, true);
+		if(ret < 0) return null;
+
+		// 4. data 추출
+		int dataLen = RspPacket.length - 5;
+		if(dataLen <= 0) return null;
+
+		byte [] retDataBuffer = new byte [dataLen];
+		for(int i=0 ; i<dataLen ; i++) retDataBuffer[i] = RspPacket[4+i];
+
+		return retDataBuffer;
+	}
+
+	/**
+	 * 명령어를 요청하고 응답을 리턴받는다. (고정 10byte 용이며 STX부터 CS까지 모든 패킷을 응답한다.)
+	 *
+	 * @param ReqCMD  - (byte) 요청할 명령어
+	 * @param ReqData - (byte []) 요청 데이터
+	 *
+	 * @return (byte []) 응답 데이터 - null 일경우 Error
+	 */
+	public byte [] SendNRead_Fixed_ReturnAllPacket(byte Address, byte ReqCMD, byte [] ReqData)
+	{
+		// 1. Make Packet
+		byte [] ReqPaket = MakeFixedPacket(Address, ReqCMD, ReqData);
+		if(ReqPaket == null)
+		{
+			Log.w(getTAG(), "[" + DeviceName + ":SendNRead_Fixed] MakeFixedPacket return null !!!");
+			return null;
+		}
+
+		// 2. WriteNRead Packet
+		byte [] RspPacket = WriteNReadPacket(ReqPaket, Address, true);
+
+		// 3. Check ReadPacekt
+		boolean RspCmdCheck = true;
+		int ret = CheckFixedPacket(ReqPaket, RspPacket, (byte) 0x00, RspCmdCheck, true);
+		if(ret < 0) return null;
+
+		return RspPacket;
+	}
+
+	/**
+	 * 고정패킷을 만든다.
+	 *
+	 * @param Id   - (byte) ID
+	 * @param Cmd  - (byte) 명령어
+	 * @param Data - (byte []) 데이터
+	 *
+	 * @return (byte []) 만들어진 Packet 리턴
+	 */
+	public byte [] MakeFixedPacket(byte Id, byte Cmd, byte [] Data)
+	{
+		if(Data == null)
+		{
+			return null;
+		}
+		if(Data.length != 5)
+		{
+			Log.w("DeviceManager", "[MakeFixedPacket] Data length Error - (len:" + Data.length + ")");
+			return null;
+		}
+
+		byte length = 10;
+		byte [] retBuffer = new byte [length];
+
+		int index = 0;
+		retBuffer[index++] = STX;             // STX
+		retBuffer[index++] = Id;              // ID
+		retBuffer[index++] = Cmd;             // CMD
+		retBuffer[index++] = Get_Sequence();  // SEQ
+		if(Data != null)
+		{
+			for(int i=0 ; i<Data.length ; i++) retBuffer[index++] = Data[i];       // DATA
+		}
+		retBuffer[index++] = Check_Byte(retBuffer, retBuffer.length-1);            // CS
+
+		return retBuffer;
+	}
+
+	/**
+	 * 고정패킷 응답의 기본 포멧을 체크한다.
+	 *
+	 * @param ReqPaket   - (byte []) 요청패킷
+	 * @param RspPacket  - (byte []) 응답패킷
+	 * @param ExpectRspLen - (byte) 기대하는 응답패킷 길이 (체크하지않을 경우 0x00 입력)
+	 * @param RspCmdCheck  - (boolean) 응답 명령어 체크 여부 (true : 체크, false : 미체크)
+	 * @param ErrorLogOutput - (boolean) 에러로그 출력여부 (true : 출력, false : 미출력)
+	 *
+	 * @return (int) - >=0 : 성공, <0 : 실패
+	 */
+	public int CheckFixedPacket(byte [] ReqPaket, byte [] RspPacket, byte ExpectRspLen, boolean RspCmdCheck,boolean ErrorLogOutput)
+	{
+		// 1. Default Data Check
+		if(ReqPaket == null) return -1;        // 요청패킷 null
+		if(ReqPaket.length != 10) return -2;   // 요청패킷 길이 체크
+
+		if(RspPacket == null) return -10;      // 응답패킷 null
+		if(RspPacket.length != 10) return -11; // 응답패킷 길이 체크
+
+		// 2. ID Check
+		if(ReqPaket[1] != RspPacket[1])
+		{
+			if(ErrorLogOutput) Log.e(getTAG(), "[" + DeviceName + ":CheckFixedPacket] - ID Not Match !!! - ReqPaket ID " + String.format("[0x%02X]", ReqPaket[1]) + " / RspPacket ID " + String.format("[0x%02X]", RspPacket[1]) );
+			return -20;
+		}
+
+		// 3. LEN Check
+
+		// 4. CMD Check
+		if(RspCmdCheck)
+		{
+			byte CheckCmd = (byte)(ReqPaket[2] | (byte)0x80);
+			if( CheckCmd != RspPacket[2])
+			{
+				if(ErrorLogOutput) Log.e(getTAG(), "[" + DeviceName + ":CheckFixedPacket] - CMD Not Match !!! - CheckCmd " + String.format("[0x%02X]", CheckCmd) + " / RspPacket CMD " + String.format("[0x%02X]", RspPacket[2]) );
+				return -22;
+			}
+		}
+
+		// 5. SEQ Check
+		if(ReqPaket[3] != RspPacket[3])
+		{
+			if(ErrorLogOutput) Log.e(getTAG(), "[" + DeviceName + ":CheckFixedPacket] - SEQ Not Match !!! - ReqPaket SEQ " + String.format("[0x%02X]", ReqPaket[3]) + " / RspPacket SEQ " + String.format("[0x%02X]", RspPacket[3]) );
+			return -23;
+		}
+
+		return 0;
+	}
+
+	/**
+	 * 명령어를 요청하고 응답을 리턴받는다. (가변패킷용)
+	 *
+	 * @param Address - (byte) 요청 주소
+	 * @param ReqCMD  - (byte) 요청할 명령어
+	 * @param ReqData - (byte []) 요청 데이터
+	 *
+	 * @return (byte []) 응답 데이터 - null 일경우 Error
+	 */
+	public byte [] SendNRead_Variable(byte Address, byte ReqCMD, byte [] ReqData) {
+		// 1. Make Packet
+		byte [] ReqPaket = MakeVariablePacket(Address, ReqCMD, Get_Sequence(), ReqData);
+		if (ReqPaket == null) {
+			Log.w(getTAG(), "[" + DeviceName + ":SendNRead_Variable] MakeVariablePacket return null !!!");
+			return null;
+		}
+
+		// 2. WriteNRead Packet
+		byte [] RspPacket = WriteNReadPacket(ReqPaket, Address, false);
+
+		// 3. Check ReadPacekt
+		boolean RspCmdCheck = true;
+		if ((ReadFormatType == 1) || (ReadFormatType == 3)) RspCmdCheck = false;
+		int ret = CheckVariablePacket(ReqPaket, RspPacket, (byte) 0x00, RspCmdCheck, true);
+		if (ret < 0) return null;
+
+		// 4. data 추출
+		int dataLen = RspPacket.length - 6;
+		byte [] retDataBuffer = null;
+		if (dataLen < 0) {
+			Log.w(getTAG(), "[" + DeviceName + ":SendNRead_Variable] dataLen < 0 : (dataLen:" + dataLen + ")");
+			return null;
+		}
+		else if (dataLen == 0) {
+			if (ReadFormatType == 1) {
+				if (RspPacket[3] == (byte)0x8F) retDataBuffer = new byte[] { (byte)0x8F };
+			}
+
+			if (ReadFormatType == 3) {
+				if(RspPacket[3] == (byte)0x82) retDataBuffer = new byte[] { (byte)0x82 };
+			}
+			else {
+				retDataBuffer = new byte[] { (byte)0x00 };
+			}
+		}
+		else {
+			retDataBuffer = new byte [dataLen];
+			for (int i=0 ; i<dataLen ; i++) retDataBuffer[i] = RspPacket[5+i];
+		}
+		return retDataBuffer;
+	}
+
+	/**
+	 * 가변패킷을 만든다.
+	 *
+	 * @param Id   - (byte) ID
+	 * @param Cmd  - (byte) 명령어
+	 * @param Seq  - (byte) 시퀀스
+	 * @param Data - (byte []) 데이터
+	 *
+	 * @return (byte []) 만들어진 Packet 리턴
+	 */
+	public byte [] MakeVariablePacket(byte Id, byte Cmd, byte Seq, byte [] Data)
+	{
+		byte length = 0;
+		if(Data == null) length = 6;
+		else length = (byte)(6 + Data.length);
+
+		byte [] retBuffer = new byte [length];
+
+		int index = 0;
+		retBuffer[index++] = STX;          // STX
+		retBuffer[index++] = Id;           // ID
+		retBuffer[index++] = length;       // LEN
+		retBuffer[index++] = Cmd;          // CMD
+		retBuffer[index++] = Seq;          // SEQ
+		if(Data != null)
+		{
+			for(int i=0 ; i<Data.length ; i++) retBuffer[index++] = Data[i];       // DATA
+		}
+		retBuffer[index++] = Check_Byte(retBuffer, retBuffer.length-1);            // CS
+
+		return retBuffer;
+	}
+
+	/**
+	 * 가변패킷 응답의 기본 포멧을 체크한다.
+	 *
+	 * @param ReqPaket   - (byte []) 요청패킷
+	 * @param RspPacket  - (byte []) 응답패킷
+	 * @param ExpectRspLen - (byte) 기대하는 응답패킷 길이 (체크하지않을 경우 0x00 입력)
+	 * @param RspCmdCheck  - (boolean) 응답 명령어 체크 여부 (true : 체크, false : 미체크)
+	 * @param ErrorLogOutput - (boolean) 에러로그 출력여부 (true : 출력, false : 미출력)
+	 *
+	 * @return (int) - >=0 : 성공, <0 : 실패
+	 */
+	public int CheckVariablePacket(byte [] ReqPaket, byte [] RspPacket, byte ExpectRspLen, boolean RspCmdCheck,boolean ErrorLogOutput)
+	{
+		// 1. Default Data Check
+		if(ReqPaket == null) return -1;        // 요청패킷 null
+		if(ReqPaket.length < 6) return -2;     // 요청패킷 길이 체크
+
+		if(RspPacket == null) return -10;      // 응답패킷 null
+		if(RspPacket.length < 6) return -11;   // 응답패킷 길이 체크
+
+		// 2. ID Check
+		if(ReqPaket[1] != RspPacket[1])
+		{
+			if(ErrorLogOutput) Log.e(getTAG(), "[" + DeviceName + ":CheckVariablePacket] - ID Not Match !!! - ReqPaket ID " + String.format("[0x%02X]", ReqPaket[1]) + " / RspPacket ID " + String.format("[0x%02X]", RspPacket[1]) );
+			return -20;
+		}
+
+		// 3. LEN Check
+		if(ExpectRspLen != 0)
+		{
+			if(ExpectRspLen != RspPacket[2])
+			{
+				if(ErrorLogOutput) Log.e(getTAG(), "[" + DeviceName + ":CheckVariablePacket] - LEN Not Match !!! - ExpectRspLen " + String.format("[0x%02X]", ExpectRspLen) + " / RspPacket LEN " + String.format("[0x%02X]", RspPacket[2]) );
+				return -21;
+			}
+		}
+
+		// 4. CMD Check
+		if(RspCmdCheck)
+		{
+			byte CheckCmd = (byte)(ReqPaket[3] | (byte)0x80);
+			if(CheckCmd != RspPacket[3])
+			{
+				if (ErrorLogOutput)
+					Log.e(getTAG(), "[" + DeviceName + ":CheckVariablePacket] - CMD Not Match !!! - CheckCmd " + String.format("[0x%02X]", CheckCmd) + " / RspPacket CMD " + String.format("[0x%02X]", RspPacket[3]));
+				return -22;
+			}
+		}
+
+		// 5. SEQ Check
+		if(ReqPaket[4] != RspPacket[4])
+		{
+			if(ErrorLogOutput) Log.e(getTAG(), "[" + DeviceName + ":CheckVariablePacket] - SEQ Not Match !!! - ReqPaket SEQ " + String.format("[0x%02X]", ReqPaket[4]) + " / RspPacket SEQ " + String.format("[0x%02X]", RspPacket[4]) );
+			return -23;
+		}
+
+		return 0;
+	}
+
+	/**
+	 * CheckSum 을 생성한다.
+	 *
+	 * @param target - (byte []) 대상버퍼
+	 * @param len    - (int) 패킷 길이
+	 *
+	 * @return (byte) 생성된 CheckSum
+	 */
+	protected byte Check_Byte(byte[] target, int len)
+	{
+		if(target == null) return 0x00;
+		if(target.length < len) return 0x00;
+
+		byte cbyte = STX;
+
+		for(int i=1;i<len;i++)
+		{
+			cbyte^=target[i];
+			cbyte++;
+		}
+
+		return cbyte;
+	}
+
+
+	// =================================================================================================
+	// [[ 기기제어 명령어 관련 ]] region
+	// =================================================================================================
+	/**
+	 * 기기제어 명령어 Pasing 데이터 포멧
+	 */
+	class CtrDevFormat
+	{
+		public byte [] param;
+		public String CmdStr;
+		public int ret;
+
+		public CtrDevFormat()
+		{
+			param = null;
+			CmdStr = null;
+			ret = -10000;
+		}
+	}
+
+	/**
+	 * String 으로 전달받은 기기제어 명령을 Parsing 한다.
+	 *
+	 * @param in          - (String) 명령어
+	 * @param Paramlength - (int)    기대 Param 길이
+	 *
+	 * @return (CtrDevFormat) CtrDevFormat.ret 으로 판단 ( >=0 : 성공, <0 : 실패 )
+	 */
+	public CtrDevFormat GetCtrDevParamParsing(String in, int Paramlength)
+	{
+		CtrDevFormat ctrDevFormat = new CtrDevFormat();
+
+		if(Paramlength <= 0) { ctrDevFormat.ret = -1; return ctrDevFormat; }
+		try
+		{
+			String[] datalist = in.split(":");
+			if(datalist == null) { ctrDevFormat.ret = -2; return ctrDevFormat; }
+			if(datalist.length != Paramlength+1) { ctrDevFormat.ret = -3; return ctrDevFormat; }
+
+			ctrDevFormat.CmdStr = datalist[0];
+
+			ctrDevFormat.param = new byte[Paramlength];
+			for(int i=0 ; i<Paramlength ; i++)
+			{
+				ctrDevFormat.param[i] = Byte.parseByte(datalist[1+i]);
+			}
+
+			ctrDevFormat.ret = APIErrorCode.C_SUCCESS;
+			return ctrDevFormat;
+		}
+		catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+			ctrDevFormat.ret = -100;
+        }
+		catch (Exception e) {
+			Log.e(getTAG(), "[Exception Error] GetCtrDevParamParsing#1");
+			//e.printStackTrace();
+            LogUtil.errorLogInfo("", TAG, e);
+			ctrDevFormat.ret = -100;
+		}
+		return ctrDevFormat;
+	}
+
+	/**
+	 * String 으로 전달받은 기기제어 명령을 Parsing 한다.
+	 *
+	 * @param in          - (String) 명령어
+	 *
+	 * @return (CtrDevFormat) CtrDevFormat.ret 으로 판단 ( >=0 : 성공, <0 : 실패 )
+	 */
+	public CtrDevFormat GetCtrDevParamParsing(String in)
+	{
+		CtrDevFormat ctrDevFormat = new CtrDevFormat();
+
+		try
+		{
+			String[] datalist = in.split(":");
+			if(datalist == null) { ctrDevFormat.ret = -2; return ctrDevFormat; }
+
+			ctrDevFormat.CmdStr = datalist[0];
+			int Paramlength = datalist.length-1;
+			ctrDevFormat.param = new byte[Paramlength];
+			for(int i=0 ; i<Paramlength ; i++)
+			{
+				ctrDevFormat.param[i] = Byte.parseByte(datalist[1+i]);
+			}
+
+			ctrDevFormat.ret = APIErrorCode.C_SUCCESS;
+			return ctrDevFormat;
+		}
+		catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+			ctrDevFormat.ret = -100;
+        }
+		catch (Exception e) {
+			Log.e(getTAG(), "[Exception Error] GetCtrDevParamParsing#2");
+			//e.printStackTrace();
+            LogUtil.errorLogInfo("", TAG, e);
+			ctrDevFormat.ret = -100;
+		}
+		return ctrDevFormat;
+	}
+
+	// =================================================================================================
+	// [[ CountDownTimer ]] region
+	// =================================================================================================
+	/**
+	 * CountDownTimer 관련 class 를 정의한다. </br>
+	 * 생성:Create, 리셋:Reset, 삭제:Destroy 를 지원하며, </br>
+	 * 타이머 종료 및 Tick 이벤트 발생시 호출되는 메소드를 지원한다.
+	 */
+	public class CountDownTimerClass
+	{
+		String CLASS_NAME = "[" + DeviceName  +" :CountDownTimer]";
+
+		/** 타이머 */
+		private CountDownTimer mCountDownTimer;
+
+		/** 타이머 활성화 여부 */
+		private boolean mCountDownTimerEnable;
+
+		/** 생성자 */
+		public CountDownTimerClass()
+		{
+			mCountDownTimer = null;
+			mCountDownTimerEnable = false;
+		}
+
+		/**
+		 * 타이머 생성
+		 *
+		 * @param nFinishTimeSec - (int) 종료 시간
+		 *
+		 * @return (boolean) 정상 생성 여부 - true:정상, false:에러
+		 */
+		public boolean Create(int nFinishTimeSec)
+		{
+			// Param Check
+			if(nFinishTimeSec <= 0)
+			{
+				Log.e(TAG, CLASS_NAME + "Create - param : nEndTime - Out of range !!! (" + nFinishTimeSec + ")");
+				return false;
+			}
+
+			// Timer Make
+			if(mCountDownTimer != null) mCountDownTimer.cancel();
+			mCountDownTimer = new CountDownTimer( (long)(nFinishTimeSec * 1000), 1000) {
+				@Override
+				public void onFinish() {
+					finish();
+				}
+
+				@Override
+				public void onTick(long arg0) {
+					long RemainingTime = (long)(arg0/1000);
+					tick((int)RemainingTime);
+				}
+			};
+
+			mCountDownTimer.cancel();
+			mCountDownTimer.start();
+
+			mCountDownTimerEnable = true;
+			return true;
+		}
+
+		/**
+		 * 타이머 리셋
+		 *
+		 * @return (boolean) 정상 생성 여부 - true:정상, false:에러
+		 */
+		public boolean Reset()
+		{
+			if(mCountDownTimerEnable)
+			{
+				if(mCountDownTimer != null)
+				{
+					mCountDownTimer.cancel();
+					mCountDownTimer.start();
+				}
+				return true;
+			}
+			return false;
+		}
+
+		/**
+		 * 타이머 삭제
+		 *
+		 * @return (boolean) 정상 생성 여부 - true:정상, false:에러
+		 */
+		public boolean Destroy()
+		{
+			mCountDownTimerEnable = false;
+			if(mCountDownTimer != null)
+			{
+				mCountDownTimer.cancel();
+				mCountDownTimer = null;
+				return true;
+			}
+			return false;
+		}
+
+		/**
+		 * 타이머 종료시 호출된다.
+		 */
+		protected void finish()
+		{
+		}
+
+		/**
+		 * 타이머가 1초단위로 Tick 발생시 호출된다.
+		 * @param RemainingTime - (int) 잔여시간 (단위:초)
+		 */
+		protected void tick(int RemainingTime)
+		{
+		}
+	}
+
+	// =================================================================================================
+	// [[ Util ]] region
+	// =================================================================================================
+	/**
+	 * byte 를 int 로 변환한다.
+	 *
+	 * @param in - (byte) 변환할 byte 데이터
+	 *
+	 * @return (int) 변환된 int 데이터
+	 */
+	public int getInt(byte in)
+	{
+		if (in < 0) return in+256;
+		return in;
+	}
+
+	/**
+	 * 2byte 데이터를 소수점1자리 double 데이터로 변환한다.
+	 *
+	 * @param hi  - (byte) 상위 byte
+	 * @param low - (byte) 하위 byte
+	 *
+	 * @return (double) 변환된값
+	 */
+	public double Converter2ByteToDoubleP1(byte hi, byte low)
+	{
+		int Hi = getInt(hi);
+		int Low = getInt(low);
+		int iTemp = (Hi<<8) | Low;
+		double dTemp = (double)iTemp * (double)0.1;
+		return Double.parseDouble(String.format("%.1f", dTemp));
+	}
+
+	/**
+	 * 2byte 데이터를 소수점2자리 double 데이터로 변환한다.
+	 *
+	 * @param hi  - (byte) 상위 byte
+	 * @param low - (byte) 하위 byte
+	 *
+	 * @return (double) 변환된값
+	 */
+	public double Converter2ByteToDoubleP2(byte hi, byte low)
+	{
+		int Hi = getInt(hi);
+		int Low = getInt(low);
+		int iTemp = (Hi<<8) | Low;
+		double dTemp = (double)iTemp * (double)0.01;
+		return Double.parseDouble(String.format("%.01f", dTemp));
+	}
+
+	/**
+	 * 2byte 데이터를 double 데이터로 변환한다. (누적 전력값 단위 Wh 사용 시)
+	 *
+	 * @param hi  - (byte) 상위 byte
+	 * @param low - (byte) 하위 byte
+	 *
+	 * @return (double) 변환된값
+	 */
+	public double Converter2ByteToDouble_Wh(byte hi, byte low)
+	{
+		int Hi = getInt(hi);
+		int Low = getInt(low);
+		int iTemp = (Hi<<8) | Low;
+		double dTemp = (double)iTemp * (double)1;
+		return Double.parseDouble(String.format("%.1f", dTemp));
+	}
+
+	/**
+	 * 2byte 데이터를 int 데이터로 변환한다.
+	 *
+	 * @param hi  - (byte) 상위 byte
+	 * @param low - (byte) 하위 byte
+	 *
+	 * @return (int) 변환된값
+	 */
+	public int Converter2ByteToInt(byte hi, byte low)
+	{
+		int Hi = getInt(hi);
+		int Low = getInt(low);
+		return (int)((Hi<<8) | Low);
+	}
+
+	/**
+	 * 3byte 데이터를 int 데이터로 변환한다.
+	 *
+	 * @param hi  - (byte) 상위 byte
+	 * @param mid - (byte) 중간 byte
+	 * @param low - (byte) 하위 byte
+	 *
+	 * @return (int) 변환된값
+	 */
+	public int Converter3ByteToInt(byte hi, byte mid, byte low)
+	{
+		int Hi = getInt(hi);
+		int Mid = getInt(mid);
+		int Low = getInt(low);
+		return (int)((Hi<<16) | (Mid<<8) | Low);
+	}
+
+	/**
+	 * byte 배열 데이터를 String 데이터로 변환한다.
+	 *
+	 * @param in - (byte []) 출력할 byte 배열 데이터
+	 *
+	 * @return (String) 변환된 String 값
+	 */
+	public String ToByteString(byte [] in)
+	{
+		if(in == null) return "null";
+
+		String result = "Len:" + in.length + " [";
+
+		for(int i=0 ; i<in.length ; i++)
+			result += String.format("%02X ", in[i]);
+
+		result += "]";
+
+		return result;
+	}
+
+	/**
+	 * byte 배열 데이터를 Size 만큼 String 데이터로 변환한다.
+	 *
+	 * @param in - (byte []) 출력할 byte 배열 데이터
+	 * @param size - (int) 변환요청할 사이즈
+	 *
+	 * @return (String) 변환된 String 값
+	 */
+	public String ToByteString(byte [] in, int size)
+	{
+		if(in == null) return "null";
+		if(in.length < size) return "null";
+		String result = "Len:" + size + " [";
+
+		for(int i=0 ; i<size ; i++)
+			result += String.format("%02X ", in[i]);
+
+		result += "]";
+
+		return result;
+	}
+
+	/**
+	 * byte 데이터를 [HEX format] String 데이터로 변환한다.
+	 *
+	 * @param in - (byte) 변환할 byte 데이터
+	 *
+	 * @return (String) 변환된 String
+	 */
+	public String ToByteString(byte in)
+	{
+		return String.format("0x%02X", in);
+	}
+
+	/**
+	 * sleep
+	 *
+	 * @param time - sleep 할 시간 (milliseconds 단위 시간 설정)
+	 */
+	public void Sleep(long time)
+	{
+		try{Thread.sleep(time);}
+		catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+        }
+		catch (Exception e) {
+			Log.e(getTAG(), "[Exception Error] Sleep - DeviceName:" + DeviceName);
+			//e.printStackTrace();
+            LogUtil.errorLogInfo("", TAG, e);
+		}
+	}
+	// =================================================================================================
+	// =================================================================================================
+}

+ 1779 - 1767
WallPadDevService/src/main/java/com/artncore/wallpaddevservice/driver/DriverInterOpAPI.java

@@ -1,1767 +1,1779 @@
-package com.artncore.wallpaddevservice.driver;
-
-import kr.co.icontrols.wallpadsupport.Version;
-import android.os.Handler;
-import android.os.Message;
-import android.util.Log;
-
-import com.artncore.WallPadDataMgr.WallpadDeviceSet;
-import com.artncore.commons.APIErrorCode;
-import com.artncore.commons.DataClasses;
-import com.artncore.commons.define;
-import com.artncore.commons.DataClasses.HeatingV2;
-import com.artncore.wallpaddevservice.ServiceMain;
-
-import com.util.LogUtil;
-import static com.artncore.wallpaddevservice.driver.Sdb_Controller.DEVICE_INDEX.ALL;
-import static com.artncore.wallpaddevservice.driver.Sdb_Controller.DEVICE_INDEX.DC_APU;
-import static com.artncore.wallpaddevservice.driver.Sdb_Controller.DEVICE_INDEX.ENERGY_CONT;
-import static com.artncore.wallpaddevservice.driver.Sdb_Controller.DEVICE_INDEX.ENERGY_METER;
-import static com.artncore.wallpaddevservice.driver.Sdb_Controller.DEVICE_INDEX.INTPOWER_CONT;
-
-public class DriverInterOpAPI {
-    private final String TAG = "DriverInterOpAPI";
-
-    Handler MainHandler;
-
-    private int mModelType = Version.MODEL_TYPE.OTHER;
-
-    public DriverInterOpAPI(Handler setHandler) {
-        MainHandler = setHandler;
-        mModelType = Version.getModelType();
-    }
-
-    public void DeviceLog(String tag, String msg) {
-        Log.d("ServiceTest",APIErrorCode.GetLogPrefix()+" Driver Inter  : "+ msg);
-    }
-
-    public int GetDoorLockStatus() {
-        if (ServiceMain.dataBaseLoader.data.wallpadDeviceSet.Get_DoorLock_Info[1] == WallpadDeviceSet.DOORLOCK_TYPE_RF) {
-            if (ServiceMain.dLock_Controller != null) {
-                return DLock_Controller.GetDoorStatus();
-            }
-            else {
-                return APIErrorCode.DEVICEISNOTREADY;
-            }
-        }
-        else if (ServiceMain.dataBaseLoader.data.wallpadDeviceSet.Get_DoorLock_Info[1] == WallpadDeviceSet.DOORLOCK_TYPE_FINGERPRINT) {
-            if (ServiceMain.fp_dLock_controller != null) {
-                return FP_DLock_Controller.GetDoorStatus();
-            }
-            else {
-                return APIErrorCode.DEVICEISNOTREADY;
-            }
-        }
-        return APIErrorCode.DEVICEISNOTREADY;
-    }
-
-    /**
-     * 드라이버간 명령어 전송시 TYPE의 범위를 체크한다.
-     *
-     * @param MsgWhat - (int) 체크할 MsgWhat
-     *
-     * @return (boolean) true : 정상, false : 범위이탈
-     */
-    private boolean CheckRangeMsgWhat(int MsgWhat) {
-        if (MsgWhat == ServiceMain.MSG_DEV_CTR) return true;
-        if (MsgWhat == ServiceMain.MSG_REMOCON_CTR) return true;
-        return false;
-    }
-
-    /**
-     * 가스 - 밸브 닫기
-     *
-     * @param MsgWhat   - (int) 메시지 타입
-     *
-     * @return (int) - >=0 : 성공, <0 : 실패
-     */
-    public int Gas_SetClose(int MsgWhat) {
-        DeviceLog(null, "[Gas_SetClose] Start");
-
-        // 1. 드라이버 로딩체크 & 동작여부 체크
-        if (ServiceMain.gasValve_Controller == null) {
-            Log.w(TAG, "[Gas_SetClose] dLock_Controller is null !!!");
-            return -1;
-        }
-
-        // 2. 파라미터 범위체크
-        if (!CheckRangeMsgWhat(MsgWhat)) {
-            Log.w(TAG, "[Gas_SetClose] MsgWhat - Out Of Range !!! (MsgWhat:" + MsgWhat + ")");
-            return -2;
-        }
-
-        // 3. Make Param & Message
-        String CmdStr = MakeSendMessageFormat(define.DRIVER_TITLE_GASVALVE, define.APICMD_SINKCTRL, "SetClose", 0, 0, 0, 0, 0);
-
-        // 4. Send Message
-        SendDevCtrlMessage(MsgWhat, CmdStr);
-
-        DeviceLog("HIGH","[Gas_SetClose] SendDevCtrlMessage - CmdStr:[" + CmdStr + "]");
-
-        return 0;
-    }
-
-    public byte GasRegBR(String acname) {
-        String CmdStr = define.DRIVER_TITLE_GASVALVE + ";" + define.APICMD_REGBR + ";" + acname;
-        Message msg = MainHandler.obtainMessage();
-        msg.what = ServiceMain.MSG_DEV_CTR;
-        msg.obj = CmdStr;
-        Log.d("WALLPADAPI","Gasvalve onoff cmd "+CmdStr);
-        MainHandler.sendMessage(msg);
-        return 0;
-
-    }
-
-    /*
-     스마트 분전반 BR 등록
-     */
-    public byte SdbRegBR(String acname) {
-        String CmdStr = define.DRIVER_TITLE_SMART_DISTRIBUTION_BD + ";" + define.APICMD_REGBR + ";" + acname;
-        Message msg = MainHandler.obtainMessage();
-        msg.what = ServiceMain.MSG_DEV_CTR;
-        msg.obj = CmdStr;
-        Log.d("WALLPADAPI","Sdb_RegBR onoff cmd "+CmdStr);
-        MainHandler.sendMessage(msg);
-        return 0;
-    }
-
-    /*
-    거실에너지미터 BR 등록
-    */
-    public byte SdbLivingRegBR(String acname) {
-        String CmdStr = define.DRIVER_TITLE_SDB_LIVINGROOM_LIGHT + ";" + define.APICMD_REGBR + ";" + acname;
-        Message msg = MainHandler.obtainMessage();
-        msg.what = ServiceMain.MSG_DEV_CTR;
-        msg.obj = CmdStr;
-        Log.d("WALLPADAPI","Sdb_Living_RegBR onoff cmd "+CmdStr);
-        MainHandler.sendMessage(msg);
-        return 0;
-    }
-
-    /**
-     * 도어락 - 문열기 대기모드 설정
-     * 무선도어락, 지문인식 도어락의 경우 제어됨
-     *
-     * @param OnOff   - (boolean) 설정할 상태 (true:ON , false:OFF)
-     * @param TimeSec - (byte) 설정시간 (범위:0~10 , 설정 = 0 일경우 본값은 0 , 설정 = 1 일경우 본값은 1~10 [단위:초])
-     *
-     * @return (int) - >=0 : 성공, <0 : 실패
-     */
-    public int DLock_SetDoorOpenStandbyMode(boolean OnOff, byte TimeSec) {
-        DeviceLog(null, "[DLock_SetDoorOpenStandbyMode] Start (OnOff:" + OnOff + ", TimeSec:" + TimeSec + ")");
-
-        if (ServiceMain.dataBaseLoader.data.wallpadDeviceSet.Get_DoorLock_Info[1] == WallpadDeviceSet.DOORLOCK_TYPE_NORMAL) {
-            // 1. 드라이버 로딩체크 & 동작여부 체크
-            if (ServiceMain.dLock_Controller == null) {
-                Log.w(TAG, "[DLock_SetDoorOpenStandbyMode1] dLock_Controller is null !!!");
-                return -1;
-            }
-
-            // 2. 파라미터 범위체크
-            //     2.1. TimeSec
-            if (OnOff) {
-                if (!((TimeSec >= 0x01) && (TimeSec <= 0x0A))) {
-                    Log.w(TAG, "[DLock_SetDoorOpenStandbyMode1] Param : TimeSec - Out of Range #1 (TimeSec:" + TimeSec + ")");
-                    return -2;
-                }
-            }
-            else {
-                if (TimeSec != 0) {
-                    Log.w(TAG, "[DLock_SetDoorOpenStandbyMode1] Param : TimeSec - Out of Range #2 (TimeSec:" + TimeSec + ")");
-                    return -3;
-                }
-            }
-
-            // 3. Make Param & Message
-            String CmdStr = MakeSendMessageFormat(define.DRIVER_TITLE_DLOCK, define.APICMD_SINKCTRL, "SetDoorOpenStandbyMode", ((OnOff)?1:0), TimeSec, 0, 0, 0);
-
-            // 4. Send Message
-            int MsgWhat = ServiceMain.MSG_DEV_CTR;
-            SendDevCtrlMessage(MsgWhat, CmdStr);
-
-            DeviceLog("HIGH","[DLock_SetDoorOpenStandbyMode1] SendDevCtrlMessage - CmdStr:[" + CmdStr + "]");
-        }
-        else if (ServiceMain.dataBaseLoader.data.wallpadDeviceSet.Get_DoorLock_Info[1] == WallpadDeviceSet.DOORLOCK_TYPE_FINGERPRINT) {
-            // 1. 드라이버 로딩체크 & 동작여부 체크
-            if (ServiceMain.fp_dLock_controller == null) {
-                Log.w(TAG, "[DLock_SetDoorOpenStandbyMode2] fp_dLock_controller is null !!!");
-                return -1;
-            }
-
-            // 2. 파라미터 범위체크
-            //     2.1. TimeSec
-            if (OnOff) {
-                if (!((TimeSec >= 0x01) && (TimeSec <= 0x0A))) {
-                    Log.w(TAG, "[DLock_SetDoorOpenStandbyMode2] Param : TimeSec - Out of Range #1 (TimeSec:" + TimeSec + ")");
-                    return -2;
-                }
-            }
-            else {
-                if (TimeSec != 0) {
-                    Log.w(TAG, "[DLock_SetDoorOpenStandbyMode2] Param : TimeSec - Out of Range #2 (TimeSec:" + TimeSec + ")");
-                    return -3;
-                }
-            }
-
-            // 3. Make Param & Message
-            String CmdStr = MakeSendMessageFormat(define.DRIVER_TITLE_FP_DLOCK, define.APICMD_SINKCTRL, "SetDoorOpenStandbyMode", ((OnOff)?1:0), TimeSec, 0, 0, 0);
-
-            // 4. Send Message
-            int MsgWhat = ServiceMain.MSG_DEV_CTR;
-            SendDevCtrlMessage(MsgWhat, CmdStr);
-
-            DeviceLog("HIGH","[DLock_SetDoorOpenStandbyMode2] SendDevCtrlMessage - CmdStr:[" + CmdStr + "]");
-        }
-        return 0;
-    }
-    /**
-     * 지문인식 도어락 - 문열기 제어
-     *
-     * @return (int) - >=0 : 성공, <0 : 실패
-     */
-    public int FPdLock_SetDoorOpen() {
-        DeviceLog(null, "[FPdLock_SetDoorOpen] Start ");
-
-        if (ServiceMain.dataBaseLoader.data.wallpadDeviceSet.Get_DoorLock_Info[1] == WallpadDeviceSet.DOORLOCK_TYPE_FINGERPRINT) {
-            // 1. 드라이버 로딩체크 & 동작여부 체크
-            if (ServiceMain.fp_dLock_controller == null) {
-                Log.w(TAG, "[FPdLock_SetDoorOpen] fp_dLock_controller is null !!!");
-                return -1;
-            }
-
-            // 3. Make Param & Message
-            String CmdStr = MakeSendMessageFormat(define.DRIVER_TITLE_FP_DLOCK, define.APICMD_SINKCTRL, "SetDoorOpen", 0,0, 0, 0, 0);
-
-            // 4. Send Message
-            int MsgWhat = ServiceMain.MSG_DEV_CTR;
-            SendDevCtrlMessage(MsgWhat, CmdStr);
-
-            DeviceLog("HIGH","[FPdLock_SetDoorOpen] SendDevCtrlMessage - CmdStr:[" + CmdStr + "]");
-        }
-        return 0;
-    }
-
-    public int SmartIotDCam_CtrLed(boolean doit) {
-        int[] camTypes = null;
-        try {
-            WallpadDeviceSet wds = new WallpadDeviceSet(ServiceMain.svcContext);
-            camTypes =  wds.Get_RFDoorCAM_Info();
-            wds.closeDB();
-        } catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-            return -1;
-        } catch (Exception ex) {
-            Log.e(TAG, "[SmartIotDCam_CtrLed] - Get_RFDoorCAM_Info Exception !!!");
-            //ex.printStackTrace();
-            LogUtil.errorLogInfo("", TAG, ex);
-            return -1;
-        }
-
-        byte onoff = (byte)0x00;            // 기본 : 조명 OFF
-        if (doit) { onoff = (byte)0x01; } // 조명 ON
-        else { onoff = (byte)0x00; } // 조명 OFF
-
-        if (camTypes != null && camTypes[1] == WallpadDeviceSet.DOORTYPE_IOT_SMART) {
-            String CmdStr = MakeSendMessageFormat(define.DRIVER_TITLE_SMARTKEYRFDOOR, define.APICMD_SINKCTRL, "SetLEDmode", onoff, 0, 0, 0, 0);
-
-            // 4. Send Message
-            int MsgWhat = ServiceMain.MSG_DEV_CTR;
-            SendDevCtrlMessage(MsgWhat, CmdStr);
-
-            DeviceLog(TAG, "[SmartIotDCam_CtrLed] SendDevCtrlMessage - CmdStr:[" + CmdStr + "]");
-        }
-        else {
-            return -2;
-        }
-        return 0;
-    }
-
-    /**
-     * 난방V1 각방 제어 (운전모드 및 설정온도 변경)
-     *
-     * @param MsgWhat   - (int) 메시지 타입
-     * @param RoomIndex - (byte) 변경할 방 인덱스
-     * @param SetMode   - (byte) 변경할 운전모드(0:미설정, 1:ON, 2:OFF)
-     * @param SetTemp   - (double) 변경할 설정온도 (미설정시 '0')
-     *
-     * @return (int) - >=0 : 성공, <0 : 실패
-     */
-    public int HeatingV1_SetEachRoomStatus(int MsgWhat, byte RoomIndex, byte SetMode, double SetTemp) {
-        DeviceLog("HIGH","[HeatingV1_SetEachRoomStatus] Start (RoomIndex:" + RoomIndex + ", SetMode:" + SetMode + ", SetTemp" + SetTemp + ")");
-
-        // 1. 드라이버 로딩체크 & 동작여부 체크
-        if (ServiceMain.heatingV1_Controller == null) {
-            Log.w(TAG, "[HeatingV1_SetEachRoomStatus] heatingV1_Controller is null !!!");
-            return -1;
-        }
-
-        if (!ServiceMain.heatingV1_Controller.Doing) {
-            Log.w(TAG, "[HeatingV1_SetEachRoomStatus] Doing is false !!!");
-            return -2;
-        }
-
-        // 2. 파라미터 범위체크
-        if (!CheckRangeMsgWhat(MsgWhat)) {
-            Log.w(TAG, "[HeatingV1_SetEachRoomStatus] MsgWhat - Out Of Range !!! (MsgWhat:" + MsgWhat + ")");
-            return -10;
-        }
-
-        //     2.1. RoomIndex
-        byte RoomCount = ServiceMain.heatingV1_Controller.GetRoomCount();
-        if ((RoomIndex < 0) || (RoomIndex >= RoomCount)) {
-            Log.w(TAG, "[HeatingV1_SetEachRoomStatus] Param : RoomIndex Out of Range (RoomIndex:" + RoomIndex + ")");
-            return -21;
-        }
-
-        //     2.2. SetMode
-        switch (SetMode) {
-            case 0x00: case 0x01: case 0x02:
-                break;
-
-            default:
-                Log.w(TAG, "[HeatingV1_SetEachRoomStatus] Param : SetMode Out of Range (SetMode:" + String.format("0x%02X", SetMode) + ")");
-                return -22;
-        }
-
-        //     2.3. SetTemp
-        if ((SetTemp < (double)5.0) || (SetTemp > (double)40.0)) {
-            Log.w(TAG, "[HeatingV1_SetEachRoomStatus] Param : SetTemp Out of Range (SetTemp:" + SetTemp + ")");
-            return -23;
-        }
-
-        // 3. Make Param & Message
-        byte ByteTemp = 0;
-        byte Point    = 0;
-        if (SetTemp != 0) {
-            ByteTemp = (byte) SetTemp;
-            Point = (PointExist(SetTemp)?(byte)1:(byte)0);
-        }
-
-        String CmdStr = MakeSendMessageFormat(define.DRIVER_TITLE_HEATINGV1, define.APICMD_SINKCTRL, "SetEachRoomStatus", RoomIndex, SetMode, ByteTemp, Point, 0);
-
-        // 4. Send Message
-        SendDevCtrlMessage(MsgWhat, CmdStr);
-        DeviceLog("HIGH","[HeatingV1_SetEachRoomStatus] SendDevCtrlMessage - CmdStr:[" + CmdStr + "]");
-        return 0;
-    }
-
-    /**
-     * 난방V2 각방 제어 (운전모드 및 설정온도 변경)
-     *
-     * @param MsgWhat   - (int) 메시지 타입
-     * @param RoomIndex - (byte) 변경할 방 인덱스
-     * @param SetMode   - (byte) 변경할 운전모드(0:미설정, 1:ON, 2:OFF)
-     * @param SetTemp   - (double) 변경할 설정온도 (미설정시 '0')
-     *
-     * @return (int) - >=0 : 성공, <0 : 실패
-     */
-    public int HeatingV2_SetEachRoomStatus(int MsgWhat, byte RoomIndex, byte SetMode, double SetTemp) {
-        DeviceLog("HIGH","[HeatingV2_SetEachRoomStatus] Start (RoomIndex:" + RoomIndex + ", SetMode:" + SetMode + ", SetTemp" + SetTemp + ")");
-
-        // 1. 드라이버 로딩체크
-        if (ServiceMain.heatingV2_Controller == null) {
-            Log.w(TAG, "[HeatingV2_SetEachRoomStatus] heatingV1_Controller is null !!!");
-            return -1;
-        }
-
-        if (!ServiceMain.heatingV2_Controller.Doing) {
-            Log.w(TAG, "[HeatingV2_SetEachRoomStatus] Doing is false !!!");
-            return -2;
-        }
-
-        // 2. 파라미터 범위체크
-        if (!CheckRangeMsgWhat(MsgWhat)) {
-            Log.w(TAG, "[HeatingV2_SetEachRoomStatus] MsgWhat - Out Of Range !!! (MsgWhat:" + MsgWhat + ")");
-            return -10;
-        }
-
-        //     2.1. RoomIndex
-        byte RoomCount = ServiceMain.heatingV2_Controller.GetRoomCount();
-        if ((RoomIndex < 0) || (RoomIndex >= RoomCount)) {
-            Log.w(TAG, "[HeatingV2_SetEachRoomStatus] Param : RoomIndex Out of Range (RoomIndex:" + RoomIndex + ")");
-            return -21;
-        }
-
-        //     2.2. SetMode
-        if (!HeatingV2.MODE.CheckSetMode(SetMode)) {
-            Log.w(TAG, "[HeatingV2_SetEachRoomStatus] Param : SetMode Out of Range (SetMode:" + String.format("0x%02X", SetMode) + ")");
-            return -22;
-        }
-        //     2.3. SetTemp
-        //        if( (SetTemp < (double)5.0) || (SetTemp > (double)40.0) )
-        //        {
-        //            Log.w(TAG, "[HeatingV2_SetEachRoomStatus] Param : SetTemp Out of Range (SetTemp:" + SetTemp + ")");
-        //            return -23;
-        //        }
-
-        // 3. Make Param & Message
-        byte ByteTemp = 0;
-        byte Point    = 0;
-        if (SetTemp != 0) {
-            ByteTemp = (byte) SetTemp;
-            Point = (PointExist(SetTemp)?(byte)1:(byte)0);
-        }
-
-        String CmdStr = MakeSendMessageFormat(define.DRIVER_TITLE_HEATINGV2, define.APICMD_SINKCTRL, "SetEachRoomStatus", RoomIndex, SetMode, ByteTemp, Point, 0);
-
-        // 4. Send Message
-        SendDevCtrlMessage(MsgWhat, CmdStr);
-        DeviceLog("HIGH","[HeatingV2_SetEachRoomStatus] SendDevCtrlMessage - CmdStr:[" + CmdStr + "]");
-        return 0;
-    }
-
-    /**
-     * 게이트웨이를 통하여 에너지미터를 리셋한다.
-     *
-     * @return (int) - >=0 : 성공, <0 : 실패
-     */
-    public int IGW200D_EnergyReset() {
-        // 1. 드라이버 로딩체크
-        if (ServiceMain.iGW200D_Controller == null) {
-            Log.w(TAG, "[IGW200D_EnergyReset] iGW200D_Controller is null !!!");
-            return -1;
-        }
-
-        if (!ServiceMain.iGW200D_Controller.Doing) {
-            Log.w(TAG, "[IGW200D_EnergyReset] Doing is false !!!");
-            return -2;
-        }
-
-        // 2. 파라미터 범위체크
-
-        // 3. Make Param & Message
-        String CmdStr = MakeSendMessageFormat(define.DRIVER_TITLE_IGW200D, define.APICMD_SINKCTRL, "EnergyReset", 0, 0, 0, 0, 0);
-
-        // 4. Send Message
-        SendDevCtrlMessage(ServiceMain.MSG_DEV_CTR, CmdStr);
-        DeviceLog("HIGH","[IGW200D_EnergyReset] SendDevCtrlMessage - CmdStr:[" + CmdStr + "]");
-        return 0;
-    }
-
-    /**
-     * 게이트웨이를 통하여 무선도어락을 제어한다.
-     *
-     * @param  Open - (boolean) ture : 문열림(펄스2번) , false : 등록(펄스3번)
-     * @return (int) - >=0 : 성공, <0 : 실패
-     */
-    public int IGW_SetWddrCont(boolean Open) {
-        DeviceManager IGW_Controller = null;
-        String Driver_Title = null;
-
-        // 1. 모델명 체크
-        if (mModelType == Version.MODEL_TYPE.IHN_1020GL) {
-            IGW_Controller = ServiceMain.iGW200D_Controller;
-            Driver_Title   = define.DRIVER_TITLE_IGW200D;
-        }
-        else if (mModelType == Version.MODEL_TYPE.IHN_D101 || mModelType == Version.MODEL_TYPE.IHN_D101_I
-                || mModelType == Version.MODEL_TYPE.IHN_D101K || mModelType == Version.MODEL_TYPE.IHN_D101K_I
-                || mModelType == Version.MODEL_TYPE.IHN_1010GL || mModelType == Version.MODEL_TYPE.IHN_1010GL_I
-                || mModelType == Version.MODEL_TYPE.IHN_1010GL_I_2443ALT || mModelType == Version.MODEL_TYPE.IHN_1010GL_I_6410ALT)
-        {
-            IGW_Controller = ServiceMain.iGW300_Controller;
-            Driver_Title   = define.DRIVER_TITLE_IGW300;
-        }
-        else {
-            Log.w(TAG, "[IGW_SetWddrCont] Not Support ModelType !!! (mModelType:" + mModelType + ")");
-            return -1;
-        }
-
-        // 2. 드라이버 로딩체크
-        if (IGW_Controller == null) {
-            Log.w(TAG, "[IGW_SetWddrCont] IGW_Controller is null !!!");
-            return -11;
-        }
-
-        if (!IGW_Controller.Doing) {
-            Log.w(TAG, "[IGW_SetWddrCont] Doing is false !!!");
-            return -12;
-        }
-
-        // 3. 파라미터 범위체크
-
-        // 4. Make Param & Message
-        String CmdStr = MakeSendMessageFormat(Driver_Title, define.APICMD_SINKCTRL, "SetWddrCont", (Open) ? 0x02 : 0x01, 0, 0, 0, 0);
-
-        // 5. Send Message
-        SendDevCtrlMessage(ServiceMain.MSG_DEV_CTR, CmdStr);
-        DeviceLog("HIGH","[IGW_SetWddrCont] SendDevCtrlMessage - CmdStr:[" + CmdStr + "]");
-        return 0;
-    }
-
-    /**
-     * 게이트웨이를 통하여 무선도어락 문열림 대기모드를 설정한다.
-     *
-     * @param  DelayTime - (int) 문열림 시간 - 0초간, 3초간, 5초간, 10초간
-     * @return (int) - >=0 : 성공, <0 : 실패
-     */
-    public int IGW_SetWddrOpenDelayCont(int DelayTime) {
-        DeviceManager IGW_Controller = null;
-        String Driver_Title = null;
-
-        // 1. 모델명 체크
-        if (mModelType == Version.MODEL_TYPE.IHN_1020GL) {
-            IGW_Controller = ServiceMain.iGW200D_Controller;
-            Driver_Title   = define.DRIVER_TITLE_IGW200D;
-        }
-        else if (mModelType == Version.MODEL_TYPE.IHN_D101 || mModelType == Version.MODEL_TYPE.IHN_D101_I
-                || mModelType == Version.MODEL_TYPE.IHN_D101K || mModelType == Version.MODEL_TYPE.IHN_D101K_I
-                || mModelType == Version.MODEL_TYPE.IHN_1010GL || mModelType == Version.MODEL_TYPE.IHN_1010GL_I
-                || mModelType == Version.MODEL_TYPE.IHN_1010GL_I_2443ALT || mModelType == Version.MODEL_TYPE.IHN_1010GL_I_6410ALT)
-        {
-            IGW_Controller = ServiceMain.iGW300_Controller;
-            Driver_Title   = define.DRIVER_TITLE_IGW300;
-        }
-        else {
-            Log.w(TAG, "[IGW_SetWddrOpenDelayCont] Not Support ModelType !!! (mModelType:" + mModelType + ")");
-            return -1;
-        }
-
-        // 2. 드라이버 로딩체크
-        if (IGW_Controller == null) {
-            Log.w(TAG, "[IGW_SetWddrOpenDelayCont] IGW_Controller is null !!!");
-            return -11;
-        }
-
-        if (!IGW_Controller.Doing) {
-            Log.w(TAG, "[IGW_SetWddrOpenDelayCont] Doing is false !!!");
-            return -12;
-        }
-
-        // 3. 파라미터 범위체크
-        if (!((DelayTime == 0) || (DelayTime == 3) || (DelayTime == 5) || (DelayTime == 10))) {
-            Log.w(TAG, "[IGW_SetWddrOpenDelayCont] DelayTime is Error :" + DelayTime);
-            return -101;
-        }
-
-        // 4. Make Param & Message
-        String CmdStr = MakeSendMessageFormat(Driver_Title, define.APICMD_SINKCTRL, "SetWddrOpenDelayCont", DelayTime, 0, 0, 0, 0);
-
-        // 5. Send Message
-        SendDevCtrlMessage(ServiceMain.MSG_DEV_CTR, CmdStr);
-        DeviceLog("HIGH","[IGW_SetWddrOpenDelayCont] SendDevCtrlMessage - CmdStr:[" + CmdStr + "]");
-        return 0;
-    }
-
-    public static final byte DOOR_POWER = 24;
-    public static final byte BELL_CONT = 25;
-    public static final byte VIDEO_SEL = 27;
-    /**
-     * 게이트웨이(IGW-200/300)를 통하여 현관카메라 LED를 제어한다.
-     *
-     * @param  onoff - (boolean) true 켜기 / false 끄기
-     * @return (int) - >=0 : 성공, <0 : 실패
-     */
-    public int IGW_SetLedOnOff(boolean onoff) {
-        DeviceManager IGW_Controller = null;
-        String Driver_Title = null;
-
-        // 1. 모델명 체크
-        if (mModelType == Version.MODEL_TYPE.IHN_1020GL) {
-            IGW_Controller = ServiceMain.iGW200D_Controller;
-            Driver_Title   = define.DRIVER_TITLE_IGW200D;
-        }
-        else if (mModelType == Version.MODEL_TYPE.IHN_D101 || mModelType == Version.MODEL_TYPE.IHN_D101_I
-                || mModelType == Version.MODEL_TYPE.IHN_D101K || mModelType == Version.MODEL_TYPE.IHN_D101K_I
-                || mModelType == Version.MODEL_TYPE.IHN_1010GL || mModelType == Version.MODEL_TYPE.IHN_1010GL_I
-                || mModelType == Version.MODEL_TYPE.IHN_1010GL_I_2443ALT || mModelType == Version.MODEL_TYPE.IHN_1010GL_I_6410ALT)
-        {
-            IGW_Controller = ServiceMain.iGW300_Controller;
-            Driver_Title   = define.DRIVER_TITLE_IGW300;
-        }
-        else {
-            Log.w(TAG, "[IGW_SetLedOnOff] Not Support ModelType !!! (mModelType:" + mModelType + ")");
-            return -1;
-        }
-
-        // 2. 드라이버 로딩체크
-        if (IGW_Controller == null) {
-            Log.w(TAG, "[IGW_SetLedOnOff] IGW_Controller is null !!!");
-            return -11;
-        }
-
-        if (!IGW_Controller.Doing) {
-            Log.w(TAG, "[IGW_SetLedOnOff] Doing is false !!!");
-            return -12;
-        }
-
-        // SendNReadCMD_int(define.APICMD_NOSINKCTRL, "ControlOutput", kind, onoff, 0, 0, 0);
-        // 3. Make Param & Message
-        String CmdStr = MakeSendMessageFormat(Driver_Title, define.APICMD_NOSINKCTRL, "ControlOutput", DOOR_POWER, (onoff ? 1 : 0), 0, 0, 0);
-
-        // 4. Send Message
-        SendDevCtrlMessage(ServiceMain.MSG_DEV_CTR, CmdStr);
-        DeviceLog("HIGH","[IGW_SetLedOnOff] SendDevCtrlMessage - CmdStr:[" + CmdStr + "]");
-        return 0;
-    }
-
-    /**
-     * 환기 - ON/OFF 제어
-     *
-     * @param MsgWhat   - (int) 메시지 타입
-     * @param OnOff   - (boolean) 설정할 상태 (true:ON , false:OFF)
-     *
-     * @return (int) - >=0 : 성공, <0 : 실패
-     */
-    public int Ventilation_SetOnOff(int MsgWhat, boolean OnOff) {
-        DeviceLog(null, "[Ventilation_SetOnOff] Start (OnOff:" + OnOff + ")");
-
-        // 1. 드라이버 로딩체크 & 동작여부 체크
-        if (ServiceMain.ventilation_Controller == null) {
-            Log.w(TAG, "[Ventilation_SetOnOff] ventilation_Controller is null !!!");
-            return -1;
-        }
-
-        // 2. 파라미터 범위체크
-        if (!CheckRangeMsgWhat(MsgWhat)) {
-            Log.w(TAG, "[Ventilation_SetOnOff] MsgWhat - Out Of Range !!! (MsgWhat:" + MsgWhat + ")");
-            return -10;
-        }
-
-        // 3. Make Param & Message
-        String CmdStr = MakeSendMessageFormat(define.DRIVER_TITLE_VENTILATION, define.APICMD_SINKCTRL, "SetOnOff", ((OnOff) ? 1 : 0), 0, 0, 0, 0);
-
-        // 4. Send Message
-        SendDevCtrlMessage(MsgWhat, CmdStr);
-        DeviceLog("HIGH","[Ventilation_SetOnOff] SendDevCtrlMessage - CmdStr:[" + CmdStr + "]");
-        return 0;
-    }
-
-    /**
-     * 환기 - 풍량세기 변경
-     *
-     * @param MsgWhat    - (int) 메시지 타입
-     * @param ChangeWind - (byte) 변경할 풍량상태
-     *
-     * @return (int) - >=0 : 성공, <0 : 실패
-     */
-    public int Ventilation_SetWind(int MsgWhat, byte ChangeWind) {
-        DeviceLog(null, "[Ventilation_SetWind] Start (ChangeWind:" + ChangeWind + ")");
-
-        // 1. 드라이버 로딩체크 & 동작여부 체크
-        if (ServiceMain.ventilation_Controller == null) {
-            Log.w(TAG, "[Ventilation_SetWind] ventilation_Controller is null !!!");
-            return -1;
-        }
-
-        // 2. 파라미터 범위체크
-        if (!CheckRangeMsgWhat(MsgWhat)) {
-            Log.w(TAG, "[Ventilation_SetWind] MsgWhat - Out Of Range !!! (MsgWhat:" + MsgWhat + ")");
-            return -10;
-        }
-
-        if (!DataClasses.Venti.WIND.CheckRange(ChangeWind)) {
-            Log.w(TAG, "[Ventilation_SetWind] ChangeWind - Out Of Range (ChangeWind:" + ChangeWind + ")");
-            return -20;
-        }
-
-        // 3. Make Param & Message
-        String CmdStr = MakeSendMessageFormat(define.DRIVER_TITLE_VENTILATION, define.APICMD_SINKCTRL, "SetWind", ChangeWind, 0, 0, 0, 0);
-
-        // 4. Send Message
-        SendDevCtrlMessage(MsgWhat, CmdStr);
-        DeviceLog("HIGH","[Ventilation_SetWind] SendDevCtrlMessage - CmdStr:[" + CmdStr + "]");
-        return 0;
-    }
-
-    /**
-     * 환기 - 타이머설정값 변경
-     *
-     * @param MsgWhat     - (int) 메시지 타입
-     * @param ChangeTimer - (byte) 변경할 타이머 상태
-     *
-     * @return (int) - >=0 : 성공, <0 : 실패
-     */
-    public int Ventilation_SetTimer(int MsgWhat, byte ChangeTimer) {
-        DeviceLog(null, "[Ventilation_SetTimer] Start (ChangeTimer:" + ChangeTimer + ")");
-
-        // 1. 드라이버 로딩체크 & 동작여부 체크
-        if (ServiceMain.ventilation_Controller == null) {
-            Log.w(TAG, "[Ventilation_SetTimer] ventilation_Controller is null !!!");
-            return -1;
-        }
-
-        // 2. 파라미터 범위체크
-        if (!CheckRangeMsgWhat(MsgWhat)) {
-            Log.w(TAG, "[Ventilation_SetTimer] MsgWhat - Out Of Range !!! (MsgWhat:" + MsgWhat + ")");
-            return -10;
-        }
-
-        // 3. Make Param & Message
-        String CmdStr = MakeSendMessageFormat(define.DRIVER_TITLE_VENTILATION, define.APICMD_SINKCTRL, "SetTimer", ChangeTimer, 0, 0, 0, 0);
-
-        // 4. Send Message
-        SendDevCtrlMessage(MsgWhat, CmdStr);
-        DeviceLog("HIGH","[Ventilation_SetTimer] SendDevCtrlMessage - CmdStr:[" + CmdStr + "]");
-        return 0;
-    }
-
-    /**
-     * 제어기 구분없이 일괄소등 상태를 제어한다.
-     *
-     * @param OnOff - (boolean) true:일괄소등해제상태(조명ON) , false:일괄소등상태(조명OFF)
-     *
-     * @return (int) - >=0 : 성공, <0 : 실패
-     */
-    public int setAllLight(boolean OnOff) {
-        try {
-            if (mModelType == Version.MODEL_TYPE.IHN_D101 || mModelType == Version.MODEL_TYPE.IHN_D101_I
-                    || mModelType == Version.MODEL_TYPE.IHN_D101K || mModelType == Version.MODEL_TYPE.IHN_D101K_I) {
-                int onoff = 0;
-                if(OnOff) onoff = 1;
-
-                WallpadDeviceSet wds = new WallpadDeviceSet(ServiceMain.svcContext);
-                int nDistributionPanelType = wds.Get_DistributionPannelType_Info();
-                wds.closeDB();
-
-                String DistributeName = "";
-                if (nDistributionPanelType == Version.DISTRIBUTION_MODEL.SMART_DIST) {
-                    // 스마트 분전반
-                    DistributeName = define.DRIVER_TITLE_SMART_DISTRIBUTION_BD;
-                }
-                else if (nDistributionPanelType == Version.DISTRIBUTION_MODEL.KNX_DIST) {
-                    // KNX 분전반
-                    DistributeName = define.DRIVER_TITLE_KNX_DISTRIBUTION_BD;
-                }
-                else {
-                    // 그밖의 경우, 스마트분전반을 기본으로 로딩.
-                    DistributeName = define.DRIVER_TITLE_SMART_DISTRIBUTION_BD;
-                }
-
-                Log.i(TAG, "setAllLight --- IHN_D101 (OnOff:" + OnOff + ")");
-                Message msg = MainHandler.obtainMessage();
-                String CmdStr = MakeSendMessageFormat(DistributeName, define.APICMD_SINKCTRL, "AllLightOnOff", onoff, 0, 0, 0, 0);
-                msg.what = ServiceMain.MSG_DEV_CTR;
-                msg.obj = CmdStr;
-                DeviceLog(null, "setAllLight - onoff (cmd:" + CmdStr + ")");
-                MainHandler.sendMessage(msg);
-
-                return 0;
-            }
-            else if (mModelType == Version.MODEL_TYPE.IHN_1020GL
-                    || mModelType == Version.MODEL_TYPE.IHN_1010GL || mModelType == Version.MODEL_TYPE.IHN_1010GL_I
-                    || mModelType == Version.MODEL_TYPE.IHN_1010GL_I_2443ALT || mModelType == Version.MODEL_TYPE.IHN_1010GL_I_6410ALT) {
-                DeviceLog(null, "setAllLight - Start");
-
-                int onoff = 0;
-                if (OnOff) onoff = 1;
-
-                if (!ServiceMain.Get_HDCIntLightType()) {
-                    Message msg = MainHandler.obtainMessage();
-                    String CmdStr = MakeSendMessageFormat(define.DRIVER_TITLE_BATCHLIGHTHDC, define.APICMD_SINKCTRL, "AllLightControl", onoff, 0, 0, 0, 0);
-                    msg.what = ServiceMain.MSG_DEV_CTR;
-                    msg.obj = CmdStr;
-                    DeviceLog(null, "setAllLight - onoff (cmd:" + CmdStr + ")");
-                    MainHandler.sendMessage(msg);
-                }
-                else {
-                    Message msg = MainHandler.obtainMessage();
-                    String CmdStr = MakeSendMessageFormat(define.DRIVER_TITLE_INTLIGHT, define.APICMD_SINKCTRL, "LightControl", 6, onoff, 0, 0, 0);
-                    msg.what = ServiceMain.MSG_DEV_CTR;
-                    msg.obj = CmdStr;
-                    DeviceLog(null, "setAllLight - onoff (cmd:" + CmdStr + ")");
-                    MainHandler.sendMessage(msg);
-                }
-                return 0;
-            }
-            else {
-                // 대외
-                int [] Get_BatchSW_Info = ServiceMain.dataBaseLoader.data.wallpadDeviceSet.Get_BatchSW_Info;
-                if (Get_BatchSW_Info == null) return -20;
-                if (Get_BatchSW_Info[0] < 3)  return -21;
-                if (Get_BatchSW_Info[0] == 0) return -22;
-
-                if (Get_BatchSW_Info[1] == WallpadDeviceSet.BATCH_TYPE_GENERAL) {
-                    // 일괄소등제어기
-                }
-                else if (Get_BatchSW_Info[1] == WallpadDeviceSet.BATCH_TYPE_SMART) {
-                    // 대외향 스마트스위치
-                }
-                else {
-                    return -23;
-                }
-            }
-        } catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-            return -100;
-        } catch (Exception e) {
-            Log.e("DriverInterOpAPI", "[Exception Error] setAllLight(" + OnOff + ")");
-            //e.printStackTrace();
-            LogUtil.errorLogInfo("", TAG, e);
-            return -100;
-        }
-
-        return -1;
-    }
-
-    /**
-     * 제어기 구분없이 일괄소등 상태를 반환한다.
-     *
-     * @return (boolean) true:일괄소등해제상태(조명ON) , false:일괄소등상태(조명OFF)
-     */
-    public boolean getAllLight() {
-        try {
-            if (mModelType == Version.MODEL_TYPE.IHN_D101 || mModelType == Version.MODEL_TYPE.IHN_D101_I
-                    || mModelType == Version.MODEL_TYPE.IHN_D101K || mModelType == Version.MODEL_TYPE.IHN_D101K_I) {
-                //Log.i(TAG, "[getAllLight] - IHN_D101");
-
-                WallpadDeviceSet wds = new WallpadDeviceSet(ServiceMain.svcContext);
-                int nDistributionPanelType = wds.Get_DistributionPannelType_Info();
-                wds.closeDB();
-
-                boolean bRet = false;
-
-                if (nDistributionPanelType == Version.DISTRIBUTION_MODEL.SMART_DIST) {
-                    // 스마트 분전반
-                    if(ServiceMain.sdb_Controller == null) return true;
-                    bRet = ServiceMain.sdb_Controller.GetAllLightStatus();
-                }
-                else if (nDistributionPanelType == Version.DISTRIBUTION_MODEL.KNX_DIST) {
-                    // KNX 분전반
-                    if(ServiceMain.knx_Controller == null) return true;
-                    bRet = ServiceMain.knx_Controller.GetAllLightStatus();
-                }
-                else {
-                    // 그밖의 경우, 스마트분전반을 기본으로 로딩.
-                    if(ServiceMain.sdb_Controller == null) return true;
-                    bRet = ServiceMain.sdb_Controller.GetAllLightStatus();
-                }
-
-                return bRet;
-            }
-            else if (mModelType == Version.MODEL_TYPE.IHN_1020GL
-                    || mModelType == Version.MODEL_TYPE.IHN_1010GL || mModelType == Version.MODEL_TYPE.IHN_1010GL_I
-                    || mModelType == Version.MODEL_TYPE.IHN_1010GL_I_2443ALT || mModelType == Version.MODEL_TYPE.IHN_1010GL_I_6410ALT)
-            {
-                if (!ServiceMain.Get_HDCIntLightType()) {
-                    if (ServiceMain.allLightHDC_Controller == null) return true;
-                    boolean bRet = AllLightHDC_Controller.GetAllLightStatus();
-                    return bRet;
-                }
-                else {
-                    if (ServiceMain.intLight_Controller == null) return true;
-                    boolean bRet = IntLight_Controller.GetAllLightStatus();
-                    return bRet;
-                }
-            }
-            else {
-                // 대외
-                int [] Get_BatchSW_Info = ServiceMain.dataBaseLoader.data.wallpadDeviceSet.Get_BatchSW_Info;
-                if (Get_BatchSW_Info == null) return false;
-                if (Get_BatchSW_Info[0] < 3)  return false;
-                if (Get_BatchSW_Info[0] == 0) return false;
-
-                if (Get_BatchSW_Info[1] == WallpadDeviceSet.BATCH_TYPE_GENERAL) {
-                    // 일괄소등제어기
-                }
-                else if (Get_BatchSW_Info[1] == WallpadDeviceSet.BATCH_TYPE_SMART) {
-                    // 대외향 스마트스위치
-                }
-                else {
-                    return false;
-                }
-            }
-        }
-        catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-            return false;
-        }
-        catch (Exception e) {
-            Log.e("DriverInterOpAPI", "[Exception Error] getAllLight()");
-            //e.printStackTrace();
-            LogUtil.errorLogInfo("", TAG, e);
-            return false;
-        }
-
-        return false;
-    }
-
-    /**
-     * 조명제어기에 BR을 등록한다.<br>
-     * 현산 대외 모델과 상관없이 동작한다.<br>
-     * <br>
-     * 현산 - 일체형조명제어기 제어<br>
-     * 대외 - 거실조명 : 거실조명제어<br>
-     *       멀티스위치 : 멀티스위치 1번기기 제어<br>
-     *
-     * @param acname - (String) 등록할 name
-     *
-     * @return (int) - >=0 : 성공, <0 : 실패
-     */
-    public int setLightRegBR(String acname) {
-        try {
-            String DriverTitleStr = null;
-
-            if (mModelType == Version.MODEL_TYPE.IHN_D101 || mModelType == Version.MODEL_TYPE.IHN_D101_I
-                    || mModelType == Version.MODEL_TYPE.IHN_D101K || mModelType == Version.MODEL_TYPE.IHN_D101K_I) {
-                //DriverTitleStr = define.DRIVER_TITLE_SDB_LIVINGROOM_LIGHT;
-                WallpadDeviceSet wds = new WallpadDeviceSet(ServiceMain.svcContext);
-                int nDistributionPanelType = wds.Get_DistributionPannelType_Info();
-                wds.closeDB();
-
-                if (nDistributionPanelType == Version.DISTRIBUTION_MODEL.SMART_DIST) {
-                    // 스마트 분전반
-                    DriverTitleStr = define.DRIVER_TITLE_SDB_LIVINGROOM_LIGHT;
-                }
-                else if (nDistributionPanelType == Version.DISTRIBUTION_MODEL.KNX_DIST) {
-                    // KNX 분전반
-                    DriverTitleStr = define.DRIVER_TITLE_KNX_LIVINGROOM_LIGHT;
-                }
-                else {
-                    // 그밖의 경우, 스마트분전반을 기본으로 로딩.
-                    DriverTitleStr = define.DRIVER_TITLE_SDB_LIVINGROOM_LIGHT;
-                }
-            }
-            else if (mModelType == Version.MODEL_TYPE.IHN_1020GL
-                    || mModelType == Version.MODEL_TYPE.IHN_1010GL || mModelType == Version.MODEL_TYPE.IHN_1010GL_I
-                    || mModelType == Version.MODEL_TYPE.IHN_1010GL_I_2443ALT || mModelType == Version.MODEL_TYPE.IHN_1010GL_I_6410ALT) {
-                // 현산 일체형조명제어기
-                DriverTitleStr = define.DRIVER_TITLE_INTLIGHT;
-            }
-            else {
-                // 대외
-                int [] Get_Light_info = ServiceMain.dataBaseLoader.data.wallpadDeviceSet.Get_Light_info;
-                if (Get_Light_info == null)     return -20;
-                if (Get_Light_info.length < 3)  return -21;
-                if (Get_Light_info[0] == 0)     return -22;
-
-                if (Get_Light_info[1] == WallpadDeviceSet.LIGHT_TYPE_LIVING) {
-                    // 거실조명
-                    DriverTitleStr = define.DRIVER_TITLE_LIGHT;
-                }
-                else if (Get_Light_info[1] == WallpadDeviceSet.LIGHT_TYPE_ROOM) {
-                    // 멀티스위치
-                    DriverTitleStr = define.DRIVER_TITLE_MULTISW;
-                }
-                else if (Get_Light_info[1] == WallpadDeviceSet.LIGHT_TYPE_ZEROENERGY_ENERGYMETER) {
-                    // 에너지미터
-                    DriverTitleStr = define.DRIVER_TITLE_ENERGYMETER;
-                }
-                else {
-                    return -23;
-                }
-            }
-
-            if (DriverTitleStr != null) {
-                String CmdStr = DriverTitleStr + ";" + define.APICMD_REGBR + ";" + acname;
-                Message msg = MainHandler.obtainMessage();
-                msg.what = ServiceMain.MSG_DEV_CTR;
-                msg.obj = CmdStr;
-                MainHandler.sendMessage(msg);
-                return 0;
-            }
-        } catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-            return -100;
-        } catch (Exception e) {
-            Log.e("DriverInterOpAPI", "[Exception Error] setLightRegBR(" + acname + ")");
-            //e.printStackTrace();
-            LogUtil.errorLogInfo("", TAG, e);
-            return -100;
-        }
-        return APIErrorCode.NOT_SUPPORT;
-    }
-
-    /**
-     * 조명제어기를 켜고 끈다.<br>
-     * 현산 대외 모델과 상관없이 동작한다.<br>
-     * <br>
-     * 현산 - 일체형조명제어기 제어<br>
-     * 대외 - 거실조명 : 거실조명제어<br>
-     *       멀티스위치 : 멀티스위치 1번기기 제어<br>
-     *
-     * @param MsgWhat - (int) 메시지 타입
-     * @param index   - (int) 제어할 조명 번호
-     * @param OnOff   - (boolean) true:ON , false:OFF
-     *
-     * @return (int) - >=0 : 성공, <0 : 실패
-     */
-    public int setLight(int MsgWhat, int index, boolean OnOff) {
-        // 1. 파라미터 범위체크
-        if (!CheckRangeMsgWhat(MsgWhat)) {
-            Log.w(TAG, "[setLight] MsgWhat - Out Of Range !!! (MsgWhat:" + MsgWhat + ")");
-            return -10;
-        }
-
-        try {
-            if (mModelType == Version.MODEL_TYPE.IHN_D101 || mModelType == Version.MODEL_TYPE.IHN_D101_I
-                    || mModelType == Version.MODEL_TYPE.IHN_D101K || mModelType == Version.MODEL_TYPE.IHN_D101K_I) {
-                // 스마트분전반 - 거실에너지미터 조명 제어
-                DeviceLog(null, "setLight(Sdb_LivingEM) - Start");
-
-                WallpadDeviceSet wds = new WallpadDeviceSet(ServiceMain.svcContext);
-                int nDistributionPanelType = wds.Get_DistributionPannelType_Info();
-                wds.closeDB();
-
-                if (nDistributionPanelType == Version.DISTRIBUTION_MODEL.SMART_DIST) {
-                    // 스마트 분전반
-                    if (ServiceMain.sdb_LivingRoomLight_Controller == null) return -1;
-
-                    if (!(index == (byte)0xFF) && !((index >= 1) && (index <= 4)) ) return -10;
-
-                    if (index != (byte)0xFF) index -= 1;
-
-                    String CmdStr = MakeSendMessageFormat(define.DRIVER_TITLE_SDB_LIVINGROOM_LIGHT, define.APICMD_SINKCTRL, "SetLightOnOff", index, (OnOff)?1:0, 0, 0, 0);
-                    SendDevCtrlMessage(MsgWhat, CmdStr);
-                }
-                else if (nDistributionPanelType == Version.DISTRIBUTION_MODEL.KNX_DIST) {
-                    // KNX 분전반
-                    if (ServiceMain.knx_livingRoomLight_controller == null) return -1;
-
-                    if (!(index == (byte)0xFF) && !((index >= 1) && (index <= 4)) ) return -10;
-
-                    if (index != (byte)0xFF) index -= 1;
-
-                    String CmdStr = MakeSendMessageFormat(define.DRIVER_TITLE_KNX_LIVINGROOM_LIGHT, define.APICMD_SINKCTRL, "SetLightOnOff", index, (OnOff)?1:0, 0, 0, 0);
-                    SendDevCtrlMessage(MsgWhat, CmdStr);
-                }
-                else {
-                    // 그밖의 경우, 스마트분전반을 기본으로 로딩.
-                    if (ServiceMain.sdb_LivingRoomLight_Controller == null) return -1;
-
-                    if (!(index == (byte)0xFF) && !((index >= 1) && (index <= 4))) return -10;
-
-                    if (index != (byte)0xFF) index -= 1;
-
-                    String CmdStr = MakeSendMessageFormat(define.DRIVER_TITLE_SDB_LIVINGROOM_LIGHT, define.APICMD_SINKCTRL, "SetLightOnOff", index, (OnOff)?1:0, 0, 0, 0);
-                    SendDevCtrlMessage(MsgWhat, CmdStr);
-                }
-                return 0;
-            }
-            else if (mModelType == Version.MODEL_TYPE.IHN_1020GL
-                    || mModelType == Version.MODEL_TYPE.IHN_1010GL || mModelType == Version.MODEL_TYPE.IHN_1010GL_I
-                    || mModelType == Version.MODEL_TYPE.IHN_1010GL_I_2443ALT || mModelType == Version.MODEL_TYPE.IHN_1010GL_I_6410ALT) {
-                // 현산
-                DeviceLog(null, "setLight - Start");
-
-                if (!(index == (byte)0xFF) && !((index >= 1) && (index <= 6))) return -10;
-
-                int onoff = 0;
-                if (OnOff) onoff = 1;
-                Message msg = MainHandler.obtainMessage();
-                String CmdStr = MakeSendMessageFormat(define.DRIVER_TITLE_INTLIGHT, define.APICMD_SINKCTRL, "LightControl", index, onoff, 0, 0, 0);
-
-                msg.what = MsgWhat;
-                msg.obj = CmdStr;
-                DeviceLog("HIGH","setLight - onoff (cmd:" + CmdStr + ")");
-                MainHandler.sendMessage(msg);
-
-                return 0;
-            }
-            else {
-                // 대외
-                int [] Get_Light_info = ServiceMain.dataBaseLoader.data.wallpadDeviceSet.Get_Light_info;
-                if (Get_Light_info == null) return -20;
-                if (Get_Light_info.length < 3) return -21;
-                if (Get_Light_info[0] == 0) return -22;
-
-                if (Get_Light_info[1] == WallpadDeviceSet.LIGHT_TYPE_LIVING) {
-                    // 거실조명
-                    DeviceLog(null, "setLight - Start");
-
-                    if (!(index == (byte)0xFF) && !((index >= 1) && (index <= 8))) return -10;
-
-                    int onoff = 0;
-                    if (OnOff) onoff = 1;
-                    Message msg = MainHandler.obtainMessage();
-                    String CmdStr = MakeSendMessageFormat(define.DRIVER_TITLE_LIGHT, define.APICMD_SINKCTRL, "SetLightOnOff", index, onoff, 0, 0, 0);
-                    msg.what = MsgWhat;
-                    msg.obj = CmdStr;
-                    DeviceLog("HIGH","setLight - onoff (cmd:" + CmdStr + ")");
-                    MainHandler.sendMessage(msg);
-                    return 0;
-                }
-                else if (Get_Light_info[1] == WallpadDeviceSet.LIGHT_TYPE_ROOM) {
-                    // 멀티스위치 1번기기
-                    DeviceLog(null, "setLight - Start");
-
-                    if (!(index == (byte)0xFF) && !((index >= 1) && (index <= 8))) return -10;
-
-                    int onoff = 0;
-                    if (OnOff) onoff = 1;
-
-                    byte LightIdx = (byte)index;
-                    if (index != define.DEVICE_ALL_OR_NOTHING) LightIdx--;
-
-                    Message msg = MainHandler.obtainMessage();
-                    String CmdStr = MakeSendMessageFormat(define.DRIVER_TITLE_MULTISW, define.APICMD_SINKCTRL, "SetLightOnOff", 0, LightIdx, onoff, 0, 0);
-                    msg.what = MsgWhat;
-                    msg.obj = CmdStr;
-                    DeviceLog("HIGH","setLight - onoff (cmd:" + CmdStr + ")");
-                    MainHandler.sendMessage(msg);
-
-                    return 0;
-                }
-                //제로에너지하우스 에너지미터 사용 시
-                else if (Get_Light_info[1] == WallpadDeviceSet.LIGHT_TYPE_ZEROENERGY_ENERGYMETER) {
-                    // 에너지미터 1번 기기
-                    DeviceLog(null, "setLight(EnergyMeter) - Start");
-
-                    if (ServiceMain.energyMeter_Controller == null) return -1;
-
-                    if (!(index == (byte)0xFF) && !((index >= 1) && (index <= 8))) return -10;
-
-                    int onoff = 0;
-                    if (OnOff) onoff = 1;
-
-                    byte LightIdx = (byte)index;
-                    if (index != define.DEVICE_ALL_OR_NOTHING) LightIdx--;
-
-                    String CmdStr = MakeSendMessageFormat(define.DRIVER_TITLE_ENERGYMETER, define.APICMD_SINKCTRL, "SetLightOnOff", 0, LightIdx, onoff, 0, 0);
-                    SendDevCtrlMessage(ServiceMain.MSG_DEV_CTR, CmdStr);
-                    DeviceLog(null, "setEnergyMeterLightOnOff - onoff (cmd:" + CmdStr + ")");
-                    return 0;
-                }
-                else {
-                    return -23;
-                }
-            }
-        } catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-            return -100;
-        } catch (Exception e) {
-            Log.e("DriverInterOpAPI", "[Exception Error] setLight");
-            //e.printStackTrace();
-            LogUtil.errorLogInfo("", TAG, e);
-            return -100;
-        }
-
-        //return APIErrorCode.NOT_SUPPORT;
-    }
-
-
-    public String sdbRefresh(byte type, byte index) {
-        String ret = "";
-
-        if (type == ENERGY_METER) {
-            DeviceLog(null, "setLight(EnergyMeter) - Start");
-            if (ServiceMain.sdb_Controller == null) return null;
-
-            if (!(index == (byte)0xFF) && !((index >= 1) && (index <= 8))) return null;
-
-            String CmdStr = MakeSendMessageFormat(define.DRIVER_TITLE_SMART_DISTRIBUTION_BD, define.APICMD_NOSINKCTRL, "Refresh", index, 0, 0, 0, 0);
-
-            SendDevCtrlMessage(ServiceMain.MSG_DEV_CTR, CmdStr);
-            DeviceLog(null, "[sdbRefresh] - (cmd:" + CmdStr + ")");
-
-            return ServiceMain.sdb_Controller.GetAllLightStatus()+"";
-        }
-        else if (type == ENERGY_CONT) {
-
-        }
-        else if (type == INTPOWER_CONT) {
-
-        }
-        else if (type == DC_APU) {
-
-        }
-        else if (type == ALL) {
-
-        }
-
-        return ret;
-    }
-
-    /**
-     * 조명제어기를 상태를 가져온다.<br>
-     * 현산 대외 모델과 상관없이 동작한다.<br>
-     * <br>
-     * 현산 - 일체형조명제어기 제어<br>
-     * 대외 - 거실조명 : 거실조명제어<br>
-     *       멀티스위치 : 멀티스위치 1번기기 제어<br>
-     *
-     * @param index - (byte) 가져올 조명 인덱스
-     *
-     * @return (boolean) - true : 켜짐, false : 꺼짐
-     */
-    public boolean getLight(byte index) {
-        try {
-            if (mModelType == Version.MODEL_TYPE.IHN_D101 || mModelType == Version.MODEL_TYPE.IHN_D101_I
-                    || mModelType == Version.MODEL_TYPE.IHN_D101K || mModelType == Version.MODEL_TYPE.IHN_D101K_I) {
-                WallpadDeviceSet wds = new WallpadDeviceSet(ServiceMain.svcContext);
-                int nDistributionPanelType = wds.Get_DistributionPannelType_Info();
-                wds.closeDB();
-
-                if (nDistributionPanelType == Version.DISTRIBUTION_MODEL.SMART_DIST) {
-                    // 스마트 분전반
-                    return ServiceMain.sdb_LivingRoomLight_Controller.GetLightOnOff(index);
-                }
-                else if (nDistributionPanelType == Version.DISTRIBUTION_MODEL.KNX_DIST) {
-                    // KNX 분전반
-                    return ServiceMain.knx_livingRoomLight_controller.GetLightOnOff(index);
-                }
-                else {
-                    // 그밖의 경우, 스마트분전반을 기본으로 로딩.
-                    return ServiceMain.sdb_LivingRoomLight_Controller.GetLightOnOff(index);
-                }
-            }
-            else if (mModelType == Version.MODEL_TYPE.IHN_1020GL
-                    || mModelType == Version.MODEL_TYPE.IHN_1010GL || mModelType == Version.MODEL_TYPE.IHN_1010GL_I
-                    || mModelType == Version.MODEL_TYPE.IHN_1010GL_I_2443ALT || mModelType == Version.MODEL_TYPE.IHN_1010GL_I_6410ALT)
-            {
-                return IntLight_Controller.GetLightStatus(index);
-            }
-            else {
-                int [] Get_Light_info = ServiceMain.dataBaseLoader.data.wallpadDeviceSet.Get_Light_info;
-                if (Get_Light_info[1] == WallpadDeviceSet.LIGHT_TYPE_LIVING) {
-                    return ServiceMain.light_Controller.Get_OnOff()[index];
-                }
-                else if (Get_Light_info[1] == WallpadDeviceSet.LIGHT_TYPE_ROOM) {
-                    return ServiceMain.multiSwitch_Controller.getLightPower((byte)0, index);
-                }
-                else if (Get_Light_info[1] == WallpadDeviceSet.LIGHT_TYPE_ZEROENERGY_ENERGYMETER) {
-                    return ServiceMain.energyMeter_Controller.GetLightOnOff((byte)0, index);
-                }
-            }
-        } catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-            return false;
-        } catch (Exception e) {
-            Log.e("DriverInterOpAPI", "[Exception Error] getLight()");
-            //e.printStackTrace();
-            LogUtil.errorLogInfo("", TAG, e);
-            return false;
-        }
-
-        return false;
-    }
-
-    public int setLightProgramControl(byte ProgramIdx, byte OnOff) {
-        try {
-            if (mModelType == Version.MODEL_TYPE.IHN_1020GL
-                    || mModelType == Version.MODEL_TYPE.IHN_1010GL || mModelType == Version.MODEL_TYPE.IHN_1010GL_I
-                    || mModelType == Version.MODEL_TYPE.IHN_1010GL_I_2443ALT || mModelType == Version.MODEL_TYPE.IHN_1010GL_I_6410ALT) {
-                DeviceLog("HIGH","setLightProgramControl - Start");
-
-                // 1. Parameter Check
-                switch (ProgramIdx) {
-                    case (byte) 0x01:  break;
-                    case (byte) 0x02:  break;
-                    default: return APIErrorCode.INVALIDPARAMETER;
-                }
-
-                switch (OnOff) {
-                    case 0x00: case 0x01: case 0x02: break;
-                    default: return APIErrorCode.INVALIDPARAMETER;
-                }
-
-                Message msg = MainHandler.obtainMessage();
-                String CmdStr = MakeSendMessageFormat(define.DRIVER_TITLE_INTLIGHT, define.APICMD_SINKCTRL, "LightProgramControl", ProgramIdx, OnOff, 0, 0, 0);
-
-                msg.what = ServiceMain.MSG_DEV_CTR;
-                msg.obj = CmdStr;
-                DeviceLog("HIGH","setLightProgramControl - onoff (cmd:" + CmdStr + ")");
-                MainHandler.sendMessage(msg);
-
-                return 0;
-            }
-            else {
-                Log.w(TAG, "[setLightProgramControl] not supported model type -> " + mModelType);
-            }
-        } catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-            return -100;
-        } catch (Exception e) {
-            Log.e("DriverInterOpAPI", "[Exception Error] setLightProgramControl(" + OnOff + ")");
-            //e.printStackTrace();
-            LogUtil.errorLogInfo("", TAG, e);
-            return -100;
-        }
-
-        return -1;
-    }
-
-    /**
-     * 에너지미터의 전체 조명을 제어한다.
-     *
-     * @param OnOff - (boolean) true : 전체ON , false : 전체OFF
-     *
-     * @return (int) - >=0 : 성공, <0 : 실패
-     */
-    public int setEnergyMeterAllLightOnOff(boolean OnOff) {
-        try {
-            if (mModelType == Version.MODEL_TYPE.IHN_1020GL
-                    || mModelType == Version.MODEL_TYPE.IHN_1010GL || mModelType == Version.MODEL_TYPE.IHN_1010GL_I
-                    || mModelType == Version.MODEL_TYPE.IHN_1010GL_I_2443ALT || mModelType == Version.MODEL_TYPE.IHN_1010GL_I_6410ALT) {
-                DeviceLog("HIGH","setEnergyMeterAllLightOnOff - Start");
-
-                if (ServiceMain.energyMeter_Controller == null) return -1;
-                //if((index <= 0) || (index >= 6)) return -10;
-
-                int onoff = 0;
-                if (OnOff) onoff = 1;
-
-                String CmdStr = MakeSendMessageFormat(define.DRIVER_TITLE_ENERGYMETER, define.APICMD_SINKCTRL, "SetAllLightOnOff", onoff, 0, 0, 0, 0);
-
-                SendDevCtrlMessage(ServiceMain.MSG_DEV_CTR, CmdStr);
-                DeviceLog("HIGH","setLight - onoff (cmd:" + CmdStr + ")");
-
-                return 0;
-            }
-        } catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-            return -100;
-        } catch (Exception e) {
-            Log.e("DriverInterOpAPI", "[Exception Error] setEnergyMeterAllLightOnOff(" + OnOff + ")");
-            //e.printStackTrace();
-            LogUtil.errorLogInfo("", TAG, e);
-            return -100;
-        }
-        return -2;
-    }
-
-    /**
-     * 에너지미터의 개별방 조명 ON/OFF 제어
-     *
-     * @param RoomIndex   - (byte) 방인덱스     (00:1번방 ~ 05:6번방) * 방개수를 초과할수 없음.
-     * @param LightIndex  - (byte) 조명인덱스  (00:1번조명 ~ 03:4번조명, FF:전체)
-     * @param OnOff       - (boolean) 변경할 ON/OFF 상태 (true : ON , false : OFF)
-     *
-     * @return (int) - >=0 : 성공, <0 : 실패
-     */
-    public int setEnergyMeterLightOnOff(byte RoomIndex, byte LightIndex, boolean OnOff) {
-        try {
-            if (mModelType == Version.MODEL_TYPE.IHN_1020GL
-                    || mModelType == Version.MODEL_TYPE.IHN_1010GL || mModelType == Version.MODEL_TYPE.IHN_1010GL_I
-                    || mModelType == Version.MODEL_TYPE.IHN_1010GL_I_2443ALT || mModelType == Version.MODEL_TYPE.IHN_1010GL_I_6410ALT) {
-                DeviceLog(null ,"setEnergyMeterLightOnOff - Start");
-
-                if (ServiceMain.energyMeter_Controller == null) return -1;
-
-                int onoff = 0;
-                if (OnOff) onoff = 1;
-
-                String CmdStr = MakeSendMessageFormat(define.DRIVER_TITLE_ENERGYMETER, define.APICMD_SINKCTRL, "SetLightOnOff", RoomIndex, LightIndex, onoff, 0, 0);
-
-                SendDevCtrlMessage(ServiceMain.MSG_DEV_CTR, CmdStr);
-                DeviceLog(null, "setEnergyMeterLightOnOff - onoff (cmd:" + CmdStr + ")");
-
-                return 0;
-            }
-        } catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-            return -100;
-        } catch (Exception e) {
-            Log.e("DriverInterOpAPI", "[Exception Error] setEnergyMeterLightOnOff(" + OnOff + ")");
-            //e.printStackTrace();
-            LogUtil.errorLogInfo("", TAG, e);
-            return -100;
-        }
-
-        return -2;
-    }
-
-    /**
-     * 에너지미터의 개별방 콘센트 ON/OFF 제어
-     *
-     * @param RoomIndex    - (byte) 방인덱스     (00:1번방 ~ 05:6번방) * 방개수를 초과할수 없음.
-     * @param ConcentIndex - (byte) 콘센트인덱스
-     * @param OnOff        - (boolean) 변경할 ON/OFF 상태 (true : ON , false : OFF)
-     *
-     * @return (int) - >=0 : 성공, <0 : 실패
-     */
-    public int setEnergyMeterConcentOnOff(byte RoomIndex, byte ConcentIndex, boolean OnOff) {
-        try {
-            if (mModelType == Version.MODEL_TYPE.IHN_1020GL
-                    || mModelType == Version.MODEL_TYPE.IHN_1010GL || mModelType == Version.MODEL_TYPE.IHN_1010GL_I
-                    || mModelType == Version.MODEL_TYPE.IHN_1010GL_I_2443ALT || mModelType == Version.MODEL_TYPE.IHN_1010GL_I_6410ALT) {
-                DeviceLog(null ,"setEnergyMeterConcentOnOff - Start");
-
-                if (ServiceMain.energyMeter_Controller == null) return -1;
-
-                int onoff = 0;
-                if (OnOff) onoff = 1;
-
-                String CmdStr = MakeSendMessageFormat(define.DRIVER_TITLE_ENERGYMETER, define.APICMD_SINKCTRL, "SetConcentOnOff", RoomIndex, ConcentIndex, onoff, 0, 0);
-
-                SendDevCtrlMessage(ServiceMain.MSG_DEV_CTR, CmdStr);
-                DeviceLog(null, "setEnergyMeterConcentOnOff - onoff (cmd:" + CmdStr + ")");
-
-                return 0;
-            }
-
-        } catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-            return -100;
-        } catch (Exception e) {
-            Log.e("DriverInterOpAPI", "[Exception Error] setEnergyMeterConcentOnOff(" + OnOff + ")");
-            //e.printStackTrace();
-            LogUtil.errorLogInfo("", TAG, e);
-            return -100;
-        }
-
-        return -2;
-    }
-
-    /**
-     * 스마트분전반의 전체 조명을 제어한다.
-     *
-     * @param OnOff   - (boolean) 조명 ON/OFF 상태
-     * @param Dimming - (byte) 변경할 디밍 상태
-     * @param Color   - (byte) 변경할 색온도 상태
-     * @param ColorControl   - (boolean) 색온도 제어 여부
-     *
-     * @return (int) - >=0 : 성공, <0 : 실패
-     */
-    public int setSdbAllLightControl(boolean OnOff, byte Dimming, byte Color, boolean ColorControl) {
-        try {
-            if (mModelType == Version.MODEL_TYPE.IHN_D101 || mModelType == Version.MODEL_TYPE.IHN_D101_I
-                    || mModelType == Version.MODEL_TYPE.IHN_D101K || mModelType == Version.MODEL_TYPE.IHN_D101K_I) {
-                DeviceLog(null ,"setSdbAllLightControl(OnOff:" + OnOff + ", Dimming:" + Dimming + ", Color:" + Color + ", ColorControl:" + ColorControl + ")");
-
-                if (ServiceMain.sdb_Controller == null) return -1;
-
-                String CmdStr = MakeSendMessageFormat(define.DRIVER_TITLE_SMART_DISTRIBUTION_BD,
-                        define.APICMD_SINKCTRL,
-                        "SetAllLightControl",
-                        (OnOff)?0x01:0x02, Dimming, Color,
-                        (ColorControl)?0x01:0x00, 0);
-
-                SendDevCtrlMessage(ServiceMain.MSG_DEV_CTR, CmdStr);
-                DeviceLog(null, "setSdbAllLightControl - (cmd:" + CmdStr + ")");
-
-                return 0;
-            }
-        } catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-            return -100;
-        } catch (Exception e) {
-            Log.e("DriverInterOpAPI", "[Exception Error] setSdbAllLightControl(" + OnOff + ")");
-            //e.printStackTrace();
-            LogUtil.errorLogInfo("", TAG, e);
-            return -100;
-        }
-        return APIErrorCode.NOT_SUPPORT;
-    }
-
-	/**
-	 * 스마트분전반 각방의 조명을 제어한다.
-	 *
-     * @param RoomIndex -(byte) 제어할 방 인덱스 (0:거실EM,1:침실EM 첫번째...)
-	 * @param OnOff - (boolean) 조명 ON/OFF 상태
-	 * @return (int) - >=0 : 성공, <0 : 실패
-	 */
-    public int setSdbEachRoomLightOnOffControl(byte RoomIndex, boolean OnOff) {
-		try {
-			if (mModelType == Version.MODEL_TYPE.IHN_D101 || mModelType == Version.MODEL_TYPE.IHN_D101_I
-                    || mModelType == Version.MODEL_TYPE.IHN_D101K || mModelType == Version.MODEL_TYPE.IHN_D101K_I) {
-				DeviceLog(null ,"D101 - setSdbEachRoomLightControl - Start");
-
-				if (ServiceMain.sdb_Controller == null) return -1;
-				if (ServiceMain.sdb_LivingRoomLight_Controller == null) return -1;
-
-				// 조명이 켜져 있을 때, 해당 방의 조명을 끄도록 한다.
-				if (RoomIndex == 0) {
-                    // 거실
-					DeviceLog(null, "setSdbEachRoomLightControl - Living(Liv.EM) light CTR ~~~");
-
-                    String CmdStr = MakeSendMessageFormat(define.DRIVER_TITLE_SDB_LIVINGROOM_LIGHT, define.APICMD_SINKCTRL, "SetLightOnOff", define.DEVICE_ALL_OR_NOTHING, (OnOff)?0x01:0x00,0,0,0);
-                    //******* 모든조명 / 조명 ON/OFF / Don't care / Don't care / Don't care
-
-                    SendDevCtrlMessage(ServiceMain.MSG_DEV_CTR, CmdStr);
-                    DeviceLog(null, "setSdbEachRoomLightControl - (cmd:" + CmdStr + ")");
-
-					return 0;
-				}
-				else {
-                    DeviceLog(null, "setSdbEachRoomLightControl - Each Room(Bed.EM) light CTR ~~~");
-
-					String CmdStr = MakeSendMessageFormat(define.DRIVER_TITLE_SMART_DISTRIBUTION_BD, define.APICMD_SINKCTRL, "SetLightOnOff", RoomIndex-1, define.DEVICE_ALL_OR_NOTHING, (OnOff)?0x01:0x00,0,0);
-					//*******침실EM ID / 모든조명 / 조명 ON/OFF / Don't care / Don't care
-
-					SendDevCtrlMessage(ServiceMain.MSG_DEV_CTR, CmdStr);
-					DeviceLog(null, "setSdbEachRoomLightControl - (cmd:" + CmdStr + ")");
-					return 0;
-				}
-			}
-		} catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-            return -100;
-        } catch (Exception e) {
-			Log.e("DriverInterOpAPI", "[Exception Error] setSdbEachRoomLightControl(" + OnOff + ")");
-			//e.printStackTrace();
-            LogUtil.errorLogInfo("", TAG, e);
-			return -100;
-		}
-		return APIErrorCode.NOT_SUPPORT;
-	}
-
-    /**
-     * 스마트분전반 각방의 디밍을 제어한다.
-     *
-     * @param RoomIndex -(byte) 제어할 방 인덱스 (0:거실EM,1:침실EM 첫번째...)
-     * @param DimLevel - (byte) 제어할 디밍 단계
-     * @return (int) - >=0 : 성공, <0 : 실패
-     */
-    public int setSdbEachRoomDimControl(byte RoomIndex, byte LightIndex, byte DimLevel) {
-        try {
-            if (mModelType == Version.MODEL_TYPE.IHN_D101 || mModelType == Version.MODEL_TYPE.IHN_D101_I
-                    || mModelType == Version.MODEL_TYPE.IHN_D101K || mModelType == Version.MODEL_TYPE.IHN_D101K_I) {
-                DeviceLog(null ,"D101 - setSdbEachRoomDimControl - Start");
-
-                if (ServiceMain.sdb_Controller == null) return -1;
-                if (ServiceMain.sdb_LivingRoomLight_Controller == null) return -1;
-
-                // 조명이 켜져 있을 때, 해당 방의 조명을 끄도록 한다.
-                if (RoomIndex == 0) {
-                    // 거실
-                    DeviceLog(null, "setSdbEachRoomDimControl - Living(Liv.EM) Dim CTR ~~~");
-
-                    String CmdStr = MakeSendMessageFormat(define.DRIVER_TITLE_SDB_LIVINGROOM_LIGHT, define.APICMD_SINKCTRL, "SetLightDimming", LightIndex, DimLevel,0,0,0);
-                    //******* 모든조명 / 조명 ON/OFF / Don't care / Don't care / Don't care
-
-                    SendDevCtrlMessage(ServiceMain.MSG_DEV_CTR, CmdStr);
-                    DeviceLog(null, "setSdbEachRoomDimControl - (cmd:" + CmdStr + ")");
-
-                    return 0;
-                }
-                else {
-                    DeviceLog(null, "setSdbEachRoomDimControl - Each Room(Bed.EM) Dim CTR ~~~");
-
-                    String CmdStr = MakeSendMessageFormat(define.DRIVER_TITLE_SMART_DISTRIBUTION_BD, define.APICMD_SINKCTRL, "SetLightDimming", RoomIndex, LightIndex, DimLevel,0,0);
-                    //*******침실EM ID / 모든조명 / 조명 ON/OFF / Don't care / Don't care
-
-                    SendDevCtrlMessage(ServiceMain.MSG_DEV_CTR, CmdStr);
-                    DeviceLog(null, "setSdbEachRoomDimControl - (cmd:" + CmdStr + ")");
-
-                    return 0;
-                }
-            }
-        } catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-            return -100;
-        } catch (Exception e) {
-            Log.e("DriverInterOpAPI", "[Exception Error] setSdbEachRoomDimControl(" + DimLevel + ")");
-            //e.printStackTrace();
-            LogUtil.errorLogInfo("", TAG, e);
-            return -100;
-        }
-
-        return APIErrorCode.NOT_SUPPORT;
-    }
-
-    /**
-     * 실시간 검침기에 전력 누적전력사용량 저장명령을 내린다.
-     *
-     * @return (int) - >=0 : 성공, <0 : 실패
-     */
-    public int setRealTimeMeterElecAccSave() {
-        try {
-            if (mModelType == Version.MODEL_TYPE.IHN_D101 || mModelType == Version.MODEL_TYPE.IHN_D101_I
-                    || mModelType == Version.MODEL_TYPE.IHN_D101K || mModelType == Version.MODEL_TYPE.IHN_D101K_I) {
-                DeviceLog(null ,"setRealTimeMeterElecAccSave()");
-
-                if (ServiceMain.realTimeMeter_Controller == null) return -1;
-
-                String CmdStr = MakeSendMessageFormat(define.DRIVER_TITLE_REALTIMEMETER, define.APICMD_NOSINKCTRL, "ElecAccSave", 0, 0, 0, 0, 0);
-
-                SendDevCtrlMessage(ServiceMain.MSG_DEV_CTR, CmdStr);
-                DeviceLog(null, "setSdbAllLightControl - (cmd:" + CmdStr + ")");
-
-                return 0;
-            }
-        } catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-            return -100;
-        } catch (Exception e) {
-            Log.e("DriverInterOpAPI", "[Exception Error] setRealTimeMeterElecAccSave()");
-            //e.printStackTrace();
-            LogUtil.errorLogInfo("", TAG, e);
-            return -100;
-        }
-
-        return APIErrorCode.NOT_SUPPORT;
-    }
-
-
-
-
-
-
-
-
-
-
-    /**
-     * 시스템에어컨에 BR을 등록한다.<br>
-     * 현산 대외 모델과 상관없이 동작한다.<br>
-     *
-     * @param acname - (String) 등록할 name
-     *
-     * @return (int) - >=0 : 성공, <0 : 실패
-     */
-    public int setAirconRegBR(String acname) {
-        try {
-            WallpadDeviceSet mWallpadDeviceSet = new WallpadDeviceSet(ServiceMain.svcContext);
-            int nAirconSetting = mWallpadDeviceSet.Get_AirCON_Info();
-            mWallpadDeviceSet.closeDB();
-
-            String DriverTitleStr = null;
-
-            if (nAirconSetting == WallpadDeviceSet.SYSTEMAIRCON_SAMSUNG_AIR
-                    || nAirconSetting == WallpadDeviceSet.SYSTEMAIRCON_SAMSUNG_AIR_HEAT
-                    || nAirconSetting == WallpadDeviceSet.SYSTEMAIRCON_LG_AIR
-                    || nAirconSetting == WallpadDeviceSet.SYSTEMAIRCON_LG_AIR_HEAT
-                    || nAirconSetting == WallpadDeviceSet.SYSTEMAIRCON_ETC) {
-                DriverTitleStr = define.DRIVER_TITLE_AIRCON;
-            }
-            else return -23;
-
-            if (DriverTitleStr != null) {
-                String CmdStr = DriverTitleStr + ";" + define.APICMD_REGBR + ";" + acname;
-                Message msg = MainHandler.obtainMessage();
-                msg.what = ServiceMain.MSG_DEV_CTR;
-                msg.obj = CmdStr;
-                MainHandler.sendMessage(msg);
-                return 0;
-            }
-        } catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-            return -100;
-        } catch (Exception e) {
-            Log.e("DriverInterOpAPI", "[Exception Error] setAirconRegBR(" + acname + ")");
-            //e.printStackTrace();
-            LogUtil.errorLogInfo("", TAG, e);
-            return -100;
-        }
-        return APIErrorCode.NOT_SUPPORT;
-    }
-
-    /**
-     * 조명제어기를 켜고 끈다.<br>
-     * 현산 대외 모델과 상관없이 동작한다.<br>
-     * <br>
-     * 현산 - 일체형조명제어기 제어<br>
-     * 대외 - 거실조명 : 거실조명제어<br>
-     *       멀티스위치 : 멀티스위치 1번기기 제어<br>
-     *
-     * @param MsgWhat - (int) 메시지 타입
-     *
-     * @return (int) - >=0 : 성공, <0 : 실패
-     */
-    public int ctrlAircon(int MsgWhat, byte hIndex, byte hCtrlOption, byte hSetData, byte hSetTemper) {
-        // 1. 파라미터 범위체크
-        if (!CheckRangeMsgWhat(MsgWhat)) {
-            Log.w(TAG, "[ctrlAircon] MsgWhat - Out Of Range !!! (MsgWhat:" + MsgWhat + ")");
-            return -10;
-        }
-
-        try {
-            if (ServiceMain.systemAircon_controller == null) return -1;
-
-            Log.i(TAG, "[ctrlAircon] hIndex [" + String.format("0x%02X", hIndex) + "], hCtrlOption [" + String.format("0x%02X", hCtrlOption) + "], hSetData [" + String.format("0x%02X", hSetData) + "], hSetTemper [" + String.format("0x%02X", hSetTemper) + "]");
-            String CmdStr = MakeSendMessageFormat(define.DRIVER_TITLE_AIRCON, define.APICMD_SINKCTRL, "SetUnitDeviceStatusV2", hIndex - 1, hCtrlOption, hSetData, hSetTemper, 0);
-            SendDevCtrlMessage(MsgWhat, CmdStr);
-
-            return 0;
-
-        } catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-            return -100;
-        } catch (Exception e) {
-            Log.e("DriverInterOpAPI", "[Exception Error] ctrlAircon(int MsgWhat, byte hIndex, byte hCtrlOption, byte hSetData, byte hSetTemper)");
-            //e.printStackTrace();
-            LogUtil.errorLogInfo("", TAG, e);
-            return -100;
-        }
-
-        //return APIErrorCode.NOT_SUPPORT;
-    }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-    /**
-     * 제어시 사용되는 SendCMD 및 Return Value Check 의 공통부분 메소드이다.
-     *
-     * @param TitleStr - (String) 드라이버 타이틀
-     * @param MainCMD  - (String) 주 명령어    (define.APICMD_SINKCTRL  or  define.APICMD_NOSINKCTRL)
-     * @param SubCMD   - (String) 서브 명령어
-     * @param param1   - (int) 첫번째 파라미터
-     * @param param2   - (int) 두번째 파라미터
-     * @param param3   - (int) 세번째 파라미터
-     * @param param3   - (int) 네번째 파라미터
-     * @param param3   - (int) 다섯번째 파라미터
-     *
-     * @return (String) 결과
-     */
-    private String MakeSendMessageFormat(String TitleStr, String MainCMD, String SubCMD, int param1, int param2, int param3, int param4, int param5) {
-        return String.format("%s;%s;%s:%d:%d:%d:%d:%d", TitleStr, MainCMD, SubCMD, param1, param2, param3, param4, param5);
-    }
-
-    /**
-     * 제어시 사용되는 SendCMD 및 Return Value Check 의 공통부분 메소드이다.
-     *
-     * @param TitleStr - (String) 드라이버 타이틀
-     * @param MainCMD  - (String) 주 명령어    (define.APICMD_SINKCTRL  or  define.APICMD_NOSINKCTRL)
-     * @param SubCMD   - (String) 서브 명령어
-     * @param param   - (byte[]) byte[] 파라미터
-     *
-     * @return (String) 결과
-     */
-    private String MakeSendMessageFormat(String TitleStr, String MainCMD, String SubCMD, byte[] param) {
-        String CmdStr = String.format("%s;%s;%s:", TitleStr, MainCMD, SubCMD);
-        for (int i=0 ; i<param.length ; i++) CmdStr += param[i] + ":";
-        return CmdStr;
-    }
-
-    /**
-     * 드라이버에 제어 메시지를 전달한다.
-     *
-     * @param MsgWhat - (int) 메시지 타입
-     * @param CmdStr  - (String) 전달할 명령어 String
-     */
-    private void SendDevCtrlMessage(int MsgWhat, String CmdStr) {
-        Message msg = MainHandler.obtainMessage();
-        msg.what = MsgWhat;
-        msg.obj = CmdStr;
-        MainHandler.sendMessage(msg);
-    }
-
-    /**
-     * 설정온도 소수점 0.5 도 존재 유무를 판별한다.
-     *
-     * @param n - (double) 값
-     *
-     * @return  - (boolean) true : 있음 , false : 없음
-     */
-    private boolean PointExist(double n) {
-        double FilterData = Double.parseDouble(String.format("%.1f", n));
-        int IntValue = (int)FilterData;
-        double Point = FilterData - IntValue;
-
-        if (Point >= 0.5) return true;
-        return false;
-    }
-}
+package com.artncore.wallpaddevservice.driver;
+
+import kr.co.icontrols.wallpadsupport.Version;
+import android.os.Handler;
+import android.os.Message;
+import android.util.Log;
+
+import com.artncore.WallPadDataMgr.WallpadDeviceSet;
+import com.artncore.commons.APIErrorCode;
+import com.artncore.commons.DataClasses;
+import com.artncore.commons.define;
+import com.artncore.commons.DataClasses.HeatingV2;
+import com.artncore.wallpaddevservice.ServiceMain;
+
+import com.util.LogUtil;
+import static com.artncore.wallpaddevservice.driver.Sdb_Controller.DEVICE_INDEX.ALL;
+import static com.artncore.wallpaddevservice.driver.Sdb_Controller.DEVICE_INDEX.DC_APU;
+import static com.artncore.wallpaddevservice.driver.Sdb_Controller.DEVICE_INDEX.ENERGY_CONT;
+import static com.artncore.wallpaddevservice.driver.Sdb_Controller.DEVICE_INDEX.ENERGY_METER;
+import static com.artncore.wallpaddevservice.driver.Sdb_Controller.DEVICE_INDEX.INTPOWER_CONT;
+
+public class DriverInterOpAPI {
+    private final String TAG = "DriverInterOpAPI";
+
+    Handler MainHandler;
+
+    private int mModelType = Version.MODEL_TYPE.OTHER;
+
+    public DriverInterOpAPI(Handler setHandler) {
+        MainHandler = setHandler;
+        mModelType = Version.getModelType();
+    }
+
+    public void DeviceLog(String tag, String msg) {
+        Log.d("ServiceTest",APIErrorCode.GetLogPrefix()+" Driver Inter  : "+ msg);
+    }
+
+    public int GetDoorLockStatus() {
+        if (ServiceMain.dataBaseLoader.data.wallpadDeviceSet.Get_DoorLock_Info[1] == WallpadDeviceSet.DOORLOCK_TYPE_RF) {
+            if (ServiceMain.dLock_Controller != null) {
+                return DLock_Controller.GetDoorStatus();
+            }
+            else {
+                return APIErrorCode.DEVICEISNOTREADY;
+            }
+        }
+        else if (ServiceMain.dataBaseLoader.data.wallpadDeviceSet.Get_DoorLock_Info[1] == WallpadDeviceSet.DOORLOCK_TYPE_FINGERPRINT) {
+            if (ServiceMain.fp_dLock_controller != null) {
+                return FP_DLock_Controller.GetDoorStatus();
+            }
+            else {
+                return APIErrorCode.DEVICEISNOTREADY;
+            }
+        }
+        return APIErrorCode.DEVICEISNOTREADY;
+    }
+
+    /**
+     * 드라이버간 명령어 전송시 TYPE의 범위를 체크한다.
+     *
+     * @param MsgWhat - (int) 체크할 MsgWhat
+     *
+     * @return (boolean) true : 정상, false : 범위이탈
+     */
+    private boolean CheckRangeMsgWhat(int MsgWhat) {
+        if (MsgWhat == ServiceMain.MSG_DEV_CTR) return true;
+        if (MsgWhat == ServiceMain.MSG_REMOCON_CTR) return true;
+        return false;
+    }
+
+    /**
+     * 가스 - 밸브 닫기
+     *
+     * @param MsgWhat   - (int) 메시지 타입
+     *
+     * @return (int) - >=0 : 성공, <0 : 실패
+     */
+    public int Gas_SetClose(int MsgWhat) {
+        DeviceLog(null, "[Gas_SetClose] Start");
+
+        // 1. 드라이버 로딩체크 & 동작여부 체크
+        if (ServiceMain.gasValve_Controller == null) {
+            Log.w(TAG, "[Gas_SetClose] dLock_Controller is null !!!");
+            return -1;
+        }
+
+        // 2. 파라미터 범위체크
+        if (!CheckRangeMsgWhat(MsgWhat)) {
+            Log.w(TAG, "[Gas_SetClose] MsgWhat - Out Of Range !!! (MsgWhat:" + MsgWhat + ")");
+            return -2;
+        }
+
+        // 3. Make Param & Message
+        String CmdStr = MakeSendMessageFormat(define.DRIVER_TITLE_GASVALVE, define.APICMD_SINKCTRL, "SetClose", 0, 0, 0, 0, 0);
+
+        // 4. Send Message
+        SendDevCtrlMessage(MsgWhat, CmdStr);
+
+        DeviceLog("HIGH","[Gas_SetClose] SendDevCtrlMessage - CmdStr:[" + CmdStr + "]");
+
+        return 0;
+    }
+
+    public byte GasRegBR(String acname) {
+        String CmdStr = define.DRIVER_TITLE_GASVALVE + ";" + define.APICMD_REGBR + ";" + acname;
+        Message msg = MainHandler.obtainMessage();
+        msg.what = ServiceMain.MSG_DEV_CTR;
+        msg.obj = CmdStr;
+        Log.d("WALLPADAPI","Gasvalve onoff cmd "+CmdStr);
+        MainHandler.sendMessage(msg);
+        return 0;
+
+    }
+
+    /*
+     스마트 분전반 BR 등록
+     */
+    public byte SdbRegBR(String acname) {
+        String CmdStr = define.DRIVER_TITLE_SMART_DISTRIBUTION_BD + ";" + define.APICMD_REGBR + ";" + acname;
+        Message msg = MainHandler.obtainMessage();
+        msg.what = ServiceMain.MSG_DEV_CTR;
+        msg.obj = CmdStr;
+        Log.d("WALLPADAPI","Sdb_RegBR onoff cmd "+CmdStr);
+        MainHandler.sendMessage(msg);
+        return 0;
+    }
+
+    /*
+    거실에너지미터 BR 등록
+    */
+    public byte SdbLivingRegBR(String acname) {
+        String CmdStr = define.DRIVER_TITLE_SDB_LIVINGROOM_LIGHT + ";" + define.APICMD_REGBR + ";" + acname;
+        Message msg = MainHandler.obtainMessage();
+        msg.what = ServiceMain.MSG_DEV_CTR;
+        msg.obj = CmdStr;
+        Log.d("WALLPADAPI","Sdb_Living_RegBR onoff cmd "+CmdStr);
+        MainHandler.sendMessage(msg);
+        return 0;
+    }
+
+    /**
+     * 도어락 - 문열기 대기모드 설정
+     * 무선도어락, 지문인식 도어락의 경우 제어됨
+     *
+     * @param OnOff   - (boolean) 설정할 상태 (true:ON , false:OFF)
+     * @param TimeSec - (byte) 설정시간 (범위:0~10 , 설정 = 0 일경우 본값은 0 , 설정 = 1 일경우 본값은 1~10 [단위:초])
+     *
+     * @return (int) - >=0 : 성공, <0 : 실패
+     */
+    public int DLock_SetDoorOpenStandbyMode(boolean OnOff, byte TimeSec) {
+        DeviceLog(null, "[DLock_SetDoorOpenStandbyMode] Start (OnOff:" + OnOff + ", TimeSec:" + TimeSec + ")");
+
+        if (ServiceMain.dataBaseLoader.data.wallpadDeviceSet.Get_DoorLock_Info[1] == WallpadDeviceSet.DOORLOCK_TYPE_NORMAL) {
+            // 1. 드라이버 로딩체크 & 동작여부 체크
+            if (ServiceMain.dLock_Controller == null) {
+                Log.w(TAG, "[DLock_SetDoorOpenStandbyMode1] dLock_Controller is null !!!");
+                return -1;
+            }
+
+            // 2. 파라미터 범위체크
+            //     2.1. TimeSec
+            if (OnOff) {
+                if (!((TimeSec >= 0x01) && (TimeSec <= 0x0A))) {
+                    Log.w(TAG, "[DLock_SetDoorOpenStandbyMode1] Param : TimeSec - Out of Range #1 (TimeSec:" + TimeSec + ")");
+                    return -2;
+                }
+            }
+            else {
+                if (TimeSec != 0) {
+                    Log.w(TAG, "[DLock_SetDoorOpenStandbyMode1] Param : TimeSec - Out of Range #2 (TimeSec:" + TimeSec + ")");
+                    return -3;
+                }
+            }
+
+            // 3. Make Param & Message
+            String CmdStr = MakeSendMessageFormat(define.DRIVER_TITLE_DLOCK, define.APICMD_SINKCTRL, "SetDoorOpenStandbyMode", ((OnOff)?1:0), TimeSec, 0, 0, 0);
+
+            // 4. Send Message
+            int MsgWhat = ServiceMain.MSG_DEV_CTR;
+            SendDevCtrlMessage(MsgWhat, CmdStr);
+
+            DeviceLog("HIGH","[DLock_SetDoorOpenStandbyMode1] SendDevCtrlMessage - CmdStr:[" + CmdStr + "]");
+        }
+        else if (ServiceMain.dataBaseLoader.data.wallpadDeviceSet.Get_DoorLock_Info[1] == WallpadDeviceSet.DOORLOCK_TYPE_FINGERPRINT) {
+            // 1. 드라이버 로딩체크 & 동작여부 체크
+            if (ServiceMain.fp_dLock_controller == null) {
+                Log.w(TAG, "[DLock_SetDoorOpenStandbyMode2] fp_dLock_controller is null !!!");
+                return -1;
+            }
+
+            // 2. 파라미터 범위체크
+            //     2.1. TimeSec
+            if (OnOff) {
+                if (!((TimeSec >= 0x01) && (TimeSec <= 0x0A))) {
+                    Log.w(TAG, "[DLock_SetDoorOpenStandbyMode2] Param : TimeSec - Out of Range #1 (TimeSec:" + TimeSec + ")");
+                    return -2;
+                }
+            }
+            else {
+                if (TimeSec != 0) {
+                    Log.w(TAG, "[DLock_SetDoorOpenStandbyMode2] Param : TimeSec - Out of Range #2 (TimeSec:" + TimeSec + ")");
+                    return -3;
+                }
+            }
+
+            // 3. Make Param & Message
+            String CmdStr = MakeSendMessageFormat(define.DRIVER_TITLE_FP_DLOCK, define.APICMD_SINKCTRL, "SetDoorOpenStandbyMode", ((OnOff)?1:0), TimeSec, 0, 0, 0);
+
+            // 4. Send Message
+            int MsgWhat = ServiceMain.MSG_DEV_CTR;
+            SendDevCtrlMessage(MsgWhat, CmdStr);
+
+            DeviceLog("HIGH","[DLock_SetDoorOpenStandbyMode2] SendDevCtrlMessage - CmdStr:[" + CmdStr + "]");
+        }
+        return 0;
+    }
+    /**
+     * 지문인식 도어락 - 문열기 제어
+     *
+     * @return (int) - >=0 : 성공, <0 : 실패
+     */
+    public int FPdLock_SetDoorOpen() {
+        DeviceLog(null, "[FPdLock_SetDoorOpen] Start ");
+
+        if (ServiceMain.dataBaseLoader.data.wallpadDeviceSet.Get_DoorLock_Info[1] == WallpadDeviceSet.DOORLOCK_TYPE_FINGERPRINT) {
+            // 1. 드라이버 로딩체크 & 동작여부 체크
+            if (ServiceMain.fp_dLock_controller == null) {
+                Log.w(TAG, "[FPdLock_SetDoorOpen] fp_dLock_controller is null !!!");
+                return -1;
+            }
+
+            // 3. Make Param & Message
+            String CmdStr = MakeSendMessageFormat(define.DRIVER_TITLE_FP_DLOCK, define.APICMD_SINKCTRL, "SetDoorOpen", 0,0, 0, 0, 0);
+
+            // 4. Send Message
+            int MsgWhat = ServiceMain.MSG_DEV_CTR;
+            SendDevCtrlMessage(MsgWhat, CmdStr);
+
+            DeviceLog("HIGH","[FPdLock_SetDoorOpen] SendDevCtrlMessage - CmdStr:[" + CmdStr + "]");
+        }
+        return 0;
+    }
+
+    public int SmartIotDCam_CtrLed(boolean doit) {
+        int[] camTypes = null;
+        try {
+            WallpadDeviceSet wds = new WallpadDeviceSet(ServiceMain.svcContext);
+            camTypes =  wds.Get_RFDoorCAM_Info();
+            wds.closeDB();
+        } catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+            return -1;
+        } catch (Exception ex) {
+            Log.e(TAG, "[SmartIotDCam_CtrLed] - Get_RFDoorCAM_Info Exception !!!");
+            //ex.printStackTrace();
+            LogUtil.errorLogInfo("", TAG, ex);
+            return -1;
+        }
+
+        byte onoff = (byte)0x00;            // 기본 : 조명 OFF
+        if (doit) { onoff = (byte)0x01; } // 조명 ON
+        else { onoff = (byte)0x00; } // 조명 OFF
+
+        if (camTypes != null && camTypes[1] == WallpadDeviceSet.DOORTYPE_IOT_SMART) {
+            String CmdStr = MakeSendMessageFormat(define.DRIVER_TITLE_SMARTKEYRFDOOR, define.APICMD_SINKCTRL, "SetLEDmode", onoff, 0, 0, 0, 0);
+
+            // 4. Send Message
+            int MsgWhat = ServiceMain.MSG_DEV_CTR;
+            SendDevCtrlMessage(MsgWhat, CmdStr);
+
+            DeviceLog(TAG, "[SmartIotDCam_CtrLed] SendDevCtrlMessage - CmdStr:[" + CmdStr + "]");
+        }
+        else {
+            return -2;
+        }
+        return 0;
+    }
+
+    /**
+     * 난방V1 각방 제어 (운전모드 및 설정온도 변경)
+     *
+     * @param MsgWhat   - (int) 메시지 타입
+     * @param RoomIndex - (byte) 변경할 방 인덱스
+     * @param SetMode   - (byte) 변경할 운전모드(0:미설정, 1:ON, 2:OFF)
+     * @param SetTemp   - (double) 변경할 설정온도 (미설정시 '0')
+     *
+     * @return (int) - >=0 : 성공, <0 : 실패
+     */
+    public int HeatingV1_SetEachRoomStatus(int MsgWhat, byte RoomIndex, byte SetMode, double SetTemp) {
+        DeviceLog("HIGH","[HeatingV1_SetEachRoomStatus] Start (RoomIndex:" + RoomIndex + ", SetMode:" + SetMode + ", SetTemp" + SetTemp + ")");
+
+        // 1. 드라이버 로딩체크 & 동작여부 체크
+        if (ServiceMain.heatingV1_Controller == null) {
+            Log.w(TAG, "[HeatingV1_SetEachRoomStatus] heatingV1_Controller is null !!!");
+            return -1;
+        }
+
+        if (!ServiceMain.heatingV1_Controller.Doing) {
+            Log.w(TAG, "[HeatingV1_SetEachRoomStatus] Doing is false !!!");
+            return -2;
+        }
+
+        // 2. 파라미터 범위체크
+        if (!CheckRangeMsgWhat(MsgWhat)) {
+            Log.w(TAG, "[HeatingV1_SetEachRoomStatus] MsgWhat - Out Of Range !!! (MsgWhat:" + MsgWhat + ")");
+            return -10;
+        }
+
+        //     2.1. RoomIndex
+        byte RoomCount = ServiceMain.heatingV1_Controller.GetRoomCount();
+        if ((RoomIndex < 0) || (RoomIndex >= RoomCount)) {
+            Log.w(TAG, "[HeatingV1_SetEachRoomStatus] Param : RoomIndex Out of Range (RoomIndex:" + RoomIndex + ")");
+            return -21;
+        }
+
+        //     2.2. SetMode
+        switch (SetMode) {
+            case 0x00: case 0x01: case 0x02:
+                break;
+
+            default:
+                Log.w(TAG, "[HeatingV1_SetEachRoomStatus] Param : SetMode Out of Range (SetMode:" + String.format("0x%02X", SetMode) + ")");
+                return -22;
+        }
+
+        //     2.3. SetTemp
+        if ((SetTemp < (double)5.0) || (SetTemp > (double)40.0)) {
+            Log.w(TAG, "[HeatingV1_SetEachRoomStatus] Param : SetTemp Out of Range (SetTemp:" + SetTemp + ")");
+            return -23;
+        }
+
+        // 3. Make Param & Message
+        byte ByteTemp = 0;
+        byte Point    = 0;
+        if (SetTemp != 0) {
+            ByteTemp = (byte) SetTemp;
+            Point = (PointExist(SetTemp)?(byte)1:(byte)0);
+        }
+
+        String CmdStr = MakeSendMessageFormat(define.DRIVER_TITLE_HEATINGV1, define.APICMD_SINKCTRL, "SetEachRoomStatus", RoomIndex, SetMode, ByteTemp, Point, 0);
+
+        // 4. Send Message
+        SendDevCtrlMessage(MsgWhat, CmdStr);
+        DeviceLog("HIGH","[HeatingV1_SetEachRoomStatus] SendDevCtrlMessage - CmdStr:[" + CmdStr + "]");
+        return 0;
+    }
+
+    /**
+     * 난방V2 각방 제어 (운전모드 및 설정온도 변경)
+     *
+     * @param MsgWhat   - (int) 메시지 타입
+     * @param RoomIndex - (byte) 변경할 방 인덱스
+     * @param SetMode   - (byte) 변경할 운전모드(0:미설정, 1:ON, 2:OFF)
+     * @param SetTemp   - (double) 변경할 설정온도 (미설정시 '0')
+     *
+     * @return (int) - >=0 : 성공, <0 : 실패
+     */
+    public int HeatingV2_SetEachRoomStatus(int MsgWhat, byte RoomIndex, byte SetMode, double SetTemp) {
+        DeviceLog("HIGH","[HeatingV2_SetEachRoomStatus] Start (RoomIndex:" + RoomIndex + ", SetMode:" + SetMode + ", SetTemp" + SetTemp + ")");
+
+        // 1. 드라이버 로딩체크
+        if (ServiceMain.heatingV2_Controller == null) {
+            Log.w(TAG, "[HeatingV2_SetEachRoomStatus] heatingV1_Controller is null !!!");
+            return -1;
+        }
+
+        if (!ServiceMain.heatingV2_Controller.Doing) {
+            Log.w(TAG, "[HeatingV2_SetEachRoomStatus] Doing is false !!!");
+            return -2;
+        }
+
+        // 2. 파라미터 범위체크
+        if (!CheckRangeMsgWhat(MsgWhat)) {
+            Log.w(TAG, "[HeatingV2_SetEachRoomStatus] MsgWhat - Out Of Range !!! (MsgWhat:" + MsgWhat + ")");
+            return -10;
+        }
+
+        //     2.1. RoomIndex
+        byte RoomCount = ServiceMain.heatingV2_Controller.GetRoomCount();
+        if ((RoomIndex < 0) || (RoomIndex >= RoomCount)) {
+            Log.w(TAG, "[HeatingV2_SetEachRoomStatus] Param : RoomIndex Out of Range (RoomIndex:" + RoomIndex + ")");
+            return -21;
+        }
+
+        //     2.2. SetMode
+        if (!HeatingV2.MODE.CheckSetMode(SetMode)) {
+            Log.w(TAG, "[HeatingV2_SetEachRoomStatus] Param : SetMode Out of Range (SetMode:" + String.format("0x%02X", SetMode) + ")");
+            return -22;
+        }
+        //     2.3. SetTemp
+        //        if( (SetTemp < (double)5.0) || (SetTemp > (double)40.0) )
+        //        {
+        //            Log.w(TAG, "[HeatingV2_SetEachRoomStatus] Param : SetTemp Out of Range (SetTemp:" + SetTemp + ")");
+        //            return -23;
+        //        }
+
+        // 3. Make Param & Message
+        byte ByteTemp = 0;
+        byte Point    = 0;
+        if (SetTemp != 0) {
+            ByteTemp = (byte) SetTemp;
+            Point = (PointExist(SetTemp)?(byte)1:(byte)0);
+        }
+
+        String CmdStr = MakeSendMessageFormat(define.DRIVER_TITLE_HEATINGV2, define.APICMD_SINKCTRL, "SetEachRoomStatus", RoomIndex, SetMode, ByteTemp, Point, 0);
+
+        // 4. Send Message
+        SendDevCtrlMessage(MsgWhat, CmdStr);
+        DeviceLog("HIGH","[HeatingV2_SetEachRoomStatus] SendDevCtrlMessage - CmdStr:[" + CmdStr + "]");
+        return 0;
+    }
+
+    /**
+     * 게이트웨이를 통하여 에너지미터를 리셋한다.
+     *
+     * @return (int) - >=0 : 성공, <0 : 실패
+     */
+    public int IGW200D_EnergyReset() {
+        // 1. 드라이버 로딩체크
+        if (ServiceMain.iGW200D_Controller == null) {
+            Log.w(TAG, "[IGW200D_EnergyReset] iGW200D_Controller is null !!!");
+            return -1;
+        }
+
+        if (!ServiceMain.iGW200D_Controller.Doing) {
+            Log.w(TAG, "[IGW200D_EnergyReset] Doing is false !!!");
+            return -2;
+        }
+
+        // 2. 파라미터 범위체크
+
+        // 3. Make Param & Message
+        String CmdStr = MakeSendMessageFormat(define.DRIVER_TITLE_IGW200D, define.APICMD_SINKCTRL, "EnergyReset", 0, 0, 0, 0, 0);
+
+        // 4. Send Message
+        SendDevCtrlMessage(ServiceMain.MSG_DEV_CTR, CmdStr);
+        DeviceLog("HIGH","[IGW200D_EnergyReset] SendDevCtrlMessage - CmdStr:[" + CmdStr + "]");
+        return 0;
+    }
+
+    /**
+     * 게이트웨이를 통하여 무선도어락을 제어한다.
+     *
+     * @param  Open - (boolean) ture : 문열림(펄스2번) , false : 등록(펄스3번)
+     * @return (int) - >=0 : 성공, <0 : 실패
+     */
+    public int IGW_SetWddrCont(boolean Open) {
+        DeviceManager IGW_Controller = null;
+        String Driver_Title = null;
+
+        // 1. 모델명 체크
+        if (mModelType == Version.MODEL_TYPE.IHN_1020GL) {
+            IGW_Controller = ServiceMain.iGW200D_Controller;
+            Driver_Title   = define.DRIVER_TITLE_IGW200D;
+        }
+        else if (mModelType == Version.MODEL_TYPE.IHN_D101 || mModelType == Version.MODEL_TYPE.IHN_D101_I
+                || mModelType == Version.MODEL_TYPE.IHN_D101K || mModelType == Version.MODEL_TYPE.IHN_D101K_I
+                || mModelType == Version.MODEL_TYPE.IHN_1010GL || mModelType == Version.MODEL_TYPE.IHN_1010GL_I
+                || mModelType == Version.MODEL_TYPE.IHN_1010GL_I_2443ALT || mModelType == Version.MODEL_TYPE.IHN_1010GL_I_6410ALT
+                || mModelType == Version.MODEL_TYPE.IHN_D101_I_OCF)
+        {
+            IGW_Controller = ServiceMain.iGW300_Controller;
+            Driver_Title   = define.DRIVER_TITLE_IGW300;
+        }
+        else {
+            Log.w(TAG, "[IGW_SetWddrCont] Not Support ModelType !!! (mModelType:" + mModelType + ")");
+            return -1;
+        }
+
+        // 2. 드라이버 로딩체크
+        if (IGW_Controller == null) {
+            Log.w(TAG, "[IGW_SetWddrCont] IGW_Controller is null !!!");
+            return -11;
+        }
+
+        if (!IGW_Controller.Doing) {
+            Log.w(TAG, "[IGW_SetWddrCont] Doing is false !!!");
+            return -12;
+        }
+
+        // 3. 파라미터 범위체크
+
+        // 4. Make Param & Message
+        String CmdStr = MakeSendMessageFormat(Driver_Title, define.APICMD_SINKCTRL, "SetWddrCont", (Open) ? 0x02 : 0x01, 0, 0, 0, 0);
+
+        // 5. Send Message
+        SendDevCtrlMessage(ServiceMain.MSG_DEV_CTR, CmdStr);
+        DeviceLog("HIGH","[IGW_SetWddrCont] SendDevCtrlMessage - CmdStr:[" + CmdStr + "]");
+        return 0;
+    }
+
+    /**
+     * 게이트웨이를 통하여 무선도어락 문열림 대기모드를 설정한다.
+     *
+     * @param  DelayTime - (int) 문열림 시간 - 0초간, 3초간, 5초간, 10초간
+     * @return (int) - >=0 : 성공, <0 : 실패
+     */
+    public int IGW_SetWddrOpenDelayCont(int DelayTime) {
+        DeviceManager IGW_Controller = null;
+        String Driver_Title = null;
+
+        // 1. 모델명 체크
+        if (mModelType == Version.MODEL_TYPE.IHN_1020GL) {
+            IGW_Controller = ServiceMain.iGW200D_Controller;
+            Driver_Title   = define.DRIVER_TITLE_IGW200D;
+        }
+        else if (mModelType == Version.MODEL_TYPE.IHN_D101 || mModelType == Version.MODEL_TYPE.IHN_D101_I
+                || mModelType == Version.MODEL_TYPE.IHN_D101K || mModelType == Version.MODEL_TYPE.IHN_D101K_I
+                || mModelType == Version.MODEL_TYPE.IHN_1010GL || mModelType == Version.MODEL_TYPE.IHN_1010GL_I
+                || mModelType == Version.MODEL_TYPE.IHN_1010GL_I_2443ALT || mModelType == Version.MODEL_TYPE.IHN_1010GL_I_6410ALT
+                || mModelType == Version.MODEL_TYPE.IHN_D101_I_OCF)
+        {
+            IGW_Controller = ServiceMain.iGW300_Controller;
+            Driver_Title   = define.DRIVER_TITLE_IGW300;
+        }
+        else {
+            Log.w(TAG, "[IGW_SetWddrOpenDelayCont] Not Support ModelType !!! (mModelType:" + mModelType + ")");
+            return -1;
+        }
+
+        // 2. 드라이버 로딩체크
+        if (IGW_Controller == null) {
+            Log.w(TAG, "[IGW_SetWddrOpenDelayCont] IGW_Controller is null !!!");
+            return -11;
+        }
+
+        if (!IGW_Controller.Doing) {
+            Log.w(TAG, "[IGW_SetWddrOpenDelayCont] Doing is false !!!");
+            return -12;
+        }
+
+        // 3. 파라미터 범위체크
+        if (!((DelayTime == 0) || (DelayTime == 3) || (DelayTime == 5) || (DelayTime == 10))) {
+            Log.w(TAG, "[IGW_SetWddrOpenDelayCont] DelayTime is Error :" + DelayTime);
+            return -101;
+        }
+
+        // 4. Make Param & Message
+        String CmdStr = MakeSendMessageFormat(Driver_Title, define.APICMD_SINKCTRL, "SetWddrOpenDelayCont", DelayTime, 0, 0, 0, 0);
+
+        // 5. Send Message
+        SendDevCtrlMessage(ServiceMain.MSG_DEV_CTR, CmdStr);
+        DeviceLog("HIGH","[IGW_SetWddrOpenDelayCont] SendDevCtrlMessage - CmdStr:[" + CmdStr + "]");
+        return 0;
+    }
+
+    public static final byte DOOR_POWER = 24;
+    public static final byte BELL_CONT = 25;
+    public static final byte VIDEO_SEL = 27;
+    /**
+     * 게이트웨이(IGW-200/300)를 통하여 현관카메라 LED를 제어한다.
+     *
+     * @param  onoff - (boolean) true 켜기 / false 끄기
+     * @return (int) - >=0 : 성공, <0 : 실패
+     */
+    public int IGW_SetLedOnOff(boolean onoff) {
+        DeviceManager IGW_Controller = null;
+        String Driver_Title = null;
+
+        // 1. 모델명 체크
+        if (mModelType == Version.MODEL_TYPE.IHN_1020GL) {
+            IGW_Controller = ServiceMain.iGW200D_Controller;
+            Driver_Title   = define.DRIVER_TITLE_IGW200D;
+        }
+        else if (mModelType == Version.MODEL_TYPE.IHN_D101 || mModelType == Version.MODEL_TYPE.IHN_D101_I
+                || mModelType == Version.MODEL_TYPE.IHN_D101K || mModelType == Version.MODEL_TYPE.IHN_D101K_I
+                || mModelType == Version.MODEL_TYPE.IHN_1010GL || mModelType == Version.MODEL_TYPE.IHN_1010GL_I
+                || mModelType == Version.MODEL_TYPE.IHN_1010GL_I_2443ALT || mModelType == Version.MODEL_TYPE.IHN_1010GL_I_6410ALT
+                || mModelType == Version.MODEL_TYPE.IHN_D101_I_OCF)
+        {
+            IGW_Controller = ServiceMain.iGW300_Controller;
+            Driver_Title   = define.DRIVER_TITLE_IGW300;
+        }
+        else {
+            Log.w(TAG, "[IGW_SetLedOnOff] Not Support ModelType !!! (mModelType:" + mModelType + ")");
+            return -1;
+        }
+
+        // 2. 드라이버 로딩체크
+        if (IGW_Controller == null) {
+            Log.w(TAG, "[IGW_SetLedOnOff] IGW_Controller is null !!!");
+            return -11;
+        }
+
+        if (!IGW_Controller.Doing) {
+            Log.w(TAG, "[IGW_SetLedOnOff] Doing is false !!!");
+            return -12;
+        }
+
+        // SendNReadCMD_int(define.APICMD_NOSINKCTRL, "ControlOutput", kind, onoff, 0, 0, 0);
+        // 3. Make Param & Message
+        String CmdStr = MakeSendMessageFormat(Driver_Title, define.APICMD_NOSINKCTRL, "ControlOutput", DOOR_POWER, (onoff ? 1 : 0), 0, 0, 0);
+
+        // 4. Send Message
+        SendDevCtrlMessage(ServiceMain.MSG_DEV_CTR, CmdStr);
+        DeviceLog("HIGH","[IGW_SetLedOnOff] SendDevCtrlMessage - CmdStr:[" + CmdStr + "]");
+        return 0;
+    }
+
+    /**
+     * 환기 - ON/OFF 제어
+     *
+     * @param MsgWhat   - (int) 메시지 타입
+     * @param OnOff   - (boolean) 설정할 상태 (true:ON , false:OFF)
+     *
+     * @return (int) - >=0 : 성공, <0 : 실패
+     */
+    public int Ventilation_SetOnOff(int MsgWhat, boolean OnOff) {
+        DeviceLog(null, "[Ventilation_SetOnOff] Start (OnOff:" + OnOff + ")");
+
+        // 1. 드라이버 로딩체크 & 동작여부 체크
+        if (ServiceMain.ventilation_Controller == null) {
+            Log.w(TAG, "[Ventilation_SetOnOff] ventilation_Controller is null !!!");
+            return -1;
+        }
+
+        // 2. 파라미터 범위체크
+        if (!CheckRangeMsgWhat(MsgWhat)) {
+            Log.w(TAG, "[Ventilation_SetOnOff] MsgWhat - Out Of Range !!! (MsgWhat:" + MsgWhat + ")");
+            return -10;
+        }
+
+        // 3. Make Param & Message
+        String CmdStr = MakeSendMessageFormat(define.DRIVER_TITLE_VENTILATION, define.APICMD_SINKCTRL, "SetOnOff", ((OnOff) ? 1 : 0), 0, 0, 0, 0);
+
+        // 4. Send Message
+        SendDevCtrlMessage(MsgWhat, CmdStr);
+        DeviceLog("HIGH","[Ventilation_SetOnOff] SendDevCtrlMessage - CmdStr:[" + CmdStr + "]");
+        return 0;
+    }
+
+    /**
+     * 환기 - 풍량세기 변경
+     *
+     * @param MsgWhat    - (int) 메시지 타입
+     * @param ChangeWind - (byte) 변경할 풍량상태
+     *
+     * @return (int) - >=0 : 성공, <0 : 실패
+     */
+    public int Ventilation_SetWind(int MsgWhat, byte ChangeWind) {
+        DeviceLog(null, "[Ventilation_SetWind] Start (ChangeWind:" + ChangeWind + ")");
+
+        // 1. 드라이버 로딩체크 & 동작여부 체크
+        if (ServiceMain.ventilation_Controller == null) {
+            Log.w(TAG, "[Ventilation_SetWind] ventilation_Controller is null !!!");
+            return -1;
+        }
+
+        // 2. 파라미터 범위체크
+        if (!CheckRangeMsgWhat(MsgWhat)) {
+            Log.w(TAG, "[Ventilation_SetWind] MsgWhat - Out Of Range !!! (MsgWhat:" + MsgWhat + ")");
+            return -10;
+        }
+
+        if (!DataClasses.Venti.WIND.CheckRange(ChangeWind)) {
+            Log.w(TAG, "[Ventilation_SetWind] ChangeWind - Out Of Range (ChangeWind:" + ChangeWind + ")");
+            return -20;
+        }
+
+        // 3. Make Param & Message
+        String CmdStr = MakeSendMessageFormat(define.DRIVER_TITLE_VENTILATION, define.APICMD_SINKCTRL, "SetWind", ChangeWind, 0, 0, 0, 0);
+
+        // 4. Send Message
+        SendDevCtrlMessage(MsgWhat, CmdStr);
+        DeviceLog("HIGH","[Ventilation_SetWind] SendDevCtrlMessage - CmdStr:[" + CmdStr + "]");
+        return 0;
+    }
+
+    /**
+     * 환기 - 타이머설정값 변경
+     *
+     * @param MsgWhat     - (int) 메시지 타입
+     * @param ChangeTimer - (byte) 변경할 타이머 상태
+     *
+     * @return (int) - >=0 : 성공, <0 : 실패
+     */
+    public int Ventilation_SetTimer(int MsgWhat, byte ChangeTimer) {
+        DeviceLog(null, "[Ventilation_SetTimer] Start (ChangeTimer:" + ChangeTimer + ")");
+
+        // 1. 드라이버 로딩체크 & 동작여부 체크
+        if (ServiceMain.ventilation_Controller == null) {
+            Log.w(TAG, "[Ventilation_SetTimer] ventilation_Controller is null !!!");
+            return -1;
+        }
+
+        // 2. 파라미터 범위체크
+        if (!CheckRangeMsgWhat(MsgWhat)) {
+            Log.w(TAG, "[Ventilation_SetTimer] MsgWhat - Out Of Range !!! (MsgWhat:" + MsgWhat + ")");
+            return -10;
+        }
+
+        // 3. Make Param & Message
+        String CmdStr = MakeSendMessageFormat(define.DRIVER_TITLE_VENTILATION, define.APICMD_SINKCTRL, "SetTimer", ChangeTimer, 0, 0, 0, 0);
+
+        // 4. Send Message
+        SendDevCtrlMessage(MsgWhat, CmdStr);
+        DeviceLog("HIGH","[Ventilation_SetTimer] SendDevCtrlMessage - CmdStr:[" + CmdStr + "]");
+        return 0;
+    }
+
+    /**
+     * 제어기 구분없이 일괄소등 상태를 제어한다.
+     *
+     * @param OnOff - (boolean) true:일괄소등해제상태(조명ON) , false:일괄소등상태(조명OFF)
+     *
+     * @return (int) - >=0 : 성공, <0 : 실패
+     */
+    public int setAllLight(boolean OnOff) {
+        try {
+            if (mModelType == Version.MODEL_TYPE.IHN_D101 || mModelType == Version.MODEL_TYPE.IHN_D101_I
+                    || mModelType == Version.MODEL_TYPE.IHN_D101K || mModelType == Version.MODEL_TYPE.IHN_D101K_I
+                    || mModelType == Version.MODEL_TYPE.IHN_D101_I_OCF) {
+                int onoff = 0;
+                if(OnOff) onoff = 1;
+
+                WallpadDeviceSet wds = new WallpadDeviceSet(ServiceMain.svcContext);
+                int nDistributionPanelType = wds.Get_DistributionPannelType_Info();
+                wds.closeDB();
+
+                String DistributeName = "";
+                if (nDistributionPanelType == Version.DISTRIBUTION_MODEL.SMART_DIST) {
+                    // 스마트 분전반
+                    DistributeName = define.DRIVER_TITLE_SMART_DISTRIBUTION_BD;
+                }
+                else if (nDistributionPanelType == Version.DISTRIBUTION_MODEL.KNX_DIST) {
+                    // KNX 분전반
+                    DistributeName = define.DRIVER_TITLE_KNX_DISTRIBUTION_BD;
+                }
+                else {
+                    // 그밖의 경우, 스마트분전반을 기본으로 로딩.
+                    DistributeName = define.DRIVER_TITLE_SMART_DISTRIBUTION_BD;
+                }
+
+                Log.i(TAG, "setAllLight --- IHN_D101 (OnOff:" + OnOff + ")");
+                Message msg = MainHandler.obtainMessage();
+                String CmdStr = MakeSendMessageFormat(DistributeName, define.APICMD_SINKCTRL, "AllLightOnOff", onoff, 0, 0, 0, 0);
+                msg.what = ServiceMain.MSG_DEV_CTR;
+                msg.obj = CmdStr;
+                DeviceLog(null, "setAllLight - onoff (cmd:" + CmdStr + ")");
+                MainHandler.sendMessage(msg);
+
+                return 0;
+            }
+            else if (mModelType == Version.MODEL_TYPE.IHN_1020GL
+                    || mModelType == Version.MODEL_TYPE.IHN_1010GL || mModelType == Version.MODEL_TYPE.IHN_1010GL_I
+                    || mModelType == Version.MODEL_TYPE.IHN_1010GL_I_2443ALT || mModelType == Version.MODEL_TYPE.IHN_1010GL_I_6410ALT) {
+                DeviceLog(null, "setAllLight - Start");
+
+                int onoff = 0;
+                if (OnOff) onoff = 1;
+
+                if (!ServiceMain.Get_HDCIntLightType()) {
+                    Message msg = MainHandler.obtainMessage();
+                    String CmdStr = MakeSendMessageFormat(define.DRIVER_TITLE_BATCHLIGHTHDC, define.APICMD_SINKCTRL, "AllLightControl", onoff, 0, 0, 0, 0);
+                    msg.what = ServiceMain.MSG_DEV_CTR;
+                    msg.obj = CmdStr;
+                    DeviceLog(null, "setAllLight - onoff (cmd:" + CmdStr + ")");
+                    MainHandler.sendMessage(msg);
+                }
+                else {
+                    Message msg = MainHandler.obtainMessage();
+                    String CmdStr = MakeSendMessageFormat(define.DRIVER_TITLE_INTLIGHT, define.APICMD_SINKCTRL, "LightControl", 6, onoff, 0, 0, 0);
+                    msg.what = ServiceMain.MSG_DEV_CTR;
+                    msg.obj = CmdStr;
+                    DeviceLog(null, "setAllLight - onoff (cmd:" + CmdStr + ")");
+                    MainHandler.sendMessage(msg);
+                }
+                return 0;
+            }
+            else {
+                // 대외
+                int [] Get_BatchSW_Info = ServiceMain.dataBaseLoader.data.wallpadDeviceSet.Get_BatchSW_Info;
+                if (Get_BatchSW_Info == null) return -20;
+                if (Get_BatchSW_Info[0] < 3)  return -21;
+                if (Get_BatchSW_Info[0] == 0) return -22;
+
+                if (Get_BatchSW_Info[1] == WallpadDeviceSet.BATCH_TYPE_GENERAL) {
+                    // 일괄소등제어기
+                }
+                else if (Get_BatchSW_Info[1] == WallpadDeviceSet.BATCH_TYPE_SMART) {
+                    // 대외향 스마트스위치
+                }
+                else {
+                    return -23;
+                }
+            }
+        } catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+            return -100;
+        } catch (Exception e) {
+            Log.e("DriverInterOpAPI", "[Exception Error] setAllLight(" + OnOff + ")");
+            //e.printStackTrace();
+            LogUtil.errorLogInfo("", TAG, e);
+            return -100;
+        }
+
+        return -1;
+    }
+
+    /**
+     * 제어기 구분없이 일괄소등 상태를 반환한다.
+     *
+     * @return (boolean) true:일괄소등해제상태(조명ON) , false:일괄소등상태(조명OFF)
+     */
+    public boolean getAllLight() {
+        try {
+            if (mModelType == Version.MODEL_TYPE.IHN_D101 || mModelType == Version.MODEL_TYPE.IHN_D101_I
+                    || mModelType == Version.MODEL_TYPE.IHN_D101K || mModelType == Version.MODEL_TYPE.IHN_D101K_I
+                    || mModelType == Version.MODEL_TYPE.IHN_D101_I_OCF) {
+                //Log.i(TAG, "[getAllLight] - IHN_D101");
+
+                WallpadDeviceSet wds = new WallpadDeviceSet(ServiceMain.svcContext);
+                int nDistributionPanelType = wds.Get_DistributionPannelType_Info();
+                wds.closeDB();
+
+                boolean bRet = false;
+
+                if (nDistributionPanelType == Version.DISTRIBUTION_MODEL.SMART_DIST) {
+                    // 스마트 분전반
+                    if(ServiceMain.sdb_Controller == null) return true;
+                    bRet = ServiceMain.sdb_Controller.GetAllLightStatus();
+                }
+                else if (nDistributionPanelType == Version.DISTRIBUTION_MODEL.KNX_DIST) {
+                    // KNX 분전반
+                    if(ServiceMain.knx_Controller == null) return true;
+                    bRet = ServiceMain.knx_Controller.GetAllLightStatus();
+                }
+                else {
+                    // 그밖의 경우, 스마트분전반을 기본으로 로딩.
+                    if(ServiceMain.sdb_Controller == null) return true;
+                    bRet = ServiceMain.sdb_Controller.GetAllLightStatus();
+                }
+
+                return bRet;
+            }
+            else if (mModelType == Version.MODEL_TYPE.IHN_1020GL
+                    || mModelType == Version.MODEL_TYPE.IHN_1010GL || mModelType == Version.MODEL_TYPE.IHN_1010GL_I
+                    || mModelType == Version.MODEL_TYPE.IHN_1010GL_I_2443ALT || mModelType == Version.MODEL_TYPE.IHN_1010GL_I_6410ALT)
+            {
+                if (!ServiceMain.Get_HDCIntLightType()) {
+                    if (ServiceMain.allLightHDC_Controller == null) return true;
+                    boolean bRet = AllLightHDC_Controller.GetAllLightStatus();
+                    return bRet;
+                }
+                else {
+                    if (ServiceMain.intLight_Controller == null) return true;
+                    boolean bRet = IntLight_Controller.GetAllLightStatus();
+                    return bRet;
+                }
+            }
+            else {
+                // 대외
+                int [] Get_BatchSW_Info = ServiceMain.dataBaseLoader.data.wallpadDeviceSet.Get_BatchSW_Info;
+                if (Get_BatchSW_Info == null) return false;
+                if (Get_BatchSW_Info[0] < 3)  return false;
+                if (Get_BatchSW_Info[0] == 0) return false;
+
+                if (Get_BatchSW_Info[1] == WallpadDeviceSet.BATCH_TYPE_GENERAL) {
+                    // 일괄소등제어기
+                }
+                else if (Get_BatchSW_Info[1] == WallpadDeviceSet.BATCH_TYPE_SMART) {
+                    // 대외향 스마트스위치
+                }
+                else {
+                    return false;
+                }
+            }
+        }
+        catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+            return false;
+        }
+        catch (Exception e) {
+            Log.e("DriverInterOpAPI", "[Exception Error] getAllLight()");
+            //e.printStackTrace();
+            LogUtil.errorLogInfo("", TAG, e);
+            return false;
+        }
+
+        return false;
+    }
+
+    /**
+     * 조명제어기에 BR을 등록한다.<br>
+     * 현산 대외 모델과 상관없이 동작한다.<br>
+     * <br>
+     * 현산 - 일체형조명제어기 제어<br>
+     * 대외 - 거실조명 : 거실조명제어<br>
+     *       멀티스위치 : 멀티스위치 1번기기 제어<br>
+     *
+     * @param acname - (String) 등록할 name
+     *
+     * @return (int) - >=0 : 성공, <0 : 실패
+     */
+    public int setLightRegBR(String acname) {
+        try {
+            String DriverTitleStr = null;
+
+            if (mModelType == Version.MODEL_TYPE.IHN_D101 || mModelType == Version.MODEL_TYPE.IHN_D101_I
+                    || mModelType == Version.MODEL_TYPE.IHN_D101K || mModelType == Version.MODEL_TYPE.IHN_D101K_I
+                    || mModelType == Version.MODEL_TYPE.IHN_D101_I_OCF) {
+                //DriverTitleStr = define.DRIVER_TITLE_SDB_LIVINGROOM_LIGHT;
+                WallpadDeviceSet wds = new WallpadDeviceSet(ServiceMain.svcContext);
+                int nDistributionPanelType = wds.Get_DistributionPannelType_Info();
+                wds.closeDB();
+
+                if (nDistributionPanelType == Version.DISTRIBUTION_MODEL.SMART_DIST) {
+                    // 스마트 분전반
+                    DriverTitleStr = define.DRIVER_TITLE_SDB_LIVINGROOM_LIGHT;
+                }
+                else if (nDistributionPanelType == Version.DISTRIBUTION_MODEL.KNX_DIST) {
+                    // KNX 분전반
+                    DriverTitleStr = define.DRIVER_TITLE_KNX_LIVINGROOM_LIGHT;
+                }
+                else {
+                    // 그밖의 경우, 스마트분전반을 기본으로 로딩.
+                    DriverTitleStr = define.DRIVER_TITLE_SDB_LIVINGROOM_LIGHT;
+                }
+            }
+            else if (mModelType == Version.MODEL_TYPE.IHN_1020GL
+                    || mModelType == Version.MODEL_TYPE.IHN_1010GL || mModelType == Version.MODEL_TYPE.IHN_1010GL_I
+                    || mModelType == Version.MODEL_TYPE.IHN_1010GL_I_2443ALT || mModelType == Version.MODEL_TYPE.IHN_1010GL_I_6410ALT) {
+                // 현산 일체형조명제어기
+                DriverTitleStr = define.DRIVER_TITLE_INTLIGHT;
+            }
+            else {
+                // 대외
+                int [] Get_Light_info = ServiceMain.dataBaseLoader.data.wallpadDeviceSet.Get_Light_info;
+                if (Get_Light_info == null)     return -20;
+                if (Get_Light_info.length < 3)  return -21;
+                if (Get_Light_info[0] == 0)     return -22;
+
+                if (Get_Light_info[1] == WallpadDeviceSet.LIGHT_TYPE_LIVING) {
+                    // 거실조명
+                    DriverTitleStr = define.DRIVER_TITLE_LIGHT;
+                }
+                else if (Get_Light_info[1] == WallpadDeviceSet.LIGHT_TYPE_ROOM) {
+                    // 멀티스위치
+                    DriverTitleStr = define.DRIVER_TITLE_MULTISW;
+                }
+                else if (Get_Light_info[1] == WallpadDeviceSet.LIGHT_TYPE_ZEROENERGY_ENERGYMETER) {
+                    // 에너지미터
+                    DriverTitleStr = define.DRIVER_TITLE_ENERGYMETER;
+                }
+                else {
+                    return -23;
+                }
+            }
+
+            if (DriverTitleStr != null) {
+                String CmdStr = DriverTitleStr + ";" + define.APICMD_REGBR + ";" + acname;
+                Message msg = MainHandler.obtainMessage();
+                msg.what = ServiceMain.MSG_DEV_CTR;
+                msg.obj = CmdStr;
+                MainHandler.sendMessage(msg);
+                return 0;
+            }
+        } catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+            return -100;
+        } catch (Exception e) {
+            Log.e("DriverInterOpAPI", "[Exception Error] setLightRegBR(" + acname + ")");
+            //e.printStackTrace();
+            LogUtil.errorLogInfo("", TAG, e);
+            return -100;
+        }
+        return APIErrorCode.NOT_SUPPORT;
+    }
+
+    /**
+     * 조명제어기를 켜고 끈다.<br>
+     * 현산 대외 모델과 상관없이 동작한다.<br>
+     * <br>
+     * 현산 - 일체형조명제어기 제어<br>
+     * 대외 - 거실조명 : 거실조명제어<br>
+     *       멀티스위치 : 멀티스위치 1번기기 제어<br>
+     *
+     * @param MsgWhat - (int) 메시지 타입
+     * @param index   - (int) 제어할 조명 번호
+     * @param OnOff   - (boolean) true:ON , false:OFF
+     *
+     * @return (int) - >=0 : 성공, <0 : 실패
+     */
+    public int setLight(int MsgWhat, int index, boolean OnOff) {
+        // 1. 파라미터 범위체크
+        if (!CheckRangeMsgWhat(MsgWhat)) {
+            Log.w(TAG, "[setLight] MsgWhat - Out Of Range !!! (MsgWhat:" + MsgWhat + ")");
+            return -10;
+        }
+
+        try {
+            if (mModelType == Version.MODEL_TYPE.IHN_D101 || mModelType == Version.MODEL_TYPE.IHN_D101_I
+                    || mModelType == Version.MODEL_TYPE.IHN_D101K || mModelType == Version.MODEL_TYPE.IHN_D101K_I
+                    || mModelType == Version.MODEL_TYPE.IHN_D101_I_OCF) {
+                // 스마트분전반 - 거실에너지미터 조명 제어
+                DeviceLog(null, "setLight(Sdb_LivingEM) - Start");
+
+                WallpadDeviceSet wds = new WallpadDeviceSet(ServiceMain.svcContext);
+                int nDistributionPanelType = wds.Get_DistributionPannelType_Info();
+                wds.closeDB();
+
+                if (nDistributionPanelType == Version.DISTRIBUTION_MODEL.SMART_DIST) {
+                    // 스마트 분전반
+                    if (ServiceMain.sdb_LivingRoomLight_Controller == null) return -1;
+
+                    if (!(index == (byte)0xFF) && !((index >= 1) && (index <= 4)) ) return -10;
+
+                    if (index != (byte)0xFF) index -= 1;
+
+                    String CmdStr = MakeSendMessageFormat(define.DRIVER_TITLE_SDB_LIVINGROOM_LIGHT, define.APICMD_SINKCTRL, "SetLightOnOff", index, (OnOff)?1:0, 0, 0, 0);
+                    SendDevCtrlMessage(MsgWhat, CmdStr);
+                }
+                else if (nDistributionPanelType == Version.DISTRIBUTION_MODEL.KNX_DIST) {
+                    // KNX 분전반
+                    if (ServiceMain.knx_livingRoomLight_controller == null) return -1;
+
+                    if (!(index == (byte)0xFF) && !((index >= 1) && (index <= 4)) ) return -10;
+
+                    if (index != (byte)0xFF) index -= 1;
+
+                    String CmdStr = MakeSendMessageFormat(define.DRIVER_TITLE_KNX_LIVINGROOM_LIGHT, define.APICMD_SINKCTRL, "SetLightOnOff", index, (OnOff)?1:0, 0, 0, 0);
+                    SendDevCtrlMessage(MsgWhat, CmdStr);
+                }
+                else {
+                    // 그밖의 경우, 스마트분전반을 기본으로 로딩.
+                    if (ServiceMain.sdb_LivingRoomLight_Controller == null) return -1;
+
+                    if (!(index == (byte)0xFF) && !((index >= 1) && (index <= 4))) return -10;
+
+                    if (index != (byte)0xFF) index -= 1;
+
+                    String CmdStr = MakeSendMessageFormat(define.DRIVER_TITLE_SDB_LIVINGROOM_LIGHT, define.APICMD_SINKCTRL, "SetLightOnOff", index, (OnOff)?1:0, 0, 0, 0);
+                    SendDevCtrlMessage(MsgWhat, CmdStr);
+                }
+                return 0;
+            }
+            else if (mModelType == Version.MODEL_TYPE.IHN_1020GL
+                    || mModelType == Version.MODEL_TYPE.IHN_1010GL || mModelType == Version.MODEL_TYPE.IHN_1010GL_I
+                    || mModelType == Version.MODEL_TYPE.IHN_1010GL_I_2443ALT || mModelType == Version.MODEL_TYPE.IHN_1010GL_I_6410ALT) {
+                // 현산
+                DeviceLog(null, "setLight - Start");
+
+                if (!(index == (byte)0xFF) && !((index >= 1) && (index <= 6))) return -10;
+
+                int onoff = 0;
+                if (OnOff) onoff = 1;
+                Message msg = MainHandler.obtainMessage();
+                String CmdStr = MakeSendMessageFormat(define.DRIVER_TITLE_INTLIGHT, define.APICMD_SINKCTRL, "LightControl", index, onoff, 0, 0, 0);
+
+                msg.what = MsgWhat;
+                msg.obj = CmdStr;
+                DeviceLog("HIGH","setLight - onoff (cmd:" + CmdStr + ")");
+                MainHandler.sendMessage(msg);
+
+                return 0;
+            }
+            else {
+                // 대외
+                int [] Get_Light_info = ServiceMain.dataBaseLoader.data.wallpadDeviceSet.Get_Light_info;
+                if (Get_Light_info == null) return -20;
+                if (Get_Light_info.length < 3) return -21;
+                if (Get_Light_info[0] == 0) return -22;
+
+                if (Get_Light_info[1] == WallpadDeviceSet.LIGHT_TYPE_LIVING) {
+                    // 거실조명
+                    DeviceLog(null, "setLight - Start");
+
+                    if (!(index == (byte)0xFF) && !((index >= 1) && (index <= 8))) return -10;
+
+                    int onoff = 0;
+                    if (OnOff) onoff = 1;
+                    Message msg = MainHandler.obtainMessage();
+                    String CmdStr = MakeSendMessageFormat(define.DRIVER_TITLE_LIGHT, define.APICMD_SINKCTRL, "SetLightOnOff", index, onoff, 0, 0, 0);
+                    msg.what = MsgWhat;
+                    msg.obj = CmdStr;
+                    DeviceLog("HIGH","setLight - onoff (cmd:" + CmdStr + ")");
+                    MainHandler.sendMessage(msg);
+                    return 0;
+                }
+                else if (Get_Light_info[1] == WallpadDeviceSet.LIGHT_TYPE_ROOM) {
+                    // 멀티스위치 1번기기
+                    DeviceLog(null, "setLight - Start");
+
+                    if (!(index == (byte)0xFF) && !((index >= 1) && (index <= 8))) return -10;
+
+                    int onoff = 0;
+                    if (OnOff) onoff = 1;
+
+                    byte LightIdx = (byte)index;
+                    if (index != define.DEVICE_ALL_OR_NOTHING) LightIdx--;
+
+                    Message msg = MainHandler.obtainMessage();
+                    String CmdStr = MakeSendMessageFormat(define.DRIVER_TITLE_MULTISW, define.APICMD_SINKCTRL, "SetLightOnOff", 0, LightIdx, onoff, 0, 0);
+                    msg.what = MsgWhat;
+                    msg.obj = CmdStr;
+                    DeviceLog("HIGH","setLight - onoff (cmd:" + CmdStr + ")");
+                    MainHandler.sendMessage(msg);
+
+                    return 0;
+                }
+                //제로에너지하우스 에너지미터 사용 시
+                else if (Get_Light_info[1] == WallpadDeviceSet.LIGHT_TYPE_ZEROENERGY_ENERGYMETER) {
+                    // 에너지미터 1번 기기
+                    DeviceLog(null, "setLight(EnergyMeter) - Start");
+
+                    if (ServiceMain.energyMeter_Controller == null) return -1;
+
+                    if (!(index == (byte)0xFF) && !((index >= 1) && (index <= 8))) return -10;
+
+                    int onoff = 0;
+                    if (OnOff) onoff = 1;
+
+                    byte LightIdx = (byte)index;
+                    if (index != define.DEVICE_ALL_OR_NOTHING) LightIdx--;
+
+                    String CmdStr = MakeSendMessageFormat(define.DRIVER_TITLE_ENERGYMETER, define.APICMD_SINKCTRL, "SetLightOnOff", 0, LightIdx, onoff, 0, 0);
+                    SendDevCtrlMessage(ServiceMain.MSG_DEV_CTR, CmdStr);
+                    DeviceLog(null, "setEnergyMeterLightOnOff - onoff (cmd:" + CmdStr + ")");
+                    return 0;
+                }
+                else {
+                    return -23;
+                }
+            }
+        } catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+            return -100;
+        } catch (Exception e) {
+            Log.e("DriverInterOpAPI", "[Exception Error] setLight");
+            //e.printStackTrace();
+            LogUtil.errorLogInfo("", TAG, e);
+            return -100;
+        }
+
+        //return APIErrorCode.NOT_SUPPORT;
+    }
+
+
+    public String sdbRefresh(byte type, byte index) {
+        String ret = "";
+
+        if (type == ENERGY_METER) {
+            DeviceLog(null, "setLight(EnergyMeter) - Start");
+            if (ServiceMain.sdb_Controller == null) return null;
+
+            if (!(index == (byte)0xFF) && !((index >= 1) && (index <= 8))) return null;
+
+            String CmdStr = MakeSendMessageFormat(define.DRIVER_TITLE_SMART_DISTRIBUTION_BD, define.APICMD_NOSINKCTRL, "Refresh", index, 0, 0, 0, 0);
+
+            SendDevCtrlMessage(ServiceMain.MSG_DEV_CTR, CmdStr);
+            DeviceLog(null, "[sdbRefresh] - (cmd:" + CmdStr + ")");
+
+            return ServiceMain.sdb_Controller.GetAllLightStatus()+"";
+        }
+        else if (type == ENERGY_CONT) {
+
+        }
+        else if (type == INTPOWER_CONT) {
+
+        }
+        else if (type == DC_APU) {
+
+        }
+        else if (type == ALL) {
+
+        }
+
+        return ret;
+    }
+
+    /**
+     * 조명제어기를 상태를 가져온다.<br>
+     * 현산 대외 모델과 상관없이 동작한다.<br>
+     * <br>
+     * 현산 - 일체형조명제어기 제어<br>
+     * 대외 - 거실조명 : 거실조명제어<br>
+     *       멀티스위치 : 멀티스위치 1번기기 제어<br>
+     *
+     * @param index - (byte) 가져올 조명 인덱스
+     *
+     * @return (boolean) - true : 켜짐, false : 꺼짐
+     */
+    public boolean getLight(byte index) {
+        try {
+            if (mModelType == Version.MODEL_TYPE.IHN_D101 || mModelType == Version.MODEL_TYPE.IHN_D101_I
+                    || mModelType == Version.MODEL_TYPE.IHN_D101K || mModelType == Version.MODEL_TYPE.IHN_D101K_I
+                    || mModelType == Version.MODEL_TYPE.IHN_D101_I_OCF) {
+                WallpadDeviceSet wds = new WallpadDeviceSet(ServiceMain.svcContext);
+                int nDistributionPanelType = wds.Get_DistributionPannelType_Info();
+                wds.closeDB();
+
+                if (nDistributionPanelType == Version.DISTRIBUTION_MODEL.SMART_DIST) {
+                    // 스마트 분전반
+                    return ServiceMain.sdb_LivingRoomLight_Controller.GetLightOnOff(index);
+                }
+                else if (nDistributionPanelType == Version.DISTRIBUTION_MODEL.KNX_DIST) {
+                    // KNX 분전반
+                    return ServiceMain.knx_livingRoomLight_controller.GetLightOnOff(index);
+                }
+                else {
+                    // 그밖의 경우, 스마트분전반을 기본으로 로딩.
+                    return ServiceMain.sdb_LivingRoomLight_Controller.GetLightOnOff(index);
+                }
+            }
+            else if (mModelType == Version.MODEL_TYPE.IHN_1020GL
+                    || mModelType == Version.MODEL_TYPE.IHN_1010GL || mModelType == Version.MODEL_TYPE.IHN_1010GL_I
+                    || mModelType == Version.MODEL_TYPE.IHN_1010GL_I_2443ALT || mModelType == Version.MODEL_TYPE.IHN_1010GL_I_6410ALT)
+            {
+                return IntLight_Controller.GetLightStatus(index);
+            }
+            else {
+                int [] Get_Light_info = ServiceMain.dataBaseLoader.data.wallpadDeviceSet.Get_Light_info;
+                if (Get_Light_info[1] == WallpadDeviceSet.LIGHT_TYPE_LIVING) {
+                    return ServiceMain.light_Controller.Get_OnOff()[index];
+                }
+                else if (Get_Light_info[1] == WallpadDeviceSet.LIGHT_TYPE_ROOM) {
+                    return ServiceMain.multiSwitch_Controller.getLightPower((byte)0, index);
+                }
+                else if (Get_Light_info[1] == WallpadDeviceSet.LIGHT_TYPE_ZEROENERGY_ENERGYMETER) {
+                    return ServiceMain.energyMeter_Controller.GetLightOnOff((byte)0, index);
+                }
+            }
+        } catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+            return false;
+        } catch (Exception e) {
+            Log.e("DriverInterOpAPI", "[Exception Error] getLight()");
+            //e.printStackTrace();
+            LogUtil.errorLogInfo("", TAG, e);
+            return false;
+        }
+
+        return false;
+    }
+
+    public int setLightProgramControl(byte ProgramIdx, byte OnOff) {
+        try {
+            if (mModelType == Version.MODEL_TYPE.IHN_1020GL
+                    || mModelType == Version.MODEL_TYPE.IHN_1010GL || mModelType == Version.MODEL_TYPE.IHN_1010GL_I
+                    || mModelType == Version.MODEL_TYPE.IHN_1010GL_I_2443ALT || mModelType == Version.MODEL_TYPE.IHN_1010GL_I_6410ALT) {
+                DeviceLog("HIGH","setLightProgramControl - Start");
+
+                // 1. Parameter Check
+                switch (ProgramIdx) {
+                    case (byte) 0x01:  break;
+                    case (byte) 0x02:  break;
+                    default: return APIErrorCode.INVALIDPARAMETER;
+                }
+
+                switch (OnOff) {
+                    case 0x00: case 0x01: case 0x02: break;
+                    default: return APIErrorCode.INVALIDPARAMETER;
+                }
+
+                Message msg = MainHandler.obtainMessage();
+                String CmdStr = MakeSendMessageFormat(define.DRIVER_TITLE_INTLIGHT, define.APICMD_SINKCTRL, "LightProgramControl", ProgramIdx, OnOff, 0, 0, 0);
+
+                msg.what = ServiceMain.MSG_DEV_CTR;
+                msg.obj = CmdStr;
+                DeviceLog("HIGH","setLightProgramControl - onoff (cmd:" + CmdStr + ")");
+                MainHandler.sendMessage(msg);
+
+                return 0;
+            }
+            else {
+                Log.w(TAG, "[setLightProgramControl] not supported model type -> " + mModelType);
+            }
+        } catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+            return -100;
+        } catch (Exception e) {
+            Log.e("DriverInterOpAPI", "[Exception Error] setLightProgramControl(" + OnOff + ")");
+            //e.printStackTrace();
+            LogUtil.errorLogInfo("", TAG, e);
+            return -100;
+        }
+
+        return -1;
+    }
+
+    /**
+     * 에너지미터의 전체 조명을 제어한다.
+     *
+     * @param OnOff - (boolean) true : 전체ON , false : 전체OFF
+     *
+     * @return (int) - >=0 : 성공, <0 : 실패
+     */
+    public int setEnergyMeterAllLightOnOff(boolean OnOff) {
+        try {
+            if (mModelType == Version.MODEL_TYPE.IHN_1020GL
+                    || mModelType == Version.MODEL_TYPE.IHN_1010GL || mModelType == Version.MODEL_TYPE.IHN_1010GL_I
+                    || mModelType == Version.MODEL_TYPE.IHN_1010GL_I_2443ALT || mModelType == Version.MODEL_TYPE.IHN_1010GL_I_6410ALT) {
+                DeviceLog("HIGH","setEnergyMeterAllLightOnOff - Start");
+
+                if (ServiceMain.energyMeter_Controller == null) return -1;
+                //if((index <= 0) || (index >= 6)) return -10;
+
+                int onoff = 0;
+                if (OnOff) onoff = 1;
+
+                String CmdStr = MakeSendMessageFormat(define.DRIVER_TITLE_ENERGYMETER, define.APICMD_SINKCTRL, "SetAllLightOnOff", onoff, 0, 0, 0, 0);
+
+                SendDevCtrlMessage(ServiceMain.MSG_DEV_CTR, CmdStr);
+                DeviceLog("HIGH","setLight - onoff (cmd:" + CmdStr + ")");
+
+                return 0;
+            }
+        } catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+            return -100;
+        } catch (Exception e) {
+            Log.e("DriverInterOpAPI", "[Exception Error] setEnergyMeterAllLightOnOff(" + OnOff + ")");
+            //e.printStackTrace();
+            LogUtil.errorLogInfo("", TAG, e);
+            return -100;
+        }
+        return -2;
+    }
+
+    /**
+     * 에너지미터의 개별방 조명 ON/OFF 제어
+     *
+     * @param RoomIndex   - (byte) 방인덱스     (00:1번방 ~ 05:6번방) * 방개수를 초과할수 없음.
+     * @param LightIndex  - (byte) 조명인덱스  (00:1번조명 ~ 03:4번조명, FF:전체)
+     * @param OnOff       - (boolean) 변경할 ON/OFF 상태 (true : ON , false : OFF)
+     *
+     * @return (int) - >=0 : 성공, <0 : 실패
+     */
+    public int setEnergyMeterLightOnOff(byte RoomIndex, byte LightIndex, boolean OnOff) {
+        try {
+            if (mModelType == Version.MODEL_TYPE.IHN_1020GL
+                    || mModelType == Version.MODEL_TYPE.IHN_1010GL || mModelType == Version.MODEL_TYPE.IHN_1010GL_I
+                    || mModelType == Version.MODEL_TYPE.IHN_1010GL_I_2443ALT || mModelType == Version.MODEL_TYPE.IHN_1010GL_I_6410ALT) {
+                DeviceLog(null ,"setEnergyMeterLightOnOff - Start");
+
+                if (ServiceMain.energyMeter_Controller == null) return -1;
+
+                int onoff = 0;
+                if (OnOff) onoff = 1;
+
+                String CmdStr = MakeSendMessageFormat(define.DRIVER_TITLE_ENERGYMETER, define.APICMD_SINKCTRL, "SetLightOnOff", RoomIndex, LightIndex, onoff, 0, 0);
+
+                SendDevCtrlMessage(ServiceMain.MSG_DEV_CTR, CmdStr);
+                DeviceLog(null, "setEnergyMeterLightOnOff - onoff (cmd:" + CmdStr + ")");
+
+                return 0;
+            }
+        } catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+            return -100;
+        } catch (Exception e) {
+            Log.e("DriverInterOpAPI", "[Exception Error] setEnergyMeterLightOnOff(" + OnOff + ")");
+            //e.printStackTrace();
+            LogUtil.errorLogInfo("", TAG, e);
+            return -100;
+        }
+
+        return -2;
+    }
+
+    /**
+     * 에너지미터의 개별방 콘센트 ON/OFF 제어
+     *
+     * @param RoomIndex    - (byte) 방인덱스     (00:1번방 ~ 05:6번방) * 방개수를 초과할수 없음.
+     * @param ConcentIndex - (byte) 콘센트인덱스
+     * @param OnOff        - (boolean) 변경할 ON/OFF 상태 (true : ON , false : OFF)
+     *
+     * @return (int) - >=0 : 성공, <0 : 실패
+     */
+    public int setEnergyMeterConcentOnOff(byte RoomIndex, byte ConcentIndex, boolean OnOff) {
+        try {
+            if (mModelType == Version.MODEL_TYPE.IHN_1020GL
+                    || mModelType == Version.MODEL_TYPE.IHN_1010GL || mModelType == Version.MODEL_TYPE.IHN_1010GL_I
+                    || mModelType == Version.MODEL_TYPE.IHN_1010GL_I_2443ALT || mModelType == Version.MODEL_TYPE.IHN_1010GL_I_6410ALT) {
+                DeviceLog(null ,"setEnergyMeterConcentOnOff - Start");
+
+                if (ServiceMain.energyMeter_Controller == null) return -1;
+
+                int onoff = 0;
+                if (OnOff) onoff = 1;
+
+                String CmdStr = MakeSendMessageFormat(define.DRIVER_TITLE_ENERGYMETER, define.APICMD_SINKCTRL, "SetConcentOnOff", RoomIndex, ConcentIndex, onoff, 0, 0);
+
+                SendDevCtrlMessage(ServiceMain.MSG_DEV_CTR, CmdStr);
+                DeviceLog(null, "setEnergyMeterConcentOnOff - onoff (cmd:" + CmdStr + ")");
+
+                return 0;
+            }
+
+        } catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+            return -100;
+        } catch (Exception e) {
+            Log.e("DriverInterOpAPI", "[Exception Error] setEnergyMeterConcentOnOff(" + OnOff + ")");
+            //e.printStackTrace();
+            LogUtil.errorLogInfo("", TAG, e);
+            return -100;
+        }
+
+        return -2;
+    }
+
+    /**
+     * 스마트분전반의 전체 조명을 제어한다.
+     *
+     * @param OnOff   - (boolean) 조명 ON/OFF 상태
+     * @param Dimming - (byte) 변경할 디밍 상태
+     * @param Color   - (byte) 변경할 색온도 상태
+     * @param ColorControl   - (boolean) 색온도 제어 여부
+     *
+     * @return (int) - >=0 : 성공, <0 : 실패
+     */
+    public int setSdbAllLightControl(boolean OnOff, byte Dimming, byte Color, boolean ColorControl) {
+        try {
+            if (mModelType == Version.MODEL_TYPE.IHN_D101 || mModelType == Version.MODEL_TYPE.IHN_D101_I
+                    || mModelType == Version.MODEL_TYPE.IHN_D101K || mModelType == Version.MODEL_TYPE.IHN_D101K_I
+                    || mModelType == Version.MODEL_TYPE.IHN_D101_I_OCF) {
+                DeviceLog(null ,"setSdbAllLightControl(OnOff:" + OnOff + ", Dimming:" + Dimming + ", Color:" + Color + ", ColorControl:" + ColorControl + ")");
+
+                if (ServiceMain.sdb_Controller == null) return -1;
+
+                String CmdStr = MakeSendMessageFormat(define.DRIVER_TITLE_SMART_DISTRIBUTION_BD,
+                        define.APICMD_SINKCTRL,
+                        "SetAllLightControl",
+                        (OnOff)?0x01:0x02, Dimming, Color,
+                        (ColorControl)?0x01:0x00, 0);
+
+                SendDevCtrlMessage(ServiceMain.MSG_DEV_CTR, CmdStr);
+                DeviceLog(null, "setSdbAllLightControl - (cmd:" + CmdStr + ")");
+
+                return 0;
+            }
+        } catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+            return -100;
+        } catch (Exception e) {
+            Log.e("DriverInterOpAPI", "[Exception Error] setSdbAllLightControl(" + OnOff + ")");
+            //e.printStackTrace();
+            LogUtil.errorLogInfo("", TAG, e);
+            return -100;
+        }
+        return APIErrorCode.NOT_SUPPORT;
+    }
+
+	/**
+	 * 스마트분전반 각방의 조명을 제어한다.
+	 *
+     * @param RoomIndex -(byte) 제어할 방 인덱스 (0:거실EM,1:침실EM 첫번째...)
+	 * @param OnOff - (boolean) 조명 ON/OFF 상태
+	 * @return (int) - >=0 : 성공, <0 : 실패
+	 */
+    public int setSdbEachRoomLightOnOffControl(byte RoomIndex, boolean OnOff) {
+		try {
+			if (mModelType == Version.MODEL_TYPE.IHN_D101 || mModelType == Version.MODEL_TYPE.IHN_D101_I
+                    || mModelType == Version.MODEL_TYPE.IHN_D101K || mModelType == Version.MODEL_TYPE.IHN_D101K_I
+                    || mModelType == Version.MODEL_TYPE.IHN_D101_I_OCF) {
+				DeviceLog(null ,"D101 - setSdbEachRoomLightControl - Start");
+
+				if (ServiceMain.sdb_Controller == null) return -1;
+				if (ServiceMain.sdb_LivingRoomLight_Controller == null) return -1;
+
+				// 조명이 켜져 있을 때, 해당 방의 조명을 끄도록 한다.
+				if (RoomIndex == 0) {
+                    // 거실
+					DeviceLog(null, "setSdbEachRoomLightControl - Living(Liv.EM) light CTR ~~~");
+
+                    String CmdStr = MakeSendMessageFormat(define.DRIVER_TITLE_SDB_LIVINGROOM_LIGHT, define.APICMD_SINKCTRL, "SetLightOnOff", define.DEVICE_ALL_OR_NOTHING, (OnOff)?0x01:0x00,0,0,0);
+                    //******* 모든조명 / 조명 ON/OFF / Don't care / Don't care / Don't care
+
+                    SendDevCtrlMessage(ServiceMain.MSG_DEV_CTR, CmdStr);
+                    DeviceLog(null, "setSdbEachRoomLightControl - (cmd:" + CmdStr + ")");
+
+					return 0;
+				}
+				else {
+                    DeviceLog(null, "setSdbEachRoomLightControl - Each Room(Bed.EM) light CTR ~~~");
+
+					String CmdStr = MakeSendMessageFormat(define.DRIVER_TITLE_SMART_DISTRIBUTION_BD, define.APICMD_SINKCTRL, "SetLightOnOff", RoomIndex-1, define.DEVICE_ALL_OR_NOTHING, (OnOff)?0x01:0x00,0,0);
+					//*******침실EM ID / 모든조명 / 조명 ON/OFF / Don't care / Don't care
+
+					SendDevCtrlMessage(ServiceMain.MSG_DEV_CTR, CmdStr);
+					DeviceLog(null, "setSdbEachRoomLightControl - (cmd:" + CmdStr + ")");
+					return 0;
+				}
+			}
+		} catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+            return -100;
+        } catch (Exception e) {
+			Log.e("DriverInterOpAPI", "[Exception Error] setSdbEachRoomLightControl(" + OnOff + ")");
+			//e.printStackTrace();
+            LogUtil.errorLogInfo("", TAG, e);
+			return -100;
+		}
+		return APIErrorCode.NOT_SUPPORT;
+	}
+
+    /**
+     * 스마트분전반 각방의 디밍을 제어한다.
+     *
+     * @param RoomIndex -(byte) 제어할 방 인덱스 (0:거실EM,1:침실EM 첫번째...)
+     * @param DimLevel - (byte) 제어할 디밍 단계
+     * @return (int) - >=0 : 성공, <0 : 실패
+     */
+    public int setSdbEachRoomDimControl(byte RoomIndex, byte LightIndex, byte DimLevel) {
+        try {
+            if (mModelType == Version.MODEL_TYPE.IHN_D101 || mModelType == Version.MODEL_TYPE.IHN_D101_I
+                    || mModelType == Version.MODEL_TYPE.IHN_D101K || mModelType == Version.MODEL_TYPE.IHN_D101K_I
+                    || mModelType == Version.MODEL_TYPE.IHN_D101_I_OCF) {
+                DeviceLog(null ,"D101 - setSdbEachRoomDimControl - Start");
+
+                if (ServiceMain.sdb_Controller == null) return -1;
+                if (ServiceMain.sdb_LivingRoomLight_Controller == null) return -1;
+
+                // 조명이 켜져 있을 때, 해당 방의 조명을 끄도록 한다.
+                if (RoomIndex == 0) {
+                    // 거실
+                    DeviceLog(null, "setSdbEachRoomDimControl - Living(Liv.EM) Dim CTR ~~~");
+
+                    String CmdStr = MakeSendMessageFormat(define.DRIVER_TITLE_SDB_LIVINGROOM_LIGHT, define.APICMD_SINKCTRL, "SetLightDimming", LightIndex, DimLevel,0,0,0);
+                    //******* 모든조명 / 조명 ON/OFF / Don't care / Don't care / Don't care
+
+                    SendDevCtrlMessage(ServiceMain.MSG_DEV_CTR, CmdStr);
+                    DeviceLog(null, "setSdbEachRoomDimControl - (cmd:" + CmdStr + ")");
+
+                    return 0;
+                }
+                else {
+                    DeviceLog(null, "setSdbEachRoomDimControl - Each Room(Bed.EM) Dim CTR ~~~");
+
+                    String CmdStr = MakeSendMessageFormat(define.DRIVER_TITLE_SMART_DISTRIBUTION_BD, define.APICMD_SINKCTRL, "SetLightDimming", RoomIndex, LightIndex, DimLevel,0,0);
+                    //*******침실EM ID / 모든조명 / 조명 ON/OFF / Don't care / Don't care
+
+                    SendDevCtrlMessage(ServiceMain.MSG_DEV_CTR, CmdStr);
+                    DeviceLog(null, "setSdbEachRoomDimControl - (cmd:" + CmdStr + ")");
+
+                    return 0;
+                }
+            }
+        } catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+            return -100;
+        } catch (Exception e) {
+            Log.e("DriverInterOpAPI", "[Exception Error] setSdbEachRoomDimControl(" + DimLevel + ")");
+            //e.printStackTrace();
+            LogUtil.errorLogInfo("", TAG, e);
+            return -100;
+        }
+
+        return APIErrorCode.NOT_SUPPORT;
+    }
+
+    /**
+     * 실시간 검침기에 전력 누적전력사용량 저장명령을 내린다.
+     *
+     * @return (int) - >=0 : 성공, <0 : 실패
+     */
+    public int setRealTimeMeterElecAccSave() {
+        try {
+            if (mModelType == Version.MODEL_TYPE.IHN_D101 || mModelType == Version.MODEL_TYPE.IHN_D101_I
+                    || mModelType == Version.MODEL_TYPE.IHN_D101K || mModelType == Version.MODEL_TYPE.IHN_D101K_I
+                    || mModelType == Version.MODEL_TYPE.IHN_D101_I_OCF) {
+                DeviceLog(null ,"setRealTimeMeterElecAccSave()");
+
+                if (ServiceMain.realTimeMeter_Controller == null) return -1;
+
+                String CmdStr = MakeSendMessageFormat(define.DRIVER_TITLE_REALTIMEMETER, define.APICMD_NOSINKCTRL, "ElecAccSave", 0, 0, 0, 0, 0);
+
+                SendDevCtrlMessage(ServiceMain.MSG_DEV_CTR, CmdStr);
+                DeviceLog(null, "setSdbAllLightControl - (cmd:" + CmdStr + ")");
+
+                return 0;
+            }
+        } catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+            return -100;
+        } catch (Exception e) {
+            Log.e("DriverInterOpAPI", "[Exception Error] setRealTimeMeterElecAccSave()");
+            //e.printStackTrace();
+            LogUtil.errorLogInfo("", TAG, e);
+            return -100;
+        }
+
+        return APIErrorCode.NOT_SUPPORT;
+    }
+
+
+
+
+
+
+
+
+
+
+    /**
+     * 시스템에어컨에 BR을 등록한다.<br>
+     * 현산 대외 모델과 상관없이 동작한다.<br>
+     *
+     * @param acname - (String) 등록할 name
+     *
+     * @return (int) - >=0 : 성공, <0 : 실패
+     */
+    public int setAirconRegBR(String acname) {
+        try {
+            WallpadDeviceSet mWallpadDeviceSet = new WallpadDeviceSet(ServiceMain.svcContext);
+            int nAirconSetting = mWallpadDeviceSet.Get_AirCON_Info();
+            mWallpadDeviceSet.closeDB();
+
+            String DriverTitleStr = null;
+
+            if (nAirconSetting == WallpadDeviceSet.SYSTEMAIRCON_SAMSUNG_AIR
+                    || nAirconSetting == WallpadDeviceSet.SYSTEMAIRCON_SAMSUNG_AIR_HEAT
+                    || nAirconSetting == WallpadDeviceSet.SYSTEMAIRCON_LG_AIR
+                    || nAirconSetting == WallpadDeviceSet.SYSTEMAIRCON_LG_AIR_HEAT
+                    || nAirconSetting == WallpadDeviceSet.SYSTEMAIRCON_ETC) {
+                DriverTitleStr = define.DRIVER_TITLE_AIRCON;
+            }
+            else return -23;
+
+            if (DriverTitleStr != null) {
+                String CmdStr = DriverTitleStr + ";" + define.APICMD_REGBR + ";" + acname;
+                Message msg = MainHandler.obtainMessage();
+                msg.what = ServiceMain.MSG_DEV_CTR;
+                msg.obj = CmdStr;
+                MainHandler.sendMessage(msg);
+                return 0;
+            }
+        } catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+            return -100;
+        } catch (Exception e) {
+            Log.e("DriverInterOpAPI", "[Exception Error] setAirconRegBR(" + acname + ")");
+            //e.printStackTrace();
+            LogUtil.errorLogInfo("", TAG, e);
+            return -100;
+        }
+        return APIErrorCode.NOT_SUPPORT;
+    }
+
+    /**
+     * 조명제어기를 켜고 끈다.<br>
+     * 현산 대외 모델과 상관없이 동작한다.<br>
+     * <br>
+     * 현산 - 일체형조명제어기 제어<br>
+     * 대외 - 거실조명 : 거실조명제어<br>
+     *       멀티스위치 : 멀티스위치 1번기기 제어<br>
+     *
+     * @param MsgWhat - (int) 메시지 타입
+     *
+     * @return (int) - >=0 : 성공, <0 : 실패
+     */
+    public int ctrlAircon(int MsgWhat, byte hIndex, byte hCtrlOption, byte hSetData, byte hSetTemper) {
+        // 1. 파라미터 범위체크
+        if (!CheckRangeMsgWhat(MsgWhat)) {
+            Log.w(TAG, "[ctrlAircon] MsgWhat - Out Of Range !!! (MsgWhat:" + MsgWhat + ")");
+            return -10;
+        }
+
+        try {
+            if (ServiceMain.systemAircon_controller == null) return -1;
+
+            Log.i(TAG, "[ctrlAircon] hIndex [" + String.format("0x%02X", hIndex) + "], hCtrlOption [" + String.format("0x%02X", hCtrlOption) + "], hSetData [" + String.format("0x%02X", hSetData) + "], hSetTemper [" + String.format("0x%02X", hSetTemper) + "]");
+            String CmdStr = MakeSendMessageFormat(define.DRIVER_TITLE_AIRCON, define.APICMD_SINKCTRL, "SetUnitDeviceStatusV2", hIndex - 1, hCtrlOption, hSetData, hSetTemper, 0);
+            SendDevCtrlMessage(MsgWhat, CmdStr);
+
+            return 0;
+
+        } catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+            return -100;
+        } catch (Exception e) {
+            Log.e("DriverInterOpAPI", "[Exception Error] ctrlAircon(int MsgWhat, byte hIndex, byte hCtrlOption, byte hSetData, byte hSetTemper)");
+            //e.printStackTrace();
+            LogUtil.errorLogInfo("", TAG, e);
+            return -100;
+        }
+
+        //return APIErrorCode.NOT_SUPPORT;
+    }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+    /**
+     * 제어시 사용되는 SendCMD 및 Return Value Check 의 공통부분 메소드이다.
+     *
+     * @param TitleStr - (String) 드라이버 타이틀
+     * @param MainCMD  - (String) 주 명령어    (define.APICMD_SINKCTRL  or  define.APICMD_NOSINKCTRL)
+     * @param SubCMD   - (String) 서브 명령어
+     * @param param1   - (int) 첫번째 파라미터
+     * @param param2   - (int) 두번째 파라미터
+     * @param param3   - (int) 세번째 파라미터
+     * @param param3   - (int) 네번째 파라미터
+     * @param param3   - (int) 다섯번째 파라미터
+     *
+     * @return (String) 결과
+     */
+    private String MakeSendMessageFormat(String TitleStr, String MainCMD, String SubCMD, int param1, int param2, int param3, int param4, int param5) {
+        return String.format("%s;%s;%s:%d:%d:%d:%d:%d", TitleStr, MainCMD, SubCMD, param1, param2, param3, param4, param5);
+    }
+
+    /**
+     * 제어시 사용되는 SendCMD 및 Return Value Check 의 공통부분 메소드이다.
+     *
+     * @param TitleStr - (String) 드라이버 타이틀
+     * @param MainCMD  - (String) 주 명령어    (define.APICMD_SINKCTRL  or  define.APICMD_NOSINKCTRL)
+     * @param SubCMD   - (String) 서브 명령어
+     * @param param   - (byte[]) byte[] 파라미터
+     *
+     * @return (String) 결과
+     */
+    private String MakeSendMessageFormat(String TitleStr, String MainCMD, String SubCMD, byte[] param) {
+        String CmdStr = String.format("%s;%s;%s:", TitleStr, MainCMD, SubCMD);
+        for (int i=0 ; i<param.length ; i++) CmdStr += param[i] + ":";
+        return CmdStr;
+    }
+
+    /**
+     * 드라이버에 제어 메시지를 전달한다.
+     *
+     * @param MsgWhat - (int) 메시지 타입
+     * @param CmdStr  - (String) 전달할 명령어 String
+     */
+    private void SendDevCtrlMessage(int MsgWhat, String CmdStr) {
+        Message msg = MainHandler.obtainMessage();
+        msg.what = MsgWhat;
+        msg.obj = CmdStr;
+        MainHandler.sendMessage(msg);
+    }
+
+    /**
+     * 설정온도 소수점 0.5 도 존재 유무를 판별한다.
+     *
+     * @param n - (double) 값
+     *
+     * @return  - (boolean) true : 있음 , false : 없음
+     */
+    private boolean PointExist(double n) {
+        double FilterData = Double.parseDouble(String.format("%.1f", n));
+        int IntValue = (int)FilterData;
+        double Point = FilterData - IntValue;
+
+        if (Point >= 0.5) return true;
+        return false;
+    }
+}

+ 1203 - 1204
WallPadDevService/src/main/java/com/artncore/wallpaddevservice/driver/GasValve_Controller.java

@@ -1,1204 +1,1203 @@
-
-package com.artncore.wallpaddevservice.driver;
-
-import android.annotation.SuppressLint;
-import android.content.Intent;
-import android.util.Log;
-
-import com.artncore.WallPadDataMgr.WallpadDevStatus;
-import com.artncore.WallPadDataMgr.WallpadStatusData;
-import com.artncore.commons.APIErrorCode;
-import com.artncore.commons.define;
-import com.artncore.wallpaddevservice.CommonDefine;
-import com.artncore.wallpaddevservice.ServiceMain;
-import com.util.LogUtil;
-
-
-/**
- * 가스밸브 의 드라이버 모듈이다.
- */
-@SuppressLint("HandlerLeak")
-public class GasValve_Controller extends DeviceManager
-{
-    private final static String TAG = "GasValve_Controller";
-
-    private final byte DEVICE_ADDRESS  = (byte) 0x31;
-
-    /** 더미패킷 사용 유무 */
-    private final boolean USE_DUMMY_PACKET = false;
-
-    private static byte GasStatus = GASSTATUS.Operation;
-    public static byte GetGasStatus() { return GasStatus; }
-
-    /** 최대 기기 개수 */
-    private final byte MAX_DEVICE_COUNT  = 2;
-
-    /** 초기 기기 검색 횟수  */
-    private final int MAX_SEARCH_COUNT   = 3;
-
-    /** 감지 패킷 수신 횟수  */
-    private int DetectInputCount = 0;
-
-
-    private final int MAX_Detect_COUNT   = 5;
-
-
-    /** 가스밸브 상태 */
-    public static class STATUS
-    {
-        /** 가스밸브 상태 */
-        public byte GasStatus;
-
-        /** 경고/이상 */
-        public byte Fault;
-
-        /** 제어기 이상 */
-        public boolean bFaultController;
-        /** 가스누출 감지 */
-        public boolean bFaultGasDetected;
-        /** 화재발생 감지 */
-        public boolean bFaultFireDetected;
-        /** 가스센서 이상 */
-        public boolean bFaultGasSensor;
-        /** 화재센서 이상 */
-        public boolean bFaultFireSensor;
-        /** 설치상태 (true:설치 , false:미설치) */
-        public boolean Install;
-
-        public STATUS()
-        {
-            GasStatus = GASSTATUS.Operation;
-            Fault = 0x00;
-            bFaultController = false;
-            bFaultGasDetected = false;
-            bFaultFireDetected = false;
-            bFaultGasSensor = false;
-            bFaultFireSensor = false;
-            Install = false;
-        }
-
-        /** 디버깅 메시지 출력 */
-        public String ToDebugString()
-        {
-            String retStr =
-                    "==========================\r\n" +
-                            "STATUS\r\n" +
-                            "==========================\r\n" +
-                            "Status       : " + GASSTATUS.ToDebugString(GasStatus)         + "\r\n" +
-                            "Fault        : " + String.format("0x%02X", Fault)     + "\r\n" +
-                            "\r\n" +
-                            "bFaultController   : " + bFaultController + "\r\n" +
-                            "bFaultGasDetected  : " + bFaultGasDetected + "\r\n" +
-                            "bFaultFireDetected : " + bFaultFireDetected + "\r\n" +
-                            "bFaultGasSensor    : " + bFaultGasSensor + "\r\n" +
-                            "bFaultFireSensor   : " + bFaultFireSensor + "\r\n" +
-                            "==========================";
-            return retStr;
-        }
-    }
-
-    /** 가스밸브 상태 정의 */
-    public static class GASSTATUS
-    {
-        /** 닫힘 */
-        public static byte Close         = 0x00;
-        /** 열림 */
-        public static byte Open          = 0x01;
-        /** 동작중 */
-        public static byte Operation     = 0x02;
-
-        /**
-         * 범위를 체크한다.
-         *
-         * @param nStatus - (byte) 체크할 상태
-         *
-         * @return (boolean) ture:정상 , false:범위이탈
-         */
-        public static boolean CheckRange(byte nStatus)
-        {
-            if(nStatus == GASSTATUS.Close)                   return true;
-            else if(nStatus == GASSTATUS.Open)               return true;
-            else if(nStatus == GASSTATUS.Operation)          return true;
-            return false;
-        }
-
-        public static String ToDebugString(byte nStatus)
-        {
-            String retStr;
-            if(nStatus == GASSTATUS.Close)                   retStr = "Close";
-            else if(nStatus == GASSTATUS.Open)               retStr = "Open";
-            else if(nStatus == GASSTATUS.Operation)          retStr = "Operation";
-            else retStr = "UnDefined";
-            return retStr;
-        }
-    }
-
-    public class Driver
-    {
-        private PollingList Polling;
-
-        private STATUS[] Status;
-
-        public Driver()
-        {
-            Polling = new PollingList();
-            Status = new STATUS[MAX_DEVICE_COUNT];
-            for(int i=0 ; i<MAX_DEVICE_COUNT ; i++) Status[i] = new STATUS();
-        }
-
-        /** Polling 관련 */
-        private class PollingList
-        {
-            private final class STATUS
-            {
-                /** 초기화 과정 */
-                public final static byte First = 0;
-                /** 초기화 타임아웃 */
-                public final static byte FirstTimeOut = 1;
-                /** 평상시 */
-                public final static byte Normal = 2;
-                /** 닫기 */
-                public final static byte Close = 3;
-                /** 모든 가스벨브 닫기 */
-                public final static byte AllClose = 4;
-            }
-
-            public byte CurrentAddress;
-            public byte SearchDeviceCount;
-            public boolean SearchEnd;
-            public byte Status;
-            public int SearchTryCount;
-            public int CloseReTryCount;
-            public int AllCloseReTryCount;
-            public byte ControlAddress;
-
-            private PollingList()
-            {
-                CurrentAddress = 0;
-                Status = STATUS.First;
-                SearchDeviceCount = 0;
-                SearchEnd = false;
-                SearchTryCount = 0;
-                CloseReTryCount = 0;
-                AllCloseReTryCount = 0;
-                ControlAddress = 0;
-            }
-
-            public void SetStatus(byte ChangeStatus)
-            {
-                switch(ChangeStatus)
-                {
-                    case STATUS.First:
-                        Status = ChangeStatus;
-                        break;
-                    case STATUS.FirstTimeOut:
-                        Status = ChangeStatus;
-                        break;
-                    case STATUS.Normal:
-                        Status = ChangeStatus;
-                        break;
-                    case STATUS.Close:
-                        Status = ChangeStatus;
-                        CloseReTryCount = 0;
-                        break;
-                    case STATUS.AllClose:
-                        Status = ChangeStatus;
-                        AllCloseReTryCount = 0;
-                        break;
-                    default:
-                        break;
-                }
-            }
-        }
-    }
-
-    private Driver mDriver = null;
-
-
-    /**
-     * 생성자
-     */
-    public GasValve_Controller()
-    {
-        /* 로그 초기상태 */
-//        log_sw = true;
-//        SerialLog = true;
-
-        /* 통신성공률 변수 초기화 */
-        super.CommDataGeneration(1);
-
-        /* 드라이버 내부 변수 초기화 */
-        mDriver = new Driver();
-
-        Log.i(TAG, "Create !!!");
-    }
-
-    @Override
-    public void DeviceLog(String msg)
-    {
-        if (!log_sw) return;
-        Log.d(TAG, msg);
-    }
-
-    /**
-     * 로딩후 처음 폴링 시퀀스
-     */
-    @Override
-    protected void do_boot()
-    {
-    }
-
-    ///////////////////////////////////////////////////////////////////////////////////////////////
-    // Polling
-    ///////////////////////////////////////////////////////////////////////////////////////////////
-    /**
-     * do_ctr : 폴링스케쥴러
-     */
-    @Override
-    protected void do_ctr()
-    {
-        DeviceLog("Polling ");
-
-        /* [[ First & FirstTimeOut ]]
-         * 초기 디바이스정보  검색 */
-        if(mDriver.Polling.Status == Driver.PollingList.STATUS.First)
-        {
-            // 1. 디바이스 검색
-            byte MaxDeviceID = 0;
-            for(byte DeviceIdx = 0 ; DeviceIdx<MAX_DEVICE_COUNT ; DeviceIdx++)
-            {
-                STATUS Status = Send_GetStatus(DeviceIdx);
-                if(Status != null)
-                {
-                    MaxDeviceID = (byte)(DeviceIdx+1);
-                    UpdateVariables(DeviceIdx, Status, true);
-
-                    Log.i(TAG, "SearchDevice     DeviceNum = " + (byte)(DeviceIdx+1) + "      OK!!!");
-                }
-                else
-                {
-                    Log.i(TAG, "SearchDevice     DeviceNum = " + (byte)(DeviceIdx+1) + "      Fail...");
-                }
-                Sleep(1000);
-            }
-
-            // 2. 가장 높은 ID 저장
-            if (MaxDeviceID > mDriver.Polling.SearchDeviceCount) mDriver.Polling.SearchDeviceCount = MaxDeviceID;
-
-            // 3. 검색 횟수 체크
-            if(++mDriver.Polling.SearchTryCount >= MAX_SEARCH_COUNT)
-            {
-                if(mDriver.Polling.SearchDeviceCount != 0)
-                {
-                    mDriver.Polling.SearchEnd = true;
-                    mDriver.Polling.Status = Driver.PollingList.STATUS.Normal;
-                    Log.i(TAG, "First - Search Device END - SearchDeviceCount : " + mDriver.Polling.SearchDeviceCount);
-                }
-                else
-                {
-                    mDriver.Polling.Status = Driver.PollingList.STATUS.FirstTimeOut;
-
-                    Log.i(TAG, "--------------------------------------------------");
-                    Log.i(TAG, "SearchDevice Fail... FirstTimeOut ");
-                    Log.i(TAG, "--------------------------------------------------");
-                }
-                ServiceMain.deviceInitChecker.Remove(super.DeviceName);
-            }
-        }
-
-        /* [[ FirstTimeOut ]]
-         * 초기 디바이스 검색하지못함. */
-        else if(mDriver.Polling.Status == Driver.PollingList.STATUS.FirstTimeOut)
-        {
-            STATUS Status = Send_GetStatus(mDriver.Polling.CurrentAddress);
-            if(Status != null)
-            {
-                UpdateVariables(mDriver.Polling.CurrentAddress, Status, true);
-                mDriver.Polling.SearchDeviceCount = (byte) (mDriver.Polling.CurrentAddress + 1);
-            }
-
-            if(++mDriver.Polling.CurrentAddress >= MAX_DEVICE_COUNT)
-            {
-                mDriver.Polling.CurrentAddress = 0;
-
-                if(mDriver.Polling.SearchDeviceCount != 0)
-                {
-                    mDriver.Polling.SearchEnd = true;
-                    mDriver.Polling.Status = Driver.PollingList.STATUS.Normal;
-                    Log.i(TAG, "FirstTimeOut - Search Device END - SearchDeviceCount : " + mDriver.Polling.SearchDeviceCount);
-                }
-            }
-        }
-
-        /* [[ Normal ]]
-         * 평상시 */
-        else if(mDriver.Polling.Status == Driver.PollingList.STATUS.Normal)
-        {
-            if(mDriver.Polling.SearchEnd)
-            {
-                mDriver.Polling.SearchEnd = false;
-
-                int DeviceCount = mDriver.Polling.SearchDeviceCount;
-
-                super.CommDataGeneration(DeviceCount);
-
-                for(byte DeviceIdx=0 ; DeviceIdx<DeviceCount ; DeviceIdx++)
-                {
-                    DeviceLog("Gas ID: " + DeviceIdx + " DebugMessage: " + mDriver.Status[DeviceIdx].ToDebugString());
-                }
-            }
-
-            byte CurrentAddress = mDriver.Polling.CurrentAddress;
-            STATUS Status = Send_GetStatus(CurrentAddress);
-            if(Status != null)
-            {
-                UpdateVariables(CurrentAddress, Status, false);
-            }
-
-            if(++mDriver.Polling.CurrentAddress >= mDriver.Polling.SearchDeviceCount)
-                mDriver.Polling.CurrentAddress = 0;
-        }
-        /* [[ Close ]]
-         * 닫기 */
-        else if(mDriver.Polling.Status == Driver.PollingList.STATUS.Close)
-        {
-            // 2013-03-04
-            // 한국 소방 가스밸브의 경우 기기 특성상 가변 패킷 이후에 약 1초의 Term을 주어야 밸브패킷을 수신할수 있다.
-            // 따라서, 현재 폴링속도가 빨라지고 가변패킷이 온도조절기외에 실시간검침기가 추가됨에 따라 한국소방의 패킷수신률이
-            // 현저히 떨어졌으며, 이를 보완하기 위하여 닫기 명령이 왔을때 폴링시퀀스상에서 1초의 Term을 주고 송신하도록 처리하였다.
-
-            // Retry는 최대 5회까지 하도록한다.
-            mDriver.Polling.CloseReTryCount++;
-            Log.i(TAG, "Close ReTry Count = " + mDriver.Polling.CloseReTryCount);
-            if (mDriver.Polling.CloseReTryCount >= 5)
-            {
-                mDriver.Polling.SetStatus(Driver.PollingList.STATUS.Normal);
-                mDriver.Polling.ControlAddress = 0;
-            }
-
-            Sleep(1000);
-
-            STATUS Status = Send_SetClose(mDriver.Polling.ControlAddress);
-            if(Status != null)
-            {
-                Log.i(TAG, "Close ReTry Control Success !!!");
-                mDriver.Polling.SetStatus(Driver.PollingList.STATUS.Normal);
-                UpdateVariables(mDriver.Polling.ControlAddress, Status, true);
-                mDriver.Polling.ControlAddress = 0;
-            }
-        }
-        else if(mDriver.Polling.Status == Driver.PollingList.STATUS.AllClose)
-        {
-            mDriver.Polling.AllCloseReTryCount++;
-            Log.i(TAG, "All Close ReTry Count = " + mDriver.Polling.AllCloseReTryCount);
-            if (mDriver.Polling.AllCloseReTryCount >= 5)
-            {
-                mDriver.Polling.SetStatus(Driver.PollingList.STATUS.Normal);
-            }
-
-            Sleep(1000);
-
-            boolean result = true;
-            for(int i = 0; i < mDriver.Polling.SearchDeviceCount; i++)
-            {
-                if(mDriver.Status[i].Install)
-                {
-                    STATUS Status = Send_SetClose((byte)i);
-                    if(Status != null)
-                    {
-                        UpdateVariables((byte)i, Status, true);
-                    }
-                    else
-                    {
-                        result = false;
-                    }
-                    Sleep(100);
-                }
-                else
-                {
-                    result = false;
-                }
-            }
-            if(result)
-            {
-                Log.i(TAG, "All Close Control Success !!!");
-                mDriver.Polling.SetStatus(Driver.PollingList.STATUS.Normal);
-            }
-        }
-        /*
-         * 예외처리 */
-        else
-        {
-            mDriver = new Driver();
-        }
-    }
-
-    ///////////////////////////////////////////////////////////////////////////////////////////////
-    // Ctrl
-    ///////////////////////////////////////////////////////////////////////////////////////////////
-    /**
-     * NoSink 제어
-     *
-     * @param StrArg
-     *
-     * @return
-     */
-    public String NoSinkCtrl(String StrArg)
-    {
-        DeviceLog("[NoSinkCtrl] Start");
-
-        // 1. 디바이스 초기화시 에러리턴
-        if( (mDriver.Polling.Status == Driver.PollingList.STATUS.First) ||
-                (mDriver.Polling.Status == Driver.PollingList.STATUS.FirstTimeOut) )
-        {
-            Log.w(TAG, "[NoSinkCtrl] - Not Yet !!!");
-            return "FAIL;" + APIErrorCode.DEVICEISNOTREADY;
-        }
-
-        CtrDevFormat ctrDevFormat = GetCtrDevParamParsing(StrArg, 5);
-        if(ctrDevFormat.ret != APIErrorCode.C_SUCCESS)
-        {
-            Log.w(TAG, "[NoSinkCtrl] GetCtrDevParamParsing Error (ret:" + ctrDevFormat.ret + ")");
-            return "FAIL;" + APIErrorCode.DEFAULT_PARSING_ERR;
-        }
-
-        if(ctrDevFormat.CmdStr!=null)
-        {
-            //////////////////////////////////////////////////////////
-            // Refresh : 데이터 갱신 (No Sink)
-            //////////////////////////////////////////////////////////
-            if(ctrDevFormat.CmdStr.equals("Refresh"))
-            {
-                byte Index         = ctrDevFormat.param[0];
-                DeviceLog("[Refresh] Index : " + String.format("0x%02X", Index));
-
-                return RefreshResult(Index);
-            }
-
-            //////////////////////////////////////////////////////////
-            // GetDeviceCount : 기기 개수 가져오기 (No Sink)
-            //////////////////////////////////////////////////////////
-            else if(ctrDevFormat.CmdStr.equals("GetDeviceCount"))
-            {
-                DeviceLog("[GetDeviceCount]");
-
-                return RefreshResult_GetDeviceCount();
-            }
-        }
-
-
-        return "FAIL;" + APIErrorCode.UNKNOWNCOMMAND;
-    }
-
-    /**
-     * do_ctrEmm : 싱크 제어
-     */
-    @Override
-    @SuppressLint("DefaultLocale")
-    protected String do_ctrEmm(DeviceCtrSHMem SHMem)
-    {
-        DeviceLog("[do_ctrEmm] Start");
-        DeviceLog("cmd    : " + SHMem.cmd);
-        DeviceLog("StrArg : " + SHMem.StrArg);
-
-        // 1. 디바이스 초기화시 에러리턴
-        if( (mDriver.Polling.Status == Driver.PollingList.STATUS.First) ||
-                (mDriver.Polling.Status == Driver.PollingList.STATUS.FirstTimeOut) )
-        {
-            Log.w(TAG, "[do_ctrEmm] - Not Yet !!!");
-            return SHMem.retVal = "FAIL;" + APIErrorCode.DEVICEISNOTREADY;
-        }
-
-        CtrDevFormat ctrDevFormat = GetCtrDevParamParsing(SHMem.StrArg, 5);
-        if(ctrDevFormat.ret != APIErrorCode.C_SUCCESS)
-        {
-            Log.w(TAG, "[do_ctrEmm] GetCtrDevParamParsing Error (ret:" + ctrDevFormat.ret + ")");
-            return SHMem.retVal = "FAIL;" + APIErrorCode.DEFAULT_PARSING_ERR;
-        }
-
-        if(ctrDevFormat.CmdStr!=null)
-        {
-            //////////////////////////////////////////////////////////
-            // Refresh : 데이터 갱신 (Sink)
-            //////////////////////////////////////////////////////////
-            if(ctrDevFormat.CmdStr.equals("Refresh"))
-            {
-                byte Index         = ctrDevFormat.param[0];
-                DeviceLog("[Refresh] Index : " + String.format("0x%02X", Index));
-
-                STATUS Status = Send_GetStatus(Index);
-                if(Status != null)
-                {
-                    UpdateVariables(Index, Status, false);
-                    return SHMem.retVal = RefreshResult(Index);
-                }
-                else
-                {
-                    return SHMem.retVal = "FAIL;" + APIErrorCode.DEVICEISNORESPONSE;
-                }
-            }
-            //////////////////////////////////////////////////////////
-            // SetClose : 가스밸브 닫기 (Sink)
-            //////////////////////////////////////////////////////////
-            else if(ctrDevFormat.CmdStr.equals("SetClose"))
-            {
-                byte Index         = ctrDevFormat.param[0];
-                DeviceLog("[SetClose] Index : " + String.format("0x%02X", Index));
-
-                // 1. 범위체크
-                if(Index != define.DEVICE_ALL_OR_NOTHING)
-                {
-                    if(!DeviceIndexRangeCheck(Index))
-                    {
-                        Log.w(TAG, "[do_ctrEmm -> SetClose] Param : Index - Out Of Range #1 !!! (Index:" + Index + ")");
-                        return SHMem.retVal = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
-                    }
-
-                    if(!mDriver.Status[Index].Install)
-                    {
-                        Log.w(TAG, "[do_ctrEmm -> SetClose] Device [" + Index + "]  No Install !!!");
-                        return SHMem.retVal = "FAIL;" + APIErrorCode.DEVICEISNOTREADY;
-                    }
-                }
-
-                if(Index == define.DEVICE_ALL_OR_NOTHING)
-                {
-                    mDriver.Polling.SetStatus(Driver.PollingList.STATUS.AllClose);
-                    return SHMem.retVal = "SUCCESS";
-                }
-                else
-                {
-                    STATUS Status = Send_SetClose(Index);
-                    if(Status != null)
-                    {
-                        UpdateVariables(Index, Status, true);
-                        return SHMem.retVal = "SUCCESS";
-                    }
-                    else
-                    {
-                        mDriver.Polling.ControlAddress = Index;
-                        mDriver.Polling.SetStatus(Driver.PollingList.STATUS.Close);
-                        return SHMem.retVal = "FAIL;" + APIErrorCode.DEVICEISNORESPONSE;
-                    }
-                }
-            }
-        }
-
-
-        return SHMem.retVal = "UNKNOWNCMD";
-    }
-
-    /**
-     * 기기 인덱스의 범위체크를 한다.
-     *
-     * @param Index - (byte) 범위체크할 인덱스
-     *
-     * @return (boolean) 결과 - true : 정상, false : 에러
-     */
-    private boolean DeviceIndexRangeCheck(byte Index)
-    {
-        try
-        {
-            if((Index < 0) || (Index >= mDriver.Polling.SearchDeviceCount)) return false;
-            return true;
-        }
-        catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-            return false;
-        }
-        catch (Exception e) {
-            Log.e(TAG, "[Exception Error] DeviceIndexRangeCheck");
-            //e.printStackTrace();
-            LogUtil.errorLogInfo("", TAG, e);
-            return false;
-        }
-    }
-
-    ///////////////////////////////////////////////////////////////////////////////////////////////
-    // RefreshResult
-    ///////////////////////////////////////////////////////////////////////////////////////////////
-    /**
-     * XXXX Refresh 에 대한 응답포멧 정의
-     *
-     * param (byte) Index - 방 인덱스 (범위 : 0 ~ 7)
-     *
-     * @return (String) "SUCCESS; ..." 성공 , "FAIL; ... " 실패
-     */
-    private String RefreshResult(byte Index)
-    {
-        String result = null;
-
-        DeviceLog("RefreshResult call : ");
-
-        // 1. Check Polling Status
-        if( (mDriver.Polling.Status == Driver.PollingList.STATUS.First) ||
-                (mDriver.Polling.Status == Driver.PollingList.STATUS.FirstTimeOut) )
-        {
-            result = "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
-            return result;
-        }
-
-        // 2. Param Range Check
-        if(!(Index >= 0 && Index < mDriver.Polling.SearchDeviceCount))
-        {
-            result = "FAIL;"+APIErrorCode.INVALIDPARAMETER;
-            return result;
-        }
-
-        // 3. Make Return String Format
-        try
-        {
-            if(mDriver == null)           return "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
-            if(mDriver.Status == null)    return "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
-            if(mDriver.Status[Index].Install == false)    return "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
-
-            /*
-             * [Format]
-             *
-             * SUCCESS       - (String) 성공
-             *
-             * GasStatus  - (byte) 가스상태
-             * Fault      - (byte) 경고/이상 상태
-             */
-
-            result = APIErrorCode.SUCCESS + ";";
-
-            result += mDriver.Status[Index].GasStatus  + ";" +
-                    mDriver.Status[Index].Fault      + ";";
-        }
-        catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-            result = "FAIL;"+APIErrorCode.EXCEPTION;
-        }
-        catch (Exception e) {
-            Log.e(TAG, "[Exception Error] RefreshResult");
-            //e.printStackTrace();
-            LogUtil.errorLogInfo("", TAG, e);
-            result = "FAIL;"+APIErrorCode.EXCEPTION;
-        }
-        DeviceLog(" RefreshResult_Sample return : "+result);
-
-        return result;
-    }
-
-
-    /**
-     * GetDeviceCount 에 대한 응답포멧 정의
-     *
-     * @return (String) "SUCCESS; ..." 성공 , "FAIL; ... " 실패
-     */
-    private String RefreshResult_GetDeviceCount()
-    {
-        String result = null;
-
-        DeviceLog("RefreshResult_GetDeviceCount call : ");
-
-        // 1. Check Polling Status
-        if( (mDriver.Polling.Status == Driver.PollingList.STATUS.First) ||
-                (mDriver.Polling.Status == Driver.PollingList.STATUS.FirstTimeOut) )
-        {
-            result = "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
-            return result;
-        }
-
-        // 2. Param Range Check
-
-        // 3. Make Return String Format
-        try
-        {
-            if(mDriver == null)                      return "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
-            if(mDriver.Polling == null)              return "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
-
-            /*
-             * [Format]
-             *
-             * SUCCESS        - (String) 성공
-             *
-             * DeviceCount    - (byte) 기기개수
-             */
-            result = APIErrorCode.SUCCESS + ";";
-            result += mDriver.Polling.SearchDeviceCount + ";";
-        }
-        catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-            result = "FAIL;"+APIErrorCode.EXCEPTION;
-        }
-        catch (Exception e) {
-            Log.e(TAG, "[Exception Error] RefreshResult_GetDeviceCount");
-            //e.printStackTrace();
-            LogUtil.errorLogInfo("", TAG, e);
-            result = "FAIL;"+APIErrorCode.EXCEPTION;
-        }
-        DeviceLog("RefreshResult_GetDeviceCount return : " + result);
-
-        return result;
-    }
-
-    ///////////////////////////////////////////////////////////////////////////////////////////////
-    // Protocol Command Send Func
-    ///////////////////////////////////////////////////////////////////////////////////////////////
-
-    /**
-     * 가스밸브 상태값 요청/반환
-     *
-     * param (byte) Device ID
-     * @return (STATUS) null - Error , Not null - OK
-     */
-    private STATUS Send_GetStatus(byte DeviceIdx)
-    {
-        DeviceLog("[Send_GetStatus] Start");
-        Send_DummyPacket();
-
-        // 1. In 파라미터 확인
-        if((DeviceIdx < 0) || (DeviceIdx >= MAX_DEVICE_COUNT))
-        {
-            Log.w(TAG, "[Send_GetStatus] param [DeviceIdx] Out of Range!!! " + DeviceIdx);
-            return null;
-        }
-
-        // 2. 패킷 데이터 만들기
-        byte [] ReqData = new byte [] { 0x00, 0x00, 0x00, 0x00, 0x00 };
-
-        // 3. 데이터 전송 및 응답
-        byte [] Reply;
-        byte [] TempReply = null;
-        if(ServiceMain.dataBaseLoader.data.wallpadDeviceSet.Get_GasValve_Debug)
-        {
-        	// a. All Data 임시 저장
-            TempReply = SendNRead_Fixed_ReturnAllPacket( (byte)(DEVICE_ADDRESS + DeviceIdx), CMDList.Req.GetStatus, ReqData);
-            if(TempReply!=null)
-            {
-                // b. data 추출
-                int dataLen = TempReply.length - 5;
-                if(dataLen <= 0) return null;
-
-                byte [] retDataBuffer = new byte [dataLen];
-                for(int i=0 ; i<dataLen ; i++) retDataBuffer[i] = TempReply[4+i];
-                Reply = retDataBuffer;
-            }
-            else
-            {
-                Reply = null;
-            }
-        }
-        else
-        {
-            Reply = SendNRead_Fixed( (byte)(DEVICE_ADDRESS + DeviceIdx), CMDList.Req.GetStatus, ReqData);
-        }
-
-        STATUS Status = ReplyParsing(Reply);
-        if(Status == null)
-        {
-            DeviceLog("[Send_GetStatus] Reply is null");
-            AddDoCount(false);
-            return null;
-        }
-        AddDoCount(true);
-
-        if(ServiceMain.dataBaseLoader.data.wallpadDeviceSet.Get_GasValve_Debug)
-        {
-            if((Status.bFaultGasDetected == true) || (Status.bFaultFireDetected == true))
-            {
-                if(TempReply != null)
-                {
-                    //DB 저장
-                    WallpadDevStatus devset = new WallpadDevStatus(ServiceMain.svcContext);
-                    if(devset.RowCountGasDebugData() > 300)
-                    {
-                        devset.DeleteGasDebugData(Integer.toString(10));
-                    }
-                    String tempPacket = ToByteString(TempReply, TempReply.length);
-                    devset.InsertGasDebugData(tempPacket);
-                    devset.closeDB();
-                }
-            }
-        }
-
-        return Status;
-    }
-
-    /**
-     * 가스밸브 상태값 해제 요청/반환
-     *
-     * @param DeviceIdx - (byte) 제어할 ID
-     * @param FreeFault  - (byte) 해제할 경고/이상 상태
-     *
-     * @return (STATUS) null - Error , Not null - OK
-     */
-    private STATUS Send_SetFreeStatus(byte DeviceIdx, byte FreeFault)
-    {
-        DeviceLog("[Send_SetFreeStatus] Start (FreeFault:" + ToByteString(FreeFault) + ")");
-        Send_DummyPacket();
-
-        // 1. In 파라미터 확인
-        if((DeviceIdx < 0) || (DeviceIdx >= MAX_DEVICE_COUNT))
-        {
-            Log.w(TAG, "[Send_GetStatus] param [DeviceIdx] Out of Range!!! " + DeviceIdx);
-            return null;
-        }
-
-        if ((FreeFault & (byte)(BIT1 | BIT4 | BIT7)) != 0x00)
-        {
-            // 미사용 비트'0' 확인
-            Log.w(TAG, "[Send_SetFreeStatus] FreeFault : Unused Bit Set !!! " + ToByteString(FreeFault));
-            return null;
-        }
-
-        // 2. 패킷 데이터 만들기
-        byte [] ReqData = new byte [] { 0x00, 0x00, 0x00, 0x00, FreeFault };
-
-        // 3. 데이터 전송 및 응답
-        byte [] Reply = SendNRead_Fixed( (byte)(DEVICE_ADDRESS + DeviceIdx), CMDList.Req.SetFreeStatus, ReqData);
-        STATUS Status = ReplyParsing(Reply);
-        if(Status == null)
-        {
-            DeviceLog("[Send_GetStatus] Reply is null");
-            AddDoCount(false);
-            return null;
-        }
-        AddDoCount(true);
-
-        return Status;
-    }
-
-    /**
-     * 닫기 제어 요청/반환
-     *
-     * @param DeviceIdx - (byte) 제어할 ID
-     *
-     * @return (STATUS) null - Error , Not null - OK
-     */
-    private STATUS Send_SetClose(byte DeviceIdx)
-    {
-        DeviceLog("[Send_SetClose] Start");
-        Send_DummyPacket();
-
-        // 1. In 파라미터 확인
-
-        // 2. 패킷 데이터 만들기
-        byte [] ReqData = new byte [] { 0x00, 0x00, 0x00, 0x00, 0x00 };
-
-        // 3. 데이터 전송 및 응답
-        byte [] Reply = SendNRead_Fixed( (byte)(DEVICE_ADDRESS + DeviceIdx), CMDList.Req.SetClose, ReqData);
-        STATUS Status = ReplyParsing(Reply);
-        if(Status == null)
-        {
-            DeviceLog("[Send_SetClose] Reply is null");
-            AddDoCount(false);
-            return null;
-        }
-        AddDoCount(true);
-
-        return Status;
-    }
-
-    /**
-     * 응답 Parsing
-     *
-     * @param Reply     - (byte []) 응답 데이터
-     *
-     * @return (Status) null - Error , Not null - OK
-     */
-    private STATUS ReplyParsing(byte [] Reply)
-    {
-        // 1. 수신데이터 파싱
-        //     1.1. Default Check
-        if(Reply == null)
-        {
-            DeviceLog("[ReplyParsing] Reply is null");
-            return null;
-        }
-        if(Reply.length != 5)
-        {
-            // 길이 체크
-            Log.w(TAG, "[ReplyParsing] Reply.length  fail ... " + Reply.length);
-            return null;
-        }
-
-        int index = 0;
-        byte data = 0x00;
-        //          - D1 : 커맨드 수신 체크
-        data = Reply[index++];
-        if(data != (byte)0x80)
-        {
-            Log.w(TAG, "[ReplyParsing] D1 : fail ... (D1:" + String.format("0x%02X", data) + ")");
-            return null;
-        }
-
-        STATUS Status = new STATUS();
-        //          - D2 : 가스밸브 상태
-        data = Reply[index++];
-        Status.GasStatus = data;
-        if(!GASSTATUS.CheckRange(Status.GasStatus))
-        {
-            Log.w(TAG, "[ReplyParsing] D2 : GasStatus - Out Of Range !!! (GasStatus:" + String.format("0x%02X", Status.GasStatus) + ")");
-            return null;
-        }
-        //          - D3 : 0x00
-        data = Reply[index++];
-        if(data != 0x00)
-        {
-            Log.w(TAG, "[ReplyParsing] D3 : Zero Not!!! (data:" + String.format("0x%02X", data) + ")");
-            return null;
-        }
-        //          - D4 : 0x00
-        data = Reply[index++];
-        if(data != 0x00)
-        {
-            Log.w(TAG, "[ReplyParsing] D4 : Zero Not!!! (data:" + String.format("0x%02X", data) + ")");
-            return null;
-        }
-        //          - D5 : 기기 이상
-        data = Reply[index++];
-        if ((data & (byte)(BIT1 | BIT4 | BIT7)) != 0x00)
-        {
-            // 미사용 비트'0' 확인
-            Log.w(TAG, "[ReplyParsing] D5 (Fault) : Unused Bit Set !!! " + String.format("0x%02X", data));
-            return null;
-        }
-        Status.Fault = data;
-        if((data & BIT0) != 0x00) Status.bFaultController = true;
-        if((data & BIT2) != 0x00) Status.bFaultGasDetected = true;
-        if((data & BIT3) != 0x00) Status.bFaultFireDetected = true;
-        if((data & BIT5) != 0x00) Status.bFaultGasSensor = true;
-        if((data & BIT6) != 0x00) Status.bFaultFireSensor = true;
-
-        // 가스감지5회알람 설정된 경우
-        if(ServiceMain.dataBaseLoader.data.wallpadDeviceSet.Get_GasDetect_5time)
-        {
-            if(Status.bFaultGasDetected || Status.bFaultFireDetected)
-            {
-                DetectInputCount += 1;
-                //Log.i(TAG, "DetectInputCount Increase ++ : " + DetectInputCount);
-            }
-            else
-            {
-                //Log.i(TAG, "DetectInputCount --> 0");
-                DetectInputCount = 0;
-            }
-        }
-
-        return Status;
-    }
-
-    /**
-     * 더미패킷 전송<br>
-     * 구형연동 소방 수신기 (약 2013년 이전 연동제품) 의 경우<br>
-     * 앞 패킷이 가변패킷(난방등)일 경우 바로 소방패킷을 전송할 경우 수신받지못함.<br>
-     * 따라서, 본 드라이버에 송신 패킷 이전에 더미패킷을 송신할수있도록함.<br>
-     * USE_DUMMY_PACKET 변수에 따라 ON/OFF 가능
-     */
-    private void Send_DummyPacket()
-    {
-        if(!USE_DUMMY_PACKET) return;
-
-        byte [] ReqPaket = new byte[] {0x02, (byte)0xFF, 0x00, Get_Sequence(), 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
-        WritePacket(ReqPaket, true);
-
-        Sleep(100);
-    }
-
-    ///////////////////////////////////////////////////////////////////////////////////////////////
-    // CMDList
-    ///////////////////////////////////////////////////////////////////////////////////////////////
-    /**
-     * 명령어 리스트
-     */
-    public static class CMDList
-    {
-        public static final class Req
-        {
-            /** 상태값 요청 */
-            public final static byte GetStatus             = 0x00;
-
-            /** 상태값 해제 요청 */
-            public final static byte SetFreeStatus         = 0x01;
-
-            /** 닫기 제어 요청 */
-            public final static byte SetClose              = 0x02;
-        }
-    }
-
-    ///////////////////////////////////////////////////////////////////////////////////////////////
-    // UpdateVariables
-    ///////////////////////////////////////////////////////////////////////////////////////////////
-    /**
-     * 상태 데이터를 업데이트 한다.
-     * @param DeviceIdx - (byte) 디바이스 인덱스
-     * @param Status - (STATUS) 업데이트할 상태 데이터
-     * @param bNotify - (boolean) UI로 알림 설정여부
-     */
-    private void UpdateVariables(byte DeviceIdx, STATUS Status, boolean bNotify)
-    {
-        if(mDriver == null) return;
-        if(mDriver.Status == null) return;
-        if(Status == null) return;
-        if(DeviceIdx >= mDriver.Polling.SearchDeviceCount) return;
-
-        boolean bChanged = false;
-
-        // 설치 상태 ON으로 변경
-        mDriver.Status[DeviceIdx].Install = true;
-
-        // 가스밸브 상태 갱신
-        if(mDriver.Status[DeviceIdx].GasStatus != Status.GasStatus)
-        {
-            DeviceLog("[UpdateVariables] ID:" + DeviceIdx +" GasStatus Change !!! (OLD:" + GASSTATUS.ToDebugString(mDriver.Status[DeviceIdx].GasStatus) + ", " +
-                    "NOW:" + GASSTATUS.ToDebugString(Status.GasStatus) + ")");
-            mDriver.Status[DeviceIdx].GasStatus = Status.GasStatus;
-            bChanged = true;
-        }
-
-        // 기기 이상 상태 갱신
-        if(mDriver.Status[DeviceIdx].Fault != Status.Fault)
-        {
-            mDriver.Status[DeviceIdx].Fault = Status.Fault;
-
-            mDriver.Status[DeviceIdx].bFaultGasDetected = Status.bFaultGasDetected;
-            mDriver.Status[DeviceIdx].bFaultFireDetected = Status.bFaultFireDetected;
-            mDriver.Status[DeviceIdx].bFaultController = Status.bFaultController;
-            mDriver.Status[DeviceIdx].bFaultGasSensor = Status.bFaultGasSensor;
-            mDriver.Status[DeviceIdx].bFaultFireSensor = Status.bFaultFireSensor;
-
-            bChanged = true;
-        }
-
-        ///////////////////////////////////////////////
-        // 알람
-        // 설정 추가 : 연속으로 5회이상 알람이 감지된 경우, 비상 intent 송신 하도록 추가
-        ///////////////////////////////////////////////
-        // 가스누출 감지
-        if(Status.bFaultGasDetected)
-        {
-            try
-            {
-                WallpadStatusData WPDSTD = new WallpadStatusData(ServiceMain.svcContext);
-                int alarmst = WPDSTD.GetAlarmStatus();
-                int alarmtype = WPDSTD.GetAlarmType();
-                WPDSTD.closeDB();
-                if ((alarmst != WallpadStatusData.ALARM_ARISE && alarmst != WallpadStatusData.ALARM_STOP) ||
-                        ((alarmst == WallpadStatusData.ALARM_ARISE || alarmst == WallpadStatusData.ALARM_STOP)  && alarmtype != WallpadStatusData.ALARM_ALERT))
-                {
-                    // 가스감지5회알람 설정된 경우
-                    if(ServiceMain.dataBaseLoader.data.wallpadDeviceSet.Get_GasDetect_5time)
-                    {
-                        if(DetectInputCount >= 5) // 5회이상 감지 발생 --> 알람 발생!
-                        {
-                            Log.i(TAG, "[UpdateVariables] Get_GasDetect_5time - GasDetected - Send_AlertBR");
-                            Send_AlertBR(CommonDefine.W_ALERT_GAS);
-                            DetectInputCount = 0;
-                        }
-                        else
-                        {
-                            if(DetectInputCount != 0) // 감지 발생 카운트 증가중
-                            {
-                                Log.i(TAG, "[UpdateVariables] (DetectInputCount < 5) --> " + DetectInputCount);
-                            }
-                        }
-                    }
-                    else // 일반적인 현장
-                    {
-                        Log.i(TAG, "[UpdateVariables] GasDetected - Send_AlertBR");
-                        Send_AlertBR(CommonDefine.W_ALERT_GAS);
-                    }
-                }
-            }
-            catch (RuntimeException re) {
-                LogUtil.errorLogInfo("", TAG, re);
-            }
-            catch (Exception e) {
-                Log.e(TAG, "[Exception Error] UpdateVariables - bFaultGasDetected");
-                //e.printStackTrace();
-                LogUtil.errorLogInfo("", TAG, e);
-            }
-        }
-
-        // 화재발생 감지
-        if(Status.bFaultFireDetected)
-        {
-            try
-            {
-                WallpadStatusData WPDSTD = new WallpadStatusData(ServiceMain.svcContext);
-                int alarmst = WPDSTD.GetAlarmStatus();
-                int alarmtype = WPDSTD.GetAlarmType();
-                WPDSTD.closeDB();
-                if ((alarmst != WallpadStatusData.ALARM_ARISE && alarmst != WallpadStatusData.ALARM_STOP) ||
-                        ((alarmst == WallpadStatusData.ALARM_ARISE || alarmst == WallpadStatusData.ALARM_STOP)  && alarmtype != WallpadStatusData.ALARM_ALERT))
-                {
-                    // 가스감지5회알람 설정된 경우
-                    if(ServiceMain.dataBaseLoader.data.wallpadDeviceSet.Get_GasDetect_5time)
-                    {
-                        if(DetectInputCount >= 5) // 5회이상 감지 발생 --> 알람 발생!
-                        {
-                            Log.i(TAG, "[UpdateVariables] Get_GasDetect_5time - FireDetected - Send_AlertBR");
-                            Send_AlertBR(CommonDefine.W_ALERT_FIRE);
-                            DetectInputCount = 0;
-                        }
-                        else
-                        {
-                            if(DetectInputCount != 0) // 감지 발생 카운트 증가중
-                            {
-                                Log.i(TAG, "[UpdateVariables] (DetectInputCount < 5) --> " + DetectInputCount);
-                            }
-                        }
-                    }
-                    else // 일반적인 현장
-                    {
-                        Log.i(TAG, "[UpdateVariables] FireDetected - Send_AlertBR");
-                        Send_AlertBR(CommonDefine.W_ALERT_FIRE);
-                    }
-                }
-            }
-            catch (RuntimeException re) {
-                LogUtil.errorLogInfo("", TAG, re);
-            }
-            catch (Exception e) {
-                Log.e(TAG, "[Exception Error] UpdateVariables - bFaultFireDetected");
-                //e.printStackTrace();
-                LogUtil.errorLogInfo("", TAG, e);
-            }
-        }
-
-        // 이상상태 해제
-        if(Status.Fault != 0x00)
-        {
-            Send_SetFreeStatus(DeviceIdx, Status.Fault);
-        }
-
-        // 변경상태 알림
-        if(bChanged || bNotify)
-        {
-            byte TempStatus = GASSTATUS.Close;
-            for(int i = 0; i < mDriver.Polling.SearchDeviceCount; i++)
-            {
-                if(mDriver.Status[i].GasStatus == GASSTATUS.Operation)
-                {
-                    TempStatus = GASSTATUS.Operation;
-                    break;
-                }
-                else if(mDriver.Status[i].GasStatus == GASSTATUS.Open)
-                {
-                    TempStatus = GASSTATUS.Open;
-                    break;
-                }
-            }
-
-            GasStatus = TempStatus;
-            StatusChanged(TempStatus);
-            DeviceLog("UpdateVariables !!!! *************************************** " + ToByteString(mDriver.Status[DeviceIdx].GasStatus));
-        }
-    }
-
-    /**
-     * 알람 BR 송신
-     *
-     * @param kind - (int) 알람종류
-     */
-    private void Send_AlertBR(int kind)
-    {
-        Intent intent = new Intent();
-        intent.setAction("WALLPAD_ALERT");
-        intent.putExtra("KIND", kind);
-        ServiceMain.svcContext.sendBroadcast(intent);
-    }
-}
+
+package com.artncore.wallpaddevservice.driver;
+
+import android.annotation.SuppressLint;
+import android.content.Intent;
+import android.util.Log;
+
+import com.artncore.WallPadDataMgr.WallpadDevStatus;
+import com.artncore.WallPadDataMgr.WallpadStatusData;
+import com.artncore.commons.APIErrorCode;
+import com.artncore.commons.define;
+import com.artncore.wallpaddevservice.CommonDefine;
+import com.artncore.wallpaddevservice.ServiceMain;
+import com.util.LogUtil;
+
+
+/**
+ * 가스밸브 의 드라이버 모듈이다.
+ */
+@SuppressLint("HandlerLeak")
+public class GasValve_Controller extends DeviceManager
+{
+    private final static String TAG = "GasValve_Controller";
+
+    private final byte DEVICE_ADDRESS  = (byte) 0x31;
+
+    /** 더미패킷 사용 유무 */
+    private final boolean USE_DUMMY_PACKET = false;
+
+    private static byte GasStatus = GASSTATUS.Operation;
+    public static byte GetGasStatus() { return GasStatus; }
+
+    /** 최대 기기 개수 */
+    private final byte MAX_DEVICE_COUNT  = 2;
+
+    /** 초기 기기 검색 횟수  */
+    private final int MAX_SEARCH_COUNT   = 3;
+
+    /** 감지 패킷 수신 횟수  */
+    private int DetectInputCount = 0;
+
+
+    private final int MAX_Detect_COUNT   = 5;
+
+
+    /** 가스밸브 상태 */
+    public static class STATUS
+    {
+        /** 가스밸브 상태 */
+        public byte GasStatus;
+
+        /** 경고/이상 */
+        public byte Fault;
+
+        /** 제어기 이상 */
+        public boolean bFaultController;
+        /** 가스누출 감지 */
+        public boolean bFaultGasDetected;
+        /** 화재발생 감지 */
+        public boolean bFaultFireDetected;
+        /** 가스센서 이상 */
+        public boolean bFaultGasSensor;
+        /** 화재센서 이상 */
+        public boolean bFaultFireSensor;
+        /** 설치상태 (true:설치 , false:미설치) */
+        public boolean Install;
+
+        public STATUS()
+        {
+            GasStatus = GASSTATUS.Operation;
+            Fault = 0x00;
+            bFaultController = false;
+            bFaultGasDetected = false;
+            bFaultFireDetected = false;
+            bFaultGasSensor = false;
+            bFaultFireSensor = false;
+            Install = false;
+        }
+
+        /** 디버깅 메시지 출력 */
+        public String ToDebugString()
+        {
+            String retStr =
+                    "==========================\r\n" +
+                            "STATUS\r\n" +
+                            "==========================\r\n" +
+                            "Status       : " + GASSTATUS.ToDebugString(GasStatus)         + "\r\n" +
+                            "Fault        : " + String.format("0x%02X", Fault)     + "\r\n" +
+                            "\r\n" +
+                            "bFaultController   : " + bFaultController + "\r\n" +
+                            "bFaultGasDetected  : " + bFaultGasDetected + "\r\n" +
+                            "bFaultFireDetected : " + bFaultFireDetected + "\r\n" +
+                            "bFaultGasSensor    : " + bFaultGasSensor + "\r\n" +
+                            "bFaultFireSensor   : " + bFaultFireSensor + "\r\n" +
+                            "==========================";
+            return retStr;
+        }
+    }
+
+    /** 가스밸브 상태 정의 */
+    public static class GASSTATUS
+    {
+        /** 닫힘 */
+        public static byte Close         = 0x00;
+        /** 열림 */
+        public static byte Open          = 0x01;
+        /** 동작중 */
+        public static byte Operation     = 0x02;
+
+        /**
+         * 범위를 체크한다.
+         *
+         * @param nStatus - (byte) 체크할 상태
+         *
+         * @return (boolean) ture:정상 , false:범위이탈
+         */
+        public static boolean CheckRange(byte nStatus)
+        {
+            if(nStatus == GASSTATUS.Close)                   return true;
+            else if(nStatus == GASSTATUS.Open)               return true;
+            else if(nStatus == GASSTATUS.Operation)          return true;
+            return false;
+        }
+
+        public static String ToDebugString(byte nStatus)
+        {
+            String retStr;
+            if(nStatus == GASSTATUS.Close)                   retStr = "Close";
+            else if(nStatus == GASSTATUS.Open)               retStr = "Open";
+            else if(nStatus == GASSTATUS.Operation)          retStr = "Operation";
+            else retStr = "UnDefined";
+            return retStr;
+        }
+    }
+
+    public class Driver
+    {
+        private PollingList Polling;
+
+        private STATUS[] Status;
+
+        public Driver()
+        {
+            Polling = new PollingList();
+            Status = new STATUS[MAX_DEVICE_COUNT];
+            for(int i=0 ; i<MAX_DEVICE_COUNT ; i++) Status[i] = new STATUS();
+        }
+
+        /** Polling 관련 */
+        private class PollingList
+        {
+            private final class STATUS
+            {
+                /** 초기화 과정 */
+                public final static byte First = 0;
+                /** 초기화 타임아웃 */
+                public final static byte FirstTimeOut = 1;
+                /** 평상시 */
+                public final static byte Normal = 2;
+                /** 닫기 */
+                public final static byte Close = 3;
+                /** 모든 가스벨브 닫기 */
+                public final static byte AllClose = 4;
+            }
+
+            public byte CurrentAddress;
+            public byte SearchDeviceCount;
+            public boolean SearchEnd;
+            public byte Status;
+            public int SearchTryCount;
+            public int CloseReTryCount;
+            public int AllCloseReTryCount;
+            public byte ControlAddress;
+
+            private PollingList()
+            {
+                CurrentAddress = 0;
+                Status = STATUS.First;
+                SearchDeviceCount = 0;
+                SearchEnd = false;
+                SearchTryCount = 0;
+                CloseReTryCount = 0;
+                AllCloseReTryCount = 0;
+                ControlAddress = 0;
+            }
+
+            public void SetStatus(byte ChangeStatus)
+            {
+                switch(ChangeStatus)
+                {
+                    case STATUS.First:
+                        Status = ChangeStatus;
+                        break;
+                    case STATUS.FirstTimeOut:
+                        Status = ChangeStatus;
+                        break;
+                    case STATUS.Normal:
+                        Status = ChangeStatus;
+                        break;
+                    case STATUS.Close:
+                        Status = ChangeStatus;
+                        CloseReTryCount = 0;
+                        break;
+                    case STATUS.AllClose:
+                        Status = ChangeStatus;
+                        AllCloseReTryCount = 0;
+                        break;
+                    default:
+                        break;
+                }
+            }
+        }
+    }
+
+    private Driver mDriver = null;
+
+
+    /**
+     * 생성자
+     */
+    public GasValve_Controller()
+    {
+        /* 로그 초기상태 */
+        log_sw = false;
+
+        /* 통신성공률 변수 초기화 */
+        super.CommDataGeneration(1);
+
+        /* 드라이버 내부 변수 초기화 */
+        mDriver = new Driver();
+
+        Log.i(TAG, "Create !!!");
+    }
+
+    @Override
+    public void DeviceLog(String msg)
+    {
+        if (!log_sw) return;
+        Log.d(TAG, msg);
+    }
+
+    /**
+     * 로딩후 처음 폴링 시퀀스
+     */
+    @Override
+    protected void do_boot()
+    {
+    }
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    // Polling
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+     * do_ctr : 폴링스케쥴러
+     */
+    @Override
+    protected void do_ctr()
+    {
+        DeviceLog("Polling ");
+
+        /* [[ First & FirstTimeOut ]]
+         * 초기 디바이스정보  검색 */
+        if(mDriver.Polling.Status == Driver.PollingList.STATUS.First)
+        {
+            // 1. 디바이스 검색
+            byte MaxDeviceID = 0;
+            for(byte DeviceIdx = 0 ; DeviceIdx<MAX_DEVICE_COUNT ; DeviceIdx++)
+            {
+                STATUS Status = Send_GetStatus(DeviceIdx);
+                if(Status != null)
+                {
+                    MaxDeviceID = (byte)(DeviceIdx+1);
+                    UpdateVariables(DeviceIdx, Status, true);
+
+                    Log.i(TAG, "SearchDevice     DeviceNum = " + (byte)(DeviceIdx+1) + "      OK!!!");
+                }
+                else
+                {
+                    Log.i(TAG, "SearchDevice     DeviceNum = " + (byte)(DeviceIdx+1) + "      Fail...");
+                }
+                Sleep(1000);
+            }
+
+            // 2. 가장 높은 ID 저장
+            if (MaxDeviceID > mDriver.Polling.SearchDeviceCount) mDriver.Polling.SearchDeviceCount = MaxDeviceID;
+
+            // 3. 검색 횟수 체크
+            if(++mDriver.Polling.SearchTryCount >= MAX_SEARCH_COUNT)
+            {
+                if(mDriver.Polling.SearchDeviceCount != 0)
+                {
+                    mDriver.Polling.SearchEnd = true;
+                    mDriver.Polling.Status = Driver.PollingList.STATUS.Normal;
+                    Log.i(TAG, "First - Search Device END - SearchDeviceCount : " + mDriver.Polling.SearchDeviceCount);
+                }
+                else
+                {
+                    mDriver.Polling.Status = Driver.PollingList.STATUS.FirstTimeOut;
+
+                    Log.i(TAG, "--------------------------------------------------");
+                    Log.i(TAG, "SearchDevice Fail... FirstTimeOut ");
+                    Log.i(TAG, "--------------------------------------------------");
+                }
+                ServiceMain.deviceInitChecker.Remove(super.DeviceName);
+            }
+        }
+
+        /* [[ FirstTimeOut ]]
+         * 초기 디바이스 검색하지못함. */
+        else if(mDriver.Polling.Status == Driver.PollingList.STATUS.FirstTimeOut)
+        {
+            STATUS Status = Send_GetStatus(mDriver.Polling.CurrentAddress);
+            if(Status != null)
+            {
+                UpdateVariables(mDriver.Polling.CurrentAddress, Status, true);
+                mDriver.Polling.SearchDeviceCount = (byte) (mDriver.Polling.CurrentAddress + 1);
+            }
+
+            if(++mDriver.Polling.CurrentAddress >= MAX_DEVICE_COUNT)
+            {
+                mDriver.Polling.CurrentAddress = 0;
+
+                if(mDriver.Polling.SearchDeviceCount != 0)
+                {
+                    mDriver.Polling.SearchEnd = true;
+                    mDriver.Polling.Status = Driver.PollingList.STATUS.Normal;
+                    Log.i(TAG, "FirstTimeOut - Search Device END - SearchDeviceCount : " + mDriver.Polling.SearchDeviceCount);
+                }
+            }
+        }
+
+        /* [[ Normal ]]
+         * 평상시 */
+        else if(mDriver.Polling.Status == Driver.PollingList.STATUS.Normal)
+        {
+            if(mDriver.Polling.SearchEnd)
+            {
+                mDriver.Polling.SearchEnd = false;
+
+                int DeviceCount = mDriver.Polling.SearchDeviceCount;
+
+                super.CommDataGeneration(DeviceCount);
+
+                for(byte DeviceIdx=0 ; DeviceIdx<DeviceCount ; DeviceIdx++)
+                {
+                    DeviceLog("Gas ID: " + DeviceIdx + " DebugMessage: " + mDriver.Status[DeviceIdx].ToDebugString());
+                }
+            }
+
+            byte CurrentAddress = mDriver.Polling.CurrentAddress;
+            STATUS Status = Send_GetStatus(CurrentAddress);
+            if(Status != null)
+            {
+                UpdateVariables(CurrentAddress, Status, false);
+            }
+
+            if(++mDriver.Polling.CurrentAddress >= mDriver.Polling.SearchDeviceCount)
+                mDriver.Polling.CurrentAddress = 0;
+        }
+        /* [[ Close ]]
+         * 닫기 */
+        else if(mDriver.Polling.Status == Driver.PollingList.STATUS.Close)
+        {
+            // 2013-03-04
+            // 한국 소방 가스밸브의 경우 기기 특성상 가변 패킷 이후에 약 1초의 Term을 주어야 밸브패킷을 수신할수 있다.
+            // 따라서, 현재 폴링속도가 빨라지고 가변패킷이 온도조절기외에 실시간검침기가 추가됨에 따라 한국소방의 패킷수신률이
+            // 현저히 떨어졌으며, 이를 보완하기 위하여 닫기 명령이 왔을때 폴링시퀀스상에서 1초의 Term을 주고 송신하도록 처리하였다.
+
+            // Retry는 최대 5회까지 하도록한다.
+            mDriver.Polling.CloseReTryCount++;
+            Log.i(TAG, "Close ReTry Count = " + mDriver.Polling.CloseReTryCount);
+            if (mDriver.Polling.CloseReTryCount >= 5)
+            {
+                mDriver.Polling.SetStatus(Driver.PollingList.STATUS.Normal);
+                mDriver.Polling.ControlAddress = 0;
+            }
+
+            Sleep(1000);
+
+            STATUS Status = Send_SetClose(mDriver.Polling.ControlAddress);
+            if(Status != null)
+            {
+                Log.i(TAG, "Close ReTry Control Success !!!");
+                mDriver.Polling.SetStatus(Driver.PollingList.STATUS.Normal);
+                UpdateVariables(mDriver.Polling.ControlAddress, Status, true);
+                mDriver.Polling.ControlAddress = 0;
+            }
+        }
+        else if(mDriver.Polling.Status == Driver.PollingList.STATUS.AllClose)
+        {
+            mDriver.Polling.AllCloseReTryCount++;
+            Log.i(TAG, "All Close ReTry Count = " + mDriver.Polling.AllCloseReTryCount);
+            if (mDriver.Polling.AllCloseReTryCount >= 5)
+            {
+                mDriver.Polling.SetStatus(Driver.PollingList.STATUS.Normal);
+            }
+
+            Sleep(1000);
+
+            boolean result = true;
+            for(int i = 0; i < mDriver.Polling.SearchDeviceCount; i++)
+            {
+                if(mDriver.Status[i].Install)
+                {
+                    STATUS Status = Send_SetClose((byte)i);
+                    if(Status != null)
+                    {
+                        UpdateVariables((byte)i, Status, true);
+                    }
+                    else
+                    {
+                        result = false;
+                    }
+                    Sleep(100);
+                }
+                else
+                {
+                    result = false;
+                }
+            }
+            if(result)
+            {
+                Log.i(TAG, "All Close Control Success !!!");
+                mDriver.Polling.SetStatus(Driver.PollingList.STATUS.Normal);
+            }
+        }
+        /*
+         * 예외처리 */
+        else
+        {
+            mDriver = new Driver();
+        }
+    }
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    // Ctrl
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+     * NoSink 제어
+     *
+     * @param StrArg
+     *
+     * @return
+     */
+    public String NoSinkCtrl(String StrArg)
+    {
+        DeviceLog("[NoSinkCtrl] Start");
+
+        // 1. 디바이스 초기화시 에러리턴
+        if( (mDriver.Polling.Status == Driver.PollingList.STATUS.First) ||
+                (mDriver.Polling.Status == Driver.PollingList.STATUS.FirstTimeOut) )
+        {
+            Log.w(TAG, "[NoSinkCtrl] - Not Yet !!!");
+            return "FAIL;" + APIErrorCode.DEVICEISNOTREADY;
+        }
+
+        CtrDevFormat ctrDevFormat = GetCtrDevParamParsing(StrArg, 5);
+        if(ctrDevFormat.ret != APIErrorCode.C_SUCCESS)
+        {
+            Log.w(TAG, "[NoSinkCtrl] GetCtrDevParamParsing Error (ret:" + ctrDevFormat.ret + ")");
+            return "FAIL;" + APIErrorCode.DEFAULT_PARSING_ERR;
+        }
+
+        if(ctrDevFormat.CmdStr!=null)
+        {
+            //////////////////////////////////////////////////////////
+            // Refresh : 데이터 갱신 (No Sink)
+            //////////////////////////////////////////////////////////
+            if(ctrDevFormat.CmdStr.equals("Refresh"))
+            {
+                byte Index         = ctrDevFormat.param[0];
+                DeviceLog("[Refresh] Index : " + String.format("0x%02X", Index));
+
+                return RefreshResult(Index);
+            }
+
+            //////////////////////////////////////////////////////////
+            // GetDeviceCount : 기기 개수 가져오기 (No Sink)
+            //////////////////////////////////////////////////////////
+            else if(ctrDevFormat.CmdStr.equals("GetDeviceCount"))
+            {
+                DeviceLog("[GetDeviceCount]");
+
+                return RefreshResult_GetDeviceCount();
+            }
+        }
+
+
+        return "FAIL;" + APIErrorCode.UNKNOWNCOMMAND;
+    }
+
+    /**
+     * do_ctrEmm : 싱크 제어
+     */
+    @Override
+    @SuppressLint("DefaultLocale")
+    protected String do_ctrEmm(DeviceCtrSHMem SHMem)
+    {
+        DeviceLog("[do_ctrEmm] Start");
+        DeviceLog("cmd    : " + SHMem.cmd);
+        DeviceLog("StrArg : " + SHMem.StrArg);
+
+        // 1. 디바이스 초기화시 에러리턴
+        if( (mDriver.Polling.Status == Driver.PollingList.STATUS.First) ||
+                (mDriver.Polling.Status == Driver.PollingList.STATUS.FirstTimeOut) )
+        {
+            Log.w(TAG, "[do_ctrEmm] - Not Yet !!!");
+            return SHMem.retVal = "FAIL;" + APIErrorCode.DEVICEISNOTREADY;
+        }
+
+        CtrDevFormat ctrDevFormat = GetCtrDevParamParsing(SHMem.StrArg, 5);
+        if(ctrDevFormat.ret != APIErrorCode.C_SUCCESS)
+        {
+            Log.w(TAG, "[do_ctrEmm] GetCtrDevParamParsing Error (ret:" + ctrDevFormat.ret + ")");
+            return SHMem.retVal = "FAIL;" + APIErrorCode.DEFAULT_PARSING_ERR;
+        }
+
+        if(ctrDevFormat.CmdStr!=null)
+        {
+            //////////////////////////////////////////////////////////
+            // Refresh : 데이터 갱신 (Sink)
+            //////////////////////////////////////////////////////////
+            if(ctrDevFormat.CmdStr.equals("Refresh"))
+            {
+                byte Index         = ctrDevFormat.param[0];
+                DeviceLog("[Refresh] Index : " + String.format("0x%02X", Index));
+
+                STATUS Status = Send_GetStatus(Index);
+                if(Status != null)
+                {
+                    UpdateVariables(Index, Status, false);
+                    return SHMem.retVal = RefreshResult(Index);
+                }
+                else
+                {
+                    return SHMem.retVal = "FAIL;" + APIErrorCode.DEVICEISNORESPONSE;
+                }
+            }
+            //////////////////////////////////////////////////////////
+            // SetClose : 가스밸브 닫기 (Sink)
+            //////////////////////////////////////////////////////////
+            else if(ctrDevFormat.CmdStr.equals("SetClose"))
+            {
+                byte Index         = ctrDevFormat.param[0];
+                DeviceLog("[SetClose] Index : " + String.format("0x%02X", Index));
+
+                // 1. 범위체크
+                if(Index != define.DEVICE_ALL_OR_NOTHING)
+                {
+                    if(!DeviceIndexRangeCheck(Index))
+                    {
+                        Log.w(TAG, "[do_ctrEmm -> SetClose] Param : Index - Out Of Range #1 !!! (Index:" + Index + ")");
+                        return SHMem.retVal = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
+                    }
+
+                    if(!mDriver.Status[Index].Install)
+                    {
+                        Log.w(TAG, "[do_ctrEmm -> SetClose] Device [" + Index + "]  No Install !!!");
+                        return SHMem.retVal = "FAIL;" + APIErrorCode.DEVICEISNOTREADY;
+                    }
+                }
+
+                if(Index == define.DEVICE_ALL_OR_NOTHING)
+                {
+                    mDriver.Polling.SetStatus(Driver.PollingList.STATUS.AllClose);
+                    return SHMem.retVal = "SUCCESS";
+                }
+                else
+                {
+                    STATUS Status = Send_SetClose(Index);
+                    if(Status != null)
+                    {
+                        UpdateVariables(Index, Status, true);
+                        return SHMem.retVal = "SUCCESS";
+                    }
+                    else
+                    {
+                        mDriver.Polling.ControlAddress = Index;
+                        mDriver.Polling.SetStatus(Driver.PollingList.STATUS.Close);
+                        return SHMem.retVal = "FAIL;" + APIErrorCode.DEVICEISNORESPONSE;
+                    }
+                }
+            }
+        }
+
+
+        return SHMem.retVal = "UNKNOWNCMD";
+    }
+
+    /**
+     * 기기 인덱스의 범위체크를 한다.
+     *
+     * @param Index - (byte) 범위체크할 인덱스
+     *
+     * @return (boolean) 결과 - true : 정상, false : 에러
+     */
+    private boolean DeviceIndexRangeCheck(byte Index)
+    {
+        try
+        {
+            if((Index < 0) || (Index >= mDriver.Polling.SearchDeviceCount)) return false;
+            return true;
+        }
+        catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+            return false;
+        }
+        catch (Exception e) {
+            Log.e(TAG, "[Exception Error] DeviceIndexRangeCheck");
+            //e.printStackTrace();
+            LogUtil.errorLogInfo("", TAG, e);
+            return false;
+        }
+    }
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    // RefreshResult
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+     * XXXX Refresh 에 대한 응답포멧 정의
+     *
+     * param (byte) Index - 방 인덱스 (범위 : 0 ~ 7)
+     *
+     * @return (String) "SUCCESS; ..." 성공 , "FAIL; ... " 실패
+     */
+    private String RefreshResult(byte Index)
+    {
+        String result = null;
+
+        DeviceLog("RefreshResult call : ");
+
+        // 1. Check Polling Status
+        if( (mDriver.Polling.Status == Driver.PollingList.STATUS.First) ||
+                (mDriver.Polling.Status == Driver.PollingList.STATUS.FirstTimeOut) )
+        {
+            result = "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
+            return result;
+        }
+
+        // 2. Param Range Check
+        if(!(Index >= 0 && Index < mDriver.Polling.SearchDeviceCount))
+        {
+            result = "FAIL;"+APIErrorCode.INVALIDPARAMETER;
+            return result;
+        }
+
+        // 3. Make Return String Format
+        try
+        {
+            if(mDriver == null)           return "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
+            if(mDriver.Status == null)    return "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
+            if(mDriver.Status[Index].Install == false)    return "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
+
+            /*
+             * [Format]
+             *
+             * SUCCESS       - (String) 성공
+             *
+             * GasStatus  - (byte) 가스상태
+             * Fault      - (byte) 경고/이상 상태
+             */
+
+            result = APIErrorCode.SUCCESS + ";";
+
+            result += mDriver.Status[Index].GasStatus  + ";" +
+                    mDriver.Status[Index].Fault      + ";";
+        }
+        catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+            result = "FAIL;"+APIErrorCode.EXCEPTION;
+        }
+        catch (Exception e) {
+            Log.e(TAG, "[Exception Error] RefreshResult");
+            //e.printStackTrace();
+            LogUtil.errorLogInfo("", TAG, e);
+            result = "FAIL;"+APIErrorCode.EXCEPTION;
+        }
+        DeviceLog(" RefreshResult_Sample return : "+result);
+
+        return result;
+    }
+
+
+    /**
+     * GetDeviceCount 에 대한 응답포멧 정의
+     *
+     * @return (String) "SUCCESS; ..." 성공 , "FAIL; ... " 실패
+     */
+    private String RefreshResult_GetDeviceCount()
+    {
+        String result = null;
+
+        DeviceLog("RefreshResult_GetDeviceCount call : ");
+
+        // 1. Check Polling Status
+        if( (mDriver.Polling.Status == Driver.PollingList.STATUS.First) ||
+                (mDriver.Polling.Status == Driver.PollingList.STATUS.FirstTimeOut) )
+        {
+            result = "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
+            return result;
+        }
+
+        // 2. Param Range Check
+
+        // 3. Make Return String Format
+        try
+        {
+            if(mDriver == null)                      return "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
+            if(mDriver.Polling == null)              return "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
+
+            /*
+             * [Format]
+             *
+             * SUCCESS        - (String) 성공
+             *
+             * DeviceCount    - (byte) 기기개수
+             */
+            result = APIErrorCode.SUCCESS + ";";
+            result += mDriver.Polling.SearchDeviceCount + ";";
+        }
+        catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+            result = "FAIL;"+APIErrorCode.EXCEPTION;
+        }
+        catch (Exception e) {
+            Log.e(TAG, "[Exception Error] RefreshResult_GetDeviceCount");
+            //e.printStackTrace();
+            LogUtil.errorLogInfo("", TAG, e);
+            result = "FAIL;"+APIErrorCode.EXCEPTION;
+        }
+        DeviceLog("RefreshResult_GetDeviceCount return : " + result);
+
+        return result;
+    }
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    // Protocol Command Send Func
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+
+    /**
+     * 가스밸브 상태값 요청/반환
+     *
+     * param (byte) Device ID
+     * @return (STATUS) null - Error , Not null - OK
+     */
+    private STATUS Send_GetStatus(byte DeviceIdx)
+    {
+        DeviceLog("[Send_GetStatus] Start");
+        Send_DummyPacket();
+
+        // 1. In 파라미터 확인
+        if((DeviceIdx < 0) || (DeviceIdx >= MAX_DEVICE_COUNT))
+        {
+            Log.w(TAG, "[Send_GetStatus] param [DeviceIdx] Out of Range!!! " + DeviceIdx);
+            return null;
+        }
+
+        // 2. 패킷 데이터 만들기
+        byte [] ReqData = new byte [] { 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+        // 3. 데이터 전송 및 응답
+        byte [] Reply;
+        byte [] TempReply = null;
+        if(ServiceMain.dataBaseLoader.data.wallpadDeviceSet.Get_GasValve_Debug)
+        {
+        	// a. All Data 임시 저장
+            TempReply = SendNRead_Fixed_ReturnAllPacket( (byte)(DEVICE_ADDRESS + DeviceIdx), CMDList.Req.GetStatus, ReqData);
+            if(TempReply!=null)
+            {
+                // b. data 추출
+                int dataLen = TempReply.length - 5;
+                if(dataLen <= 0) return null;
+
+                byte [] retDataBuffer = new byte [dataLen];
+                for(int i=0 ; i<dataLen ; i++) retDataBuffer[i] = TempReply[4+i];
+                Reply = retDataBuffer;
+            }
+            else
+            {
+                Reply = null;
+            }
+        }
+        else
+        {
+            Reply = SendNRead_Fixed( (byte)(DEVICE_ADDRESS + DeviceIdx), CMDList.Req.GetStatus, ReqData);
+        }
+
+        STATUS Status = ReplyParsing(Reply);
+        if(Status == null)
+        {
+            DeviceLog("[Send_GetStatus] Reply is null");
+            AddDoCount(false);
+            return null;
+        }
+        AddDoCount(true);
+
+        if(ServiceMain.dataBaseLoader.data.wallpadDeviceSet.Get_GasValve_Debug)
+        {
+            if((Status.bFaultGasDetected == true) || (Status.bFaultFireDetected == true))
+            {
+                if(TempReply != null)
+                {
+                    //DB 저장
+                    WallpadDevStatus devset = new WallpadDevStatus(ServiceMain.svcContext);
+                    if(devset.RowCountGasDebugData() > 300)
+                    {
+                        devset.DeleteGasDebugData(Integer.toString(10));
+                    }
+                    String tempPacket = ToByteString(TempReply, TempReply.length);
+                    devset.InsertGasDebugData(tempPacket);
+                    devset.closeDB();
+                }
+            }
+        }
+
+        return Status;
+    }
+
+    /**
+     * 가스밸브 상태값 해제 요청/반환
+     *
+     * @param DeviceIdx - (byte) 제어할 ID
+     * @param FreeFault  - (byte) 해제할 경고/이상 상태
+     *
+     * @return (STATUS) null - Error , Not null - OK
+     */
+    private STATUS Send_SetFreeStatus(byte DeviceIdx, byte FreeFault)
+    {
+        DeviceLog("[Send_SetFreeStatus] Start (FreeFault:" + ToByteString(FreeFault) + ")");
+        Send_DummyPacket();
+
+        // 1. In 파라미터 확인
+        if((DeviceIdx < 0) || (DeviceIdx >= MAX_DEVICE_COUNT))
+        {
+            Log.w(TAG, "[Send_GetStatus] param [DeviceIdx] Out of Range!!! " + DeviceIdx);
+            return null;
+        }
+
+        if ((FreeFault & (byte)(BIT1 | BIT4 | BIT7)) != 0x00)
+        {
+            // 미사용 비트'0' 확인
+            Log.w(TAG, "[Send_SetFreeStatus] FreeFault : Unused Bit Set !!! " + ToByteString(FreeFault));
+            return null;
+        }
+
+        // 2. 패킷 데이터 만들기
+        byte [] ReqData = new byte [] { 0x00, 0x00, 0x00, 0x00, FreeFault };
+
+        // 3. 데이터 전송 및 응답
+        byte [] Reply = SendNRead_Fixed( (byte)(DEVICE_ADDRESS + DeviceIdx), CMDList.Req.SetFreeStatus, ReqData);
+        STATUS Status = ReplyParsing(Reply);
+        if(Status == null)
+        {
+            DeviceLog("[Send_GetStatus] Reply is null");
+            AddDoCount(false);
+            return null;
+        }
+        AddDoCount(true);
+
+        return Status;
+    }
+
+    /**
+     * 닫기 제어 요청/반환
+     *
+     * @param DeviceIdx - (byte) 제어할 ID
+     *
+     * @return (STATUS) null - Error , Not null - OK
+     */
+    private STATUS Send_SetClose(byte DeviceIdx)
+    {
+        DeviceLog("[Send_SetClose] Start");
+        Send_DummyPacket();
+
+        // 1. In 파라미터 확인
+
+        // 2. 패킷 데이터 만들기
+        byte [] ReqData = new byte [] { 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+        // 3. 데이터 전송 및 응답
+        byte [] Reply = SendNRead_Fixed( (byte)(DEVICE_ADDRESS + DeviceIdx), CMDList.Req.SetClose, ReqData);
+        STATUS Status = ReplyParsing(Reply);
+        if(Status == null)
+        {
+            DeviceLog("[Send_SetClose] Reply is null");
+            AddDoCount(false);
+            return null;
+        }
+        AddDoCount(true);
+
+        return Status;
+    }
+
+    /**
+     * 응답 Parsing
+     *
+     * @param Reply     - (byte []) 응답 데이터
+     *
+     * @return (Status) null - Error , Not null - OK
+     */
+    private STATUS ReplyParsing(byte [] Reply)
+    {
+        // 1. 수신데이터 파싱
+        //     1.1. Default Check
+        if(Reply == null)
+        {
+            DeviceLog("[ReplyParsing] Reply is null");
+            return null;
+        }
+        if(Reply.length != 5)
+        {
+            // 길이 체크
+            Log.w(TAG, "[ReplyParsing] Reply.length  fail ... " + Reply.length);
+            return null;
+        }
+
+        int index = 0;
+        byte data = 0x00;
+        //          - D1 : 커맨드 수신 체크
+        data = Reply[index++];
+        if(data != (byte)0x80)
+        {
+            Log.w(TAG, "[ReplyParsing] D1 : fail ... (D1:" + String.format("0x%02X", data) + ")");
+            return null;
+        }
+
+        STATUS Status = new STATUS();
+        //          - D2 : 가스밸브 상태
+        data = Reply[index++];
+        Status.GasStatus = data;
+        if(!GASSTATUS.CheckRange(Status.GasStatus))
+        {
+            Log.w(TAG, "[ReplyParsing] D2 : GasStatus - Out Of Range !!! (GasStatus:" + String.format("0x%02X", Status.GasStatus) + ")");
+            return null;
+        }
+        //          - D3 : 0x00
+        data = Reply[index++];
+        if(data != 0x00)
+        {
+            Log.w(TAG, "[ReplyParsing] D3 : Zero Not!!! (data:" + String.format("0x%02X", data) + ")");
+            return null;
+        }
+        //          - D4 : 0x00
+        data = Reply[index++];
+        if(data != 0x00)
+        {
+            Log.w(TAG, "[ReplyParsing] D4 : Zero Not!!! (data:" + String.format("0x%02X", data) + ")");
+            return null;
+        }
+        //          - D5 : 기기 이상
+        data = Reply[index++];
+        if ((data & (byte)(BIT1 | BIT4 | BIT7)) != 0x00)
+        {
+            // 미사용 비트'0' 확인
+            Log.w(TAG, "[ReplyParsing] D5 (Fault) : Unused Bit Set !!! " + String.format("0x%02X", data));
+            return null;
+        }
+        Status.Fault = data;
+        if((data & BIT0) != 0x00) Status.bFaultController = true;
+        if((data & BIT2) != 0x00) Status.bFaultGasDetected = true;
+        if((data & BIT3) != 0x00) Status.bFaultFireDetected = true;
+        if((data & BIT5) != 0x00) Status.bFaultGasSensor = true;
+        if((data & BIT6) != 0x00) Status.bFaultFireSensor = true;
+
+        // 가스감지5회알람 설정된 경우
+        if(ServiceMain.dataBaseLoader.data.wallpadDeviceSet.Get_GasDetect_5time)
+        {
+            if(Status.bFaultGasDetected || Status.bFaultFireDetected)
+            {
+                DetectInputCount += 1;
+                //Log.i(TAG, "DetectInputCount Increase ++ : " + DetectInputCount);
+            }
+            else
+            {
+                //Log.i(TAG, "DetectInputCount --> 0");
+                DetectInputCount = 0;
+            }
+        }
+
+        return Status;
+    }
+
+    /**
+     * 더미패킷 전송<br>
+     * 구형연동 소방 수신기 (약 2013년 이전 연동제품) 의 경우<br>
+     * 앞 패킷이 가변패킷(난방등)일 경우 바로 소방패킷을 전송할 경우 수신받지못함.<br>
+     * 따라서, 본 드라이버에 송신 패킷 이전에 더미패킷을 송신할수있도록함.<br>
+     * USE_DUMMY_PACKET 변수에 따라 ON/OFF 가능
+     */
+    private void Send_DummyPacket()
+    {
+        if(!USE_DUMMY_PACKET) return;
+
+        byte [] ReqPaket = new byte[] {0x02, (byte)0xFF, 0x00, Get_Sequence(), 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+        WritePacket(ReqPaket, true);
+
+        Sleep(100);
+    }
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    // CMDList
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+     * 명령어 리스트
+     */
+    public static class CMDList
+    {
+        public static final class Req
+        {
+            /** 상태값 요청 */
+            public final static byte GetStatus             = 0x00;
+
+            /** 상태값 해제 요청 */
+            public final static byte SetFreeStatus         = 0x01;
+
+            /** 닫기 제어 요청 */
+            public final static byte SetClose              = 0x02;
+        }
+    }
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    // UpdateVariables
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+     * 상태 데이터를 업데이트 한다.
+     * @param DeviceIdx - (byte) 디바이스 인덱스
+     * @param Status - (STATUS) 업데이트할 상태 데이터
+     * @param bNotify - (boolean) UI로 알림 설정여부
+     */
+    private void UpdateVariables(byte DeviceIdx, STATUS Status, boolean bNotify)
+    {
+        if(mDriver == null) return;
+        if(mDriver.Status == null) return;
+        if(Status == null) return;
+        if(DeviceIdx >= mDriver.Polling.SearchDeviceCount) return;
+
+        boolean bChanged = false;
+
+        // 설치 상태 ON으로 변경
+        mDriver.Status[DeviceIdx].Install = true;
+
+        // 가스밸브 상태 갱신
+        if(mDriver.Status[DeviceIdx].GasStatus != Status.GasStatus)
+        {
+            DeviceLog("[UpdateVariables] ID:" + DeviceIdx +" GasStatus Change !!! (OLD:" + GASSTATUS.ToDebugString(mDriver.Status[DeviceIdx].GasStatus) + ", " +
+                    "NOW:" + GASSTATUS.ToDebugString(Status.GasStatus) + ")");
+            mDriver.Status[DeviceIdx].GasStatus = Status.GasStatus;
+            bChanged = true;
+        }
+
+        // 기기 이상 상태 갱신
+        if(mDriver.Status[DeviceIdx].Fault != Status.Fault)
+        {
+            mDriver.Status[DeviceIdx].Fault = Status.Fault;
+
+            mDriver.Status[DeviceIdx].bFaultGasDetected = Status.bFaultGasDetected;
+            mDriver.Status[DeviceIdx].bFaultFireDetected = Status.bFaultFireDetected;
+            mDriver.Status[DeviceIdx].bFaultController = Status.bFaultController;
+            mDriver.Status[DeviceIdx].bFaultGasSensor = Status.bFaultGasSensor;
+            mDriver.Status[DeviceIdx].bFaultFireSensor = Status.bFaultFireSensor;
+
+            bChanged = true;
+        }
+
+        ///////////////////////////////////////////////
+        // 알람
+        // 설정 추가 : 연속으로 5회이상 알람이 감지된 경우, 비상 intent 송신 하도록 추가
+        ///////////////////////////////////////////////
+        // 가스누출 감지
+        if(Status.bFaultGasDetected)
+        {
+            try
+            {
+                WallpadStatusData WPDSTD = new WallpadStatusData(ServiceMain.svcContext);
+                int alarmst = WPDSTD.GetAlarmStatus();
+                int alarmtype = WPDSTD.GetAlarmType();
+                WPDSTD.closeDB();
+                if ((alarmst != WallpadStatusData.ALARM_ARISE && alarmst != WallpadStatusData.ALARM_STOP) ||
+                        ((alarmst == WallpadStatusData.ALARM_ARISE || alarmst == WallpadStatusData.ALARM_STOP)  && alarmtype != WallpadStatusData.ALARM_ALERT))
+                {
+                    // 가스감지5회알람 설정된 경우
+                    if(ServiceMain.dataBaseLoader.data.wallpadDeviceSet.Get_GasDetect_5time)
+                    {
+                        if(DetectInputCount >= 5) // 5회이상 감지 발생 --> 알람 발생!
+                        {
+                            Log.i(TAG, "[UpdateVariables] Get_GasDetect_5time - GasDetected - Send_AlertBR");
+                            Send_AlertBR(CommonDefine.W_ALERT_GAS);
+                            DetectInputCount = 0;
+                        }
+                        else
+                        {
+                            if(DetectInputCount != 0) // 감지 발생 카운트 증가중
+                            {
+                                Log.i(TAG, "[UpdateVariables] (DetectInputCount < 5) --> " + DetectInputCount);
+                            }
+                        }
+                    }
+                    else // 일반적인 현장
+                    {
+                        Log.i(TAG, "[UpdateVariables] GasDetected - Send_AlertBR");
+                        Send_AlertBR(CommonDefine.W_ALERT_GAS);
+                    }
+                }
+            }
+            catch (RuntimeException re) {
+                LogUtil.errorLogInfo("", TAG, re);
+            }
+            catch (Exception e) {
+                Log.e(TAG, "[Exception Error] UpdateVariables - bFaultGasDetected");
+                //e.printStackTrace();
+                LogUtil.errorLogInfo("", TAG, e);
+            }
+        }
+
+        // 화재발생 감지
+        if(Status.bFaultFireDetected)
+        {
+            try
+            {
+                WallpadStatusData WPDSTD = new WallpadStatusData(ServiceMain.svcContext);
+                int alarmst = WPDSTD.GetAlarmStatus();
+                int alarmtype = WPDSTD.GetAlarmType();
+                WPDSTD.closeDB();
+                if ((alarmst != WallpadStatusData.ALARM_ARISE && alarmst != WallpadStatusData.ALARM_STOP) ||
+                        ((alarmst == WallpadStatusData.ALARM_ARISE || alarmst == WallpadStatusData.ALARM_STOP)  && alarmtype != WallpadStatusData.ALARM_ALERT))
+                {
+                    // 가스감지5회알람 설정된 경우
+                    if(ServiceMain.dataBaseLoader.data.wallpadDeviceSet.Get_GasDetect_5time)
+                    {
+                        if(DetectInputCount >= 5) // 5회이상 감지 발생 --> 알람 발생!
+                        {
+                            Log.i(TAG, "[UpdateVariables] Get_GasDetect_5time - FireDetected - Send_AlertBR");
+                            Send_AlertBR(CommonDefine.W_ALERT_FIRE);
+                            DetectInputCount = 0;
+                        }
+                        else
+                        {
+                            if(DetectInputCount != 0) // 감지 발생 카운트 증가중
+                            {
+                                Log.i(TAG, "[UpdateVariables] (DetectInputCount < 5) --> " + DetectInputCount);
+                            }
+                        }
+                    }
+                    else // 일반적인 현장
+                    {
+                        Log.i(TAG, "[UpdateVariables] FireDetected - Send_AlertBR");
+                        Send_AlertBR(CommonDefine.W_ALERT_FIRE);
+                    }
+                }
+            }
+            catch (RuntimeException re) {
+                LogUtil.errorLogInfo("", TAG, re);
+            }
+            catch (Exception e) {
+                Log.e(TAG, "[Exception Error] UpdateVariables - bFaultFireDetected");
+                //e.printStackTrace();
+                LogUtil.errorLogInfo("", TAG, e);
+            }
+        }
+
+        // 이상상태 해제
+        if(Status.Fault != 0x00)
+        {
+            Send_SetFreeStatus(DeviceIdx, Status.Fault);
+        }
+
+        // 변경상태 알림
+        if(bChanged || bNotify)
+        {
+            byte TempStatus = GASSTATUS.Close;
+            for(int i = 0; i < mDriver.Polling.SearchDeviceCount; i++)
+            {
+                if(mDriver.Status[i].GasStatus == GASSTATUS.Operation)
+                {
+                    TempStatus = GASSTATUS.Operation;
+                    break;
+                }
+                else if(mDriver.Status[i].GasStatus == GASSTATUS.Open)
+                {
+                    TempStatus = GASSTATUS.Open;
+                    break;
+                }
+            }
+
+            GasStatus = TempStatus;
+            StatusChanged(TempStatus);
+            DeviceLog("UpdateVariables !!!! *************************************** " + ToByteString(mDriver.Status[DeviceIdx].GasStatus));
+        }
+    }
+
+    /**
+     * 알람 BR 송신
+     *
+     * @param kind - (int) 알람종류
+     */
+    private void Send_AlertBR(int kind)
+    {
+        Intent intent = new Intent();
+        intent.setAction("WALLPAD_ALERT");
+        intent.putExtra("KIND", kind);
+        ServiceMain.svcContext.sendBroadcast(intent);
+    }
+}

+ 553 - 555
WallPadDevService/src/main/java/com/artncore/wallpaddevservice/driver/HeatingFinder_Controller.java

@@ -1,555 +1,553 @@
-/*
- * Copyright (C) 2015 Android WallPad Project
- *
- * FileName  : HeatingFinder_Controller.java
- * Project   : Android WallPad Project
- * Company   : HDC I-CONTROLS ( www.icontrols.co.kr )
- * Author    : Kang Sang Ho  , lairu@icontrols.co.kr
- */
-
-package com.artncore.wallpaddevservice.driver;
-
-import kr.co.icontrols.wallpadsupport.Version;
-import android.annotation.SuppressLint;
-import android.os.Message;
-import android.util.Log;
-
-import com.artncore.WallPadDataMgr.WallpadDeviceSet;
-import com.artncore.commons.APIErrorCode;
-import com.artncore.commons.define;
-import com.artncore.wallpaddevservice.CommonDefine;
-import com.artncore.wallpaddevservice.ServiceMain;
-import com.util.LogUtil;
-
-
-/**
- * 난방 파인더 의 드라이버 모듈이다.
- */
-@SuppressLint("HandlerLeak")
-public class HeatingFinder_Controller extends DeviceManager
-{
-    private final static String TAG = "HeatingFinder_Controller";
-
-    /** 난방V1 Address */
-    private final byte DEVICE_ADDRESS_V1  = (byte) 0x21;
-    /** 난방V2 Address */
-    private final byte DEVICE_ADDRESS_V2  = (byte) 0x28;
-
-    /** 초기 기기 검색 횟수  */
-    private final int MAX_SEARCH_COUNT = 10;
-
-    /** 난방제어기 검색 횟수  */
-    private final int MAX_FIND_COUNT = 3;
-
-    private int mModelType = Version.MODEL_TYPE.OTHER;
-
-    public class Driver
-    {
-        private PollingList Polling;
-
-        private int DeviceKind;
-
-        public Driver()
-        {
-            Polling = new PollingList();
-
-            DeviceKind = 0;
-        }
-
-        /** Polling 관련 */
-        private class PollingList
-        {
-            private final class STATUS
-            {
-                /** 초기화 과정 */
-                public final static byte First = 0;
-                /** 초기화 타임아웃 */
-                public final static byte FirstTimeOut = 1;
-                /** 평상시 */
-                public final static byte Normal = 2;
-            }
-
-            public byte Status;
-            public int SearchTryCount;
-
-            public boolean Find_V1;
-            public int HeatingV1ReplyCount;
-            public int HeatingV2ReplyCount;
-
-            private PollingList()
-            {
-                Status = STATUS.First;
-                SearchTryCount = 0;
-
-                Find_V1 = true;
-                HeatingV1ReplyCount = 0;
-                HeatingV2ReplyCount = 0;
-            }
-
-            public void SetStatus(byte ChangeStatus)
-            {
-                switch(ChangeStatus)
-                {
-                    case STATUS.First:
-                        Status = ChangeStatus;
-                        break;
-                    case STATUS.FirstTimeOut:
-                        Status = ChangeStatus;
-                        break;
-                    case STATUS.Normal:
-                        Status = ChangeStatus;
-                        break;
-                    default:
-                        break;
-                }
-            }
-        }
-    }
-
-    private Driver mDriver = null;
-
-
-    /**
-     * 생성자
-     */
-    public HeatingFinder_Controller()
-    {
-        /* 로그 초기상태 */
-//        log_sw = true;
-//        SerialLog = true;
-
-
-        /* 통신성공률 변수 초기화 */
-        super.CommDataGeneration(1);
-
-        /* 모델정보 가져오기 */
-        mModelType = Version.getModelType();
-
-        /* 드라이버 내부 변수 초기화 */
-        mDriver = new Driver();
-    }
-
-    @Override
-    public void DeviceLog(String msg)
-    {
-        if (!log_sw) return;
-        Log.d(TAG, msg);
-    }
-
-    /**
-     * 로딩후 처음 폴링 시퀀스
-     */
-    @Override
-    protected void do_boot()
-    {
-    }
-
-    ///////////////////////////////////////////////////////////////////////////////////////////////
-    // Polling
-    ///////////////////////////////////////////////////////////////////////////////////////////////
-    /**
-     * do_ctr : 폴링스케쥴러
-     */
-    @Override
-    protected void do_ctr() {
-        DeviceLog("Polling ");
-
-        /* [[ First & FirstTimeOut ]]
-         * 초기 디바이스정보  검색 */
-        if ((mDriver.Polling.Status == Driver.PollingList.STATUS.First) || (mDriver.Polling.Status == Driver.PollingList.STATUS.FirstTimeOut) ) {
-            // 1. IHN_1020GL/D101 모델 난방드라이버 FIX 로딩
-            if (Version.getGatewayUsage()) {
-                Log.i(TAG, "IHN_1020GL/D101 - Heating Setting");
-
-                // 에너지제품군 사용여부 가져오기
-                int ret = DB_Get_Energy_Devices_Info();
-                if (ret == 0) {
-                    // 사용않함 (V1 로딩)
-                    LoadingDriver(define.DRIVERID_HEATINGV1);
-                    mDriver.Polling.SetStatus(Driver.PollingList.STATUS.Normal);
-                }
-                else if (ret == 1) {
-                    // 사용함 (V2 로딩)
-                    LoadingDriver(define.DRIVERID_HEATINGV2);
-                    mDriver.Polling.SetStatus(Driver.PollingList.STATUS.Normal);
-                }
-                else {
-                    // Error
-                    Log.e(TAG, "[DB_Get_Energy_Devices_Info] Error !!! (ret:" + ret + ")");
-                }
-                return;
-            }
-
-            // 2. FirstTimeOut Check
-            if (mDriver.Polling.Status == Driver.PollingList.STATUS.First) {
-                if (mDriver.Polling.SearchTryCount++ > MAX_SEARCH_COUNT) {
-                    mDriver.Polling.Status = Driver.PollingList.STATUS.FirstTimeOut;
-
-                    Log.i(TAG, "--------------------------------------------------");
-                    Log.i(TAG, "SearchDevice Fail... FirstTimeOut ");
-                    Log.i(TAG, "--------------------------------------------------");
-
-                    ServiceMain.deviceInitChecker.Remove(super.DeviceName);
-                    ServiceMain.deviceInitChecker.Remove(ServiceMain.heatingV1_Controller.DeviceName);
-                    ServiceMain.deviceInitChecker.Remove(ServiceMain.heatingV2_Controller.DeviceName);
-                }
-            }
-
-            // 3. 난방 찾기
-            if (mDriver.Polling.Find_V1) {
-                boolean bRet = Send_HeatingV1ReplyCheck();
-                if (bRet) {
-                    mDriver.Polling.HeatingV1ReplyCount++;
-                    Log.i(TAG, "Find - HeatingV1 (Count:" + mDriver.Polling.HeatingV1ReplyCount + ")");
-                }
-            }
-            else {
-                boolean bRet = Send_HeatingV2ReplyCheck();
-                if (bRet) {
-                    mDriver.Polling.HeatingV2ReplyCount++;
-                    Log.i(TAG, "Find - HeatingV2 (Count:" + mDriver.Polling.HeatingV2ReplyCount + ")");
-                }
-            }
-
-            if (!mDriver.Polling.Find_V1) {
-                if (mDriver.Polling.HeatingV1ReplyCount >= MAX_FIND_COUNT) {
-                    LoadingDriver(define.DRIVERID_HEATINGV1);
-                    mDriver.Polling.SetStatus(Driver.PollingList.STATUS.Normal);
-                    return;
-                }
-                else if (mDriver.Polling.HeatingV2ReplyCount >= MAX_FIND_COUNT) {
-                    LoadingDriver(define.DRIVERID_HEATINGV2);
-                    mDriver.Polling.SetStatus(Driver.PollingList.STATUS.Normal);
-                    return;
-                }
-            }
-
-            if (mDriver.Polling.Find_V1) mDriver.Polling.Find_V1 = false;
-            else mDriver.Polling.Find_V1 = true;
-        }
-        /* [[ Normal ]]
-         * 평상시 */
-        else if (mDriver.Polling.Status == Driver.PollingList.STATUS.Normal) {
-            Log.w(TAG, "do_ctr - Normal");
-        }
-        /*
-         * 예외처리 */
-        else {
-            mDriver = new Driver();
-        }
-    }
-
-    ///////////////////////////////////////////////////////////////////////////////////////////////
-    // Ctrl
-    ///////////////////////////////////////////////////////////////////////////////////////////////
-    /**
-     * NoSink 제어
-     *
-     * @param StrArg
-     *
-     * @return
-     */
-    public String NoSinkCtrl(String StrArg)
-    {
-        DeviceLog("[NoSinkCtrl] Start");
-
-        // 1. 디바이스 초기화시 에러리턴
-        if( (mDriver.Polling.Status == Driver.PollingList.STATUS.First) ||
-                (mDriver.Polling.Status == Driver.PollingList.STATUS.FirstTimeOut) )
-        {
-            Log.w(TAG, "[NoSinkCtrl] - Not Yet !!!");
-            return "FAIL;" + APIErrorCode.DEVICEISNOTREADY;
-        }
-
-        CtrDevFormat ctrDevFormat = GetCtrDevParamParsing(StrArg, 5);
-        if(ctrDevFormat.ret != APIErrorCode.C_SUCCESS)
-        {
-            Log.w(TAG, "[NoSinkCtrl] GetCtrDevParamParsing Error (ret:" + ctrDevFormat.ret + ")");
-            return "FAIL;" + APIErrorCode.DEFAULT_PARSING_ERR;
-        }
-
-        //////////////////////////////////////////////////////////
-        // Refresh : 데이터 갱신 (No Sink)
-        //////////////////////////////////////////////////////////
-        if(ctrDevFormat.CmdStr!=null && ctrDevFormat.CmdStr.equals("Refresh"))
-        {
-            return RefreshResult();
-        }
-
-        return "FAIL;" + APIErrorCode.UNKNOWNCOMMAND;
-    }
-
-    /**
-     * do_ctrEmm : 싱크 제어
-     */
-    @Override
-    @SuppressLint("DefaultLocale")
-    protected String do_ctrEmm(DeviceCtrSHMem SHMem)
-    {
-        DeviceLog("[do_ctrEmm] Start");
-        DeviceLog("cmd    : " + SHMem.cmd);
-        DeviceLog("StrArg : " + SHMem.StrArg);
-
-        return APIErrorCode.FAILSTR + ";" + APIErrorCode.DEVICEISNOTREADY;
-    }
-
-
-    ///////////////////////////////////////////////////////////////////////////////////////////////
-    // RefreshResult
-    ///////////////////////////////////////////////////////////////////////////////////////////////
-    /**
-     * Refresh 에 대한 응답포멧 정의
-     *
-     * @return (String) "SUCCESS; ..." 성공 , "FAIL; ... " 실패
-     */
-    private String RefreshResult()
-    {
-        String result = null;
-
-        DeviceLog("RefreshResult call : ");
-
-        // 1. Check Polling Status
-        if( (mDriver.Polling.Status == Driver.PollingList.STATUS.First) ||
-                (mDriver.Polling.Status == Driver.PollingList.STATUS.FirstTimeOut) )
-        {
-            result = "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
-            return result;
-        }
-
-        // 2. Param Range Check
-
-        // 3. Make Return String Format
-        try
-        {
-            if(mDriver == null)                   return "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
-
-            /*
-             * [Format]
-             *
-             * SUCCESS    - (String) 성공
-             *
-             * DeviceKind - (int) 디바이스 종류
-             */
-
-            result = APIErrorCode.SUCCESS + ";";
-
-            result += mDriver.DeviceKind + ";";
-        }
-        catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-            result = "FAIL;"+APIErrorCode.EXCEPTION;
-        }
-        catch (Exception e) {
-            Log.e(TAG, "[Exception Error] RefreshResult");
-            //e.printStackTrace();
-            LogUtil.errorLogInfo("", TAG, e);
-            result = "FAIL;"+APIErrorCode.EXCEPTION;
-        }
-        DeviceLog("RefreshResult return : " + result);
-
-        return result;
-    }
-
-    ///////////////////////////////////////////////////////////////////////////////////////////////
-    // Protocol Command Send Func
-    ///////////////////////////////////////////////////////////////////////////////////////////////
-    /**
-     * 난방V1의 응답유무를 체크한다.
-     *
-     * @return (boolean) true : 응답 정상 , false : 미응답
-     */
-    private boolean Send_HeatingV1ReplyCheck()
-    {
-        DeviceLog("[Send_HeatingV1ReplyCheck] Start");
-
-        // 1. In 파라미터 확인
-
-        // 2. 패킷 데이터 만들기
-        byte [] ReqData = new byte [] { (byte)0xFF };
-
-        // 3. 데이터 전송 및 응답
-        byte [] Reply = SendNRead_Variable( (byte)(DEVICE_ADDRESS_V1), CMDList.V1.Req.GetDeviceInfo, ReqData);
-
-        // 4. 수신데이터 파싱
-        //     4.1. Default Check
-        if(Reply == null)
-        {
-            DeviceLog("[Send_HeatingV1ReplyCheck] Reply is null");
-            return false;
-        }
-        if( (Reply.length != 9) && (Reply.length != 6) )
-        {
-            // 길이 체크
-            // 2013/05/13 - 현대건설 하니웰 제어기기 특징 응답이 9인데 6으로옴
-            Log.w(TAG, "[Send_HeatingV1ReplyCheck] Reply.length  fail ... " + Reply.length);
-            return false;
-        }
-        return true;
-    }
-
-    /**
-     * 난방V2의 응답유무를 체크한다.
-     *
-     * @return (boolean) true : 응답 정상 , false : 미응답
-     */
-    private boolean Send_HeatingV2ReplyCheck()
-    {
-        DeviceLog("[Send_HeatingV2ReplyCheck] Start");
-
-        // 1. In 파라미터 확인
-
-        // 2. 패킷 데이터 만들기
-        byte [] ReqData = null;
-
-        // 3. 데이터 전송 및 응답
-        byte [] Reply = SendNRead_Variable( (byte)(DEVICE_ADDRESS_V2), CMDList.V2.Req.GetDeviceInfo, ReqData);
-
-        // 4. 수신데이터 파싱
-        //     4.1. Default Check
-        if(Reply == null)
-        {
-            DeviceLog("[Send_HeatingV2ReplyCheck] Reply is null");
-            return false;
-        }
-        if(Reply.length != 12)
-        {
-            // 길이 체크
-            Log.w(TAG, "[Send_HeatingV2ReplyCheck] Reply.length  fail ... " + Reply.length);
-            return false;
-        }
-        return true;
-    }
-
-    ///////////////////////////////////////////////////////////////////////////////////////////////
-    // CMDList
-    ///////////////////////////////////////////////////////////////////////////////////////////////
-    /**
-     * 명령어 리스트
-     */
-    public static class CMDList
-    {
-        public static final class V1
-        {
-            public static final class Req
-            {
-                /** 디바이스 정보 요청 */
-                public final static byte GetDeviceInfo        = 0x18;
-            }
-        }
-        public static final class V2
-        {
-            public static final class Req
-            {
-                /** 기기 상태 읽기 요청 */
-                public final static byte GetDeviceInfo        = 0x01;
-            }
-        }
-    }
-
-    /**
-     * 에너지제품군 사용여부를 DB에서 가져온다.
-     *
-     * @return (int) - 0 : 사용하지않음 , 1 : 사용 , <0 : 실패
-     */
-    private int DB_Get_Energy_Devices_Info()
-    {
-        int ret = -1;
-        try
-        {
-            WallpadDeviceSet devset = new WallpadDeviceSet(ServiceMain.svcContext);
-            ret = devset.Get_Energy_Devices_Info();
-            devset.closeDB();
-        }
-        catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-            ret = -10;
-        }
-        catch (Exception e) {
-            Log.e(TAG, "[Exception Error] DB_Get_Energy_Devices_Info");
-            //e.printStackTrace();
-            LogUtil.errorLogInfo("", TAG, e);
-            ret = -10;
-        }
-        return ret;
-    }
-
-    /**
-     * 드라이버를 로딩시킨다.
-     *
-     * @param DeviceID - (int) define.DRIVERID_HEATINGV1  or  define.DRIVERID_HEATINGV2
-     *
-     * @return (int) - >=0 : 성공, <0 : 실패
-     */
-    private int LoadingDriver(int DeviceID)
-    {
-        // 1. Param Check
-        if( (DeviceID != define.DRIVERID_HEATINGV1) &&
-                (DeviceID != define.DRIVERID_HEATINGV2) )
-        {
-            Log.w(TAG, "[LoadingDriver] Param : DeviceID Out Of Range !!!(DeviceID:" + DeviceID + ")");
-            return -1;
-        }
-
-        // 2. Doing
-        if(DeviceID == define.DRIVERID_HEATINGV1)
-        {
-            Log.i(TAG, "+++++++++++++++++++++++++++++++++++++++");
-            Log.i(TAG, "Heating V1 - LOADING ...");
-            Log.i(TAG, "+++++++++++++++++++++++++++++++++++++++");
-
-            // 드라이버를 시작시킨다.
-            SendNewDriverStart(DeviceID);
-
-            //
-            ServiceMain.heatingV1_Controller.Set_DevID(DevID);
-
-            // V2 드라이버 초기화리스트에서 제거
-            ServiceMain.deviceInitChecker.Remove(ServiceMain.heatingV2_Controller.DeviceName);
-        }
-        else if(DeviceID == define.DRIVERID_HEATINGV2)
-        {
-            // V2 로딩
-            Log.i(TAG, "+++++++++++++++++++++++++++++++++++++++");
-            Log.i(TAG, "Heating V2 - LOADING ...");
-            Log.i(TAG, "+++++++++++++++++++++++++++++++++++++++");
-
-            // 드라이버를 시작시킨다.
-            SendNewDriverStart(DeviceID);
-
-            //
-            ServiceMain.heatingV2_Controller.Set_DevID(DevID);
-
-            // V1 드라이버 초기화리스트에서 제거
-            ServiceMain.deviceInitChecker.Remove(ServiceMain.heatingV1_Controller.DeviceName);
-        }
-        //
-        Message Nmsg = PortHandler.lhandler.obtainMessage();
-        Nmsg.what = CommonDefine.DEVCTR_REQ_CHANGEDEV;
-        Nmsg.arg1 = DevID;
-        Nmsg.arg2 = DeviceID;
-        PortHandler.lhandler.sendMessage(Nmsg);
-
-        // 디바이스 ID 셋팅
-        mDriver.DeviceKind = DeviceID;
-
-        // 본 드라이버 초기화 리스트에서 제거
-        ServiceMain.deviceInitChecker.Remove(super.DeviceName);
-
-        return 0;
-    }
-
-    /**
-     * 드라이버를 시작시킨다.
-     *
-     * @param DeviceID
-     */
-    protected void SendNewDriverStart(int DeviceID)
-    {
-        Message Nmsg = PortHandler.lhandler.obtainMessage();
-        Nmsg.what = CommonDefine.DEVCTR_NEW_DRIVER_START;
-        Nmsg.arg1  = DevID;
-        Nmsg.arg2  = DeviceID;
-
-        PortHandler.lhandler.sendMessage(Nmsg);
-    }
-}
+/*
+ * Copyright (C) 2015 Android WallPad Project
+ *
+ * FileName  : HeatingFinder_Controller.java
+ * Project   : Android WallPad Project
+ * Company   : HDC I-CONTROLS ( www.icontrols.co.kr )
+ * Author    : Kang Sang Ho  , lairu@icontrols.co.kr
+ */
+
+package com.artncore.wallpaddevservice.driver;
+
+import kr.co.icontrols.wallpadsupport.Version;
+import android.annotation.SuppressLint;
+import android.os.Message;
+import android.util.Log;
+
+import com.artncore.WallPadDataMgr.WallpadDeviceSet;
+import com.artncore.commons.APIErrorCode;
+import com.artncore.commons.define;
+import com.artncore.wallpaddevservice.CommonDefine;
+import com.artncore.wallpaddevservice.ServiceMain;
+import com.util.LogUtil;
+
+
+/**
+ * 난방 파인더 의 드라이버 모듈이다.
+ */
+@SuppressLint("HandlerLeak")
+public class HeatingFinder_Controller extends DeviceManager
+{
+    private final static String TAG = "HeatingFinder_Controller";
+
+    /** 난방V1 Address */
+    private final byte DEVICE_ADDRESS_V1  = (byte) 0x21;
+    /** 난방V2 Address */
+    private final byte DEVICE_ADDRESS_V2  = (byte) 0x28;
+
+    /** 초기 기기 검색 횟수  */
+    private final int MAX_SEARCH_COUNT = 10;
+
+    /** 난방제어기 검색 횟수  */
+    private final int MAX_FIND_COUNT = 3;
+
+    private int mModelType = Version.MODEL_TYPE.OTHER;
+
+    public class Driver
+    {
+        private PollingList Polling;
+
+        private int DeviceKind;
+
+        public Driver()
+        {
+            Polling = new PollingList();
+
+            DeviceKind = 0;
+        }
+
+        /** Polling 관련 */
+        private class PollingList
+        {
+            private final class STATUS
+            {
+                /** 초기화 과정 */
+                public final static byte First = 0;
+                /** 초기화 타임아웃 */
+                public final static byte FirstTimeOut = 1;
+                /** 평상시 */
+                public final static byte Normal = 2;
+            }
+
+            public byte Status;
+            public int SearchTryCount;
+
+            public boolean Find_V1;
+            public int HeatingV1ReplyCount;
+            public int HeatingV2ReplyCount;
+
+            private PollingList()
+            {
+                Status = STATUS.First;
+                SearchTryCount = 0;
+
+                Find_V1 = true;
+                HeatingV1ReplyCount = 0;
+                HeatingV2ReplyCount = 0;
+            }
+
+            public void SetStatus(byte ChangeStatus)
+            {
+                switch(ChangeStatus)
+                {
+                    case STATUS.First:
+                        Status = ChangeStatus;
+                        break;
+                    case STATUS.FirstTimeOut:
+                        Status = ChangeStatus;
+                        break;
+                    case STATUS.Normal:
+                        Status = ChangeStatus;
+                        break;
+                    default:
+                        break;
+                }
+            }
+        }
+    }
+
+    private Driver mDriver = null;
+
+
+    /**
+     * 생성자
+     */
+    public HeatingFinder_Controller()
+    {
+        /* 로그 초기상태 */
+        log_sw = false;
+
+        /* 통신성공률 변수 초기화 */
+        super.CommDataGeneration(1);
+
+        /* 모델정보 가져오기 */
+        mModelType = Version.getModelType();
+
+        /* 드라이버 내부 변수 초기화 */
+        mDriver = new Driver();
+    }
+
+    @Override
+    public void DeviceLog(String msg)
+    {
+        if (!log_sw) return;
+        Log.d(TAG, msg);
+    }
+
+    /**
+     * 로딩후 처음 폴링 시퀀스
+     */
+    @Override
+    protected void do_boot()
+    {
+    }
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    // Polling
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+     * do_ctr : 폴링스케쥴러
+     */
+    @Override
+    protected void do_ctr() {
+        DeviceLog("Polling ");
+
+        /* [[ First & FirstTimeOut ]]
+         * 초기 디바이스정보  검색 */
+        if ((mDriver.Polling.Status == Driver.PollingList.STATUS.First) || (mDriver.Polling.Status == Driver.PollingList.STATUS.FirstTimeOut) ) {
+            // 1. IHN_1020GL/D101 모델 난방드라이버 FIX 로딩
+            if (Version.getGatewayUsage()) {
+                Log.i(TAG, "IHN_1020GL/D101 - Heating Setting");
+
+                // 에너지제품군 사용여부 가져오기
+                int ret = DB_Get_Energy_Devices_Info();
+                if (ret == 0) {
+                    // 사용않함 (V1 로딩)
+                    LoadingDriver(define.DRIVERID_HEATINGV1);
+                    mDriver.Polling.SetStatus(Driver.PollingList.STATUS.Normal);
+                }
+                else if (ret == 1) {
+                    // 사용함 (V2 로딩)
+                    LoadingDriver(define.DRIVERID_HEATINGV2);
+                    mDriver.Polling.SetStatus(Driver.PollingList.STATUS.Normal);
+                }
+                else {
+                    // Error
+                    Log.e(TAG, "[DB_Get_Energy_Devices_Info] Error !!! (ret:" + ret + ")");
+                }
+                return;
+            }
+
+            // 2. FirstTimeOut Check
+            if (mDriver.Polling.Status == Driver.PollingList.STATUS.First) {
+                if (mDriver.Polling.SearchTryCount++ > MAX_SEARCH_COUNT) {
+                    mDriver.Polling.Status = Driver.PollingList.STATUS.FirstTimeOut;
+
+                    Log.i(TAG, "--------------------------------------------------");
+                    Log.i(TAG, "SearchDevice Fail... FirstTimeOut ");
+                    Log.i(TAG, "--------------------------------------------------");
+
+                    ServiceMain.deviceInitChecker.Remove(super.DeviceName);
+                    ServiceMain.deviceInitChecker.Remove(ServiceMain.heatingV1_Controller.DeviceName);
+                    ServiceMain.deviceInitChecker.Remove(ServiceMain.heatingV2_Controller.DeviceName);
+                }
+            }
+
+            // 3. 난방 찾기
+            if (mDriver.Polling.Find_V1) {
+                boolean bRet = Send_HeatingV1ReplyCheck();
+                if (bRet) {
+                    mDriver.Polling.HeatingV1ReplyCount++;
+                    Log.i(TAG, "Find - HeatingV1 (Count:" + mDriver.Polling.HeatingV1ReplyCount + ")");
+                }
+            }
+            else {
+                boolean bRet = Send_HeatingV2ReplyCheck();
+                if (bRet) {
+                    mDriver.Polling.HeatingV2ReplyCount++;
+                    Log.i(TAG, "Find - HeatingV2 (Count:" + mDriver.Polling.HeatingV2ReplyCount + ")");
+                }
+            }
+
+            if (!mDriver.Polling.Find_V1) {
+                if (mDriver.Polling.HeatingV1ReplyCount >= MAX_FIND_COUNT) {
+                    LoadingDriver(define.DRIVERID_HEATINGV1);
+                    mDriver.Polling.SetStatus(Driver.PollingList.STATUS.Normal);
+                    return;
+                }
+                else if (mDriver.Polling.HeatingV2ReplyCount >= MAX_FIND_COUNT) {
+                    LoadingDriver(define.DRIVERID_HEATINGV2);
+                    mDriver.Polling.SetStatus(Driver.PollingList.STATUS.Normal);
+                    return;
+                }
+            }
+
+            if (mDriver.Polling.Find_V1) mDriver.Polling.Find_V1 = false;
+            else mDriver.Polling.Find_V1 = true;
+        }
+        /* [[ Normal ]]
+         * 평상시 */
+        else if (mDriver.Polling.Status == Driver.PollingList.STATUS.Normal) {
+            Log.w(TAG, "do_ctr - Normal");
+        }
+        /*
+         * 예외처리 */
+        else {
+            mDriver = new Driver();
+        }
+    }
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    // Ctrl
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+     * NoSink 제어
+     *
+     * @param StrArg
+     *
+     * @return
+     */
+    public String NoSinkCtrl(String StrArg)
+    {
+        DeviceLog("[NoSinkCtrl] Start");
+
+        // 1. 디바이스 초기화시 에러리턴
+        if( (mDriver.Polling.Status == Driver.PollingList.STATUS.First) ||
+                (mDriver.Polling.Status == Driver.PollingList.STATUS.FirstTimeOut) )
+        {
+            Log.w(TAG, "[NoSinkCtrl] - Not Yet !!!");
+            return "FAIL;" + APIErrorCode.DEVICEISNOTREADY;
+        }
+
+        CtrDevFormat ctrDevFormat = GetCtrDevParamParsing(StrArg, 5);
+        if(ctrDevFormat.ret != APIErrorCode.C_SUCCESS)
+        {
+            Log.w(TAG, "[NoSinkCtrl] GetCtrDevParamParsing Error (ret:" + ctrDevFormat.ret + ")");
+            return "FAIL;" + APIErrorCode.DEFAULT_PARSING_ERR;
+        }
+
+        //////////////////////////////////////////////////////////
+        // Refresh : 데이터 갱신 (No Sink)
+        //////////////////////////////////////////////////////////
+        if(ctrDevFormat.CmdStr!=null && ctrDevFormat.CmdStr.equals("Refresh"))
+        {
+            return RefreshResult();
+        }
+
+        return "FAIL;" + APIErrorCode.UNKNOWNCOMMAND;
+    }
+
+    /**
+     * do_ctrEmm : 싱크 제어
+     */
+    @Override
+    @SuppressLint("DefaultLocale")
+    protected String do_ctrEmm(DeviceCtrSHMem SHMem)
+    {
+        DeviceLog("[do_ctrEmm] Start");
+        DeviceLog("cmd    : " + SHMem.cmd);
+        DeviceLog("StrArg : " + SHMem.StrArg);
+
+        return APIErrorCode.FAILSTR + ";" + APIErrorCode.DEVICEISNOTREADY;
+    }
+
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    // RefreshResult
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+     * Refresh 에 대한 응답포멧 정의
+     *
+     * @return (String) "SUCCESS; ..." 성공 , "FAIL; ... " 실패
+     */
+    private String RefreshResult()
+    {
+        String result = null;
+
+        DeviceLog("RefreshResult call : ");
+
+        // 1. Check Polling Status
+        if( (mDriver.Polling.Status == Driver.PollingList.STATUS.First) ||
+                (mDriver.Polling.Status == Driver.PollingList.STATUS.FirstTimeOut) )
+        {
+            result = "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
+            return result;
+        }
+
+        // 2. Param Range Check
+
+        // 3. Make Return String Format
+        try
+        {
+            if(mDriver == null)                   return "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
+
+            /*
+             * [Format]
+             *
+             * SUCCESS    - (String) 성공
+             *
+             * DeviceKind - (int) 디바이스 종류
+             */
+
+            result = APIErrorCode.SUCCESS + ";";
+
+            result += mDriver.DeviceKind + ";";
+        }
+        catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+            result = "FAIL;"+APIErrorCode.EXCEPTION;
+        }
+        catch (Exception e) {
+            Log.e(TAG, "[Exception Error] RefreshResult");
+            //e.printStackTrace();
+            LogUtil.errorLogInfo("", TAG, e);
+            result = "FAIL;"+APIErrorCode.EXCEPTION;
+        }
+        DeviceLog("RefreshResult return : " + result);
+
+        return result;
+    }
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    // Protocol Command Send Func
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+     * 난방V1의 응답유무를 체크한다.
+     *
+     * @return (boolean) true : 응답 정상 , false : 미응답
+     */
+    private boolean Send_HeatingV1ReplyCheck()
+    {
+        DeviceLog("[Send_HeatingV1ReplyCheck] Start");
+
+        // 1. In 파라미터 확인
+
+        // 2. 패킷 데이터 만들기
+        byte [] ReqData = new byte [] { (byte)0xFF };
+
+        // 3. 데이터 전송 및 응답
+        byte [] Reply = SendNRead_Variable( (byte)(DEVICE_ADDRESS_V1), CMDList.V1.Req.GetDeviceInfo, ReqData);
+
+        // 4. 수신데이터 파싱
+        //     4.1. Default Check
+        if(Reply == null)
+        {
+            DeviceLog("[Send_HeatingV1ReplyCheck] Reply is null");
+            return false;
+        }
+        if( (Reply.length != 9) && (Reply.length != 6) )
+        {
+            // 길이 체크
+            // 2013/05/13 - 현대건설 하니웰 제어기기 특징 응답이 9인데 6으로옴
+            Log.w(TAG, "[Send_HeatingV1ReplyCheck] Reply.length  fail ... " + Reply.length);
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * 난방V2의 응답유무를 체크한다.
+     *
+     * @return (boolean) true : 응답 정상 , false : 미응답
+     */
+    private boolean Send_HeatingV2ReplyCheck()
+    {
+        DeviceLog("[Send_HeatingV2ReplyCheck] Start");
+
+        // 1. In 파라미터 확인
+
+        // 2. 패킷 데이터 만들기
+        byte [] ReqData = null;
+
+        // 3. 데이터 전송 및 응답
+        byte [] Reply = SendNRead_Variable( (byte)(DEVICE_ADDRESS_V2), CMDList.V2.Req.GetDeviceInfo, ReqData);
+
+        // 4. 수신데이터 파싱
+        //     4.1. Default Check
+        if(Reply == null)
+        {
+            DeviceLog("[Send_HeatingV2ReplyCheck] Reply is null");
+            return false;
+        }
+        if(Reply.length != 12)
+        {
+            // 길이 체크
+            Log.w(TAG, "[Send_HeatingV2ReplyCheck] Reply.length  fail ... " + Reply.length);
+            return false;
+        }
+        return true;
+    }
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    // CMDList
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+     * 명령어 리스트
+     */
+    public static class CMDList
+    {
+        public static final class V1
+        {
+            public static final class Req
+            {
+                /** 디바이스 정보 요청 */
+                public final static byte GetDeviceInfo        = 0x18;
+            }
+        }
+        public static final class V2
+        {
+            public static final class Req
+            {
+                /** 기기 상태 읽기 요청 */
+                public final static byte GetDeviceInfo        = 0x01;
+            }
+        }
+    }
+
+    /**
+     * 에너지제품군 사용여부를 DB에서 가져온다.
+     *
+     * @return (int) - 0 : 사용하지않음 , 1 : 사용 , <0 : 실패
+     */
+    private int DB_Get_Energy_Devices_Info()
+    {
+        int ret = -1;
+        try
+        {
+            WallpadDeviceSet devset = new WallpadDeviceSet(ServiceMain.svcContext);
+            ret = devset.Get_Energy_Devices_Info();
+            devset.closeDB();
+        }
+        catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+            ret = -10;
+        }
+        catch (Exception e) {
+            Log.e(TAG, "[Exception Error] DB_Get_Energy_Devices_Info");
+            //e.printStackTrace();
+            LogUtil.errorLogInfo("", TAG, e);
+            ret = -10;
+        }
+        return ret;
+    }
+
+    /**
+     * 드라이버를 로딩시킨다.
+     *
+     * @param DeviceID - (int) define.DRIVERID_HEATINGV1  or  define.DRIVERID_HEATINGV2
+     *
+     * @return (int) - >=0 : 성공, <0 : 실패
+     */
+    private int LoadingDriver(int DeviceID)
+    {
+        // 1. Param Check
+        if( (DeviceID != define.DRIVERID_HEATINGV1) &&
+                (DeviceID != define.DRIVERID_HEATINGV2) )
+        {
+            Log.w(TAG, "[LoadingDriver] Param : DeviceID Out Of Range !!!(DeviceID:" + DeviceID + ")");
+            return -1;
+        }
+
+        // 2. Doing
+        if(DeviceID == define.DRIVERID_HEATINGV1)
+        {
+            Log.i(TAG, "+++++++++++++++++++++++++++++++++++++++");
+            Log.i(TAG, "Heating V1 - LOADING ...");
+            Log.i(TAG, "+++++++++++++++++++++++++++++++++++++++");
+
+            // 드라이버를 시작시킨다.
+            SendNewDriverStart(DeviceID);
+
+            //
+            ServiceMain.heatingV1_Controller.Set_DevID(DevID);
+
+            // V2 드라이버 초기화리스트에서 제거
+            ServiceMain.deviceInitChecker.Remove(ServiceMain.heatingV2_Controller.DeviceName);
+        }
+        else if(DeviceID == define.DRIVERID_HEATINGV2)
+        {
+            // V2 로딩
+            Log.i(TAG, "+++++++++++++++++++++++++++++++++++++++");
+            Log.i(TAG, "Heating V2 - LOADING ...");
+            Log.i(TAG, "+++++++++++++++++++++++++++++++++++++++");
+
+            // 드라이버를 시작시킨다.
+            SendNewDriverStart(DeviceID);
+
+            //
+            ServiceMain.heatingV2_Controller.Set_DevID(DevID);
+
+            // V1 드라이버 초기화리스트에서 제거
+            ServiceMain.deviceInitChecker.Remove(ServiceMain.heatingV1_Controller.DeviceName);
+        }
+        //
+        Message Nmsg = PortHandler.lhandler.obtainMessage();
+        Nmsg.what = CommonDefine.DEVCTR_REQ_CHANGEDEV;
+        Nmsg.arg1 = DevID;
+        Nmsg.arg2 = DeviceID;
+        PortHandler.lhandler.sendMessage(Nmsg);
+
+        // 디바이스 ID 셋팅
+        mDriver.DeviceKind = DeviceID;
+
+        // 본 드라이버 초기화 리스트에서 제거
+        ServiceMain.deviceInitChecker.Remove(super.DeviceName);
+
+        return 0;
+    }
+
+    /**
+     * 드라이버를 시작시킨다.
+     *
+     * @param DeviceID
+     */
+    protected void SendNewDriverStart(int DeviceID)
+    {
+        Message Nmsg = PortHandler.lhandler.obtainMessage();
+        Nmsg.what = CommonDefine.DEVCTR_NEW_DRIVER_START;
+        Nmsg.arg1  = DevID;
+        Nmsg.arg2  = DeviceID;
+
+        PortHandler.lhandler.sendMessage(Nmsg);
+    }
+}

+ 1696 - 1697
WallPadDevService/src/main/java/com/artncore/wallpaddevservice/driver/HeatingV1_Controller.java

@@ -1,1697 +1,1696 @@
-/*
- * Copyright (C) 2014 Android WallPad Project
- *
- * FileName  : HeatingV1_Controller.java
- * Project   : Android WallPad Project
- * Company   : HDC I-CONTROLS ( www.icontrols.co.kr )
- * Author    : Kang Sang Ho  , lairu@icontrols.co.kr
- */
-
-package com.artncore.wallpaddevservice.driver;
-
-import java.util.Calendar;
-import java.util.GregorianCalendar;
-
-import android.annotation.SuppressLint;
-import android.util.Log;
-
-import com.artncore.commons.APIErrorCode;
-import com.artncore.commons.DataClasses.HeatingV1;
-import com.artncore.commons.DataClasses.HeatingV1.*;
-import com.artncore.commons.define;
-import com.util.LogUtil;
-import com.artncore.wallpaddevservice.ServiceMain;
-
-
-/**
- * 난방V1의 드라이버 모듈이다.
- */
-@SuppressLint("HandlerLeak")
-public class HeatingV1_Controller extends DeviceManager
-{
-    private final static String TAG = "HeatingV1_Driver";
-
-    private final byte DEVICE_ADDRESS  = (byte) 0x21;
-
-    /** 밸브상태 사용 여부 (true:상태반영, false:상태미반영 only false) */
-    private final boolean USE_VALVE_STATUS = true;
-
-    /////////////////////////////////////////////////////////
-    // 기본 지원 방개수
-    /////////////////////////////////////////////////////////
-    /** 지원 방개수 (하한값) */
-    private final byte ROOM_COUNT_LOW  = (byte) 1;
-    /** 지원 방개수 (상한값) */
-    private final byte ROOM_COUNT_HI   = (byte) 8;
-
-    /////////////////////////////////////////////////////////
-    // 지원 설정온도
-    /////////////////////////////////////////////////////////
-    /** 지원 최저설정온도 */
-    private final double SETTEMP_MIN  = (double) 5.0;
-    /** 지원 최대설정온도 */
-    private final double SETTEMP_MAX  = (double) 40.0;
-
-    /** 초기 기기 검색 횟수  */
-    private final int MAX_SEARCH_COUNT   = 3;
-
-    /** Refresh 시 사용되는 index 를 정의한다. */
-    public final static class REFRESH_IDX
-    {
-        /** 방1 */
-        public final static byte ROOM1 = 0;
-        /** 방2 */
-        public final static byte ROOM2 = 1;
-        /** 방3 */
-        public final static byte ROOM3 = 2;
-        /** 방4 */
-        public final static byte ROOM4 = 3;
-        /** 방5 */
-        public final static byte ROOM5 = 4;
-        /** 방6 */
-        public final static byte ROOM6 = 5;
-        /** 방7 */
-        public final static byte ROOM7 = 6;
-        /** 방8 */
-        public final static byte ROOM8 = 7;
-
-        /** 기기 정보 및 일시정지 상태 */
-        public final static byte INFO_N_PAUSE = 100;
-    }
-
-    public class Driver
-    {
-        private PollingList Polling;
-
-        private HeatingV1 Device;
-
-        public Driver()
-        {
-            Polling = new PollingList();
-            Device = new HeatingV1();
-        }
-
-        /** Polling 관련 */
-        private class PollingList
-        {
-            private final class STATUS
-            {
-                /** 초기화 과정 */
-                public final static byte First = 0;
-                /** 초기화 타임아웃 */
-                public final static byte FirstTimeOut = 1;
-                /** 평상시 */
-                public final static byte Normal = 2;
-                /** 지정방 상태조회 */
-                public final static byte FixRoom = 3;
-            }
-
-            public byte Status;
-            public int SearchTryCount;
-            public byte RoomIndex;
-
-            private PollingList()
-            {
-                Status = STATUS.First;
-                SearchTryCount = 0;
-                RoomIndex = 0;
-            }
-        }
-    }
-
-    private Driver mDriver = null;
-
-
-    /**
-     * 생성자
-     */
-    public HeatingV1_Controller()
-    {
-        /** 로그 초기상태 */
-//        log_sw = true;
-//        SerialLog = true;
-
-        /** 통신성공률 변수 초기화 */
-        super.CommDataGeneration(1);
-
-        /** 드라이버 변수 초기화 */
-        mDriver = new Driver();
-    }
-
-    @Override
-    public void DeviceLog(String msg)
-    {
-        if (!log_sw) return;
-        Log.d(TAG, msg);
-    }
-
-    /**
-     * 로딩후 처음 폴링 시퀀스
-     */
-    @Override
-    protected void do_boot()
-    {
-    }
-
-    /**
-     * do_ctr : 폴링스케쥴러
-     */
-    @Override
-    protected void do_ctr()
-    {
-        //DeviceLog("Polling ");
-
-        /* [[ First & FirstTimeOut ]]
-         * 초기 디바이스정보  검색 */
-        if( (mDriver.Polling.Status == Driver.PollingList.STATUS.First) ||
-                (mDriver.Polling.Status == Driver.PollingList.STATUS.FirstTimeOut) )
-        {
-            if(mDriver.Polling.Status == Driver.PollingList.STATUS.First)
-            {
-                if(mDriver.Polling.SearchTryCount++ > MAX_SEARCH_COUNT)
-                {
-                    mDriver.Polling.Status = Driver.PollingList.STATUS.FirstTimeOut;
-
-                    Log.i(TAG, "--------------------------------------------------");
-                    Log.i(TAG, "SearchDevice Fail... FirstTimeOut ");
-                    Log.i(TAG, "--------------------------------------------------");
-
-                    ServiceMain.deviceInitChecker.Remove(super.DeviceName);
-                }
-            }
-
-            // 기기정보 가져오기
-            if(!mDriver.Device.info.GetSet())
-            {
-                HeatingV1.Info info = Send_GetDeviceInfo();
-                if(info != null)
-                {
-                    mDriver.Device.info = info;
-                    Log.i(TAG, info.ToDebugString());
-                }
-                Sleep(100);
-            }
-
-            // 전체방 상태 갱신 (방개수 & 온도단위 & 일시정지상태 갱신)
-            HeatingV1.AllRoomData allRoomData = Send_GetAllRoomStatus();
-            if(allRoomData != null)
-            {
-                byte RoomCount = allRoomData.RoomCount;
-                mDriver.Device.SetRoomCount(RoomCount);
-                mDriver.Device.SetTempPoint05 = allRoomData.SetTempPoint05;
-                UpdateVariables(allRoomData, false);
-
-                mDriver.Polling.Status = Driver.PollingList.STATUS.Normal;
-
-                ServiceMain.deviceInitChecker.Remove(super.DeviceName);
-
-                Sleep(100);
-
-                // 시간데이터 1회 전송
-                boolean bRet = Send_SetTime();
-                Log.i(TAG, "Send_SetTime = " + bRet);
-            }
-        }
-
-        /* [[ Normal & FixRoom ]]
-         * 평상시 */
-        else if( (mDriver.Polling.Status == Driver.PollingList.STATUS.Normal) ||
-                (mDriver.Polling.Status == Driver.PollingList.STATUS.FixRoom) )
-        {
-            // 전체방 조회를 1회한다. (일시정지 상태 감시)
-            HeatingV1.AllRoomData allRoomData = Send_GetAllRoomStatus();
-            if(allRoomData != null) UpdateVariables(allRoomData, true);
-            Sleep(100);
-
-            // Normal : 각방 상태 가져오기 (1개씩 순차적)
-            if(mDriver.Polling.Status == Driver.PollingList.STATUS.Normal)
-            {
-                HeatingV1.RoomData roomData = Send_GetEachRoomStatus(mDriver.Polling.RoomIndex);
-                if(roomData != null) UpdateVariables(mDriver.Polling.RoomIndex, roomData);
-
-                if(++mDriver.Polling.RoomIndex >= mDriver.Device.RoomCount) mDriver.Polling.RoomIndex = 0;
-            }
-            // FixRoom : 지정방 상태 가져오기
-            else if(mDriver.Polling.Status == Driver.PollingList.STATUS.FixRoom)
-            {
-                HeatingV1.RoomData roomData = Send_GetEachRoomStatus(mDriver.Polling.RoomIndex);
-                if(roomData != null) UpdateVariables(mDriver.Polling.RoomIndex, roomData);
-            }
-        }
-        else
-        {
-            mDriver = new Driver();
-        }
-    }
-
-    /** 방개수를 반환한다. */
-    public byte GetRoomCount()
-    {
-        if(mDriver == null) return 0;
-        return mDriver.Device.RoomCount;
-    }
-
-    /**
-     * (프로토콜 데이터 반환)<br>
-     * 각 방의 운전모드를 프로토콜 데이터로 반환한다.
-     *
-     * @param RoomIndex - (byte) 요청 방 인덱스
-     *
-     * @return (byte) 운전모드
-     */
-    public byte GetRoomMode(int RoomIndex)
-    {
-        byte retMode = 0x00;
-        if(mDriver == null) return retMode;
-        try
-        {
-            if((RoomIndex < 0) || (RoomIndex >= mDriver.Device.RoomCount)) return retMode;
-
-            if(mDriver.Device.Room[RoomIndex].bOnOff) retMode = BIT1;
-        }
-        catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-        }
-        catch (Exception e) {
-            Log.e(TAG, "[GetRoomMode] Exception Error");
-            //e.printStackTrace();            
-            LogUtil.errorLogInfo("", TAG, e);
-        }
-        return retMode;
-    }
-
-    /**
-     * (프로토콜 데이터 반환)<br>
-     * 각 방의 현재온도를 프로토콜 데이터로 반환한다.
-     *
-     * @param RoomIndex - (byte) 요청 방 인덱스
-     *
-     * @return (byte) 현재온도
-     */
-    public byte GetRoomNowTemp(int RoomIndex)
-    {
-        byte retNowTemp = 0x00;
-        if(mDriver == null) return retNowTemp;
-        try
-        {
-            if((RoomIndex < 0) || (RoomIndex >= mDriver.Device.RoomCount)) return retNowTemp;
-            retNowTemp = ConverterTemp(mDriver.Device.Room[RoomIndex].NowTemp);
-        }
-        catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-        }
-        catch (Exception e) {
-            Log.e(TAG, "[GetRoomNowTemp] Exception Error");
-            //e.printStackTrace();            
-            LogUtil.errorLogInfo("", TAG, e);
-        }
-        return retNowTemp;
-    }
-
-    /**
-     * (프로토콜 데이터 반환)<br>
-     * 각 방의 설정온도를 프로토콜 데이터로 반환한다.
-     *
-     * @param RoomIndex - (byte) 요청 방 인덱스
-     *
-     * @return (byte) 설정온도
-     */
-    public byte GetRoomSetTemp(int RoomIndex)
-    {
-        byte retSetTemp = 0x00;
-        if(mDriver == null) return retSetTemp;
-        try
-        {
-            if((RoomIndex < 0) || (RoomIndex >= mDriver.Device.RoomCount)) return retSetTemp;
-            retSetTemp = ConverterTemp(mDriver.Device.Room[RoomIndex].SetTemp);
-        }
-        catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-        }
-        catch (Exception e) {
-            Log.e(TAG, "[GetRoomSetTemp] Exception Error");
-            //e.printStackTrace();            
-            LogUtil.errorLogInfo("", TAG, e);
-        }
-        return retSetTemp;
-    }
-
-    /**
-     * NoSink 제어
-     *
-     * @param StrArg - (String) 입력받은 Arg
-     *
-     * @return (String) 결과
-     */
-    public String NoSinkCtrl(String StrArg)
-    {
-        DeviceLog("[NoSinkCtrl] Start");
-
-        // 1. 디바이스 초기화시 에러리턴
-        if( (mDriver.Polling.Status == Driver.PollingList.STATUS.First) ||
-                (mDriver.Polling.Status == Driver.PollingList.STATUS.FirstTimeOut) )
-        {
-            Log.w(TAG, "[NoSinkCtrl] - Not Yet !!!");
-            return "FAIL;" + APIErrorCode.DEVICEISNOTREADY;
-        }
-
-        CtrDevFormat ctrDevFormat = GetCtrDevParamParsing(StrArg, 5);
-        if(ctrDevFormat.ret != APIErrorCode.C_SUCCESS)
-        {
-            Log.w(TAG, "[NoSinkCtrl] GetCtrDevParamParsing Error (ret:" + ctrDevFormat.ret + ")");
-            return "FAIL;" + APIErrorCode.DEFAULT_PARSING_ERR;
-        }
-
-        //////////////////////////////////////////////////////////
-        // Refresh : 데이터 갱신 (No Sink)
-        //////////////////////////////////////////////////////////
-        if(ctrDevFormat.CmdStr!=null && ctrDevFormat.CmdStr.equals("Refresh"))
-        {
-            byte Index         = ctrDevFormat.param[0];
-
-            DeviceLog("[Refresh] Index : " + String.format("0x%02X", Index));
-
-            // 각방
-            if((Index >= REFRESH_IDX.ROOM1) && (Index <= REFRESH_IDX.ROOM8))
-            {
-                return RefreshResult_Room(Index);
-            }
-            // 기기정보 및 일시정지 상태
-            else if(Index == REFRESH_IDX.INFO_N_PAUSE)
-            {
-                return RefreshResult_InfoNPause();
-            }
-            // 예외처리
-            else
-            {
-                return "FAIL;" + APIErrorCode.INVALIDPARAMETER;
-            }
-        }
-
-        return "FAIL;" + APIErrorCode.UNKNOWNCOMMAND;
-    }
-
-    /**
-     * do_ctrEmm : 싱크 제어
-     */
-    @Override
-    @SuppressLint("DefaultLocale")
-    protected String do_ctrEmm(DeviceCtrSHMem SHMem)
-    {
-        DeviceLog("[do_ctrEmm] Start");
-        DeviceLog("cmd    : " + SHMem.cmd);
-        DeviceLog("StrArg : " + SHMem.StrArg);
-
-        // 1. 디바이스 초기화시 에러리턴
-        if( (mDriver.Polling.Status == Driver.PollingList.STATUS.First) ||
-                (mDriver.Polling.Status == Driver.PollingList.STATUS.FirstTimeOut) )
-        {
-            Log.w(TAG, "[do_ctrEmm] - Not Yet !!!");
-            return SHMem.retVal = "FAIL;" + APIErrorCode.DEVICEISNOTREADY;
-        }
-
-        CtrDevFormat ctrDevFormat = GetCtrDevParamParsing(SHMem.StrArg, 5);
-        if(ctrDevFormat.ret != APIErrorCode.C_SUCCESS)
-        {
-            Log.w(TAG, "[do_ctrEmm] GetCtrDevParamParsing Error (ret:" + ctrDevFormat.ret + ")");
-            return SHMem.retVal = "FAIL;" + APIErrorCode.DEFAULT_PARSING_ERR;
-        }
-
-        if(ctrDevFormat.CmdStr!=null)
-        {
-            //////////////////////////////////////////////////////////
-            // Refresh : 데이터 갱신 (Sink)
-            //
-            // param[0] - Index ( 0~7:개별방 , 0xFF:전체방, 100:설정및일시정지상태 )
-            //////////////////////////////////////////////////////////
-            if(ctrDevFormat.CmdStr.equals("Refresh"))
-            {
-                byte Index    = ctrDevFormat.param[0];
-                SHMem.retVal = "FAIL;" + APIErrorCode.DEVICEISNORESPONSE;
-
-                // 전체방
-                if(Index == define.DEVICE_ALL_OR_NOTHING)
-                {
-                    byte i=0;
-                    for(i=0 ; i<mDriver.Device.RoomCount ; i++)
-                    {
-                        HeatingV1.RoomData roomData = Send_GetEachRoomStatus(i);
-                        if(roomData != null)
-                        {
-                            mDriver.Device.Room[i] = roomData;
-                        }
-                        else break;
-                    }
-
-                    if(i == mDriver.Device.RoomCount)
-                    {
-                        SHMem.retVal = "SUCCESS";
-                    }
-                    else
-                    {
-                        SHMem.retVal = "FAIL;" + APIErrorCode.DEVICEISNORESPONSE;
-                    }
-                }
-                // 개별방
-                else if((Index >= REFRESH_IDX.ROOM1) && (Index <= REFRESH_IDX.ROOM8))
-                {
-                    HeatingV1.RoomData roomData = Send_GetEachRoomStatus(Index);
-                    if(roomData != null)
-                    {
-                        mDriver.Device.Room[Index] = roomData;
-                        SHMem.retVal = RefreshResult_Room(Index);
-                    }
-                }
-                // 기기정보 및 일시정지 상태
-                else if(Index == REFRESH_IDX.INFO_N_PAUSE)
-                {
-                    HeatingV1.AllRoomData allRoomData = Send_GetAllRoomStatus();
-                    if(allRoomData != null)
-                    {
-                        UpdateVariables(allRoomData, false);
-                        SHMem.retVal = RefreshResult_InfoNPause();
-                    }
-
-                }
-                // 예외처리
-                else
-                {
-                    SHMem.retVal = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
-                }
-                return SHMem.retVal;
-            }
-
-            ///////////////////////////////////////////////////////////////
-            // SetPollingMode : 폴링상태 변경
-            //
-            // param[0] - 변경할 폴링모드 (2:Normal , 3:FixRoom)
-            // param[1] - 변경할 지정방 인덱스 (범위 : 방개수만큼, 변경할 폴링모드가 3:FixRoom 일 경우에만 유효함
-            ///////////////////////////////////////////////////////////////
-            else if(ctrDevFormat.CmdStr.equals("SetPollingMode"))
-            {
-                // 1. Param Check
-                byte ChangePollingMode = ctrDevFormat.param[0];
-                byte RoomIndex         = ctrDevFormat.param[1];
-
-                if( !((ChangePollingMode == Driver.PollingList.STATUS.Normal)  ||
-                        (ChangePollingMode == Driver.PollingList.STATUS.FixRoom)) )
-                {
-                    Log.w(TAG, "[do_ctrEmm -> SetPollingMode]" + "[ChangePollingMode] Out Of Range (" + ChangePollingMode + ")");
-                    return SHMem.retVal = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
-                }
-                if(ChangePollingMode == Driver.PollingList.STATUS.FixRoom)
-                {
-                    if( (RoomIndex < 0) || (RoomIndex >= mDriver.Device.RoomCount) )
-                    {
-                        Log.w(TAG, "[do_ctrEmm -> SetPollingMode]" + "[RoomIndex] Out Of Range (" + RoomIndex + ")");
-                        return SHMem.retVal = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
-                    }
-                }
-
-                // 2. Doing
-                mDriver.Polling.Status = ChangePollingMode;
-                if(ChangePollingMode == Driver.PollingList.STATUS.FixRoom)
-                {
-                    mDriver.Polling.RoomIndex = RoomIndex;
-                }
-                else mDriver.Polling.RoomIndex = 0;
-
-                return SHMem.retVal = "SUCCESS";
-            }
-
-            ///////////////////////////////////////////////////////////////
-            // SetEachRoomStatus : 각방 제어 (운전모드 및 설정온도 변경)
-            //
-            // param[0] - RoomIndex 변경할 방 인덱스
-            // param[1] - Mode      변경할 모드 (0:이전상태유지 , 1:ON, 2:OFF)
-            // param[2] - Temp      변경할 설정온도 (0:이전상태유지, 5~40:변경설정온도)
-            // param[3] - TempPoint 변경할 설정온도 0.5도 여부
-            ///////////////////////////////////////////////////////////////
-            else if(ctrDevFormat.CmdStr.equals("SetEachRoomStatus"))
-            {
-                // 1. Param Check
-                byte RoomIndex    = ctrDevFormat.param[0];
-                byte Mode         = ctrDevFormat.param[1];
-                byte Temp         = ctrDevFormat.param[2];
-                byte TempPoint    = ctrDevFormat.param[3];
-
-                //      1.1. RoomIndex
-                if( (RoomIndex < 0) || (RoomIndex >= mDriver.Device.RoomCount) )
-                {
-                    Log.w(TAG, "[do_ctrEmm -> SetEachRoomStatus]" + "[RoomIndex] Out Of Range (" + RoomIndex + ")");
-                    return SHMem.retVal = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
-                }
-
-                //      1.2. Mode
-                switch(Mode)
-                {
-                    case 0: case 1: case 2: break;
-                    default:
-                        Log.w(TAG, "[do_ctrEmm -> SetEachRoomStatus]" + "[Mode] Out Of Range (Mode:" + Mode + ")");
-                        return SHMem.retVal = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
-                }
-
-                //      1.3. Temp & TempPoint
-                if(Temp != 0x00)
-                {
-                    if( (Temp < (byte)SETTEMP_MIN) || (Temp > (byte)SETTEMP_MAX) )
-                    {
-                        Log.w(TAG, "[do_ctrEmm -> SetEachRoomStatus]" + "[Temp] Out Of Range - (" + Temp + ")");
-                        return SHMem.retVal = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
-                    }
-
-                    if( !((TempPoint == 0x00) || (TempPoint == 0x01)) )
-                    {
-                        Log.w(TAG, "[do_ctrEmm -> SetEachRoomStatus]" + "[TempPoint] Out Of Range - (" + TempPoint + ")");
-                        return SHMem.retVal = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
-                    }
-                    //                if(TempPoint == 0x01)
-                    //                {
-                    //                    if(!mDriver.Device.SetTempPoint05)
-                    //                    {
-                    //                        Log.w(TAG, "[do_ctrEmm -> SetEachRoomStatus]" + "[TempPoint] Out Of Range - Error  Not Support SetTempPoint05  (" + TempPoint + ")");
-                    //                        return SHMem.retVal = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
-                    //                    }
-                    //                }
-                }
-
-                // 2. Make Packet Data
-                boolean SetOnOff = false;
-                switch(Mode)
-                {
-                    case 0: SetOnOff = mDriver.Device.Room[RoomIndex].bOnOff; break;
-                    case 1: SetOnOff = true; break;
-                    case 2: SetOnOff = false; break;
-                }
-
-                byte SetTemp = 0x00;
-                if(Temp == 0x00)
-                {
-                    SetTemp = (byte)mDriver.Device.Room[RoomIndex].SetTemp;
-                    if(PointExist(mDriver.Device.Room[RoomIndex].SetTemp)) SetTemp |= BIT6;
-                }
-                else
-                {
-                    SetTemp = Temp;
-                    if(mDriver.Device.SetTempPoint05)
-                    {
-                        if(TempPoint == 0x01) SetTemp |= BIT6;
-                    }
-                }
-
-                // 3. Doing
-                HeatingV1.RoomData roomData = Send_SetEachRoomStatus(RoomIndex, SetOnOff, SetTemp);
-                if(roomData == null)
-                    return SHMem.retVal = "FAIL;" + APIErrorCode.DEVICEISNORESPONSE;
-
-                UpdateVariables(RoomIndex, roomData);
-
-                return SHMem.retVal = "SUCCESS";
-            }
-
-            ///////////////////////////////////////////////////////////////
-            // SetAllRoomStatus : 전체방 제어 (운전모드 변경)
-            //
-            // param[0] - 변경할 운전모드 상태  (1:ON , 2:OFF)
-            ///////////////////////////////////////////////////////////////
-            else if(ctrDevFormat.CmdStr.equals("SetAllRoomStatus"))
-            {
-                // 1. Param Check
-                byte Mode         = ctrDevFormat.param[0];
-
-                //      1.2. Mode
-                if(!((Mode == 1) || (Mode == 2)) )
-                {
-                    Log.w(TAG, "[do_ctrEmm -> SetAllRoomStatus]" + "[Mode] Out Of Range (" + Mode + ")");
-                    return SHMem.retVal = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
-                }
-                boolean OnOff = false;
-                if(Mode == 1) OnOff = true;
-
-                // 2. Make Packet Data
-
-                // 3. Doing
-                HeatingV1.AllRoomData allRoomData = Send_SetAllRoomStatus(OnOff);
-                if(allRoomData == null)
-                    return SHMem.retVal = "FAIL;" + APIErrorCode.DEVICEISNORESPONSE;
-
-                UpdateVariables(allRoomData, true);
-
-                return SHMem.retVal = "SUCCESS";
-            }
-
-            //////////////////////////////////////////////////////////
-            // SetPause : 전체방 일시정지 제어
-            //
-            // param[0] - 변경할 일시정지 상태  (0:해제 , 1:설정)
-            //////////////////////////////////////////////////////////
-            else if(ctrDevFormat.CmdStr.equals("SetPause"))
-            {
-                // 1. Param Check
-                byte ChangePause = ctrDevFormat.param[0];
-                boolean SetPause = false;
-                if(ChangePause != 0) SetPause = true;
-
-                // 2. Doing
-                boolean bRet = Send_SetPause(SetPause);
-                if(bRet)
-                {
-                    SHMem.retVal = "SUCCESS";
-                }
-                else
-                {
-                    SHMem.retVal = "FAIL;" + APIErrorCode.DEVICEISNORESPONSE;
-                }
-            }
-        }
-
-
-        return "UNKNOWNCMD";
-    }
-
-    /**
-     * Refresh 에 대한 응답포멧 정의
-     *
-     * @return (String) "SUCCESS; ..." 성공 , "FAIL; ... " 실패
-     */
-    public String GetRefreshResult()
-    {
-        String result = null;
-        DeviceLog(" GetRefreshResult call : ");
-        try {
-            result = APIErrorCode.SUCCESS+";" ;
-        }
-        catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-            result = "FAIL;"+APIErrorCode.EXCEPTION;
-        }
-        catch (Exception e) {
-            Log.e(TAG, "[Exception Error] GetRefreshResult");
-            //e.printStackTrace();            
-            LogUtil.errorLogInfo("", TAG, e);
-            result = "FAIL;"+APIErrorCode.EXCEPTION;
-        }
-        DeviceLog(" GetSuccessResult return : "+result);
-        return result;
-    }
-
-    /**
-     * RefreshResult_Room 에 대한 응답포멧 정의
-     *
-     * @param (byte) Index - 방 인덱스 (범위 : 0 ~ 7)
-     *
-     * @return (String) "SUCCESS; ..." 성공 , "FAIL; ... " 실패
-     */
-    private String RefreshResult_Room(byte Index)
-    {
-        String result = null;
-
-        DeviceLog("RefreshResult_Room call : ");
-
-        // 1. Check Polling Status
-        if( (mDriver.Polling.Status == Driver.PollingList.STATUS.First) ||
-                (mDriver.Polling.Status == Driver.PollingList.STATUS.FirstTimeOut) )
-        {
-            result = "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
-            return result;
-        }
-
-        // 2. Param Range Check
-        if(!(Index >= 0 && Index <= mDriver.Device.RoomCount))
-        {
-            result = "FAIL;"+APIErrorCode.INVALIDPARAMETER;
-            return result;
-        }
-
-        // 3. Make Return String Format
-        try
-        {
-            if(mDriver.Device == null)                   return "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
-            if(mDriver.Device.Room == null)              return "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
-            if(mDriver.Device.Room.length <= (int)Index) return "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
-            if(mDriver.Device.Room[Index] == null)       return "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
-
-            /*
-             * [Format]
-             *
-             * SUCCESS       - (String) 성공
-             *
-             * RequestIndex  - (byte)   요청 인덱스
-             *
-             * bOnOff        - (boolean) 운전모드 ( true : ON  , false : OFF)
-             * bValveStatus  - (boolean) 밸브상태 ( ture : 열림, false : 닫힘 )
-             * SetTemp       - (double)  설정온도 ( 0.5도 혹은 1도 단위)
-             * NowTemp       - (double)  현재온도 ( 0.5도 혹은 1도 단위)
-             */
-            HeatingV1.RoomData Room = mDriver.Device.Room[Index];
-
-            result = APIErrorCode.SUCCESS + ";";
-
-            result += Index + ";";
-
-            result += Room.bOnOff + ";" +
-                    Room.bValveStatus + ";" +
-                    Room.SetTemp + ";" +
-                    Room.NowTemp + ";";
-        }
-        catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-            result = "FAIL;"+APIErrorCode.EXCEPTION;
-        }
-        catch (Exception e) {
-            Log.e(TAG, "[Exception Error] RefreshResult_Room");
-            //e.printStackTrace();            
-            LogUtil.errorLogInfo("", TAG, e);
-            result = "FAIL;"+APIErrorCode.EXCEPTION;
-        }
-        DeviceLog(" RefreshResult_Room return : "+result);
-
-        return result;
-    }
-
-    /**
-     * RefreshResult_InfoNPause 에 대한 응답포멧 정의
-     *
-     * @param (byte) Index - 방 인덱스 (범위 : 0 ~ 7)
-     *
-     * @return (String) "SUCCESS; ..." 성공 , "FAIL; ... " 실패
-     */
-    private String RefreshResult_InfoNPause()
-    {
-        String result = null;
-
-        DeviceLog("RefreshResult_InfoNPause call : ");
-
-        // 1. Check Polling Status
-        if( (mDriver.Polling.Status == Driver.PollingList.STATUS.First) ||
-                (mDriver.Polling.Status == Driver.PollingList.STATUS.FirstTimeOut) )
-        {
-            result = "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
-            return result;
-        }
-
-        // 2. Param Range Check
-
-        // 3. Make Return String Format
-        try
-        {
-            if(mDriver.Device == null)                   return "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
-            if(mDriver.Device.Room == null)              return "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
-
-            /*
-             * [Format]
-             *
-             * SUCCESS       - (String) 성공
-             *
-             * RoomCount      - (byte) 방의 개수
-             * SetTempPoint05 - (boolean) 온도단위 (ture : 0.5도, false : 1도 )
-             * Pause          - (boolean) 일시정지 여부 (ture : 설정, false : 해제)
-             * Error          - (byte)    에러상태 ( 0x00 : 정상 )
-             */
-            result = APIErrorCode.SUCCESS + ";";
-
-            result += mDriver.Device.RoomCount + ";" +
-                    mDriver.Device.SetTempPoint05 + ";" +
-                    mDriver.Device.Pause + ";" +
-                    mDriver.Device.Error + ";";
-        }
-        catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-            result = "FAIL;"+APIErrorCode.EXCEPTION;
-        }
-        catch (Exception e) {
-            Log.e(TAG, "[Exception Error] RefreshResult_All");
-            //e.printStackTrace();            
-            LogUtil.errorLogInfo("", TAG, e);
-            result = "FAIL;"+APIErrorCode.EXCEPTION;
-        }
-        DeviceLog(" RefreshResult_All return : "+result);
-
-        return result;
-    }
-
-    /**
-     * 개별 방 상태 요청/응답
-     *
-     * @param RoomIndex - (byte) 요청 방 인덱스
-     *
-     * @return (RoomData) null - Error , Not null - OK
-     */
-    private HeatingV1.RoomData Send_GetEachRoomStatus(byte RoomIndex)
-    {
-        DeviceLog("[Send_GetEachRoomStatus] Start (RoomIndex:" + RoomIndex + ")");
-
-        byte RoomNumber = (byte) (RoomIndex+1);
-        // 1. In 파라미터 확인
-        if( !((RoomNumber >= ROOM_COUNT_LOW) && (RoomNumber <= ROOM_COUNT_HI)) )
-        {
-            Log.w(TAG, "[Send_GetEachRoomStatus] RoomIndex - Out Of Range !!! (RoomIndex:" + RoomIndex + ")");
-            return null;
-        }
-
-        // 2. 패킷 데이터 만들기
-        byte [] ReqData = new byte [] { RoomNumber };
-
-        // 3. 데이터 전송 및 응답
-        byte [] Reply = SendNRead_Variable( (byte)(DEVICE_ADDRESS), CMDList.Req.GetEachRoomStatus, ReqData);
-
-        // 4. 수신데이터 파싱
-        HeatingV1.RoomData roomData = EachRoomStatus_ReplyParsing(RoomIndex, Reply);
-        if(roomData == null)
-        {
-            DeviceLog("[Send_GetEachRoomStatus] Reply is null");
-            AddDoCount(false);
-            return null;
-        }
-        AddDoCount(true);
-
-        return roomData;
-    }
-
-    /**
-     * 개별 방 제어 요청/응답
-     *
-     * @param RoomIndex - (byte) 요청 방 인덱스
-     * @param SetOnOff  - (boolean) 변경 할 운전 ON/OFF (true:ON , false:OFF)
-     * @param SetTemp   - (byte)  변경 할 설정온도 (BIT0 ~ BIT5: 설정온도 , BIT6:0.5도)
-     *
-     * @return (RoomData) null - Error , Not null - OK
-     */
-    private HeatingV1.RoomData Send_SetEachRoomStatus(byte RoomIndex, boolean SetOnOff, byte SetTemp)
-    {
-        DeviceLog("[Send_SetEachRoomStatus] Start (RoomIndex:" + RoomIndex + ", SetOnOff:" + SetOnOff + ", SetTemp:" + SetTemp + ")");
-
-        byte RoomNumber = (byte) (RoomIndex+1);
-        // 1. In 파라미터 확인
-        //     1.1. 방인덱스 범위확인
-        if( !((RoomNumber >= ROOM_COUNT_LOW) && (RoomNumber <= ROOM_COUNT_HI)) )
-        {
-            Log.w(TAG, "[Send_SetEachRoomStatus] Param : RoomIndex - Out Of Range !!! (RoomIndex:" + RoomIndex + ")");
-            return null;
-        }
-        //     1.2. 설정온도 범위확인
-        byte SetTempInteger = (byte)(SetTemp & (byte)(BIT0 | BIT1 | BIT2 | BIT3 | BIT4 | BIT5));
-        if( (SetTempInteger < (byte)SETTEMP_MIN) || (SetTempInteger > (byte)SETTEMP_MAX) )
-        {
-            Log.w(TAG, "[Send_SetEachRoomStatus] Param : SetTemp - Out Of Range #1 Integer !!!  (SetTempInteger:" + SetTempInteger + ")");
-            return null;
-        }
-        if((byte)(SetTemp & BIT6) != 0x00)
-        {
-            if(!mDriver.Device.SetTempPoint05)
-            {
-                Log.w(TAG, "[Send_SetEachRoomStatus] Param : SetTemp - Out Of Range #2 POINT !!!  (SetTemp:" + String.format("0x%02X", SetTemp) + ")");
-                return null;
-            }
-        }
-
-        // 2. 패킷 데이터 만들기
-        int Index = 0;
-        byte [] ReqData = new byte [3];
-
-        //     2.1. 제어할 방번호
-        ReqData[Index++] = RoomNumber;
-
-        //     2.2. 운전모드
-        if(SetOnOff) ReqData[Index++] = 0x02;
-        else ReqData[Index++] = 0x00;
-
-        //     2.3. 설정온도
-        ReqData[Index++] = SetTemp;
-
-        // 3. 데이터 전송 및 응답
-        byte [] Reply = SendNRead_Variable( (byte)(DEVICE_ADDRESS), CMDList.Req.SetEachRoomStatus, ReqData);
-
-        // 4. 수신데이터 파싱
-        HeatingV1.RoomData roomData = EachRoomStatus_ReplyParsing(RoomIndex, Reply);
-        if(roomData == null)
-        {
-            DeviceLog("[Send_SetEachRoomStatus] Reply is null");
-            AddDoCount(false);
-            return null;
-        }
-        AddDoCount(true);
-
-        return roomData;
-    }
-
-    /**
-     * 개별 방 상태 응답 Parsing
-     *
-     * @param RoomIndex - (byte) 요청 방 인덱스
-     * @param Reply     - (byte []) 응답 데이터
-     *
-     * @return (RoomData) null - Error , Not null - OK
-     */
-    private HeatingV1.RoomData EachRoomStatus_ReplyParsing(byte RoomIndex, byte [] Reply)
-    {
-        //     1.1. Default Check
-        if(Reply == null)
-        {
-            DeviceLog("[EachRoomStatus_ReplyParsing] Reply is null");
-            return null;
-        }
-        if(Reply.length != 6)
-        {
-            // 길이 체크
-            Log.w(TAG, "[EachRoomStatus_ReplyParsing] Reply.length  fail ... " + Reply.length);
-            return null;
-        }
-
-        int index = 0;
-        byte data = 0x00;
-        byte temp = 0x00;
-        //     1.2. Details Data Check
-        //          - D1 : 커맨드 수신
-        data = Reply[index++];
-        if(data != (byte)0x80)
-        {
-            Log.w(TAG, "[EachRoomStatus_ReplyParsing] D1 (Check CMD) : fail !!! " + String.format("0x%02X", data));
-            return null;
-        }
-        //          - D3 ~ D5 : 모두 0xFF 일 경우 존재하지않는방
-        if((Reply[2] == (byte)0xFF) && (Reply[3] == (byte)0xFF) && (Reply[4] == (byte)0xFF))
-        {
-            Log.w(TAG, "[EachRoomStatus_ReplyParsing] D3~D5 ALL 0xFF - Room does not exist (RoomNumer:!!! " + String.format("0x%02X", Reply[1]) + ")");
-            return null;
-        }
-        //          - D2 : 방 번호
-        data = Reply[index++];
-        if(data != (byte)(RoomIndex+1))
-        {
-            Log.w(TAG, "[EachRoomStatus_ReplyParsing] D2 (RoomNumber) : Not Match !!! " + String.format("0x%02X", data));
-            return null;
-        }
-        //          - D3 : 방의 운전모드와 밸브상태
-        data = Reply[index++];
-        if( (data & (byte)(BIT4 | BIT5 | BIT6 | BIT7)) != 0x00 )
-        {
-            // 미사용 비트'0' 확인
-            Log.w(TAG, "[EachRoomStatus_ReplyParsing] D3 (Mode & ValveStatus) : Unused Bit Set !!! " + String.format("0x%02X", data));
-            return null;
-        }
-        //          - D4 : 현재온도
-        data = Reply[index++];
-        if(!mDriver.Device.SetTempPoint05)
-        {
-            if( (data & (byte)(BIT6)) != 0x00 )
-            {
-                Log.w(TAG, "[EachRoomStatus_ReplyParsing] D4 (NowTemp) : BIT6 TempPoint05 Set !!! " + String.format("0x%02X", data));
-                return null;
-            }
-        }
-        temp = (byte)(data & (byte)(BIT0 | BIT1 | BIT2 | BIT3 | BIT4 | BIT5));
-        if((temp < 5) || (temp > 40))
-        {
-            Log.w(TAG, "[EachRoomStatus_ReplyParsing] D4 (NowTemp) : Temp Out Of Range !!! " + String.format("0x%02X", data));
-            return null;
-        }
-        //          - D5 : 설정온도
-        data = Reply[index++];
-        if(!mDriver.Device.SetTempPoint05)
-        {
-            if( (data & (byte)(BIT6)) != 0x00 )
-            {
-                Log.w(TAG, "[EachRoomStatus_ReplyParsing] D5 (SetTemp) : BIT6 TempPoint05 Set !!! " + String.format("0x%02X", data));
-                return null;
-            }
-        }
-        temp = (byte)(data & (byte)(BIT0 | BIT1 | BIT2 | BIT3 | BIT4 | BIT5));
-        if((temp < 5) || (temp > 40))
-        {
-            Log.w(TAG, "[EachRoomStatus_ReplyParsing] D5 (SetTemp) : Temp Out Of Range !!! " + String.format("0x%02X", data));
-            return null;
-        }
-        //          - D6 : 에러상태
-        data = Reply[index++];
-        if(!HeatingV1.ERROR.Check(data))
-        {
-            Log.w(TAG, "[EachRoomStatus_ReplyParsing] D6 (Error) : Out Of Range !!! " + String.format("0x%02X", data));
-            return null;
-        }
-
-        // 2. Data return
-        HeatingV1.RoomData roomData = new HeatingV1.RoomData();
-
-        index = 2;
-        data = 0x00;
-        temp = 0x00;
-        //          - D1 : 커맨드 수신
-        //          - D2 : 방 번호
-        //          - D3 : 방의 운전모드와 밸브상태
-        data = Reply[index++];
-        if(USE_VALVE_STATUS)
-        {
-            if( (data & (byte)(BIT0)) != 0x00 ) roomData.bValveStatus = true;
-            else roomData.bValveStatus = false;
-        }
-        else
-        {
-            roomData.bValveStatus = false;
-        }
-        if( (data & (byte)(BIT1)) != 0x00 ) roomData.bOnOff = true;
-        else roomData.bOnOff = false;
-
-        //          - D4 : 현재온도
-        data = Reply[index++];
-        double dTemp = (double)getInt( (byte)(data & (byte) (BIT0 | BIT1 | BIT2 | BIT3 | BIT4 | BIT5)));
-        if(mDriver.Device.SetTempPoint05)
-            if((data & BIT6) != 0x00) dTemp += (double)0.5;
-        if((data & BIT7) != 0x00) dTemp *= (double)-1;
-
-        if(mDriver.Device.SetTempPoint05)
-            roomData.NowTemp = Double.parseDouble(String.format("%.1f", dTemp));
-        else
-            roomData.NowTemp = Double.parseDouble(String.format("%.0f", dTemp));
-
-        //          - D5 : 설정온도온도
-        data = Reply[index++];
-        dTemp = (double)getInt( (byte)(data & (byte) (BIT0 | BIT1 | BIT2 | BIT3 | BIT4 | BIT5)));
-        if(mDriver.Device.SetTempPoint05)
-            if((data & BIT6) != 0x00) dTemp += (double)0.5;
-        if((data & BIT7) != 0x00) dTemp *= (double)-1;
-
-        if(mDriver.Device.SetTempPoint05)
-            roomData.SetTemp = Double.parseDouble(String.format("%.1f", dTemp));
-        else
-            roomData.SetTemp = Double.parseDouble(String.format("%.0f", dTemp));
-
-        //          - D6 : 에러상태
-        data = Reply[index++];
-        roomData.Error = data;
-
-        return roomData;
-    }
-
-    /**
-     * 전체 방 상태 요청/응답
-     *
-     * @return (AllRoomData) null - Error , Not null - OK
-     */
-    private HeatingV1.AllRoomData Send_GetAllRoomStatus()
-    {
-        DeviceLog("[Send_GetAllRoomStatus] Start");
-
-        // 1. In 파라미터 확인
-
-        // 2. 패킷 데이터 만들기
-        byte [] ReqData = new byte [] { (byte)(0xFF) };
-
-        // 3. 데이터 전송 및 응답
-        byte [] Reply = SendNRead_Variable( (byte)(DEVICE_ADDRESS), CMDList.Req.GetAllRoomStatus, ReqData);
-
-        // 4. 수신데이터 파싱
-        HeatingV1.AllRoomData allRoomData = AllRoomStatus_ReplyParsing(Reply);
-        if(allRoomData == null)
-        {
-            DeviceLog("[Send_GetAllRoomStatus] Reply is null");
-            AddDoCount(false);
-            return null;
-        }
-        AddDoCount(true);
-
-        return allRoomData;
-    }
-
-    /**
-     * 전체 방 난방제어 요청/응답
-     *
-     * @param OnOff - (boolean) 변경할 운전모드 (true:ON , false:OFF)
-     *
-     * @return (AllRoomData) null - Error , Not null - OK
-     */
-    private HeatingV1.AllRoomData Send_SetAllRoomStatus(boolean OnOff)
-    {
-        DeviceLog("[Send_GetAllRoomStatus] Start");
-
-        // 1. In 파라미터 확인
-
-        // 2. 패킷 데이터 만들기
-        byte AllOnOff = 0x00;
-        if(OnOff)
-        {
-            for(byte i=0 ; i<mDriver.Device.RoomCount ; i++) AllOnOff |= BIT_ARRAY[i];
-        }
-
-        byte [] ReqData = new byte [] { AllOnOff };
-
-        // 3. 데이터 전송 및 응답
-        byte [] Reply = SendNRead_Variable( (byte)(DEVICE_ADDRESS), CMDList.Req.SetAllRoomStatus, ReqData);
-
-        // 4. 수신데이터 파싱
-        HeatingV1.AllRoomData allRoomData = AllRoomStatus_ReplyParsing(Reply);
-        if(allRoomData == null)
-        {
-            DeviceLog("[Send_GetAllRoomStatus] Reply is null");
-            AddDoCount(false);
-            return null;
-        }
-        AddDoCount(true);
-
-        return allRoomData;
-    }
-
-    /**
-     * 전체 방 상태 응답 Parsing
-     *
-     * @param Reply     - (byte []) 응답 데이터
-     *
-     * @return (HeatingV1.AllRoomData) null - Error , Not null - OK
-     */
-    private HeatingV1.AllRoomData AllRoomStatus_ReplyParsing(byte [] Reply)
-    {
-        try
-        {
-            //     1.1. Default Check
-            if(Reply == null)
-            {
-                DeviceLog("[AllRoomStatus_ReplyParsing] Reply is null");
-                return null;
-            }
-            if( (Reply.length != 8) && (Reply.length != 6) )
-            {
-                // 길이 체크
-                // 2013/05/13 - 현대건설 하니웰 제어기기 특징 응답이 8인데 6으로옴
-                Log.w(TAG, "[AllRoomStatus_ReplyParsing] Reply.length  fail ... " + Reply.length);
-                return null;
-            }
-
-            int index = 0;
-            byte data = 0x00;
-            //     1.2. Details Data Check
-            //          - D1 : 커맨드 수신
-            data = Reply[index++];
-            if(data != (byte)0x80)
-            {
-                Log.w(TAG, "[AllRoomStatus_ReplyParsing] D1 (Check CMD) : fail !!! " + String.format("0x%02X", data));
-                return null;
-            }
-            //          - D2 : 방의 개수
-            data = Reply[index++];
-            byte RoomCount = (byte)(data & ((byte)(BIT0 | BIT1 | BIT2 | BIT3)));
-            if( !((RoomCount >= ROOM_COUNT_LOW) && (RoomCount <= ROOM_COUNT_HI)) )
-            {
-                Log.w(TAG, "[AllRoomStatus_ReplyParsing] D2 (RoomCount) :  Out Of Range !!! " + RoomCount);
-                return null;
-            }
-            //          - D3 : 난방 일시정지 상태
-            data = Reply[index++];
-            switch(data)
-            {
-                case (byte)0x00: case (byte)0x98:
-                case (byte)0x01: case (byte)0x90:
-                break;
-                default:
-                    Log.w(TAG, "[AllRoomStatus_ReplyParsing] D3 (Pause) -  Out Of Range !!! " + String.format("0x%02X", data));
-                    return null;
-            }
-            //          - D4 : 에러상태
-            data = Reply[index++];
-            if(!HeatingV1.ERROR.Check(data))
-            {
-                Log.w(TAG, "[AllRoomStatus_ReplyParsing] D4 (Error) : Out Of Range !!! " + String.format("0x%02X", data));
-                return null;
-            }
-            //          - D5~8 : 각방 운전모드와 밸브상태
-
-            // 2. Data return
-            HeatingV1.AllRoomData allRoomData = new HeatingV1.AllRoomData(RoomCount);
-
-            index = 1;
-
-            //          - D2 : 방의개수 및 온도단위
-            data = Reply[index++];
-            if( (data & (byte)(BIT7)) != 0x00 ) allRoomData.SetTempPoint05 = false;
-            else allRoomData.SetTempPoint05 = true;
-
-            //          - D3 : 난방 일시정지 상태
-            data = Reply[index++];
-            switch(data)
-            {
-                case (byte)0x00: case (byte)0x98:
-                allRoomData.Pause = false;
-                break;
-                case (byte)0x01: case (byte)0x90:
-                allRoomData.Pause = true;
-                break;
-            }
-
-            //          - D4 : 에러상태
-            data = Reply[index++];
-            allRoomData.Error = data;
-
-            //          - D5~8 : 각방 운전모드와 밸브상태
-            byte RoomIndex = 0;
-            boolean bValveStatus = false;
-            boolean bOnOff = false;
-
-            byte CompCount = 0;
-            switch(RoomCount)
-            {
-                case 1: case 2: CompCount = 1; break;
-                case 3: case 4: CompCount = 2; break;
-                case 5: case 6: CompCount = 3; break;
-                case 7: case 8: CompCount = 4; break;
-            }
-            for(byte i=0 ; i<CompCount ; i++)
-            {
-                data = Reply[index++];
-                if(data == (byte)0xFF) break;
-
-                if(USE_VALVE_STATUS)
-                {
-                    if( (data & (byte)(BIT0)) != 0x00 ) bValveStatus = true;
-                    else bValveStatus = false;
-                }
-                else
-                {
-                    bValveStatus = false;
-                }
-                if( (data & (byte)(BIT1)) != 0x00 ) bOnOff = true;
-                else bOnOff = false;
-
-                if(allRoomData.Room.length <= RoomIndex) break;
-                allRoomData.Room[RoomIndex].bValveStatus = bValveStatus;
-                allRoomData.Room[RoomIndex].bOnOff       = bOnOff;
-                RoomIndex++;
-
-                if(allRoomData.Room.length <= RoomIndex) break;
-                if(USE_VALVE_STATUS)
-                {
-                    if( (data & (byte)(BIT4)) != 0x00 ) bValveStatus = true;
-                    else bValveStatus = false;
-                }
-                else
-                {
-                    bValveStatus = false;
-                }
-                if( (data & (byte)(BIT5)) != 0x00 ) bOnOff = true;
-                else bOnOff = false;
-
-                allRoomData.Room[RoomIndex].bValveStatus = bValveStatus;
-                allRoomData.Room[RoomIndex].bOnOff       = bOnOff;
-                RoomIndex++;
-            }
-
-            return allRoomData;
-        }
-        catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-            return null;
-        }
-        catch (Exception e) {
-            Log.e(TAG, "[AllRoomStatus_ReplyParsing] Exception Error");
-            //e.printStackTrace();            
-            LogUtil.errorLogInfo("", TAG, e);
-            return null;
-        }
-    }
-
-    /**
-     * 난방 일시정지 요청/반환
-     *
-     * @param SetPause - (boolean) 변경할 일시정지 상태 (true:설정 , false:해제)
-     *
-     * @return (boolean) 성공여부 (true : 성공 , false : 실패)
-     */
-    private boolean Send_SetPause(boolean SetPause)
-    {
-        DeviceLog("[Send_SetPause] Start");
-
-        // 1. In 파라미터 확인
-
-        // 2. 패킷 데이터 만들기
-        byte [] ReqData = new byte [1];
-        if(SetPause) ReqData[0] = 0x01;
-        else ReqData[0] = 0x00;
-
-        // 3. 데이터 전송 및 응답
-        byte [] Reply = SendNRead_Variable( (byte)(DEVICE_ADDRESS), CMDList.Req.SetPause, ReqData);
-
-        // 4. 수신데이터 파싱
-        //     1.1. Default Check
-        if(Reply == null)
-        {
-            DeviceLog("[Send_SetPause] Reply is null");
-            AddDoCount(false);
-            return false;
-        }
-        if( Reply.length != 2 )
-        {
-            // 길이 체크
-            Log.w(TAG, "[Send_SetPause] Reply.length  fail ... " + Reply.length);
-            AddDoCount(false);
-            return false;
-        }
-
-        int index = 0;
-        byte data = 0x00;
-        //          - D1 : 커맨드 수신 체크
-        data = Reply[index++];
-        if(data != (byte)0x80)
-        {
-            Log.w(TAG, "[Send_SetPause] D1 (Check CMD) - fail ... " + String.format("0x%02X", data));
-            return false;
-        }
-
-        AddDoCount(true);
-
-        data = Reply[index++];
-        switch(data)
-        {
-            case (byte)0x00: case (byte)0x98:
-            if(!SetPause) return true;
-            break;
-            case (byte)0x01: case (byte)0x90:
-            if(SetPause) return true;
-            break;
-            default:
-                Log.w(TAG, "[Send_SetPause] D2 (Pause) - fail ... " + String.format("0x%02X", data));
-                return false;
-        }
-
-        return false;
-    }
-
-    /**
-     * 현재시간 설정 요청/반환
-     *
-     * @return (boolean) 성공여부 (true : 성공 , false : 실패)
-     */
-    private boolean Send_SetTime()
-    {
-        DeviceLog("[Send_GetDeviceInfo] Start");
-
-        // 1. In 파라미터 확인
-
-        // 2. 패킷 데이터 만들기
-        byte [] ReqData = new byte [2];
-        int index = 0;
-        Calendar cal = new GregorianCalendar();
-        ReqData[index++] = (byte) cal.get(Calendar.HOUR_OF_DAY);
-        ReqData[index++] = (byte) cal.get(Calendar.MINUTE);
-
-        // 3. 데이터 전송 및 응답
-        byte [] Reply = SendNRead_Variable( (byte)(DEVICE_ADDRESS), CMDList.Req.SetTime, ReqData);
-
-        // 4. 수신데이터 파싱
-        //     1.1. Default Check
-        if(Reply == null)
-        {
-            DeviceLog("[Send_SetTime] Reply is null");
-            AddDoCount(false);
-            return false;
-        }
-        if( Reply.length != 3 )
-        {
-            // 길이 체크
-            Log.w(TAG, "[Send_SetTime] Reply.length  fail ... " + Reply.length);
-            AddDoCount(false);
-            return false;
-        }
-
-        index = 0;
-        //          - D1 : 커맨드 수신 체크
-        if(Reply[index++] != (byte)0x80)
-        {
-            Log.w(TAG, "[Send_SetTime] Reply.length  fail ... " + Reply.length);
-            return false;
-        }
-
-        AddDoCount(true);
-
-        return true;
-    }
-
-    /**
-     * 디바이스 정보 요청 / 응답
-     *
-     * @return (Info) null - Error , Not null - OK
-     */
-    private Info Send_GetDeviceInfo()
-    {
-        DeviceLog("[Send_GetDeviceInfo] Start");
-
-        // 1. In 파라미터 확인
-
-        // 2. 패킷 데이터 만들기
-        byte [] ReqData = new byte [] { (byte)0xFF };
-
-        // 3. 데이터 전송 및 응답
-        byte [] Reply = SendNRead_Variable( (byte)(DEVICE_ADDRESS), CMDList.Req.GetDeviceInfo, ReqData);
-
-        // 4. 수신데이터 파싱
-        Info info = DeviceInfo_ReplyParsing(Reply);
-        if(info == null)
-        {
-            DeviceLog("[Send_GetDeviceInfo] Reply is null");
-            AddDoCount(false);
-            return null;
-        }
-        AddDoCount(true);
-
-        return info;
-    }
-
-    /**
-     * 디바이스 정보 응답 Parsing
-     *
-     * @param Reply     - (byte []) 응답 데이터
-     *
-     * @return (Info) null - Error , Not null - OK
-     */
-    private Info DeviceInfo_ReplyParsing(byte [] Reply)
-    {
-        // 1. 수신데이터 파싱
-        //     1.1. Default Check
-        if(Reply == null)
-        {
-            DeviceLog("[DeviceInfo_ReplyParsing] Reply is null");
-            return null;
-        }
-        if( (Reply.length != 9) && (Reply.length != 6) )
-        {
-            // 길이 체크
-            // 2013/05/13 - 현대건설 하니웰 제어기기 특징 응답이 9인데 6으로옴
-            Log.w(TAG, "[DeviceInfo_ReplyParsing] Reply.length  fail ... " + Reply.length);
-            return null;
-        }
-
-        int index = 0;
-
-        //          - D1 : 커맨드 수신 체크
-        if(Reply[index++] != (byte)0x80)
-        {
-            Log.w(TAG, "[DeviceInfo_ReplyParsing] Reply.length  fail ... " + Reply.length);
-            return null;
-        }
-
-        // 2. Data return
-        int VersionLen = Reply.length-1;
-        byte [] VersionData = new byte [VersionLen];
-        for(int i=0 ; i<VersionLen ; i++) VersionData[i] = Reply[1+i];
-
-        Info info = new Info();
-        info.SetData(VersionData);
-
-        return info;
-    }
-
-    /**
-     * 명령어 리스트
-     */
-    public static class CMDList
-    {
-        public static final class Req
-        {
-            /////////////////////////////////////////////////////////
-            // 제어
-            /////////////////////////////////////////////////////////
-            /** 각방 제어 요청 */
-            public final static byte SetEachRoomStatus    = 0x01;
-
-            /** 일시정지 요청 */
-            public final static byte SetPause             = 0x02;
-
-            /** 현재시간 설정 요청 */
-            public final static byte SetTime              = 0x06;
-
-            /** 전체 난방제어 요청 */
-            public final static byte SetAllRoomStatus     = 0x07;
-
-            /////////////////////////////////////////////////////////
-            // 상태
-            /////////////////////////////////////////////////////////
-            /** 개별방 상태 요청 */
-            public final static byte GetEachRoomStatus     = 0x10;
-
-            /** 전체 운전모드 요청 */
-            public final static byte GetAllRoomStatus      = 0x12;
-
-            /** 현재시간 요청 */
-            public final static byte GetTime               = 0x17;
-
-            /** 디바이스 정보 요청 */
-            public final static byte GetDeviceInfo         = 0x18;
-        }
-    }
-
-    /**
-     * 각방 데이터를 업데이트 한다.
-     *
-     * @param RoomIndex - (byte) 요청 방인덱스
-     * @param roomData  - (RoomData) 업데이트할 각방데이터
-     *
-     * @return (boolean) 데이터 변경여부 (true:변경 , false:미변경)
-     */
-    private boolean UpdateVariables(byte RoomIndex, HeatingV1.RoomData roomData)
-    {
-        if(mDriver.Device.Room == null) return false;
-        if(mDriver.Device.Room.length <= (int)RoomIndex) return false;
-        if(roomData == null) return false;
-
-
-        boolean bChanged = false;
-        HeatingV1.RoomData DriverRoomData = mDriver.Device.Room[RoomIndex];
-
-        // 데이터 비교
-        if(DriverRoomData.bOnOff != roomData.bOnOff) bChanged = true;
-        if(DriverRoomData.bValveStatus != roomData.bValveStatus) bChanged = true;
-        if(DriverRoomData.SetTemp != roomData.SetTemp) bChanged = true;
-        if(DriverRoomData.NowTemp != roomData.NowTemp) bChanged = true;
-        if(mDriver.Device.Error != roomData.Error) bChanged = true;
-
-        if(bChanged)
-        {
-            DeviceLog("OLD =====================");
-            DeviceLog(DriverRoomData.ToDebugString(RoomIndex));
-            DeviceLog("NEW =====================");
-            DeviceLog(roomData.ToDebugString(RoomIndex));
-
-            mDriver.Device.Room[RoomIndex] = roomData;
-            StatusChanged(RoomIndex);
-            DeviceLog("UpdateVariables !!!! *************************************** " + "RoomData - " + (byte)(RoomIndex+1));
-        }
-
-        return bChanged;
-    }
-
-    /**
-     * 전체방 데이터를 업데이트 한다.
-     *
-     * @param allRoomData  - (AllRoomData) 업데이트할 전체방데이터
-     *
-     * @return (boolean) 데이터 변경여부 (true:변경 , false:미변경)
-     */
-    private boolean UpdateVariables(HeatingV1.AllRoomData allRoomData, boolean bNotify)
-    {
-        if(allRoomData == null) return false;
-
-        // 방개수 변경 확인
-        if(mDriver.Device.RoomCount != allRoomData.RoomCount)
-        {
-            Log.w(TAG, "*****************************************************");
-            Log.w(TAG, "Warning !!!!  Device Change - RoomCount Change... (OLD:" + mDriver.Device.RoomCount + " / NOW:" + allRoomData.RoomCount + ")");
-            Log.w(TAG, "*****************************************************");
-
-            mDriver = new Driver();
-            return true;
-        }
-        // 설정온도 단위 변경 확인
-        if(mDriver.Device.SetTempPoint05 != allRoomData.SetTempPoint05)
-        {
-            Log.w(TAG, "*****************************************************");
-            Log.w(TAG, "Warning !!!!  Device Change - SetTempPoint05 Change... (OLD:" + mDriver.Device.SetTempPoint05 + " / NOW:" + allRoomData.SetTempPoint05 + ")");
-            Log.w(TAG, "*****************************************************");
-
-            mDriver = new Driver();
-            return true;
-        }
-
-        boolean bChanged = false;
-        byte RoomIndex = define.DEVICE_ALL_OR_NOTHING;
-        boolean bAllRoomChanged = false;
-
-        // 각방 운전ON/OFF 및 밸브 상태 확인
-        for(byte i=0 ; i<allRoomData.RoomCount ; i++)
-        {
-            boolean bRoomChangedCheck = false;
-            if(mDriver.Device.Room[i].bValveStatus != allRoomData.Room[i].bValveStatus)
-            {
-                mDriver.Device.Room[i].bValveStatus = allRoomData.Room[i].bValveStatus;
-                bChanged = true;
-                bRoomChangedCheck = true;
-            }
-            if(mDriver.Device.Room[i].bOnOff != allRoomData.Room[i].bOnOff)
-            {
-                mDriver.Device.Room[i].bOnOff = allRoomData.Room[i].bOnOff;
-                bChanged = true;
-                bRoomChangedCheck = true;
-            }
-            if(bRoomChangedCheck)
-            {
-                if(RoomIndex == define.DEVICE_ALL_OR_NOTHING) RoomIndex = i;
-                else bAllRoomChanged = true;
-            }
-        }
-
-        boolean bChangedPauseError = false;
-        // 난방 일시정지 상태 확인
-        if(mDriver.Device.Pause != allRoomData.Pause)
-        {
-            mDriver.Device.Pause = allRoomData.Pause;
-            bChangedPauseError = true;
-        }
-        // 에러 상태 확인
-        if(mDriver.Device.Error != allRoomData.Error)
-        {
-            mDriver.Device.Error = allRoomData.Error;
-            bChangedPauseError = true;
-        }
-
-        if(bChanged && bNotify)
-        {
-            if(bAllRoomChanged) StatusChanged(define.DEVICE_ALL_OR_NOTHING);
-            else StatusChanged(RoomIndex);
-            DeviceLog("UpdateVariables !!!! *************************************** " + "AllRoomData" + "(Index:" + RoomIndex + ")");
-        }
-        if(bChangedPauseError && bNotify)
-        {
-            StatusChanged(REFRESH_IDX.INFO_N_PAUSE);
-            DeviceLog("UpdateVariables !!!! *************************************** " + "AllRoomData" + "(Index:" + REFRESH_IDX.INFO_N_PAUSE + ")");
-        }
-
-        return bChanged;
-    }
-
-    /**
-     * 설정온도 소수점 0.5 도 존재 유무를 판별한다.
-     *
-     * @param n - (double) 값
-     *
-     * @return  - (boolean) true : 있음 , false : 없음
-     */
-    private boolean PointExist(double n)
-    {
-        double FilterData = Double.parseDouble(String.format("%.1f", n));
-        int IntValue = (int)FilterData;
-        double Point = FilterData - IntValue;
-
-        if(Point >= 0.5) return true;
-        return false;
-    }
-
-    /**
-     * double Type 의 온도를 프로토콜에서 사용하여 Byte 온도로 변환한다.
-     *
-     * @param n - (double) 온도
-     *
-     * @return (byte) 변환된 온도
-     */
-    private byte ConverterTemp(double n)
-    {
-        byte ByteTemp = (byte) n;
-        if(PointExist(n)) ByteTemp |= BIT6;
-        return ByteTemp;
-    }
-}
+/*
+ * Copyright (C) 2014 Android WallPad Project
+ *
+ * FileName  : HeatingV1_Controller.java
+ * Project   : Android WallPad Project
+ * Company   : HDC I-CONTROLS ( www.icontrols.co.kr )
+ * Author    : Kang Sang Ho  , lairu@icontrols.co.kr
+ */
+
+package com.artncore.wallpaddevservice.driver;
+
+import java.util.Calendar;
+import java.util.GregorianCalendar;
+
+import android.annotation.SuppressLint;
+import android.util.Log;
+
+import com.artncore.commons.APIErrorCode;
+import com.artncore.commons.DataClasses.HeatingV1;
+import com.artncore.commons.DataClasses.HeatingV1.*;
+import com.artncore.commons.define;
+import com.util.LogUtil;
+import com.artncore.wallpaddevservice.ServiceMain;
+
+
+/**
+ * 난방V1의 드라이버 모듈이다.
+ */
+@SuppressLint("HandlerLeak")
+public class HeatingV1_Controller extends DeviceManager
+{
+    private final static String TAG = "HeatingV1_Driver";
+
+    private final byte DEVICE_ADDRESS  = (byte) 0x21;
+
+    /** 밸브상태 사용 여부 (true:상태반영, false:상태미반영 only false) */
+    private final boolean USE_VALVE_STATUS = true;
+
+    /////////////////////////////////////////////////////////
+    // 기본 지원 방개수
+    /////////////////////////////////////////////////////////
+    /** 지원 방개수 (하한값) */
+    private final byte ROOM_COUNT_LOW  = (byte) 1;
+    /** 지원 방개수 (상한값) */
+    private final byte ROOM_COUNT_HI   = (byte) 8;
+
+    /////////////////////////////////////////////////////////
+    // 지원 설정온도
+    /////////////////////////////////////////////////////////
+    /** 지원 최저설정온도 */
+    private final double SETTEMP_MIN  = (double) 5.0;
+    /** 지원 최대설정온도 */
+    private final double SETTEMP_MAX  = (double) 40.0;
+
+    /** 초기 기기 검색 횟수  */
+    private final int MAX_SEARCH_COUNT   = 3;
+
+    /** Refresh 시 사용되는 index 를 정의한다. */
+    public final static class REFRESH_IDX
+    {
+        /** 방1 */
+        public final static byte ROOM1 = 0;
+        /** 방2 */
+        public final static byte ROOM2 = 1;
+        /** 방3 */
+        public final static byte ROOM3 = 2;
+        /** 방4 */
+        public final static byte ROOM4 = 3;
+        /** 방5 */
+        public final static byte ROOM5 = 4;
+        /** 방6 */
+        public final static byte ROOM6 = 5;
+        /** 방7 */
+        public final static byte ROOM7 = 6;
+        /** 방8 */
+        public final static byte ROOM8 = 7;
+
+        /** 기기 정보 및 일시정지 상태 */
+        public final static byte INFO_N_PAUSE = 100;
+    }
+
+    public class Driver
+    {
+        private PollingList Polling;
+
+        private HeatingV1 Device;
+
+        public Driver()
+        {
+            Polling = new PollingList();
+            Device = new HeatingV1();
+        }
+
+        /** Polling 관련 */
+        private class PollingList
+        {
+            private final class STATUS
+            {
+                /** 초기화 과정 */
+                public final static byte First = 0;
+                /** 초기화 타임아웃 */
+                public final static byte FirstTimeOut = 1;
+                /** 평상시 */
+                public final static byte Normal = 2;
+                /** 지정방 상태조회 */
+                public final static byte FixRoom = 3;
+            }
+
+            public byte Status;
+            public int SearchTryCount;
+            public byte RoomIndex;
+
+            private PollingList()
+            {
+                Status = STATUS.First;
+                SearchTryCount = 0;
+                RoomIndex = 0;
+            }
+        }
+    }
+
+    private Driver mDriver = null;
+
+
+    /**
+     * 생성자
+     */
+    public HeatingV1_Controller()
+    {
+        /** 로그 초기상태 */
+        log_sw = false;
+
+        /** 통신성공률 변수 초기화 */
+        super.CommDataGeneration(1);
+
+        /** 드라이버 변수 초기화 */
+        mDriver = new Driver();
+    }
+
+    @Override
+    public void DeviceLog(String msg)
+    {
+        if (!log_sw) return;
+        Log.d(TAG, msg);
+    }
+
+    /**
+     * 로딩후 처음 폴링 시퀀스
+     */
+    @Override
+    protected void do_boot()
+    {
+    }
+
+    /**
+     * do_ctr : 폴링스케쥴러
+     */
+    @Override
+    protected void do_ctr()
+    {
+        //DeviceLog("Polling ");
+
+        /* [[ First & FirstTimeOut ]]
+         * 초기 디바이스정보  검색 */
+        if( (mDriver.Polling.Status == Driver.PollingList.STATUS.First) ||
+                (mDriver.Polling.Status == Driver.PollingList.STATUS.FirstTimeOut) )
+        {
+            if(mDriver.Polling.Status == Driver.PollingList.STATUS.First)
+            {
+                if(mDriver.Polling.SearchTryCount++ > MAX_SEARCH_COUNT)
+                {
+                    mDriver.Polling.Status = Driver.PollingList.STATUS.FirstTimeOut;
+
+                    Log.i(TAG, "--------------------------------------------------");
+                    Log.i(TAG, "SearchDevice Fail... FirstTimeOut ");
+                    Log.i(TAG, "--------------------------------------------------");
+
+                    ServiceMain.deviceInitChecker.Remove(super.DeviceName);
+                }
+            }
+
+            // 기기정보 가져오기
+            if(!mDriver.Device.info.GetSet())
+            {
+                HeatingV1.Info info = Send_GetDeviceInfo();
+                if(info != null)
+                {
+                    mDriver.Device.info = info;
+                    Log.i(TAG, info.ToDebugString());
+                }
+                Sleep(100);
+            }
+
+            // 전체방 상태 갱신 (방개수 & 온도단위 & 일시정지상태 갱신)
+            HeatingV1.AllRoomData allRoomData = Send_GetAllRoomStatus();
+            if(allRoomData != null)
+            {
+                byte RoomCount = allRoomData.RoomCount;
+                mDriver.Device.SetRoomCount(RoomCount);
+                mDriver.Device.SetTempPoint05 = allRoomData.SetTempPoint05;
+                UpdateVariables(allRoomData, false);
+
+                mDriver.Polling.Status = Driver.PollingList.STATUS.Normal;
+
+                ServiceMain.deviceInitChecker.Remove(super.DeviceName);
+
+                Sleep(100);
+
+                // 시간데이터 1회 전송
+                boolean bRet = Send_SetTime();
+                Log.i(TAG, "Send_SetTime = " + bRet);
+            }
+        }
+
+        /* [[ Normal & FixRoom ]]
+         * 평상시 */
+        else if( (mDriver.Polling.Status == Driver.PollingList.STATUS.Normal) ||
+                (mDriver.Polling.Status == Driver.PollingList.STATUS.FixRoom) )
+        {
+            // 전체방 조회를 1회한다. (일시정지 상태 감시)
+            HeatingV1.AllRoomData allRoomData = Send_GetAllRoomStatus();
+            if(allRoomData != null) UpdateVariables(allRoomData, true);
+            Sleep(100);
+
+            // Normal : 각방 상태 가져오기 (1개씩 순차적)
+            if(mDriver.Polling.Status == Driver.PollingList.STATUS.Normal)
+            {
+                HeatingV1.RoomData roomData = Send_GetEachRoomStatus(mDriver.Polling.RoomIndex);
+                if(roomData != null) UpdateVariables(mDriver.Polling.RoomIndex, roomData);
+
+                if(++mDriver.Polling.RoomIndex >= mDriver.Device.RoomCount) mDriver.Polling.RoomIndex = 0;
+            }
+            // FixRoom : 지정방 상태 가져오기
+            else if(mDriver.Polling.Status == Driver.PollingList.STATUS.FixRoom)
+            {
+                HeatingV1.RoomData roomData = Send_GetEachRoomStatus(mDriver.Polling.RoomIndex);
+                if(roomData != null) UpdateVariables(mDriver.Polling.RoomIndex, roomData);
+            }
+        }
+        else
+        {
+            mDriver = new Driver();
+        }
+    }
+
+    /** 방개수를 반환한다. */
+    public byte GetRoomCount()
+    {
+        if(mDriver == null) return 0;
+        return mDriver.Device.RoomCount;
+    }
+
+    /**
+     * (프로토콜 데이터 반환)<br>
+     * 각 방의 운전모드를 프로토콜 데이터로 반환한다.
+     *
+     * @param RoomIndex - (byte) 요청 방 인덱스
+     *
+     * @return (byte) 운전모드
+     */
+    public byte GetRoomMode(int RoomIndex)
+    {
+        byte retMode = 0x00;
+        if(mDriver == null) return retMode;
+        try
+        {
+            if((RoomIndex < 0) || (RoomIndex >= mDriver.Device.RoomCount)) return retMode;
+
+            if(mDriver.Device.Room[RoomIndex].bOnOff) retMode = BIT1;
+        }
+        catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+        }
+        catch (Exception e) {
+            Log.e(TAG, "[GetRoomMode] Exception Error");
+            //e.printStackTrace();            
+            LogUtil.errorLogInfo("", TAG, e);
+        }
+        return retMode;
+    }
+
+    /**
+     * (프로토콜 데이터 반환)<br>
+     * 각 방의 현재온도를 프로토콜 데이터로 반환한다.
+     *
+     * @param RoomIndex - (byte) 요청 방 인덱스
+     *
+     * @return (byte) 현재온도
+     */
+    public byte GetRoomNowTemp(int RoomIndex)
+    {
+        byte retNowTemp = 0x00;
+        if(mDriver == null) return retNowTemp;
+        try
+        {
+            if((RoomIndex < 0) || (RoomIndex >= mDriver.Device.RoomCount)) return retNowTemp;
+            retNowTemp = ConverterTemp(mDriver.Device.Room[RoomIndex].NowTemp);
+        }
+        catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+        }
+        catch (Exception e) {
+            Log.e(TAG, "[GetRoomNowTemp] Exception Error");
+            //e.printStackTrace();            
+            LogUtil.errorLogInfo("", TAG, e);
+        }
+        return retNowTemp;
+    }
+
+    /**
+     * (프로토콜 데이터 반환)<br>
+     * 각 방의 설정온도를 프로토콜 데이터로 반환한다.
+     *
+     * @param RoomIndex - (byte) 요청 방 인덱스
+     *
+     * @return (byte) 설정온도
+     */
+    public byte GetRoomSetTemp(int RoomIndex)
+    {
+        byte retSetTemp = 0x00;
+        if(mDriver == null) return retSetTemp;
+        try
+        {
+            if((RoomIndex < 0) || (RoomIndex >= mDriver.Device.RoomCount)) return retSetTemp;
+            retSetTemp = ConverterTemp(mDriver.Device.Room[RoomIndex].SetTemp);
+        }
+        catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+        }
+        catch (Exception e) {
+            Log.e(TAG, "[GetRoomSetTemp] Exception Error");
+            //e.printStackTrace();            
+            LogUtil.errorLogInfo("", TAG, e);
+        }
+        return retSetTemp;
+    }
+
+    /**
+     * NoSink 제어
+     *
+     * @param StrArg - (String) 입력받은 Arg
+     *
+     * @return (String) 결과
+     */
+    public String NoSinkCtrl(String StrArg)
+    {
+        DeviceLog("[NoSinkCtrl] Start");
+
+        // 1. 디바이스 초기화시 에러리턴
+        if( (mDriver.Polling.Status == Driver.PollingList.STATUS.First) ||
+                (mDriver.Polling.Status == Driver.PollingList.STATUS.FirstTimeOut) )
+        {
+            Log.w(TAG, "[NoSinkCtrl] - Not Yet !!!");
+            return "FAIL;" + APIErrorCode.DEVICEISNOTREADY;
+        }
+
+        CtrDevFormat ctrDevFormat = GetCtrDevParamParsing(StrArg, 5);
+        if(ctrDevFormat.ret != APIErrorCode.C_SUCCESS)
+        {
+            Log.w(TAG, "[NoSinkCtrl] GetCtrDevParamParsing Error (ret:" + ctrDevFormat.ret + ")");
+            return "FAIL;" + APIErrorCode.DEFAULT_PARSING_ERR;
+        }
+
+        //////////////////////////////////////////////////////////
+        // Refresh : 데이터 갱신 (No Sink)
+        //////////////////////////////////////////////////////////
+        if(ctrDevFormat.CmdStr!=null && ctrDevFormat.CmdStr.equals("Refresh"))
+        {
+            byte Index         = ctrDevFormat.param[0];
+
+            DeviceLog("[Refresh] Index : " + String.format("0x%02X", Index));
+
+            // 각방
+            if((Index >= REFRESH_IDX.ROOM1) && (Index <= REFRESH_IDX.ROOM8))
+            {
+                return RefreshResult_Room(Index);
+            }
+            // 기기정보 및 일시정지 상태
+            else if(Index == REFRESH_IDX.INFO_N_PAUSE)
+            {
+                return RefreshResult_InfoNPause();
+            }
+            // 예외처리
+            else
+            {
+                return "FAIL;" + APIErrorCode.INVALIDPARAMETER;
+            }
+        }
+
+        return "FAIL;" + APIErrorCode.UNKNOWNCOMMAND;
+    }
+
+    /**
+     * do_ctrEmm : 싱크 제어
+     */
+    @Override
+    @SuppressLint("DefaultLocale")
+    protected String do_ctrEmm(DeviceCtrSHMem SHMem)
+    {
+        DeviceLog("[do_ctrEmm] Start");
+        DeviceLog("cmd    : " + SHMem.cmd);
+        DeviceLog("StrArg : " + SHMem.StrArg);
+
+        // 1. 디바이스 초기화시 에러리턴
+        if( (mDriver.Polling.Status == Driver.PollingList.STATUS.First) ||
+                (mDriver.Polling.Status == Driver.PollingList.STATUS.FirstTimeOut) )
+        {
+            Log.w(TAG, "[do_ctrEmm] - Not Yet !!!");
+            return SHMem.retVal = "FAIL;" + APIErrorCode.DEVICEISNOTREADY;
+        }
+
+        CtrDevFormat ctrDevFormat = GetCtrDevParamParsing(SHMem.StrArg, 5);
+        if(ctrDevFormat.ret != APIErrorCode.C_SUCCESS)
+        {
+            Log.w(TAG, "[do_ctrEmm] GetCtrDevParamParsing Error (ret:" + ctrDevFormat.ret + ")");
+            return SHMem.retVal = "FAIL;" + APIErrorCode.DEFAULT_PARSING_ERR;
+        }
+
+        if(ctrDevFormat.CmdStr!=null)
+        {
+            //////////////////////////////////////////////////////////
+            // Refresh : 데이터 갱신 (Sink)
+            //
+            // param[0] - Index ( 0~7:개별방 , 0xFF:전체방, 100:설정및일시정지상태 )
+            //////////////////////////////////////////////////////////
+            if(ctrDevFormat.CmdStr.equals("Refresh"))
+            {
+                byte Index    = ctrDevFormat.param[0];
+                SHMem.retVal = "FAIL;" + APIErrorCode.DEVICEISNORESPONSE;
+
+                // 전체방
+                if(Index == define.DEVICE_ALL_OR_NOTHING)
+                {
+                    byte i=0;
+                    for(i=0 ; i<mDriver.Device.RoomCount ; i++)
+                    {
+                        HeatingV1.RoomData roomData = Send_GetEachRoomStatus(i);
+                        if(roomData != null)
+                        {
+                            mDriver.Device.Room[i] = roomData;
+                        }
+                        else break;
+                    }
+
+                    if(i == mDriver.Device.RoomCount)
+                    {
+                        SHMem.retVal = "SUCCESS";
+                    }
+                    else
+                    {
+                        SHMem.retVal = "FAIL;" + APIErrorCode.DEVICEISNORESPONSE;
+                    }
+                }
+                // 개별방
+                else if((Index >= REFRESH_IDX.ROOM1) && (Index <= REFRESH_IDX.ROOM8))
+                {
+                    HeatingV1.RoomData roomData = Send_GetEachRoomStatus(Index);
+                    if(roomData != null)
+                    {
+                        mDriver.Device.Room[Index] = roomData;
+                        SHMem.retVal = RefreshResult_Room(Index);
+                    }
+                }
+                // 기기정보 및 일시정지 상태
+                else if(Index == REFRESH_IDX.INFO_N_PAUSE)
+                {
+                    HeatingV1.AllRoomData allRoomData = Send_GetAllRoomStatus();
+                    if(allRoomData != null)
+                    {
+                        UpdateVariables(allRoomData, false);
+                        SHMem.retVal = RefreshResult_InfoNPause();
+                    }
+
+                }
+                // 예외처리
+                else
+                {
+                    SHMem.retVal = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
+                }
+                return SHMem.retVal;
+            }
+
+            ///////////////////////////////////////////////////////////////
+            // SetPollingMode : 폴링상태 변경
+            //
+            // param[0] - 변경할 폴링모드 (2:Normal , 3:FixRoom)
+            // param[1] - 변경할 지정방 인덱스 (범위 : 방개수만큼, 변경할 폴링모드가 3:FixRoom 일 경우에만 유효함
+            ///////////////////////////////////////////////////////////////
+            else if(ctrDevFormat.CmdStr.equals("SetPollingMode"))
+            {
+                // 1. Param Check
+                byte ChangePollingMode = ctrDevFormat.param[0];
+                byte RoomIndex         = ctrDevFormat.param[1];
+
+                if( !((ChangePollingMode == Driver.PollingList.STATUS.Normal)  ||
+                        (ChangePollingMode == Driver.PollingList.STATUS.FixRoom)) )
+                {
+                    Log.w(TAG, "[do_ctrEmm -> SetPollingMode]" + "[ChangePollingMode] Out Of Range (" + ChangePollingMode + ")");
+                    return SHMem.retVal = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
+                }
+                if(ChangePollingMode == Driver.PollingList.STATUS.FixRoom)
+                {
+                    if( (RoomIndex < 0) || (RoomIndex >= mDriver.Device.RoomCount) )
+                    {
+                        Log.w(TAG, "[do_ctrEmm -> SetPollingMode]" + "[RoomIndex] Out Of Range (" + RoomIndex + ")");
+                        return SHMem.retVal = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
+                    }
+                }
+
+                // 2. Doing
+                mDriver.Polling.Status = ChangePollingMode;
+                if(ChangePollingMode == Driver.PollingList.STATUS.FixRoom)
+                {
+                    mDriver.Polling.RoomIndex = RoomIndex;
+                }
+                else mDriver.Polling.RoomIndex = 0;
+
+                return SHMem.retVal = "SUCCESS";
+            }
+
+            ///////////////////////////////////////////////////////////////
+            // SetEachRoomStatus : 각방 제어 (운전모드 및 설정온도 변경)
+            //
+            // param[0] - RoomIndex 변경할 방 인덱스
+            // param[1] - Mode      변경할 모드 (0:이전상태유지 , 1:ON, 2:OFF)
+            // param[2] - Temp      변경할 설정온도 (0:이전상태유지, 5~40:변경설정온도)
+            // param[3] - TempPoint 변경할 설정온도 0.5도 여부
+            ///////////////////////////////////////////////////////////////
+            else if(ctrDevFormat.CmdStr.equals("SetEachRoomStatus"))
+            {
+                // 1. Param Check
+                byte RoomIndex    = ctrDevFormat.param[0];
+                byte Mode         = ctrDevFormat.param[1];
+                byte Temp         = ctrDevFormat.param[2];
+                byte TempPoint    = ctrDevFormat.param[3];
+
+                //      1.1. RoomIndex
+                if( (RoomIndex < 0) || (RoomIndex >= mDriver.Device.RoomCount) )
+                {
+                    Log.w(TAG, "[do_ctrEmm -> SetEachRoomStatus]" + "[RoomIndex] Out Of Range (" + RoomIndex + ")");
+                    return SHMem.retVal = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
+                }
+
+                //      1.2. Mode
+                switch(Mode)
+                {
+                    case 0: case 1: case 2: break;
+                    default:
+                        Log.w(TAG, "[do_ctrEmm -> SetEachRoomStatus]" + "[Mode] Out Of Range (Mode:" + Mode + ")");
+                        return SHMem.retVal = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
+                }
+
+                //      1.3. Temp & TempPoint
+                if(Temp != 0x00)
+                {
+                    if( (Temp < (byte)SETTEMP_MIN) || (Temp > (byte)SETTEMP_MAX) )
+                    {
+                        Log.w(TAG, "[do_ctrEmm -> SetEachRoomStatus]" + "[Temp] Out Of Range - (" + Temp + ")");
+                        return SHMem.retVal = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
+                    }
+
+                    if( !((TempPoint == 0x00) || (TempPoint == 0x01)) )
+                    {
+                        Log.w(TAG, "[do_ctrEmm -> SetEachRoomStatus]" + "[TempPoint] Out Of Range - (" + TempPoint + ")");
+                        return SHMem.retVal = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
+                    }
+                    //                if(TempPoint == 0x01)
+                    //                {
+                    //                    if(!mDriver.Device.SetTempPoint05)
+                    //                    {
+                    //                        Log.w(TAG, "[do_ctrEmm -> SetEachRoomStatus]" + "[TempPoint] Out Of Range - Error  Not Support SetTempPoint05  (" + TempPoint + ")");
+                    //                        return SHMem.retVal = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
+                    //                    }
+                    //                }
+                }
+
+                // 2. Make Packet Data
+                boolean SetOnOff = false;
+                switch(Mode)
+                {
+                    case 0: SetOnOff = mDriver.Device.Room[RoomIndex].bOnOff; break;
+                    case 1: SetOnOff = true; break;
+                    case 2: SetOnOff = false; break;
+                }
+
+                byte SetTemp = 0x00;
+                if(Temp == 0x00)
+                {
+                    SetTemp = (byte)mDriver.Device.Room[RoomIndex].SetTemp;
+                    if(PointExist(mDriver.Device.Room[RoomIndex].SetTemp)) SetTemp |= BIT6;
+                }
+                else
+                {
+                    SetTemp = Temp;
+                    if(mDriver.Device.SetTempPoint05)
+                    {
+                        if(TempPoint == 0x01) SetTemp |= BIT6;
+                    }
+                }
+
+                // 3. Doing
+                HeatingV1.RoomData roomData = Send_SetEachRoomStatus(RoomIndex, SetOnOff, SetTemp);
+                if(roomData == null)
+                    return SHMem.retVal = "FAIL;" + APIErrorCode.DEVICEISNORESPONSE;
+
+                UpdateVariables(RoomIndex, roomData);
+
+                return SHMem.retVal = "SUCCESS";
+            }
+
+            ///////////////////////////////////////////////////////////////
+            // SetAllRoomStatus : 전체방 제어 (운전모드 변경)
+            //
+            // param[0] - 변경할 운전모드 상태  (1:ON , 2:OFF)
+            ///////////////////////////////////////////////////////////////
+            else if(ctrDevFormat.CmdStr.equals("SetAllRoomStatus"))
+            {
+                // 1. Param Check
+                byte Mode         = ctrDevFormat.param[0];
+
+                //      1.2. Mode
+                if(!((Mode == 1) || (Mode == 2)) )
+                {
+                    Log.w(TAG, "[do_ctrEmm -> SetAllRoomStatus]" + "[Mode] Out Of Range (" + Mode + ")");
+                    return SHMem.retVal = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
+                }
+                boolean OnOff = false;
+                if(Mode == 1) OnOff = true;
+
+                // 2. Make Packet Data
+
+                // 3. Doing
+                HeatingV1.AllRoomData allRoomData = Send_SetAllRoomStatus(OnOff);
+                if(allRoomData == null)
+                    return SHMem.retVal = "FAIL;" + APIErrorCode.DEVICEISNORESPONSE;
+
+                UpdateVariables(allRoomData, true);
+
+                return SHMem.retVal = "SUCCESS";
+            }
+
+            //////////////////////////////////////////////////////////
+            // SetPause : 전체방 일시정지 제어
+            //
+            // param[0] - 변경할 일시정지 상태  (0:해제 , 1:설정)
+            //////////////////////////////////////////////////////////
+            else if(ctrDevFormat.CmdStr.equals("SetPause"))
+            {
+                // 1. Param Check
+                byte ChangePause = ctrDevFormat.param[0];
+                boolean SetPause = false;
+                if(ChangePause != 0) SetPause = true;
+
+                // 2. Doing
+                boolean bRet = Send_SetPause(SetPause);
+                if(bRet)
+                {
+                    SHMem.retVal = "SUCCESS";
+                }
+                else
+                {
+                    SHMem.retVal = "FAIL;" + APIErrorCode.DEVICEISNORESPONSE;
+                }
+            }
+        }
+
+
+        return "UNKNOWNCMD";
+    }
+
+    /**
+     * Refresh 에 대한 응답포멧 정의
+     *
+     * @return (String) "SUCCESS; ..." 성공 , "FAIL; ... " 실패
+     */
+    public String GetRefreshResult()
+    {
+        String result = null;
+        DeviceLog(" GetRefreshResult call : ");
+        try {
+            result = APIErrorCode.SUCCESS+";" ;
+        }
+        catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+            result = "FAIL;"+APIErrorCode.EXCEPTION;
+        }
+        catch (Exception e) {
+            Log.e(TAG, "[Exception Error] GetRefreshResult");
+            //e.printStackTrace();            
+            LogUtil.errorLogInfo("", TAG, e);
+            result = "FAIL;"+APIErrorCode.EXCEPTION;
+        }
+        DeviceLog(" GetSuccessResult return : "+result);
+        return result;
+    }
+
+    /**
+     * RefreshResult_Room 에 대한 응답포멧 정의
+     *
+     * @param (byte) Index - 방 인덱스 (범위 : 0 ~ 7)
+     *
+     * @return (String) "SUCCESS; ..." 성공 , "FAIL; ... " 실패
+     */
+    private String RefreshResult_Room(byte Index)
+    {
+        String result = null;
+
+        DeviceLog("RefreshResult_Room call : ");
+
+        // 1. Check Polling Status
+        if( (mDriver.Polling.Status == Driver.PollingList.STATUS.First) ||
+                (mDriver.Polling.Status == Driver.PollingList.STATUS.FirstTimeOut) )
+        {
+            result = "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
+            return result;
+        }
+
+        // 2. Param Range Check
+        if(!(Index >= 0 && Index <= mDriver.Device.RoomCount))
+        {
+            result = "FAIL;"+APIErrorCode.INVALIDPARAMETER;
+            return result;
+        }
+
+        // 3. Make Return String Format
+        try
+        {
+            if(mDriver.Device == null)                   return "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
+            if(mDriver.Device.Room == null)              return "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
+            if(mDriver.Device.Room.length <= (int)Index) return "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
+            if(mDriver.Device.Room[Index] == null)       return "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
+
+            /*
+             * [Format]
+             *
+             * SUCCESS       - (String) 성공
+             *
+             * RequestIndex  - (byte)   요청 인덱스
+             *
+             * bOnOff        - (boolean) 운전모드 ( true : ON  , false : OFF)
+             * bValveStatus  - (boolean) 밸브상태 ( ture : 열림, false : 닫힘 )
+             * SetTemp       - (double)  설정온도 ( 0.5도 혹은 1도 단위)
+             * NowTemp       - (double)  현재온도 ( 0.5도 혹은 1도 단위)
+             */
+            HeatingV1.RoomData Room = mDriver.Device.Room[Index];
+
+            result = APIErrorCode.SUCCESS + ";";
+
+            result += Index + ";";
+
+            result += Room.bOnOff + ";" +
+                    Room.bValveStatus + ";" +
+                    Room.SetTemp + ";" +
+                    Room.NowTemp + ";";
+        }
+        catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+            result = "FAIL;"+APIErrorCode.EXCEPTION;
+        }
+        catch (Exception e) {
+            Log.e(TAG, "[Exception Error] RefreshResult_Room");
+            //e.printStackTrace();            
+            LogUtil.errorLogInfo("", TAG, e);
+            result = "FAIL;"+APIErrorCode.EXCEPTION;
+        }
+        DeviceLog(" RefreshResult_Room return : "+result);
+
+        return result;
+    }
+
+    /**
+     * RefreshResult_InfoNPause 에 대한 응답포멧 정의
+     *
+     * @param (byte) Index - 방 인덱스 (범위 : 0 ~ 7)
+     *
+     * @return (String) "SUCCESS; ..." 성공 , "FAIL; ... " 실패
+     */
+    private String RefreshResult_InfoNPause()
+    {
+        String result = null;
+
+        DeviceLog("RefreshResult_InfoNPause call : ");
+
+        // 1. Check Polling Status
+        if( (mDriver.Polling.Status == Driver.PollingList.STATUS.First) ||
+                (mDriver.Polling.Status == Driver.PollingList.STATUS.FirstTimeOut) )
+        {
+            result = "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
+            return result;
+        }
+
+        // 2. Param Range Check
+
+        // 3. Make Return String Format
+        try
+        {
+            if(mDriver.Device == null)                   return "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
+            if(mDriver.Device.Room == null)              return "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
+
+            /*
+             * [Format]
+             *
+             * SUCCESS       - (String) 성공
+             *
+             * RoomCount      - (byte) 방의 개수
+             * SetTempPoint05 - (boolean) 온도단위 (ture : 0.5도, false : 1도 )
+             * Pause          - (boolean) 일시정지 여부 (ture : 설정, false : 해제)
+             * Error          - (byte)    에러상태 ( 0x00 : 정상 )
+             */
+            result = APIErrorCode.SUCCESS + ";";
+
+            result += mDriver.Device.RoomCount + ";" +
+                    mDriver.Device.SetTempPoint05 + ";" +
+                    mDriver.Device.Pause + ";" +
+                    mDriver.Device.Error + ";";
+        }
+        catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+            result = "FAIL;"+APIErrorCode.EXCEPTION;
+        }
+        catch (Exception e) {
+            Log.e(TAG, "[Exception Error] RefreshResult_All");
+            //e.printStackTrace();            
+            LogUtil.errorLogInfo("", TAG, e);
+            result = "FAIL;"+APIErrorCode.EXCEPTION;
+        }
+        DeviceLog(" RefreshResult_All return : "+result);
+
+        return result;
+    }
+
+    /**
+     * 개별 방 상태 요청/응답
+     *
+     * @param RoomIndex - (byte) 요청 방 인덱스
+     *
+     * @return (RoomData) null - Error , Not null - OK
+     */
+    private HeatingV1.RoomData Send_GetEachRoomStatus(byte RoomIndex)
+    {
+        DeviceLog("[Send_GetEachRoomStatus] Start (RoomIndex:" + RoomIndex + ")");
+
+        byte RoomNumber = (byte) (RoomIndex+1);
+        // 1. In 파라미터 확인
+        if( !((RoomNumber >= ROOM_COUNT_LOW) && (RoomNumber <= ROOM_COUNT_HI)) )
+        {
+            Log.w(TAG, "[Send_GetEachRoomStatus] RoomIndex - Out Of Range !!! (RoomIndex:" + RoomIndex + ")");
+            return null;
+        }
+
+        // 2. 패킷 데이터 만들기
+        byte [] ReqData = new byte [] { RoomNumber };
+
+        // 3. 데이터 전송 및 응답
+        byte [] Reply = SendNRead_Variable( (byte)(DEVICE_ADDRESS), CMDList.Req.GetEachRoomStatus, ReqData);
+
+        // 4. 수신데이터 파싱
+        HeatingV1.RoomData roomData = EachRoomStatus_ReplyParsing(RoomIndex, Reply);
+        if(roomData == null)
+        {
+            DeviceLog("[Send_GetEachRoomStatus] Reply is null");
+            AddDoCount(false);
+            return null;
+        }
+        AddDoCount(true);
+
+        return roomData;
+    }
+
+    /**
+     * 개별 방 제어 요청/응답
+     *
+     * @param RoomIndex - (byte) 요청 방 인덱스
+     * @param SetOnOff  - (boolean) 변경 할 운전 ON/OFF (true:ON , false:OFF)
+     * @param SetTemp   - (byte)  변경 할 설정온도 (BIT0 ~ BIT5: 설정온도 , BIT6:0.5도)
+     *
+     * @return (RoomData) null - Error , Not null - OK
+     */
+    private HeatingV1.RoomData Send_SetEachRoomStatus(byte RoomIndex, boolean SetOnOff, byte SetTemp)
+    {
+        DeviceLog("[Send_SetEachRoomStatus] Start (RoomIndex:" + RoomIndex + ", SetOnOff:" + SetOnOff + ", SetTemp:" + SetTemp + ")");
+
+        byte RoomNumber = (byte) (RoomIndex+1);
+        // 1. In 파라미터 확인
+        //     1.1. 방인덱스 범위확인
+        if( !((RoomNumber >= ROOM_COUNT_LOW) && (RoomNumber <= ROOM_COUNT_HI)) )
+        {
+            Log.w(TAG, "[Send_SetEachRoomStatus] Param : RoomIndex - Out Of Range !!! (RoomIndex:" + RoomIndex + ")");
+            return null;
+        }
+        //     1.2. 설정온도 범위확인
+        byte SetTempInteger = (byte)(SetTemp & (byte)(BIT0 | BIT1 | BIT2 | BIT3 | BIT4 | BIT5));
+        if( (SetTempInteger < (byte)SETTEMP_MIN) || (SetTempInteger > (byte)SETTEMP_MAX) )
+        {
+            Log.w(TAG, "[Send_SetEachRoomStatus] Param : SetTemp - Out Of Range #1 Integer !!!  (SetTempInteger:" + SetTempInteger + ")");
+            return null;
+        }
+        if((byte)(SetTemp & BIT6) != 0x00)
+        {
+            if(!mDriver.Device.SetTempPoint05)
+            {
+                Log.w(TAG, "[Send_SetEachRoomStatus] Param : SetTemp - Out Of Range #2 POINT !!!  (SetTemp:" + String.format("0x%02X", SetTemp) + ")");
+                return null;
+            }
+        }
+
+        // 2. 패킷 데이터 만들기
+        int Index = 0;
+        byte [] ReqData = new byte [3];
+
+        //     2.1. 제어할 방번호
+        ReqData[Index++] = RoomNumber;
+
+        //     2.2. 운전모드
+        if(SetOnOff) ReqData[Index++] = 0x02;
+        else ReqData[Index++] = 0x00;
+
+        //     2.3. 설정온도
+        ReqData[Index++] = SetTemp;
+
+        // 3. 데이터 전송 및 응답
+        byte [] Reply = SendNRead_Variable( (byte)(DEVICE_ADDRESS), CMDList.Req.SetEachRoomStatus, ReqData);
+
+        // 4. 수신데이터 파싱
+        HeatingV1.RoomData roomData = EachRoomStatus_ReplyParsing(RoomIndex, Reply);
+        if(roomData == null)
+        {
+            DeviceLog("[Send_SetEachRoomStatus] Reply is null");
+            AddDoCount(false);
+            return null;
+        }
+        AddDoCount(true);
+
+        return roomData;
+    }
+
+    /**
+     * 개별 방 상태 응답 Parsing
+     *
+     * @param RoomIndex - (byte) 요청 방 인덱스
+     * @param Reply     - (byte []) 응답 데이터
+     *
+     * @return (RoomData) null - Error , Not null - OK
+     */
+    private HeatingV1.RoomData EachRoomStatus_ReplyParsing(byte RoomIndex, byte [] Reply)
+    {
+        //     1.1. Default Check
+        if(Reply == null)
+        {
+            DeviceLog("[EachRoomStatus_ReplyParsing] Reply is null");
+            return null;
+        }
+        if(Reply.length != 6)
+        {
+            // 길이 체크
+            Log.w(TAG, "[EachRoomStatus_ReplyParsing] Reply.length  fail ... " + Reply.length);
+            return null;
+        }
+
+        int index = 0;
+        byte data = 0x00;
+        byte temp = 0x00;
+        //     1.2. Details Data Check
+        //          - D1 : 커맨드 수신
+        data = Reply[index++];
+        if(data != (byte)0x80)
+        {
+            Log.w(TAG, "[EachRoomStatus_ReplyParsing] D1 (Check CMD) : fail !!! " + String.format("0x%02X", data));
+            return null;
+        }
+        //          - D3 ~ D5 : 모두 0xFF 일 경우 존재하지않는방
+        if((Reply[2] == (byte)0xFF) && (Reply[3] == (byte)0xFF) && (Reply[4] == (byte)0xFF))
+        {
+            Log.w(TAG, "[EachRoomStatus_ReplyParsing] D3~D5 ALL 0xFF - Room does not exist (RoomNumer:!!! " + String.format("0x%02X", Reply[1]) + ")");
+            return null;
+        }
+        //          - D2 : 방 번호
+        data = Reply[index++];
+        if(data != (byte)(RoomIndex+1))
+        {
+            Log.w(TAG, "[EachRoomStatus_ReplyParsing] D2 (RoomNumber) : Not Match !!! " + String.format("0x%02X", data));
+            return null;
+        }
+        //          - D3 : 방의 운전모드와 밸브상태
+        data = Reply[index++];
+        if( (data & (byte)(BIT4 | BIT5 | BIT6 | BIT7)) != 0x00 )
+        {
+            // 미사용 비트'0' 확인
+            Log.w(TAG, "[EachRoomStatus_ReplyParsing] D3 (Mode & ValveStatus) : Unused Bit Set !!! " + String.format("0x%02X", data));
+            return null;
+        }
+        //          - D4 : 현재온도
+        data = Reply[index++];
+        if(!mDriver.Device.SetTempPoint05)
+        {
+            if( (data & (byte)(BIT6)) != 0x00 )
+            {
+                Log.w(TAG, "[EachRoomStatus_ReplyParsing] D4 (NowTemp) : BIT6 TempPoint05 Set !!! " + String.format("0x%02X", data));
+                return null;
+            }
+        }
+        temp = (byte)(data & (byte)(BIT0 | BIT1 | BIT2 | BIT3 | BIT4 | BIT5));
+        if((temp < 5) || (temp > 40))
+        {
+            Log.w(TAG, "[EachRoomStatus_ReplyParsing] D4 (NowTemp) : Temp Out Of Range !!! " + String.format("0x%02X", data));
+            return null;
+        }
+        //          - D5 : 설정온도
+        data = Reply[index++];
+        if(!mDriver.Device.SetTempPoint05)
+        {
+            if( (data & (byte)(BIT6)) != 0x00 )
+            {
+                Log.w(TAG, "[EachRoomStatus_ReplyParsing] D5 (SetTemp) : BIT6 TempPoint05 Set !!! " + String.format("0x%02X", data));
+                return null;
+            }
+        }
+        temp = (byte)(data & (byte)(BIT0 | BIT1 | BIT2 | BIT3 | BIT4 | BIT5));
+        if((temp < 5) || (temp > 40))
+        {
+            Log.w(TAG, "[EachRoomStatus_ReplyParsing] D5 (SetTemp) : Temp Out Of Range !!! " + String.format("0x%02X", data));
+            return null;
+        }
+        //          - D6 : 에러상태
+        data = Reply[index++];
+        if(!HeatingV1.ERROR.Check(data))
+        {
+            Log.w(TAG, "[EachRoomStatus_ReplyParsing] D6 (Error) : Out Of Range !!! " + String.format("0x%02X", data));
+            return null;
+        }
+
+        // 2. Data return
+        HeatingV1.RoomData roomData = new HeatingV1.RoomData();
+
+        index = 2;
+        data = 0x00;
+        temp = 0x00;
+        //          - D1 : 커맨드 수신
+        //          - D2 : 방 번호
+        //          - D3 : 방의 운전모드와 밸브상태
+        data = Reply[index++];
+        if(USE_VALVE_STATUS)
+        {
+            if( (data & (byte)(BIT0)) != 0x00 ) roomData.bValveStatus = true;
+            else roomData.bValveStatus = false;
+        }
+        else
+        {
+            roomData.bValveStatus = false;
+        }
+        if( (data & (byte)(BIT1)) != 0x00 ) roomData.bOnOff = true;
+        else roomData.bOnOff = false;
+
+        //          - D4 : 현재온도
+        data = Reply[index++];
+        double dTemp = (double)getInt( (byte)(data & (byte) (BIT0 | BIT1 | BIT2 | BIT3 | BIT4 | BIT5)));
+        if(mDriver.Device.SetTempPoint05)
+            if((data & BIT6) != 0x00) dTemp += (double)0.5;
+        if((data & BIT7) != 0x00) dTemp *= (double)-1;
+
+        if(mDriver.Device.SetTempPoint05)
+            roomData.NowTemp = Double.parseDouble(String.format("%.1f", dTemp));
+        else
+            roomData.NowTemp = Double.parseDouble(String.format("%.0f", dTemp));
+
+        //          - D5 : 설정온도온도
+        data = Reply[index++];
+        dTemp = (double)getInt( (byte)(data & (byte) (BIT0 | BIT1 | BIT2 | BIT3 | BIT4 | BIT5)));
+        if(mDriver.Device.SetTempPoint05)
+            if((data & BIT6) != 0x00) dTemp += (double)0.5;
+        if((data & BIT7) != 0x00) dTemp *= (double)-1;
+
+        if(mDriver.Device.SetTempPoint05)
+            roomData.SetTemp = Double.parseDouble(String.format("%.1f", dTemp));
+        else
+            roomData.SetTemp = Double.parseDouble(String.format("%.0f", dTemp));
+
+        //          - D6 : 에러상태
+        data = Reply[index++];
+        roomData.Error = data;
+
+        return roomData;
+    }
+
+    /**
+     * 전체 방 상태 요청/응답
+     *
+     * @return (AllRoomData) null - Error , Not null - OK
+     */
+    private HeatingV1.AllRoomData Send_GetAllRoomStatus()
+    {
+        DeviceLog("[Send_GetAllRoomStatus] Start");
+
+        // 1. In 파라미터 확인
+
+        // 2. 패킷 데이터 만들기
+        byte [] ReqData = new byte [] { (byte)(0xFF) };
+
+        // 3. 데이터 전송 및 응답
+        byte [] Reply = SendNRead_Variable( (byte)(DEVICE_ADDRESS), CMDList.Req.GetAllRoomStatus, ReqData);
+
+        // 4. 수신데이터 파싱
+        HeatingV1.AllRoomData allRoomData = AllRoomStatus_ReplyParsing(Reply);
+        if(allRoomData == null)
+        {
+            DeviceLog("[Send_GetAllRoomStatus] Reply is null");
+            AddDoCount(false);
+            return null;
+        }
+        AddDoCount(true);
+
+        return allRoomData;
+    }
+
+    /**
+     * 전체 방 난방제어 요청/응답
+     *
+     * @param OnOff - (boolean) 변경할 운전모드 (true:ON , false:OFF)
+     *
+     * @return (AllRoomData) null - Error , Not null - OK
+     */
+    private HeatingV1.AllRoomData Send_SetAllRoomStatus(boolean OnOff)
+    {
+        DeviceLog("[Send_GetAllRoomStatus] Start");
+
+        // 1. In 파라미터 확인
+
+        // 2. 패킷 데이터 만들기
+        byte AllOnOff = 0x00;
+        if(OnOff)
+        {
+            for(byte i=0 ; i<mDriver.Device.RoomCount ; i++) AllOnOff |= BIT_ARRAY[i];
+        }
+
+        byte [] ReqData = new byte [] { AllOnOff };
+
+        // 3. 데이터 전송 및 응답
+        byte [] Reply = SendNRead_Variable( (byte)(DEVICE_ADDRESS), CMDList.Req.SetAllRoomStatus, ReqData);
+
+        // 4. 수신데이터 파싱
+        HeatingV1.AllRoomData allRoomData = AllRoomStatus_ReplyParsing(Reply);
+        if(allRoomData == null)
+        {
+            DeviceLog("[Send_GetAllRoomStatus] Reply is null");
+            AddDoCount(false);
+            return null;
+        }
+        AddDoCount(true);
+
+        return allRoomData;
+    }
+
+    /**
+     * 전체 방 상태 응답 Parsing
+     *
+     * @param Reply     - (byte []) 응답 데이터
+     *
+     * @return (HeatingV1.AllRoomData) null - Error , Not null - OK
+     */
+    private HeatingV1.AllRoomData AllRoomStatus_ReplyParsing(byte [] Reply)
+    {
+        try
+        {
+            //     1.1. Default Check
+            if(Reply == null)
+            {
+                DeviceLog("[AllRoomStatus_ReplyParsing] Reply is null");
+                return null;
+            }
+            if( (Reply.length != 8) && (Reply.length != 6) )
+            {
+                // 길이 체크
+                // 2013/05/13 - 현대건설 하니웰 제어기기 특징 응답이 8인데 6으로옴
+                Log.w(TAG, "[AllRoomStatus_ReplyParsing] Reply.length  fail ... " + Reply.length);
+                return null;
+            }
+
+            int index = 0;
+            byte data = 0x00;
+            //     1.2. Details Data Check
+            //          - D1 : 커맨드 수신
+            data = Reply[index++];
+            if(data != (byte)0x80)
+            {
+                Log.w(TAG, "[AllRoomStatus_ReplyParsing] D1 (Check CMD) : fail !!! " + String.format("0x%02X", data));
+                return null;
+            }
+            //          - D2 : 방의 개수
+            data = Reply[index++];
+            byte RoomCount = (byte)(data & ((byte)(BIT0 | BIT1 | BIT2 | BIT3)));
+            if( !((RoomCount >= ROOM_COUNT_LOW) && (RoomCount <= ROOM_COUNT_HI)) )
+            {
+                Log.w(TAG, "[AllRoomStatus_ReplyParsing] D2 (RoomCount) :  Out Of Range !!! " + RoomCount);
+                return null;
+            }
+            //          - D3 : 난방 일시정지 상태
+            data = Reply[index++];
+            switch(data)
+            {
+                case (byte)0x00: case (byte)0x98:
+                case (byte)0x01: case (byte)0x90:
+                break;
+                default:
+                    Log.w(TAG, "[AllRoomStatus_ReplyParsing] D3 (Pause) -  Out Of Range !!! " + String.format("0x%02X", data));
+                    return null;
+            }
+            //          - D4 : 에러상태
+            data = Reply[index++];
+            if(!HeatingV1.ERROR.Check(data))
+            {
+                Log.w(TAG, "[AllRoomStatus_ReplyParsing] D4 (Error) : Out Of Range !!! " + String.format("0x%02X", data));
+                return null;
+            }
+            //          - D5~8 : 각방 운전모드와 밸브상태
+
+            // 2. Data return
+            HeatingV1.AllRoomData allRoomData = new HeatingV1.AllRoomData(RoomCount);
+
+            index = 1;
+
+            //          - D2 : 방의개수 및 온도단위
+            data = Reply[index++];
+            if( (data & (byte)(BIT7)) != 0x00 ) allRoomData.SetTempPoint05 = false;
+            else allRoomData.SetTempPoint05 = true;
+
+            //          - D3 : 난방 일시정지 상태
+            data = Reply[index++];
+            switch(data)
+            {
+                case (byte)0x00: case (byte)0x98:
+                allRoomData.Pause = false;
+                break;
+                case (byte)0x01: case (byte)0x90:
+                allRoomData.Pause = true;
+                break;
+            }
+
+            //          - D4 : 에러상태
+            data = Reply[index++];
+            allRoomData.Error = data;
+
+            //          - D5~8 : 각방 운전모드와 밸브상태
+            byte RoomIndex = 0;
+            boolean bValveStatus = false;
+            boolean bOnOff = false;
+
+            byte CompCount = 0;
+            switch(RoomCount)
+            {
+                case 1: case 2: CompCount = 1; break;
+                case 3: case 4: CompCount = 2; break;
+                case 5: case 6: CompCount = 3; break;
+                case 7: case 8: CompCount = 4; break;
+            }
+            for(byte i=0 ; i<CompCount ; i++)
+            {
+                data = Reply[index++];
+                if(data == (byte)0xFF) break;
+
+                if(USE_VALVE_STATUS)
+                {
+                    if( (data & (byte)(BIT0)) != 0x00 ) bValveStatus = true;
+                    else bValveStatus = false;
+                }
+                else
+                {
+                    bValveStatus = false;
+                }
+                if( (data & (byte)(BIT1)) != 0x00 ) bOnOff = true;
+                else bOnOff = false;
+
+                if(allRoomData.Room.length <= RoomIndex) break;
+                allRoomData.Room[RoomIndex].bValveStatus = bValveStatus;
+                allRoomData.Room[RoomIndex].bOnOff       = bOnOff;
+                RoomIndex++;
+
+                if(allRoomData.Room.length <= RoomIndex) break;
+                if(USE_VALVE_STATUS)
+                {
+                    if( (data & (byte)(BIT4)) != 0x00 ) bValveStatus = true;
+                    else bValveStatus = false;
+                }
+                else
+                {
+                    bValveStatus = false;
+                }
+                if( (data & (byte)(BIT5)) != 0x00 ) bOnOff = true;
+                else bOnOff = false;
+
+                allRoomData.Room[RoomIndex].bValveStatus = bValveStatus;
+                allRoomData.Room[RoomIndex].bOnOff       = bOnOff;
+                RoomIndex++;
+            }
+
+            return allRoomData;
+        }
+        catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+            return null;
+        }
+        catch (Exception e) {
+            Log.e(TAG, "[AllRoomStatus_ReplyParsing] Exception Error");
+            //e.printStackTrace();            
+            LogUtil.errorLogInfo("", TAG, e);
+            return null;
+        }
+    }
+
+    /**
+     * 난방 일시정지 요청/반환
+     *
+     * @param SetPause - (boolean) 변경할 일시정지 상태 (true:설정 , false:해제)
+     *
+     * @return (boolean) 성공여부 (true : 성공 , false : 실패)
+     */
+    private boolean Send_SetPause(boolean SetPause)
+    {
+        DeviceLog("[Send_SetPause] Start");
+
+        // 1. In 파라미터 확인
+
+        // 2. 패킷 데이터 만들기
+        byte [] ReqData = new byte [1];
+        if(SetPause) ReqData[0] = 0x01;
+        else ReqData[0] = 0x00;
+
+        // 3. 데이터 전송 및 응답
+        byte [] Reply = SendNRead_Variable( (byte)(DEVICE_ADDRESS), CMDList.Req.SetPause, ReqData);
+
+        // 4. 수신데이터 파싱
+        //     1.1. Default Check
+        if(Reply == null)
+        {
+            DeviceLog("[Send_SetPause] Reply is null");
+            AddDoCount(false);
+            return false;
+        }
+        if( Reply.length != 2 )
+        {
+            // 길이 체크
+            Log.w(TAG, "[Send_SetPause] Reply.length  fail ... " + Reply.length);
+            AddDoCount(false);
+            return false;
+        }
+
+        int index = 0;
+        byte data = 0x00;
+        //          - D1 : 커맨드 수신 체크
+        data = Reply[index++];
+        if(data != (byte)0x80)
+        {
+            Log.w(TAG, "[Send_SetPause] D1 (Check CMD) - fail ... " + String.format("0x%02X", data));
+            return false;
+        }
+
+        AddDoCount(true);
+
+        data = Reply[index++];
+        switch(data)
+        {
+            case (byte)0x00: case (byte)0x98:
+            if(!SetPause) return true;
+            break;
+            case (byte)0x01: case (byte)0x90:
+            if(SetPause) return true;
+            break;
+            default:
+                Log.w(TAG, "[Send_SetPause] D2 (Pause) - fail ... " + String.format("0x%02X", data));
+                return false;
+        }
+
+        return false;
+    }
+
+    /**
+     * 현재시간 설정 요청/반환
+     *
+     * @return (boolean) 성공여부 (true : 성공 , false : 실패)
+     */
+    private boolean Send_SetTime()
+    {
+        DeviceLog("[Send_GetDeviceInfo] Start");
+
+        // 1. In 파라미터 확인
+
+        // 2. 패킷 데이터 만들기
+        byte [] ReqData = new byte [2];
+        int index = 0;
+        Calendar cal = new GregorianCalendar();
+        ReqData[index++] = (byte) cal.get(Calendar.HOUR_OF_DAY);
+        ReqData[index++] = (byte) cal.get(Calendar.MINUTE);
+
+        // 3. 데이터 전송 및 응답
+        byte [] Reply = SendNRead_Variable( (byte)(DEVICE_ADDRESS), CMDList.Req.SetTime, ReqData);
+
+        // 4. 수신데이터 파싱
+        //     1.1. Default Check
+        if(Reply == null)
+        {
+            DeviceLog("[Send_SetTime] Reply is null");
+            AddDoCount(false);
+            return false;
+        }
+        if( Reply.length != 3 )
+        {
+            // 길이 체크
+            Log.w(TAG, "[Send_SetTime] Reply.length  fail ... " + Reply.length);
+            AddDoCount(false);
+            return false;
+        }
+
+        index = 0;
+        //          - D1 : 커맨드 수신 체크
+        if(Reply[index++] != (byte)0x80)
+        {
+            Log.w(TAG, "[Send_SetTime] Reply.length  fail ... " + Reply.length);
+            return false;
+        }
+
+        AddDoCount(true);
+
+        return true;
+    }
+
+    /**
+     * 디바이스 정보 요청 / 응답
+     *
+     * @return (Info) null - Error , Not null - OK
+     */
+    private Info Send_GetDeviceInfo()
+    {
+        DeviceLog("[Send_GetDeviceInfo] Start");
+
+        // 1. In 파라미터 확인
+
+        // 2. 패킷 데이터 만들기
+        byte [] ReqData = new byte [] { (byte)0xFF };
+
+        // 3. 데이터 전송 및 응답
+        byte [] Reply = SendNRead_Variable( (byte)(DEVICE_ADDRESS), CMDList.Req.GetDeviceInfo, ReqData);
+
+        // 4. 수신데이터 파싱
+        Info info = DeviceInfo_ReplyParsing(Reply);
+        if(info == null)
+        {
+            DeviceLog("[Send_GetDeviceInfo] Reply is null");
+            AddDoCount(false);
+            return null;
+        }
+        AddDoCount(true);
+
+        return info;
+    }
+
+    /**
+     * 디바이스 정보 응답 Parsing
+     *
+     * @param Reply     - (byte []) 응답 데이터
+     *
+     * @return (Info) null - Error , Not null - OK
+     */
+    private Info DeviceInfo_ReplyParsing(byte [] Reply)
+    {
+        // 1. 수신데이터 파싱
+        //     1.1. Default Check
+        if(Reply == null)
+        {
+            DeviceLog("[DeviceInfo_ReplyParsing] Reply is null");
+            return null;
+        }
+        if( (Reply.length != 9) && (Reply.length != 6) )
+        {
+            // 길이 체크
+            // 2013/05/13 - 현대건설 하니웰 제어기기 특징 응답이 9인데 6으로옴
+            Log.w(TAG, "[DeviceInfo_ReplyParsing] Reply.length  fail ... " + Reply.length);
+            return null;
+        }
+
+        int index = 0;
+
+        //          - D1 : 커맨드 수신 체크
+        if(Reply[index++] != (byte)0x80)
+        {
+            Log.w(TAG, "[DeviceInfo_ReplyParsing] Reply.length  fail ... " + Reply.length);
+            return null;
+        }
+
+        // 2. Data return
+        int VersionLen = Reply.length-1;
+        byte [] VersionData = new byte [VersionLen];
+        for(int i=0 ; i<VersionLen ; i++) VersionData[i] = Reply[1+i];
+
+        Info info = new Info();
+        info.SetData(VersionData);
+
+        return info;
+    }
+
+    /**
+     * 명령어 리스트
+     */
+    public static class CMDList
+    {
+        public static final class Req
+        {
+            /////////////////////////////////////////////////////////
+            // 제어
+            /////////////////////////////////////////////////////////
+            /** 각방 제어 요청 */
+            public final static byte SetEachRoomStatus    = 0x01;
+
+            /** 일시정지 요청 */
+            public final static byte SetPause             = 0x02;
+
+            /** 현재시간 설정 요청 */
+            public final static byte SetTime              = 0x06;
+
+            /** 전체 난방제어 요청 */
+            public final static byte SetAllRoomStatus     = 0x07;
+
+            /////////////////////////////////////////////////////////
+            // 상태
+            /////////////////////////////////////////////////////////
+            /** 개별방 상태 요청 */
+            public final static byte GetEachRoomStatus     = 0x10;
+
+            /** 전체 운전모드 요청 */
+            public final static byte GetAllRoomStatus      = 0x12;
+
+            /** 현재시간 요청 */
+            public final static byte GetTime               = 0x17;
+
+            /** 디바이스 정보 요청 */
+            public final static byte GetDeviceInfo         = 0x18;
+        }
+    }
+
+    /**
+     * 각방 데이터를 업데이트 한다.
+     *
+     * @param RoomIndex - (byte) 요청 방인덱스
+     * @param roomData  - (RoomData) 업데이트할 각방데이터
+     *
+     * @return (boolean) 데이터 변경여부 (true:변경 , false:미변경)
+     */
+    private boolean UpdateVariables(byte RoomIndex, HeatingV1.RoomData roomData)
+    {
+        if(mDriver.Device.Room == null) return false;
+        if(mDriver.Device.Room.length <= (int)RoomIndex) return false;
+        if(roomData == null) return false;
+
+
+        boolean bChanged = false;
+        HeatingV1.RoomData DriverRoomData = mDriver.Device.Room[RoomIndex];
+
+        // 데이터 비교
+        if(DriverRoomData.bOnOff != roomData.bOnOff) bChanged = true;
+        if(DriverRoomData.bValveStatus != roomData.bValveStatus) bChanged = true;
+        if(DriverRoomData.SetTemp != roomData.SetTemp) bChanged = true;
+        if(DriverRoomData.NowTemp != roomData.NowTemp) bChanged = true;
+        if(mDriver.Device.Error != roomData.Error) bChanged = true;
+
+        if(bChanged)
+        {
+            DeviceLog("OLD =====================");
+            DeviceLog(DriverRoomData.ToDebugString(RoomIndex));
+            DeviceLog("NEW =====================");
+            DeviceLog(roomData.ToDebugString(RoomIndex));
+
+            mDriver.Device.Room[RoomIndex] = roomData;
+            StatusChanged(RoomIndex);
+            DeviceLog("UpdateVariables !!!! *************************************** " + "RoomData - " + (byte)(RoomIndex+1));
+        }
+
+        return bChanged;
+    }
+
+    /**
+     * 전체방 데이터를 업데이트 한다.
+     *
+     * @param allRoomData  - (AllRoomData) 업데이트할 전체방데이터
+     *
+     * @return (boolean) 데이터 변경여부 (true:변경 , false:미변경)
+     */
+    private boolean UpdateVariables(HeatingV1.AllRoomData allRoomData, boolean bNotify)
+    {
+        if(allRoomData == null) return false;
+
+        // 방개수 변경 확인
+        if(mDriver.Device.RoomCount != allRoomData.RoomCount)
+        {
+            Log.w(TAG, "*****************************************************");
+            Log.w(TAG, "Warning !!!!  Device Change - RoomCount Change... (OLD:" + mDriver.Device.RoomCount + " / NOW:" + allRoomData.RoomCount + ")");
+            Log.w(TAG, "*****************************************************");
+
+            mDriver = new Driver();
+            return true;
+        }
+        // 설정온도 단위 변경 확인
+        if(mDriver.Device.SetTempPoint05 != allRoomData.SetTempPoint05)
+        {
+            Log.w(TAG, "*****************************************************");
+            Log.w(TAG, "Warning !!!!  Device Change - SetTempPoint05 Change... (OLD:" + mDriver.Device.SetTempPoint05 + " / NOW:" + allRoomData.SetTempPoint05 + ")");
+            Log.w(TAG, "*****************************************************");
+
+            mDriver = new Driver();
+            return true;
+        }
+
+        boolean bChanged = false;
+        byte RoomIndex = define.DEVICE_ALL_OR_NOTHING;
+        boolean bAllRoomChanged = false;
+
+        // 각방 운전ON/OFF 및 밸브 상태 확인
+        for(byte i=0 ; i<allRoomData.RoomCount ; i++)
+        {
+            boolean bRoomChangedCheck = false;
+            if(mDriver.Device.Room[i].bValveStatus != allRoomData.Room[i].bValveStatus)
+            {
+                mDriver.Device.Room[i].bValveStatus = allRoomData.Room[i].bValveStatus;
+                bChanged = true;
+                bRoomChangedCheck = true;
+            }
+            if(mDriver.Device.Room[i].bOnOff != allRoomData.Room[i].bOnOff)
+            {
+                mDriver.Device.Room[i].bOnOff = allRoomData.Room[i].bOnOff;
+                bChanged = true;
+                bRoomChangedCheck = true;
+            }
+            if(bRoomChangedCheck)
+            {
+                if(RoomIndex == define.DEVICE_ALL_OR_NOTHING) RoomIndex = i;
+                else bAllRoomChanged = true;
+            }
+        }
+
+        boolean bChangedPauseError = false;
+        // 난방 일시정지 상태 확인
+        if(mDriver.Device.Pause != allRoomData.Pause)
+        {
+            mDriver.Device.Pause = allRoomData.Pause;
+            bChangedPauseError = true;
+        }
+        // 에러 상태 확인
+        if(mDriver.Device.Error != allRoomData.Error)
+        {
+            mDriver.Device.Error = allRoomData.Error;
+            bChangedPauseError = true;
+        }
+
+        if(bChanged && bNotify)
+        {
+            if(bAllRoomChanged) StatusChanged(define.DEVICE_ALL_OR_NOTHING);
+            else StatusChanged(RoomIndex);
+            DeviceLog("UpdateVariables !!!! *************************************** " + "AllRoomData" + "(Index:" + RoomIndex + ")");
+        }
+        if(bChangedPauseError && bNotify)
+        {
+            StatusChanged(REFRESH_IDX.INFO_N_PAUSE);
+            DeviceLog("UpdateVariables !!!! *************************************** " + "AllRoomData" + "(Index:" + REFRESH_IDX.INFO_N_PAUSE + ")");
+        }
+
+        return bChanged;
+    }
+
+    /**
+     * 설정온도 소수점 0.5 도 존재 유무를 판별한다.
+     *
+     * @param n - (double) 값
+     *
+     * @return  - (boolean) true : 있음 , false : 없음
+     */
+    private boolean PointExist(double n)
+    {
+        double FilterData = Double.parseDouble(String.format("%.1f", n));
+        int IntValue = (int)FilterData;
+        double Point = FilterData - IntValue;
+
+        if(Point >= 0.5) return true;
+        return false;
+    }
+
+    /**
+     * double Type 의 온도를 프로토콜에서 사용하여 Byte 온도로 변환한다.
+     *
+     * @param n - (double) 온도
+     *
+     * @return (byte) 변환된 온도
+     */
+    private byte ConverterTemp(double n)
+    {
+        byte ByteTemp = (byte) n;
+        if(PointExist(n)) ByteTemp |= BIT6;
+        return ByteTemp;
+    }
+}

+ 3537 - 3538
WallPadDevService/src/main/java/com/artncore/wallpaddevservice/driver/HeatingV2_Controller.java

@@ -1,3538 +1,3537 @@
-/*
- * Copyright (C) 2014 Android WallPad Project
- *
- * FileName  : HeatingV2_Controller.java
- * Project   : Android WallPad Project
- * Company   : HDC I-CONTROLS ( www.icontrols.co.kr )
- * Author    : Kang Sang Ho  , lairu@icontrols.co.kr
- */
-
-package com.artncore.wallpaddevservice.driver;
-
-import java.util.Calendar;
-import java.util.GregorianCalendar;
-
-import kr.co.icontrols.wallpadsupport.Version;
-import android.annotation.SuppressLint;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.util.Log;
-
-import com.artncore.WallPadDataMgr.WallpadStatusData;
-import com.artncore.WallPadDataMgr.WallpadStatusData.WeatherTable;
-import com.artncore.WallPadDataMgr.wallpaddbmgr;
-import com.artncore.commons.APIErrorCode;
-import com.artncore.commons.DataClasses.HeatingV2;
-import com.util.LogUtil;
-import com.artncore.commons.define;
-import com.artncore.commons.DataClasses.HeatingV2.*;
-import com.artncore.wallpaddevservice.ServiceMain;
-
-
-/**
- * 난방V2의 드라이버 모듈이다.
- */
-@SuppressLint("HandlerLeak")
-public class HeatingV2_Controller extends DeviceManager {
-    private final static String TAG = "HeatingV2_Driver";
-
-    private final byte DEVICE_ADDRESS  = (byte) 0x28;
-
-    /** 예약운전 시간 월패드 저장모드 사용유무 (true:사용, false:미사용) */
-    private final boolean USE_RESERVATION_SET_WALLPAD_SAVE = true;
-    /** (주의 : 설정값아님 값 false 에서 변경하지말것) 예약운전 시간 월패드 저장모드 (초기 부팅시 2013/05/30 일경우 활성화) */
-    private boolean MODE_RESERVATION_SET_WALLPAD_SAVE = false;
-    private boolean ModeReservationFirstCheck = false;
-
-    /** 난방OFF일시 외출/외출해제 운전모드 변경하지않음 */
-    private final boolean HEATINGOFF_NOSET_OUTTING  = true;
-
-    /** 초기 기기 검색 횟수  */
-    private final int MAX_SEARCH_COUNT   = 3;
-
-    /** 시간동기화 주기 (분단위) */
-    private final long NOW_TIME_SINK_TICK = (long) (60  * TIME_MINUTE);
-
-    /** 외기온도 전송 전송주기 (분단위) - 2012 디지털특기시방 문서상으로는 최소 1시간이다. */
-    private final long OUTSIDETEMP_SEND_TIME_TICK = (long) (30 * TIME_MINUTE);
-
-    /** 기기정보 변경체크 주기 (분단위)*/
-    private final long INFO_CHECK_TIME_TICK = (long) (5  * TIME_MINUTE);
-
-    /////////////////////////////////////////////////////////
-    // 기본 지원 방개수
-    /////////////////////////////////////////////////////////
-    /** 지원 방개수 (하한값) */
-    private final byte ROOM_COUNT_LOW  = (byte) 1;
-    /** 지원 방개수 (상한값) */
-    private final byte ROOM_COUNT_HI   = (byte) 8;
-
-    /////////////////////////////////////////////////////////
-    // 현재온도 범위
-    /////////////////////////////////////////////////////////
-    /** 지원 최저설정온도 (하한값) */
-    private final double NOWTEMP_MIN  = (double) 0.0;
-    private final double NOWTEMP_MAX  = (double) 60.0;
-
-    /////////////////////////////////////////////////////////
-    // 설정온도 범위
-    /////////////////////////////////////////////////////////
-    /** 지원 최저설정온도 (하한값) */
-    private final byte SETTEMP_MIN_LOW  = (byte) 5;
-    /** 지원 최저설정온도 (상한값) */
-    private final byte SETTEMP_MIN_HI   = (byte) 20;
-    /** 지원 최대설정온도 (하한값) */
-    private final byte SETTEMP_MAX_LOW  = (byte) 21;
-    /** 지원 최대설정온도 (상한값) */
-    private final byte SETTEMP_MAX_HI   = (byte) 50;
-
-    /////////////////////////////////////////////////////////
-    // 보일러 설정온도 범위
-    /////////////////////////////////////////////////////////
-    /** 보일러 난방수 최소 설정온도 */
-    private final byte BOILER_HEAT_WATER_MIN = 30;
-    /** 보일러 난방수 최대 설정온도 */
-    private final byte BOILER_HEAT_WATER_MAX = 90;
-    /** 보일러 온수   최소 설정온도 */
-    private final byte BOILER_HOT_WATER_MIN  = 30;
-    /** 보일러 온수   최대 설정온도*/
-    private final byte BOILER_HOT_WATER_MAX  = 90;
-
-
-    /** Refresh 시 사용되는 index 를 정의한다. */
-    public final static class REFRESH_IDX
-    {
-        /** 방1 */
-        public final static byte ROOM1 = 0;
-        /** 방2 */
-        public final static byte ROOM2 = 1;
-        /** 방3 */
-        public final static byte ROOM3 = 2;
-        /** 방4 */
-        public final static byte ROOM4 = 3;
-        /** 방5 */
-        public final static byte ROOM5 = 4;
-        /** 방6 */
-        public final static byte ROOM6 = 5;
-        /** 방7 */
-        public final static byte ROOM7 = 6;
-        /** 방8 */
-        public final static byte ROOM8 = 7;
-
-        /** 기기 정보 */
-        public final static byte INFO        = 100;
-        /** 보일러 정보 */
-        public final static byte BOILER      = 101;
-        /** 특화기능 */
-        public final static byte SPECIALFUNC = 102;
-    }
-
-    private int mModelType = Version.MODEL_TYPE.OTHER;
-
-    private class Driver
-    {
-        private PollingList Polling;
-
-        private HeatingV2 Device;
-
-        private BoilerData Boiler;
-
-        private SpecialFuncData SpecialFunc;
-
-        public boolean bFixRoomCountUse;
-        public int FixRoomCount;
-
-        private Driver()
-        {
-            Polling = new PollingList();
-            Device = new HeatingV2();
-            Boiler = null;
-            SpecialFunc = null;
-            bFixRoomCountUse = false;
-            FixRoomCount = 0;
-        }
-
-        /** Polling 관련 */
-        private class PollingList
-        {
-            private final class STATUS
-            {
-                /** 초기화 과정 */
-                public final static byte First = 0;
-                /** 초기화 타임아웃 */
-                public final static byte FirstTimeOut = 1;
-                /** 평상시 */
-                public final static byte Normal = 2;
-                /** 지정방 상태조회 */
-                public final static byte FixRoom = 3;
-                /** 보일러 상태조회 */
-                public final static byte Boiler = 4;
-                /** 특화기능 상태조회 */
-                public final static byte SpecialFunc = 5;
-            }
-
-            public byte Status;
-            public int SearchTryCount;
-            public byte RoomIndex;
-            public long InfoCheckTimeTickCount;
-            public long NowTimeSetTickCount;
-            public long OutsideTempSetTickCount;
-            public boolean bOutsideTempDateNotSet;
-            public long LeakTimeTickCount;
-            
-            private PollingList()
-            {
-                Status = STATUS.First;
-                SearchTryCount = 0;
-                RoomIndex = 1;
-
-                InfoCheckTimeTickCount = 0;
-                NowTimeSetTickCount = 0;
-                OutsideTempSetTickCount = 0;
-                bOutsideTempDateNotSet = false;
-            }
-
-            public void NowTimeSetTickCountReset()
-            {
-                NowTimeSetTickCount = 0;
-            }
-        }
-    }
-
-    private Driver mDriver = null;
-
-
-    /**
-     * 생성자
-     */
-    public HeatingV2_Controller()
-    {
-        /** 로그 초기상태 */
-//        log_sw = true;
-//        SerialLog = true;
-
-        /** 모델정보 가져오기 */
-        mModelType = Version.getModelType();
-
-        /** 통신성공률 변수 초기화 */
-        super.CommDataGeneration(1);
-
-        /** 드라이버 변수 초기화 */
-        mDriver = new Driver();
-
-        /** 현장 별 특화기능 DB정보 읽어오기 */
-        int [] TempGet_FixRoom_Info = ServiceMain.dataBaseLoader.data.wallpadDeviceSet.Heating_FixRoomCount;
-        if(TempGet_FixRoom_Info != null)
-        {
-            if(TempGet_FixRoom_Info[0] == 1)
-            {
-                mDriver.bFixRoomCountUse = true;
-                if((TempGet_FixRoom_Info[1] >= ROOM_COUNT_LOW) && (TempGet_FixRoom_Info[1] <= ROOM_COUNT_HI))
-                {
-                    mDriver.FixRoomCount = TempGet_FixRoom_Info[1];
-                }
-                else
-                {
-                    Log.w(TAG, "[TempGet_FixRoom_Info] TempGet_FixRoom_Info[1](Room Count) : Out of Range !!! " + String.format("0x%02X", TempGet_FixRoom_Info[1]));
-                    mDriver.bFixRoomCountUse = false;
-                }
-            }
-            else
-            {
-                mDriver.bFixRoomCountUse = false;
-            }
-        }
-
-
-        /** BroadcastReceiver Registration*/
-        Device_BrRegistration();
-    }
-
-    private boolean Device_BrRegistration() {
-        DeviceLog("Device_BrRegistration - Start");
-
-        try {
-            if ((ServiceMain.dataBaseLoader.data.wallpadDeviceSet.Get_ZeroEnergyHouse) || (ServiceMain.dataBaseLoader.data.wallpadDeviceSet.Get_IntegratedSwitchInfo) || Version.getGatewayUsage()) {
-                IntentFilter filter = new IntentFilter();
-                DeviceLog("Device_BrRegistration - filter.addAction - " + define.NOTIFY_ACNAME);
-                filter.addAction(define.NOTIFY_ACNAME);
-
-                ServiceMain.svcContext.registerReceiver(mWallPadNotifyBR, filter);
-                return true;
-            }
-        } catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-            return false;
-        } catch (Exception e) {
-            Log.e(TAG, "[Device_BrRegistration] Exception Error");
-            //e.printStackTrace();
-            LogUtil.errorLogInfo("", TAG, e);
-            return false;
-        }
-
-        return false;
-    }
-
-    @Override
-    public void DeviceLog(String msg)
-    {
-        if (!log_sw) return;
-        Log.d(TAG, msg);
-    }
-
-    /**
-     * BroadcastReceiver
-     */
-    private BroadcastReceiver mWallPadNotifyBR = new BroadcastReceiver()
-    {
-        public void onReceive(Context context, Intent intent)
-        {
-            String acname = intent.getAction();
-
-            DeviceLog("Receive Notify BR ["+ acname + "]");
-
-            if(mDriver.Polling.Status != Driver.PollingList.STATUS.Normal) return;
-
-            if (acname.equals(define.NOTIFY_ACNAME))
-            {
-                int kind = intent.getIntExtra("KIND", 0);
-                DeviceLog("Receive Notify BR "+ define.NOTIFY_ACNAME + " : " + kind);
-                switch (kind)
-                {
-                    case define.NOTIFY_SYSTEMTIMESETTED:
-                        Log.d(TAG, "[NOTIFY_SYSTEMTIMESETTED] - HeatingV2 Time Reset !!!");
-                        mDriver.Polling.NowTimeSetTickCountReset();
-
-                        if(mDriver.Polling.bOutsideTempDateNotSet)
-                        {
-                            mDriver.Polling.bOutsideTempDateNotSet = false;
-                            mDriver.Polling.OutsideTempSetTickCount = 0;
-                        }
-                        break;
-                }
-            }
-        }
-    };
-
-    /**
-     * 로딩후 처음 폴링 시퀀스
-     */
-    @Override
-    protected void do_boot()
-    {
-    }
-
-    /**
-     * do_ctr : 폴링스케쥴러
-     */
-    @Override
-    protected void do_ctr()
-    {
-        DeviceLog("Polling ");
-
-        /* [[ First & FirstTimeOut ]]
-         * 초기 디바이스정보  검색 */
-        if ((mDriver.Polling.Status == Driver.PollingList.STATUS.First) || (mDriver.Polling.Status == Driver.PollingList.STATUS.FirstTimeOut)) {
-            if (mDriver.Polling.Status == Driver.PollingList.STATUS.First) {
-                if (mDriver.Polling.SearchTryCount++ > MAX_SEARCH_COUNT) {
-                    mDriver.Polling.Status = Driver.PollingList.STATUS.FirstTimeOut;
-
-                    Log.i(TAG, "--------------------------------------------------");
-                    Log.i(TAG, "SearchDevice Fail... FirstTimeOut ");
-                    Log.i(TAG, "--------------------------------------------------");
-
-                    ServiceMain.deviceInitChecker.Remove(super.DeviceName);
-                }
-            }
-
-            Info info = Send_GetDeviceInfo();
-            if (info != null) {
-                mDriver.Device.info = info;
-                mDriver.Device.SetRoomCount(info.RoomCount);
-
-                Log.i(TAG, mDriver.Device.info.ToDebugString());
-
-                CheckInfoReservationSaveMode(info);
-
-                mDriver.Polling.Status = Driver.PollingList.STATUS.Normal;
-
-                mDriver.Polling.InfoCheckTimeTickCount = System.currentTimeMillis();
-
-                if (mDriver.Device.info.Support.Boiler) {
-                    Sleep(100);
-
-                    BoilerData boilerData = Send_GetBoilerStatus();
-                    if(boilerData != null) mDriver.Boiler = boilerData;
-                }
-
-                if (mDriver.Device.info.Support.AI) {
-                    Sleep(100);
-
-                    SpecialFuncData specialFuncData = Send_GetSpecialFuncStatus();
-                    if(specialFuncData != null) mDriver.SpecialFunc = specialFuncData;
-                }
-
-                ServiceMain.deviceInitChecker.Remove(super.DeviceName);
-            }
-        }
-
-        /* [[ Normal & FixRoom & Boiler & SpecialFunc ]]
-         * 평상시 */
-        else if ((mDriver.Polling.Status == Driver.PollingList.STATUS.Normal)
-                || (mDriver.Polling.Status == Driver.PollingList.STATUS.FixRoom)
-                || (mDriver.Polling.Status == Driver.PollingList.STATUS.Boiler)
-                || (mDriver.Polling.Status == Driver.PollingList.STATUS.SpecialFunc))
-        {
-            long currentTimeMillis = 0;
-
-            /*
-             * 기기정보 변동 체크
-             */
-            currentTimeMillis = System.currentTimeMillis();
-            if (Math.abs(currentTimeMillis - mDriver.Polling.InfoCheckTimeTickCount) > INFO_CHECK_TIME_TICK) {
-                Info info = Send_GetDeviceInfo();
-                if (info != null) {
-                    if (UpdateVariables(info)) return;
-                }
-                mDriver.Polling.InfoCheckTimeTickCount = currentTimeMillis;
-                Sleep(100);
-            }
-
-            /*
-             * 현재 시간 동기화
-             * 당사 에너지미터 적용여부에 따라 시간정보 전송 방식이 변경 됨
-             * 에너지미터 적용시: NOW_TIME_SINK_MINUTE 시간 마다 동기화 (1시간으로 설정되어 있음)
-             * 그외: 최초 1회만 동기화, 시간정보 변경시 동기화
-             */
-            if (Version.getGatewayUsage()
-                    || (ServiceMain.dataBaseLoader.data.wallpadDeviceSet.Get_ZeroEnergyHouse)
-                    || (ServiceMain.dataBaseLoader.data.wallpadDeviceSet.Get_IntegratedSwitchInfo)
-                    || (mDriver.Polling.NowTimeSetTickCount == 0))
-            {
-                currentTimeMillis = System.currentTimeMillis();
-                if (Math.abs(currentTimeMillis - mDriver.Polling.NowTimeSetTickCount) > NOW_TIME_SINK_TICK) {
-                    mDriver.Polling.NowTimeSetTickCount = currentTimeMillis;
-                    boolean bRet = Send_NowTimeSet();
-                    Log.d(TAG, "NowTimeSet : Result = " + bRet);
-                    Sleep(100);
-                }
-            }
-
-//            /*
-//             * 현재 시간 동기화
-//             * GLE 의 경우 현재시간을 NOW_TIME_SINK_MINUTE 시간 마다 동기화
-//             * GLE 가 아닐경우 최초 1회 동기화
-//             */
-//            if ((mModelType == Version.MODEL_TYPE.IHN_1020GL)
-//                    || (ServiceMain.dataBaseLoader.data.wallpadDeviceSet.Get_ZeroEnergyHouse == true)
-//                    || (ServiceMain.dataBaseLoader.data.wallpadDeviceSet.Get_IntegratedSwitchInfo == true)
-//                    || (mDriver.Polling.NowTimeSetTickCount == 0)
-//                    || (mModelType == Version.MODEL_TYPE.IHN_D101)
-//                    || (mModelType == Version.MODEL_TYPE.IHN_1010GL)
-//                    || mModelType == Version.MODEL_TYPE.IHN_D101K)
-//            {
-//                currentTimeMillis = System.currentTimeMillis();
-//                if (Math.abs(currentTimeMillis - mDriver.Polling.NowTimeSetTickCount) > NOW_TIME_SINK_TICK) {
-//                    mDriver.Polling.NowTimeSetTickCount = currentTimeMillis;
-//                    boolean bRet = Send_NowTimeSet();
-//                    Log.d(TAG, "NowTimeSet : Result = " + bRet);
-//                    Sleep(100);
-//                }
-//            }
-
-            /*
-             * 외기온도 사용시 외기온도 일정시간마다 전송
-             * Info 상으로 외기온도를 요구하며, iMap에서 외기온도를 1회이상 셋팅하였을 경우
-             * 본 기능은 GLE에만 적용되는 기능임.
-             */
-            if (Version.getGatewayUsage() || ServiceMain.dataBaseLoader.data.wallpadDeviceSet.Get_IntegratedSwitchInfo) {
-                if (mDriver.Device.info.Support.OutsideTempUse) {
-                    currentTimeMillis = System.currentTimeMillis();
-                    if (Math.abs(currentTimeMillis - mDriver.Polling.OutsideTempSetTickCount) > OUTSIDETEMP_SEND_TIME_TICK) {
-                        mDriver.Polling.OutsideTempSetTickCount = currentTimeMillis;
-                        int Ret = OutsideTempUpdate();
-                        if (Ret == -3) {
-                            // 날짜가 일치하지 않아 외기온도 설정을 못하였을 경우 시간이 설정되면 재설정 할수있도록 플레그 설정함.
-                            mDriver.Polling.bOutsideTempDateNotSet = true;
-                        }
-                        Log.d(TAG, "OutsideTempUpdate : Result = " + Ret);
-                        Sleep(100);
-                    }
-                }
-            }
-
-            // 전체방 조회를 1회한다.
-            AllRoomData allRoomData = Send_GetAllRoomStatus();
-            if (allRoomData != null) UpdateVariables(allRoomData);
-            Sleep(100);
-
-            /////////////////////////////////////////////////////////////////////////////////////////
-            // 폴링 모드별 처리
-            /////////////////////////////////////////////////////////////////////////////////////////
-
-            // Normal : 각방 상태 가져오기 (1개씩 순차적)
-            if (mDriver.Polling.Status == Driver.PollingList.STATUS.Normal) {
-                RoomData roomData = Send_GetEachRoomStatus(mDriver.Polling.RoomIndex);
-                if(roomData != null) UpdateVariables(mDriver.Polling.RoomIndex, roomData);
-
-                if(++mDriver.Polling.RoomIndex >= mDriver.Device.info.RoomCount) mDriver.Polling.RoomIndex = 0;
-            }
-
-            // FixRoom : 지정방 상태 가져오기
-            else if (mDriver.Polling.Status == Driver.PollingList.STATUS.FixRoom) {
-                RoomData roomData = Send_GetEachRoomStatus(mDriver.Polling.RoomIndex);
-                if(roomData != null) UpdateVariables(mDriver.Polling.RoomIndex, roomData);
-            }
-            // Boiler : 보일러 상태 가져오기
-            else if (mDriver.Polling.Status == Driver.PollingList.STATUS.Boiler) {
-                BoilerData boilerData = Send_GetBoilerStatus();
-                if(boilerData != null) UpdateVariables(boilerData);
-            }
-            // SpecialFunc : 특화기능 상태 가져오기
-            else if (mDriver.Polling.Status == Driver.PollingList.STATUS.SpecialFunc) {
-                SpecialFuncData specialFuncData = Send_GetSpecialFuncStatus();
-                if(specialFuncData != null) UpdateVariables(specialFuncData);
-            }
-        }
-        else {
-            mDriver = new Driver();
-        }
-    }
-
-    /** 방개수를 반환한다. */
-    public byte GetRoomCount() {
-        if (mDriver == null) return 0;
-        return mDriver.Device.info.RoomCount;
-    }
-
-    /**
-     * (프로토콜 데이터 반환)<br>
-     * 각 방의 운전모드를 프로토콜 데이터로 반환한다.
-     *
-     * @param RoomIndex - (byte) 요청 방 인덱스
-     *
-     * @return (byte) 운전모드
-     */
-    public byte GetRoomMode(int RoomIndex) {
-        byte retMode = HeatingV2.MODE.HeatingOFF;
-        if (mDriver == null) return retMode;
-        try {
-            if ((RoomIndex < 0) || (RoomIndex >= mDriver.Device.info.RoomCount)) return retMode;
-            retMode = mDriver.Device.Room[RoomIndex].Mode;
-        } catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-        } catch (Exception e) {
-            Log.e(TAG, "[GetRoomMode] Exception Error");
-            //e.printStackTrace();
-            LogUtil.errorLogInfo("", TAG, e);
-        }
-        return retMode;
-    }
-
-    /**
-     * (프로토콜 데이터 반환)<br>
-     * 각 방의 현재온도를 프로토콜 데이터로 반환한다.
-     *
-     * @param RoomIndex - (byte) 요청 방 인덱스
-     *
-     * @return (byte) 현재온도
-     */
-    public byte GetRoomNowTemp(int RoomIndex) {
-        byte retNowTemp = 0x00;
-        if (mDriver == null) return retNowTemp;
-        try {
-            if ((RoomIndex < 0) || (RoomIndex >= mDriver.Device.info.RoomCount)) return retNowTemp;
-            retNowTemp = ConverterTemp(mDriver.Device.Room[RoomIndex].NowTemp);
-        } catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-        } catch (Exception e) {
-            Log.e(TAG, "[GetRoomNowTemp] Exception Error");
-            //e.printStackTrace();
-            LogUtil.errorLogInfo("", TAG, e);
-        }
-        return retNowTemp;
-    }
-
-    /**
-     * (프로토콜 데이터 반환)<br>
-     * 각 방의 설정온도를 프로토콜 데이터로 반환한다.
-     *
-     * @param RoomIndex - (byte) 요청 방 인덱스
-     *
-     * @return (byte) 설정온도
-     */
-    public byte GetRoomSetTemp(int RoomIndex) {
-        byte retSetTemp = 0x00;
-        if (mDriver == null) return retSetTemp;
-        try {
-            if ((RoomIndex < 0) || (RoomIndex >= mDriver.Device.info.RoomCount)) return retSetTemp;
-            retSetTemp = ConverterTemp(mDriver.Device.Room[RoomIndex].SetTemp);
-        } catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-        } catch (Exception e) {
-            Log.e(TAG, "[GetRoomSetTemp] Exception Error");
-            //e.printStackTrace();
-            LogUtil.errorLogInfo("", TAG, e);
-        }
-        return retSetTemp;
-    }
-    
-    /**
-     * (프로토콜 데이터 반환)<br>
-     * 각 방의 밸브상태를 프로토콜 데이터로 반환한다.
-     * 
-     * @param RoomIndex - (int) 요청 방 인덱스
-     * 
-     * @return (String) 밸브상태
-     */
-    public String GetRoomValve(int RoomIndex) {
-    	boolean retMode = false;
-    	
-    	if (mDriver == null) return null;
-        try {
-            if ((RoomIndex < 0) || (RoomIndex >= mDriver.Device.info.RoomCount)) return null;
-            retMode = mDriver.Device.Room[RoomIndex].bValveStatus;
-        } catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-        } catch (Exception e) {
-            Log.e(TAG, "[GetRoomValve] Exception Error");
-            //e.printStackTrace();
-            LogUtil.errorLogInfo("", TAG, e);
-        }
-        return retMode + "";
-    }
-    
-    /**
-     * NoSink 제어
-     *
-     * @param StrArg
-     *
-     * @return
-     */
-    public String NoSinkCtrl(String StrArg) {
-        DeviceLog("[NoSinkCtrl] Start");
-
-        // 1. 디바이스 초기화시 에러리턴
-        if ((mDriver.Polling.Status == Driver.PollingList.STATUS.First) || (mDriver.Polling.Status == Driver.PollingList.STATUS.FirstTimeOut)) {
-            Log.w(TAG, "[NoSinkCtrl] - Not Yet !!!");
-            return "FAIL;" + APIErrorCode.DEVICEISNOTREADY;
-        }
-
-        CtrDevFormat ctrDevFormat = GetCtrDevParamParsing(StrArg, 5);
-        if (ctrDevFormat.ret != APIErrorCode.C_SUCCESS) {
-            Log.w(TAG, "[NoSinkCtrl] GetCtrDevParamParsing Error (ret:" + ctrDevFormat.ret + ")");
-            return "FAIL;" + APIErrorCode.DEFAULT_PARSING_ERR;
-        }
-
-        //////////////////////////////////////////////////////////
-        // Refresh : 데이터 갱신 (No Sink)
-        //////////////////////////////////////////////////////////
-        if (ctrDevFormat.CmdStr!=null && ctrDevFormat.CmdStr.equals("Refresh")) {
-            byte Index         = ctrDevFormat.param[0];
-
-            DeviceLog("[Refresh] Index : " + String.format("0x%02X", Index));
-
-            // 각방
-            if ((Index >= REFRESH_IDX.ROOM1) && (Index <= REFRESH_IDX.ROOM8)) {
-                return RefreshResult_Room(Index);
-            }
-            // 기기정보
-            else if (Index == REFRESH_IDX.INFO) {
-                return RefreshResult_Info();
-            }
-            // 보일러
-            else if (Index == REFRESH_IDX.BOILER) {
-                if(!mDriver.Device.info.Support.Boiler)
-                {
-                    Log.w(TAG, "[NoSinkCtrl] - Refresh : BOILER - Not Support Boiler !!!");
-                    return SHMem.retVal = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
-                }
-                return RefreshResult_Boiler();
-            }
-            // 특화기능
-            else if(Index == REFRESH_IDX.SPECIALFUNC)
-            {
-                if(!mDriver.Device.info.Support.AI)
-                {
-                    Log.w(TAG, "[NoSinkCtrl] - Refresh : SPECIALFUNC - Not Support AI !!!");
-                    return SHMem.retVal = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
-                }
-                return RefreshResult_SpecialFunc();
-            }
-            else
-            {
-                return "FAIL;" + APIErrorCode.INVALIDPARAMETER;
-            }
-        }
-
-        return "FAIL;" + APIErrorCode.UNKNOWNCOMMAND;
-    }
-
-    /**
-     * do_ctrEmm : 싱크 제어
-     */
-    @Override
-    @SuppressLint("DefaultLocale")
-    protected String do_ctrEmm(DeviceCtrSHMem SHMem)
-    {
-        DeviceLog("[do_ctrEmm] Start");
-        DeviceLog("cmd    : " + SHMem.cmd);
-        DeviceLog("StrArg : " + SHMem.StrArg);
-
-        // 1. 디바이스 초기화시 에러리턴
-        if( (mDriver.Polling.Status == Driver.PollingList.STATUS.First) ||
-                (mDriver.Polling.Status == Driver.PollingList.STATUS.FirstTimeOut) )
-        {
-            Log.w(TAG, "[do_ctrEmm] - Not Yet !!!");
-            return SHMem.retVal = "FAIL;" + APIErrorCode.DEVICEISNOTREADY;
-        }
-
-        CtrDevFormat ctrDevFormat = GetCtrDevParamParsing(SHMem.StrArg, 5);
-        if(ctrDevFormat.ret != APIErrorCode.C_SUCCESS)
-        {
-            Log.w(TAG, "[do_ctrEmm] GetCtrDevParamParsing Error (ret:" + ctrDevFormat.ret + ")");
-            return SHMem.retVal = "FAIL;" + APIErrorCode.DEFAULT_PARSING_ERR;
-        }
-
-        if(ctrDevFormat.CmdStr!=null)
-        {
-            //////////////////////////////////////////////////////////
-            // Refresh : 데이터 갱신 (Sink)
-            //////////////////////////////////////////////////////////
-            if(ctrDevFormat.CmdStr.equals("Refresh"))
-            {
-                byte Index    = ctrDevFormat.param[0];
-                SHMem.retVal = "FAIL;" + APIErrorCode.DEVICEISNORESPONSE;
-
-                // 전체방
-                if(Index == define.DEVICE_ALL_OR_NOTHING)
-                {
-                    byte i=0;
-                    for(i=0 ; i<mDriver.Device.info.RoomCount ; i++)
-                    {
-                        RoomData roomData = Send_GetEachRoomStatus(i);
-                        if(roomData != null)
-                        {
-                            mDriver.Device.Room[i] = roomData;
-                        }
-                        else break;
-                    }
-                    if(i == mDriver.Device.info.RoomCount)
-                    {
-                        SHMem.retVal = "SUCCESS";
-                    }
-                    else
-                    {
-                        SHMem.retVal = "FAIL;" + APIErrorCode.DEVICEISNORESPONSE;
-                    }
-                }
-                // 각방
-                else if((Index >= REFRESH_IDX.ROOM1) && (Index <= REFRESH_IDX.ROOM8))
-                {
-                    RoomData roomData = Send_GetEachRoomStatus(Index);
-                    if(roomData != null)
-                    {
-                        mDriver.Device.Room[Index] = roomData;
-                        SHMem.retVal = RefreshResult_Room(Index);
-                    }
-                }
-                // 보일러
-                else if(Index == REFRESH_IDX.BOILER)
-                {
-                    if(!mDriver.Device.info.Support.Boiler)
-                    {
-                        Log.w(TAG, "[do_ctrEmm] - Refresh : BOILER - Not Support Boiler !!!");
-                        return SHMem.retVal = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
-                    }
-                    BoilerData Boiler = Send_GetBoilerStatus();
-                    if(Boiler != null)
-                    {
-                        mDriver.Boiler = Boiler;
-                        SHMem.retVal = RefreshResult_Boiler();
-                    }
-                }
-                // 특화기능
-                else if(Index == REFRESH_IDX.SPECIALFUNC)
-                {
-                    if(!mDriver.Device.info.Support.AI)
-                    {
-                        Log.w(TAG, "[do_ctrEmm] - Refresh : SPECIALFUNC - Not Support AI !!!");
-                        return SHMem.retVal = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
-                    }
-                    SpecialFuncData SpecialFunc = Send_GetSpecialFuncStatus();
-                    if(SpecialFunc != null)
-                    {
-                        mDriver.SpecialFunc = SpecialFunc;
-                        SHMem.retVal = RefreshResult_SpecialFunc();
-                    }
-                }
-                else
-                {
-                    SHMem.retVal = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
-                }
-                return SHMem.retVal;
-            }
-            ///////////////////////////////////////////////////////////////
-            // SetPollingMode : 폴링상태 변경
-            ///////////////////////////////////////////////////////////////
-            if(ctrDevFormat.CmdStr.equals("SetPollingMode"))
-            {
-                // 1. Param Check
-                byte ChangePollingMode = ctrDevFormat.param[0];
-                byte RoomIndex         = ctrDevFormat.param[1];
-
-                if( !((ChangePollingMode == Driver.PollingList.STATUS.Normal)  ||
-                        (ChangePollingMode == Driver.PollingList.STATUS.FixRoom) ||
-                        (ChangePollingMode == Driver.PollingList.STATUS.Boiler)  ||
-                        (ChangePollingMode == Driver.PollingList.STATUS.SpecialFunc)) )
-                {
-                    Log.w(TAG, "[do_ctrEmm -> SetPollingMode]" + "[ChangePollingMode] Out Of Range (" + ChangePollingMode + ")");
-                    return SHMem.retVal = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
-                }
-                if(ChangePollingMode == Driver.PollingList.STATUS.FixRoom)
-                {
-                    if( (RoomIndex < 0) || (RoomIndex >= mDriver.Device.info.RoomCount) )
-                    {
-                        Log.w(TAG, "[do_ctrEmm -> SetPollingMode]" + "[RoomIndex] Out Of Range (" + RoomIndex + ")");
-                        return SHMem.retVal = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
-                    }
-                }
-
-                // 2. Doing
-                mDriver.Polling.Status = ChangePollingMode;
-                if(ChangePollingMode == Driver.PollingList.STATUS.FixRoom)
-                {
-                    mDriver.Polling.RoomIndex = RoomIndex;
-                }
-                else mDriver.Polling.RoomIndex = 0;
-
-                return SHMem.retVal = "SUCCESS";
-            }
-
-            ///////////////////////////////////////////////////////////////
-            // SetEachRoomStatus : 각방 제어 (운전모드 및 설정온도 변경)
-            ///////////////////////////////////////////////////////////////
-            else if(ctrDevFormat.CmdStr.equals("SetEachRoomStatus"))
-            {
-                // 1. Param Check
-                byte RoomIndex    = ctrDevFormat.param[0];
-                byte Mode         = ctrDevFormat.param[1];
-                byte Temp         = ctrDevFormat.param[2];
-                byte TempPoint    = ctrDevFormat.param[3];
-
-                //      1.1. RoomIndex
-                if( (RoomIndex < 0) || (RoomIndex >= mDriver.Device.info.RoomCount) )
-                {
-                    Log.w(TAG, "[do_ctrEmm -> SetEachRoomStatus]" + "[RoomIndex] Out Of Range (" + RoomIndex + ")");
-                    return SHMem.retVal = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
-                }
-
-                //      1.2. Mode
-                int ret = CheckSetMode(Mode);
-                if(ret < 0)
-                {
-                    Log.w(TAG, "[do_ctrEmm -> SetEachRoomStatus]" + "[Mode] Out Of Range (" + ret + ")");
-                    return SHMem.retVal = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
-                }
-
-                //      1.3. Temp & TempPoint
-                if(Temp != 0x00)
-                {
-                    if( (Temp < mDriver.Device.info.Support.MinSetTemp) || (Temp > mDriver.Device.info.Support.MaxSetTemp) )
-                    {
-                        Log.w(TAG, "[do_ctrEmm -> SetEachRoomStatus]" + "[Temp] Out Of Range - (" + Temp + ")");
-                        return SHMem.retVal = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
-                    }
-
-                    if( !((TempPoint == 0x00) || (TempPoint == 0x01)) )
-                    {
-                        Log.w(TAG, "[do_ctrEmm -> SetEachRoomStatus]" + "[TempPoint] Out Of Range - (" + TempPoint + ")");
-                        return SHMem.retVal = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
-                    }
-                    //                if(TempPoint == 0x01)
-                    //                {
-                    //                    if(!mDriver.Device.info.Support.SetTempPoint05)
-                    //                    {
-                    //                        Log.w(TAG, "[do_ctrEmm -> SetEachRoomStatus]" + "[TempPoint] Out Of Range - Error  Not Support SetTempPoint05  (" + TempPoint + ")");
-                    //                        return SHMem.retVal = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
-                    //                    }
-                    //                }
-                }
-
-                // 2. Make Packet Data
-                CtrlRoomData ctrlRoomData = new CtrlRoomData();
-
-                ctrlRoomData.Mode = Mode;
-
-                ctrlRoomData.SetTemp = (double) Temp;
-                if(mDriver.Device.info.Support.SetTempPoint05)
-                {
-                    if(TempPoint == 0x01) ctrlRoomData.SetTemp += 0.5;
-                }
-
-                // 3. Doing
-                RoomData roomData = Send_SetEachRoomStatus(RoomIndex, ctrlRoomData);
-                if(roomData == null)
-                    return SHMem.retVal = "FAIL;" + APIErrorCode.DEVICEISNORESPONSE;
-
-                UpdateVariables(RoomIndex, roomData);
-
-                return SHMem.retVal = "SUCCESS";
-            }
-
-            ///////////////////////////////////////////////////////////////
-            // SetAllRoomStatus : 전체방 제어 (운전모드 변경)
-            ///////////////////////////////////////////////////////////////
-            else if(ctrDevFormat.CmdStr.equals("SetAllRoomStatus"))
-            {
-                // 1. Param Check
-                byte Mode         = ctrDevFormat.param[0];
-
-                //      1.2. Mode
-                int ret = CheckSetMode(Mode);
-                if(ret < 0)
-                {
-                    Log.w(TAG, "[do_ctrEmm -> SetAllRoomStatus]" + "[Mode] Out Of Range (" + ret + ")");
-                    return SHMem.retVal = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
-                }
-
-                // 2. Make Packet Data
-
-                // 3. Doing
-                AllRoomData allRoomData = Send_SetAllRoomStatus(false, Mode, mDriver.Device.info.RoomCount);
-                if(allRoomData == null)
-                    return SHMem.retVal = "FAIL;" + APIErrorCode.DEVICEISNORESPONSE;
-
-                UpdateVariables(allRoomData);
-
-                return SHMem.retVal = "SUCCESS";
-            }
-
-            ///////////////////////////////////////////////////////////////
-            // SetSleep : 취침설정 변경
-            ///////////////////////////////////////////////////////////////
-            else if(ctrDevFormat.CmdStr.equals("SetSleep"))
-            {
-                // 0. Mode Check
-                if(!mDriver.Device.info.Support.Sleep)
-                {
-                    Log.w(TAG, "[do_ctrEmm -> SetSleep]" + "Not Support Sleep");
-                    return SHMem.retVal = "FAIL;" + APIErrorCode.NOT_SUPPORT;
-                }
-
-                // 1. Param Check
-                byte RoomIndex         = ctrDevFormat.param[0];
-                byte setTemp           = ctrDevFormat.param[1];
-                byte setTime           = ctrDevFormat.param[2];
-
-                //      1.1. RoomIndex
-                if( (RoomIndex < 0) || (RoomIndex >= mDriver.Device.info.RoomCount) )
-                {
-                    Log.w(TAG, "[do_ctrEmm -> SetSleep]" + "[RoomIndex] Out Of Range (" + RoomIndex + ")");
-                    return SHMem.retVal = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
-                }
-
-                // 2. Make Packet Data
-                CtrlRoomData ctrlRoomData = new CtrlRoomData();
-
-                if(!ctrlRoomData.Sleep.setTemp(setTemp))
-                {
-                    Log.w(TAG, "[do_ctrEmm -> SetSleep]" + "[setTemp] Out Of Range (" + setTemp + ")");
-                    return SHMem.retVal = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
-                }
-                if(!ctrlRoomData.Sleep.setTime(setTime))
-                {
-                    Log.w(TAG, "[do_ctrEmm -> SetSleep]" + "[setTime] Out Of Range (" + setTime + ")");
-                    return SHMem.retVal = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
-                }
-
-                // 3. Doing
-                RoomData roomData = Send_SetEachRoomStatus(RoomIndex, ctrlRoomData);
-                if(roomData == null)
-                    return SHMem.retVal = "FAIL;" + APIErrorCode.DEVICEISNORESPONSE;
-
-                UpdateVariables(RoomIndex, roomData);
-
-                return SHMem.retVal = "SUCCESS";
-            }
-
-            ///////////////////////////////////////////////////////////////
-            // SetReservation : 예약설정변경
-            ///////////////////////////////////////////////////////////////
-            else if(ctrDevFormat.CmdStr.equals("SetReservation"))
-            {
-                // 0. Mode Check
-                if(!mDriver.Device.info.Support.Reservation)
-                {
-                    Log.w(TAG, "[do_ctrEmm -> SetReservation]" + "Not Support Reservation");
-                    return SHMem.retVal = "FAIL;" + APIErrorCode.NOT_SUPPORT;
-                }
-
-                // 1. Param Check
-                byte RoomIndex         = ctrDevFormat.param[0];
-
-                //      1.1. RoomIndex
-                if( (RoomIndex < 0) || (RoomIndex >= mDriver.Device.info.RoomCount) )
-                {
-                    Log.w(TAG, "[do_ctrEmm -> SetEachRoomStatus]" + "[RoomIndex] Out Of Range (" + RoomIndex + ")");
-                    return SHMem.retVal = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
-                }
-
-                // 2. Make Packet Data
-                byte [] DataBuffer = new byte[3];
-                DataBuffer[0] = ctrDevFormat.param[1];
-                DataBuffer[1] = ctrDevFormat.param[2];
-                DataBuffer[2] = ctrDevFormat.param[3];
-
-                CtrlRoomData ctrlRoomData = new CtrlRoomData();
-                ctrlRoomData.Reservation.setByte(DataBuffer);
-
-                ////////////////////////////////////////////////////////////////////////////
-                // 예약운전 시간 월패드 저장모드
-                ////////////////////////////////////////////////////////////////////////////
-                boolean bSend = false;
-                if(MODE_RESERVATION_SET_WALLPAD_SAVE == true)
-                {
-                    mDriver.Device.Room[RoomIndex].Reservation.setByte(DataBuffer);
-
-                    SaveReservationData();
-
-                    if (mDriver.Device.Room[RoomIndex].Mode == MODE.Reservation)
-                    {
-                        ctrlRoomData.Reservation.setByte(DataBuffer);
-                        bSend = true;
-                    }
-                }
-                else
-                {
-                    ctrlRoomData.Reservation.setByte(DataBuffer);
-                    bSend = true;
-                }
-
-                // 3. Doing
-                if(bSend)
-                {
-                    RoomData roomData = Send_SetEachRoomStatus(RoomIndex, ctrlRoomData);
-                    if(roomData == null)
-                        return SHMem.retVal = "FAIL;" + APIErrorCode.DEVICEISNORESPONSE;
-
-                    UpdateVariables(RoomIndex, roomData);
-                }
-
-                return SHMem.retVal = "SUCCESS";
-            }
-
-            ///////////////////////////////////////////////////////////////
-            // 보일러 설정 변경
-            ///////////////////////////////////////////////////////////////
-            else if(ctrDevFormat.CmdStr.equals("SetBoiler"))
-            {
-                // 0. Mode Check
-                if(!mDriver.Device.info.Support.Boiler)
-                {
-                    Log.w(TAG, "[do_ctrEmm -> SetBoiler]" + "Not Support Boiler");
-                    return SHMem.retVal = "FAIL;" + APIErrorCode.NOT_SUPPORT;
-                }
-                if(mDriver.Boiler == null)
-                {
-                    Log.w(TAG, "[do_ctrEmm -> SetBoiler]" + "mDriver.Boiler is null !!!");
-                    return SHMem.retVal = "FAIL;" + APIErrorCode.DEVICEISNOTREADY;
-                }
-
-                byte HeatingWaterTemp     = ctrDevFormat.param[0];
-                byte HotWaterTemp         = ctrDevFormat.param[1];
-
-                // 2. Param Check & Doing
-                BoilerData Boiler = Send_SetBoilerStatus(HeatingWaterTemp, HotWaterTemp);
-                if(Boiler == null)
-                    return SHMem.retVal = "FAIL;" + APIErrorCode.DEVICEISNORESPONSE;
-
-                UpdateVariables(Boiler);
-
-                return SHMem.retVal = "SUCCESS";
-            }
-        }
-
-
-        return SHMem.retVal = "UNKNOWNCMD";
-    }
-
-    /**
-     * Info 에 대한 응답포멧 정의
-     *
-     * @return (String) "SUCCESS; ..." 성공 , "FAIL; ... " 실패
-     */
-    private String RefreshResult_Info()
-    {
-        String result = null;
-
-        DeviceLog("GetRefreshResultInfo call : ");
-
-        // 1. Check Polling Status
-        if( (mDriver.Polling.Status == Driver.PollingList.STATUS.First) ||
-                (mDriver.Polling.Status == Driver.PollingList.STATUS.FirstTimeOut) )
-        {
-            result = "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
-            return result;
-        }
-
-        // 2. Param Range Check
-
-        // 3. Make Return String Format
-        try
-        {
-            if(mDriver.Device == null)                   return "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
-            if(mDriver.Device.info == null)              return "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
-
-            /*
-             * [Format]
-             *
-             * SUCCESS       - (String) 성공
-             *
-             * RoomCount        - (byte) 방개수(범위 : 1~6)
-             *
-             * Vender           - (byte) 벤더
-             *
-             * FwVer_Year       - (byte) 펌웨어 빌드버전 (년)
-             * FwVer_Month      - (byte) 펌웨어 빌드버전 (월)
-             * FwVer_Day        - (byte) 펌웨어 빌드버전 (일)
-             * FwVer_Number     - (byte) 펌웨어 빌드버전 (순번)
-             *
-             * ProtocolVer_Main - (byte) 프로토콜 지원 버전 (상위)
-             * ProtocolVer_Sub  - (byte) 프로토콜 지원 버전 (하위)
-             *
-             * Support.MinSetTemp - (byte) 지원하는 최저설정온도 (범위 : 5도 ~ 20도)
-             * Support.MaxSetTemp - (byte) 지원하는 최대설정온도 (범위 : 21도 ~ 40도)
-             *
-             * Support.SetTempPoint05 - (boolean) 설정온도 단위          (ture : 0.5도단위, false : 1도단위)
-             * Support.Outing         - (boolean) 외출기능 지원여부   (ture : 지원, false : 미지원)
-             * Support.Sleep          - (boolean) 취침기능 지원여부    (ture : 지원, false : 미지원)
-             * Support.Reservation    - (boolean) 예약기능 지원여부    (ture : 지원, false : 미지원)
-             * Support.Pause          - (boolean) 일시정지 지원여부    (ture : 지원, false : 미지원)
-             *
-             * Support.AI             - (boolean) 인공지능 지원여부    (ture : 지원, false : 미지원)
-             * Support.OutsideTempUse - (boolean) 외기온도 사용여부    (ture : 사용, false : 미사용)
-             * Support.Boiler         - (boolean) 보일러 지원여부       (ture : 지원, false : 미지원)
-             */
-            Info info = mDriver.Device.info;
-
-            result = APIErrorCode.SUCCESS + ";";
-
-            result += info.RoomCount + ";" +
-            
-                      info.Vender + ";" +
-                      
-                      info.FwVer_Year + ";" +
-                      info.FwVer_Month + ";" +
-                      info.FwVer_Day + ";" +
-                      info.FwVer_Number + ";" +
-                      
-                      info.ProtocolVer_Main + ";" +
-                      info.ProtocolVer_Sub + ";" +
-                      
-                      info.Support.MinSetTemp + ";" +
-                      info.Support.MaxSetTemp + ";" +
-
-                      info.Support.SetTempPoint05 + ";" +
-                      info.Support.Outing + ";" +
-                      info.Support.Sleep + ";" +
-                      info.Support.Reservation + ";" +
-                      info.Support.Pause + ";" +
-                      
-                      info.Support.AI + ";" +
-                      info.Support.OutsideTempUse + ";" +
-                      info.Support.Boiler + ";" +
-                      info.Support.Leak + ";";
-        }
-        catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-            result = "FAIL;"+APIErrorCode.EXCEPTION;
-        }
-        catch (Exception e) {
-            Log.e(TAG, "[Exception Error] RefreshResult_Info");
-            //e.printStackTrace();
-            LogUtil.errorLogInfo("", TAG, e);
-            result = "FAIL;"+APIErrorCode.EXCEPTION;
-        }
-        DeviceLog(" GetRefreshResultInfo return : "+result);
-
-        return result;
-    }
-
-    /**
-     * Refresh 에 대한 응답포멧 정의
-     *
-     * param (byte) Index - 방 인덱스 (범위 : 0 ~ 7)
-     *
-     * @return (String) "SUCCESS; ..." 성공 , "FAIL; ... " 실패
-     */
-    private String RefreshResult_Room(byte Index)
-    {
-        String result = null;
-
-        DeviceLog("RefreshResult_Room call : ");
-
-        // 1. Check Polling Status
-        if( (mDriver.Polling.Status == Driver.PollingList.STATUS.First) ||
-                (mDriver.Polling.Status == Driver.PollingList.STATUS.FirstTimeOut) )
-        {
-            result = "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
-            return result;
-        }
-
-        // 2. Param Range Check
-        if(!(Index >= 0 && Index <= mDriver.Device.info.RoomCount))
-        {
-            result = "FAIL;"+APIErrorCode.INVALIDPARAMETER;
-            return result;
-        }
-
-        // 3. Make Return String Format
-        try
-        {
-            if(mDriver.Device == null)                   return "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
-            if(mDriver.Device.Room == null)              return "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
-            if(mDriver.Device.Room.length <= (int)Index) return "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
-            if(mDriver.Device.Room[Index] == null)       return "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
-
-            /*
-             * [Format]
-             *
-             * SUCCESS       - (String) 성공
-             *
-             * RequestIndex  - (byte)   요청 인덱스
-             *
-             * Mode          - (byte)    운전모드 (true : 설치 ,false : 미설치)
-             * bValveStatus  - (boolean) 밸브상태 ( ture : 열림, false : 닫힘 )
-             * SetTemp       - (double)  설정온도 ( 0.5도 혹은 1도 단위)
-             * NowTemp       - (double)  현재온도 ( 0.5도 혹은 1도 단위)
-             * Error         - (byte)    에러코드
-             *
-             * SLEEP         - (byte) 취침운전
-             *
-             * RESERVATION   - (int) 예약스케쥴
-             */
-            RoomData Room = mDriver.Device.Room[Index];
-
-            result = APIErrorCode.SUCCESS + ";";
-
-            result += Index + ";";
-
-            result += Room.Mode + ";" +
-                    Room.bValveStatus + ";" +
-                    Room.SetTemp + ";" +
-                    Room.NowTemp + ";" +
-                    Room.Error.getByte() + ";" +
-
-                    Room.Sleep.getByte() + ";" +
-
-                    Room.Reservation.getInt() + ";";
-        }
-        catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-            result = "FAIL;"+APIErrorCode.EXCEPTION;
-        }
-        catch (Exception e) {
-            Log.e(TAG, "[Exception Error] RefreshResult_Room");
-            //e.printStackTrace();
-            LogUtil.errorLogInfo("", TAG, e);
-            result = "FAIL;"+APIErrorCode.EXCEPTION;
-        }
-        DeviceLog(" RefreshResult_Room return : "+result);
-
-        return result;
-    }
-
-
-    /**
-     * 보일러 Refresh 에 대한 응답포멧 정의
-     *
-     * param (byte) Index - 방 인덱스 (범위 : 0 ~ 7)
-     *
-     * @return (String) "SUCCESS; ..." 성공 , "FAIL; ... " 실패
-     */
-    private String RefreshResult_Boiler()
-    {
-        String result = null;
-
-        DeviceLog("RefreshResult_Boiler call : ");
-
-        // 1. Check Polling Status
-        if( (mDriver.Polling.Status == Driver.PollingList.STATUS.First) ||
-                (mDriver.Polling.Status == Driver.PollingList.STATUS.FirstTimeOut) )
-        {
-            result = "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
-            return result;
-        }
-
-        // 2. Param Range Check
-
-        // 3. Make Return String Format
-        try
-        {
-            if(mDriver == null)                   return "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
-            if(mDriver.Boiler == null)            return "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
-
-            /*
-             * [Format]
-             *
-             * SUCCESS       - (String) 성공
-             *
-             * bFrostProtectMode - (boolean) 동파방지모드 (true : 가동, false : 정지)
-             * ErrorCode         - (byte) 에러코드 (0x00 정상 , 0x00 아닐경우 에러코드
-             *
-             * HeatingWater.bSetTempUnit5 - (boolean) 난방수  설정온도 단위 (false : 1도단위 , true : 5도 단위)
-             * HeatingWater.SetTemp       - (byte) 난방수  설정온도
-             * HeatingWater.MinSetTemp    - (byte) 난방수  최저 설정온도
-             * HeatingWater.MaxSetTemp    - (byte) 난방수  최대 설정온도
-             *
-             * HotWater.bSetTempUnit5 - (boolean) 온수  설정온도 단위 (false : 1도단위 , true : 5도 단위)
-             * HotWater.SetTemp       - (byte) 온수  설정온도
-             * HotWater.MinSetTemp    - (byte) 온수  최저 설정온도
-             * HotWater.MaxSetTemp    - (byte) 온수  최대 설정온도
-             */
-            BoilerData Boiler = mDriver.Boiler;
-
-            result = APIErrorCode.SUCCESS + ";";
-
-            result += Boiler.bFrostProtectMode + ";" +
-                    Boiler.ErrorCode + ";" +
-
-                    Boiler.HeatingWater.bSetTempUnit5 + ";" +
-                    Boiler.HeatingWater.SetTemp + ";" +
-                    Boiler.HeatingWater.MinSetTemp + ";" +
-                    Boiler.HeatingWater.MaxSetTemp + ";" +
-
-                    Boiler.HotWater.bSetTempUnit5 + ";" +
-                    Boiler.HotWater.SetTemp + ";" +
-                    Boiler.HotWater.MinSetTemp + ";" +
-                    Boiler.HotWater.MaxSetTemp + ";";
-        }
-        catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-            result = "FAIL;"+APIErrorCode.EXCEPTION;
-        }
-        catch (Exception e) {
-            Log.e(TAG, "[Exception Error] RefreshResult_Boiler");
-            //e.printStackTrace();
-            LogUtil.errorLogInfo("", TAG, e);
-            result = "FAIL;"+APIErrorCode.EXCEPTION;
-        }
-        DeviceLog(" RefreshResult_Boiler return : "+result);
-
-        return result;
-    }
-
-    /**
-     * 특화기능 Refresh 에 대한 응답포멧 정의
-     *
-     * param (byte) Index - 방 인덱스 (범위 : 0 ~ 7)
-     *
-     * @return (String) "SUCCESS; ..." 성공 , "FAIL; ... " 실패
-     */
-    private String RefreshResult_SpecialFunc()
-    {
-        String result = null;
-
-        DeviceLog("RefreshResult_SpecialFunc call : ");
-
-        // 1. Check Polling Status
-        if( (mDriver.Polling.Status == Driver.PollingList.STATUS.First) ||
-                (mDriver.Polling.Status == Driver.PollingList.STATUS.FirstTimeOut) )
-        {
-            result = "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
-            return result;
-        }
-
-        // 2. Param Range Check
-
-        // 3. Make Return String Format
-        try
-        {
-            if(mDriver == null)                   return "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
-            if(mDriver.SpecialFunc == null)       return "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
-
-            /*
-             * [Format]
-             *
-             * SUCCESS       - (String) 성공
-             *
-             * Mode        - (byte) 인공지능 동작모드
-             * OutsideTemp - (double) 설정된 외기온도
-             */
-            SpecialFuncData SpecialFunc = mDriver.SpecialFunc;
-
-            result = APIErrorCode.SUCCESS + ";";
-
-            result += SpecialFunc.Mode + ";" +
-                    SpecialFunc.OutsideTemp + ";";
-        }
-        catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-            result = "FAIL;"+APIErrorCode.EXCEPTION;
-        }
-        catch (Exception e) {
-            Log.e(TAG, "[Exception Error] RefreshResult_SpecialFunc");
-            //e.printStackTrace();
-            LogUtil.errorLogInfo("", TAG, e);
-            result = "FAIL;"+APIErrorCode.EXCEPTION;
-        }
-        DeviceLog(" RefreshResult_SpecialFunc return : "+result);
-
-        return result;
-    }
-
-    /**
-     * 보드 상태 읽기 요청 응답.
-     *
-     * @return (Info) null - Error , Not null - OK
-     */
-    private Info Send_GetDeviceInfo()
-    {
-        DeviceLog("[Send_GetDeviceInfo] Start");
-
-        // 1. In 파라미터 확인
-
-        // 2. 패킷 데이터 만들기
-        byte [] ReqData = null;
-
-        // 3. 데이터 전송 및 응답
-        byte [] Reply = SendNRead_Variable( (byte)(DEVICE_ADDRESS), CMDList.Req.GetDeviceInfo, ReqData);
-
-        // 4. 수신데이터 파싱
-        Info info = GetDeviceInfo_RepParsing(Reply);
-        if(info == null)
-        {
-            DeviceLog("[Send_GetDeviceInfo] Reply is null");
-            AddDoCount(false);
-            return null;
-        }
-        AddDoCount(true);
-
-        return info;
-    }
-
-    /**
-     * {@link #Send_GetDeviceInfo()}<br>
-     * 메소드의 응답 공통부분 메소드이다.
-     *
-     * @param Reply      - (byte []) 응답 Byte 배열
-     *
-     * @return (Info) null - Error , Not null - OK
-     */
-    private Info GetDeviceInfo_RepParsing(byte [] Reply)
-    {
-        // 1. 수신데이터 파싱
-        //     1.1. Default Check
-        if(Reply == null)
-        {
-            DeviceLog("[GetDeviceInfo_RepParsing] Reply is null");
-            return null;
-        }
-        if(Reply.length != 12)
-        {
-            Log.w(TAG, "[GetDeviceInfo_RepParsing] Reply.length  fail ... " + Reply.length);
-            return null;
-        }
-        //     1.2. Details Data Check
-        //         - D1 : 설치된 방 개수 X’01’ ~ X’08’
-        if( !((Reply[0] >= ROOM_COUNT_LOW) && (Reply[0] <= ROOM_COUNT_HI)) )
-        {
-            Log.w(TAG, "[GetDeviceInfo_RepParsing] D1 (RoomCount) : Out of Range !!! " + String.format("0x%02X", Reply[0]));
-            return null;
-        }
-        //         - D2 : 기본 기능 정보
-        if( (Reply[1] & (byte)(BIT5 | BIT6 | BIT7)) != 0x00 )
-        {
-            Log.w(TAG, "[GetDeviceInfo_RepParsing] D2 (DefultFuncInfo) : Unused Bit Set !!! " + String.format("0x%02X", Reply[1]));
-            return null;
-        }
-        //         - D3 : 특화 기능 정보
-        if( (Reply[2] & (byte)( BIT4 | BIT5 | BIT6 | BIT7)) != 0x00 )
-        {
-            Log.w(TAG, "[GetDeviceInfo_RepParsing] D3 (SpecialFuncInfo) : Unused Bit Set !!! " + String.format("0x%02X", Reply[2]));
-            return null;
-        }
-        //         - D4 : 지원하는 최저 설정온도
-        if( !((Reply[3] >= SETTEMP_MIN_LOW) && (Reply[3] <= SETTEMP_MIN_HI)) )
-        {
-            Log.w(TAG, "[GetDeviceInfo_RepParsing] D4 (MinTemp) : Out of Range !!! " + String.format("0x%02X", Reply[3]));
-            return null;
-        }
-        //         - D5 : 지원하는 최대 설정온도
-        if( !((Reply[4] >= SETTEMP_MAX_LOW) && (Reply[4] <= SETTEMP_MAX_HI)) )
-        {
-            Log.w(TAG, "[GetDeviceInfo_RepParsing] D5 (MaxTemp) : Out of Range !!! " + String.format("0x%02X", Reply[4]));
-            return null;
-        }
-        //         - D6 : 제조사 구분정보
-        if( !(Reply[5] >= 0x01) )
-        {
-            Log.w(TAG, "[GetDeviceInfo_RepParsing] D6 (Manufacturer) : Out of Range !!! " + String.format("0x%02X", Reply[5]));
-            return null;
-        }
-        //         - D7 : 펌웨어 Build Date (Year)
-        //         - D8 : 펌웨어 Build Date (Month)
-        if( !((Reply[7] >= 0x01) && (Reply[7] <= 0x0C)) )
-        {
-            Log.w(TAG, "[GetDeviceInfo_RepParsing] D8 (FW Build Data - Month) :  Out of Range !!! " + String.format("0x%02X", Reply[7]));
-            return null;
-        }
-        //         - D9 : 펌웨어 Build Date (Day)
-        if( !((Reply[8] >= 0x01) && (Reply[8] <= 0x1F)) )
-        {
-            Log.w(TAG, "[GetDeviceInfo_RepParsing] D9 (FW Build Data - Day) : Out of Range !!! " + String.format("0x%02X", Reply[8]));
-            return null;
-        }
-        //         - D10 : 펌웨어 Build Date (Number)
-        //         - D11 : Protocol 버전정보 (Main)
-        //         - D12 : Protocol 버전정보 (Sub)
-
-        // 2. Data return
-        Info info = new Info();
-        int index = 0;
-        byte data = 0;
-
-        //         - D1 : 설치된 방 개수 X’01’ ~ X’08’
-        if((mDriver.bFixRoomCountUse == true) && (mDriver.FixRoomCount >= ROOM_COUNT_LOW) && (mDriver.FixRoomCount <= ROOM_COUNT_HI))
-        {
-            /**
-             * [광주 무등산 임대세대 전용 기능]
-             임대세대는 에너지미터가 3개인데 벨브가 2개인 현장임
-             문제점:난방 제어화면에서 방이 3개로 나옴
-             해결:방개수 3개로 알려주면 강제로 2개로 설정함
-             필요사항:단지서버에서 온도조절기 회로수를 2개로 설정하면 됨
-             * **/
-            info.RoomCount = (byte) mDriver.FixRoomCount;
-            index++;
-            Log.w(TAG, "[GetDeviceInfo_RepParsing] info.RoomCount (Room Count) will be fixed : " + String.format("0x%02X", info.RoomCount));
-        }
-        else
-        {
-            info.RoomCount = Reply[index++];
-        }
-
-
-        //         - D2 : 기본 기능 정보
-        data = Reply[index++];
-        if((data & BIT0) != 0x00) info.Support.SetTempPoint05 = true;
-        else info.Support.SetTempPoint05 = false;
-        if((data & BIT1) != 0x00) info.Support.Outing = true;
-        else info.Support.Outing = false;
-        if((data & BIT2) != 0x00) info.Support.Sleep = true;
-        else info.Support.Sleep = false;
-        if((data & BIT3) != 0x00) info.Support.Reservation = true;
-        else info.Support.Reservation = false;
-        if((data & BIT4) != 0x00) info.Support.Pause = true;
-        else info.Support.Pause = false;
-
-        //         - D3 : 특화 기능 정보
-        data = Reply[index++];
-        if((data & BIT0) != 0x00) info.Support.AI = true;
-        else info.Support.AI = false;
-        if((data & BIT1) != 0x00) info.Support.OutsideTempUse = true;
-        else info.Support.OutsideTempUse = false;
-        if((data & BIT2) != 0x00) info.Support.Boiler = true;
-        else info.Support.Boiler = false;
-        if((data & BIT3) != 0x00) info.Support.Leak = true;
-        else info.Support.Leak = false;
-        
-        //         - D4 : 지원하는 최저 설정온도
-        info.Support.MinSetTemp = Reply[index++];
-        //         - D5 : 지원하는 최대 설정온도
-        info.Support.MaxSetTemp = Reply[index++];
-        //         - D6 : 제조사 구분정보
-        info.Vender           = Reply[index++];
-        //         - D7 : 펌웨어 Build Date (Year)
-        info.FwVer_Year       = Reply[index++];
-        //         - D8 : 펌웨어 Build Date (Month)
-        info.FwVer_Month      = Reply[index++];
-        //         - D9 : 펌웨어 Build Date (Day)
-        info.FwVer_Day        = Reply[index++];
-        //         - D10 : 펌웨어 Build Date (Number)
-        info.FwVer_Number     = Reply[index++];
-        //         - D11 : Protocol 버전정보 (Main)
-        info.ProtocolVer_Main = Reply[index++];
-        //         - D12 : Protocol 버전정보 (Sub)
-        info.ProtocolVer_Sub  = Reply[index++];
-
-        return info;
-    }
-
-    /**
-     * 각방 상태 요청 응답.
-     *
-     * @param RoomIndex - (byte) 요청 방인덱스
-     *
-     * @return (RoomData) null - Error , Not null - OK
-     */
-    private RoomData Send_GetEachRoomStatus(byte RoomIndex)
-    {
-        DeviceLog("[Send_GetEachRoomStatus] Start");
-
-        // 1. In 파라미터 확인
-        //         - D1 : 요청할 방번호
-        if( !((RoomIndex >= (ROOM_COUNT_LOW-1)) && (RoomIndex <= (ROOM_COUNT_HI-1))) )
-        {
-            Log.w(TAG, "[Send_GetEachRoomStatus] (RoomIndex) Request Param Out Of Range !!! " + RoomIndex);
-            return null;
-        }
-
-        // 2. 패킷 데이터 만들기
-        byte [] ReqData = new byte [] { (byte)(RoomIndex+1) };
-
-        // 3. 데이터 전송 및 응답
-        byte [] Reply = SendNRead_Variable( (byte)(DEVICE_ADDRESS), CMDList.Req.GetEachRoomStatus, ReqData);
-
-        // 4. 수신데이터 파싱
-        RoomData roomData = GetEachRoomStatus_RepParsing(RoomIndex, Reply);
-        if(roomData == null)
-        {
-            DeviceLog("[Send_GetEachRoomStatus] Reply is null");
-            AddDoCount(false);
-            return null;
-        }
-        AddDoCount(true);
-
-        return roomData;
-    }
-
-    /**
-     * 각방 제어 요청 응답.
-     *
-     * @param RoomIndex    - (byte) 제어할 방인덱스
-     * @param ctrlRoomData  - (CtrlRoomData) 제어 데이터 클래스
-     *
-     * @return (RoomData) null - Error , Not null - OK
-     */
-    private RoomData Send_SetEachRoomStatus(byte RoomIndex, CtrlRoomData ctrlRoomData)
-    {
-        DeviceLog("[Send_SetEachRoomStatus] Start");
-
-        // 1. In 파라미터 확인
-        //         - D1 : 요청할 방번호
-        if( !((RoomIndex >= (ROOM_COUNT_LOW-1)) && (RoomIndex <= (ROOM_COUNT_HI-1))) )
-        {
-            Log.w(TAG, "[Send_SetEachRoomStatus] (RoomIndex) Request Param Out Of Range !!!" + String.format("0x%02X", RoomIndex));
-            return null;
-        }
-
-        // 2. 패킷 데이터 만들기
-        byte [] ReqData = ConverterCtrlRoomData(RoomIndex, ctrlRoomData);
-        if(ReqData == null)
-        {
-            Log.w(TAG, "[Send_SetEachRoomStatus] ConverterCtrlRoomData null return");
-            return null;
-        }
-
-        // 3. 데이터 전송 및 응답
-        byte [] Reply = SendNRead_Variable( (byte)(DEVICE_ADDRESS), CMDList.Req.SetEachRoomStatus, ReqData);
-
-        // 4. 수신데이터 파싱
-        RoomData roomData = GetEachRoomStatus_RepParsing(RoomIndex, Reply);
-        if(roomData == null)
-        {
-            DeviceLog("[Send_SetEachRoomStatus] Reply is null");
-            AddDoCount(false);
-            return null;
-        }
-        AddDoCount(true);
-
-        return roomData;
-    }
-
-    /////////////////////////////////////////////////////////////////////
-    // 각방제어 명령을 통하여 예약운전스케쥴만 제어할 경우
-    // RoomNumber : 방번호, bReset (ture : 초기화, false : 복구), bPauseRelease (true : 일시정지 명령사용, false : 사용)
-    /////////////////////////////////////////////////////////////////////
-    private boolean Send_ReservationSettingInfo(byte RoomIndex, boolean bReset, boolean bPauseRelease)
-    {
-        // 제어 명령생성
-        CtrlRoomData ctrlRoomData = new CtrlRoomData();
-
-        int u32Temp = 0;
-        if (bReset == true)
-        {
-            if (bPauseRelease) ctrlRoomData.Mode = MODE.Pause;
-        }
-        else
-        {
-            u32Temp = mDriver.Device.Room[RoomIndex].Reservation.getInt();
-        }
-        ctrlRoomData.Reservation.setInt(u32Temp);
-
-        // 전송
-        RoomData roomData = Send_SetEachRoomStatus(RoomIndex, ctrlRoomData);
-        if (roomData == null) roomData = Send_SetEachRoomStatus(RoomIndex, ctrlRoomData);
-
-        if (bReset == true)
-        {
-            if (bPauseRelease)
-            {
-                Sleep(100);
-
-                ctrlRoomData.Mode = MODE.PauseRelease;
-                roomData = Send_SetEachRoomStatus(RoomIndex, ctrlRoomData);
-                if (roomData == null) roomData = Send_SetEachRoomStatus(RoomIndex, ctrlRoomData);
-            }
-        }
-
-        return true;
-    }
-
-
-    /**
-     * 각방 제어 요청 데이터 변환
-     *
-     * @param RoomIndex   - (byte) 요청할 방인덱스
-     * @param ctrlRoomData - (CtrlRoomData) 제어용 클래스
-     *
-     * @return (byte []) null - Error , Not null - OK
-     */
-    private byte [] ConverterCtrlRoomData(byte RoomIndex, CtrlRoomData ctrlRoomData)
-    {
-        // 1. Check RoomNumber
-        if((RoomIndex < 0) || (RoomIndex >= mDriver.Device.info.RoomCount))
-        {
-            Log.w(TAG, "[ConverterCtrlRoomData] RoomIndex - Out Of Range !!! " + RoomIndex);
-            return null;
-        }
-
-        // 2. Check CtrlRoomData Class
-        if(ctrlRoomData == null)
-        {
-            Log.w(TAG, "[ConverterCtrlRoomData] ctrlRoomData is null !!!");
-            return null;
-        }
-
-        // 3. Check Mode
-        byte Mode = ctrlRoomData.Mode;
-        if(!MODE.CheckSetMode(Mode))
-        {
-            Log.w(TAG, "[ConverterCtrlRoomData] Mode - Out Of Range !!! (" + String.format("%02X", Mode) + ")");
-            return null;
-        }
-
-        if((Mode == MODE.Outing) || (Mode == MODE.OutingRelease))
-        {
-            if(!mDriver.Device.info.Support.Outing)
-            {
-                Log.w(TAG, "[ConverterCtrlRoomData] Mode - No Support (Outing) !!! (" + String.format("%02X", Mode) + ")");
-                return null;
-            }
-        }
-        else if((Mode == MODE.Pause) || (Mode == MODE.PauseRelease))
-        {
-            if(!mDriver.Device.info.Support.Pause)
-            {
-                Log.w(TAG, "[ConverterCtrlRoomData] Mode - No Support (Pause) !!! (" + String.format("%02X", Mode) + ")");
-                return null;
-            }
-        }
-        else if(Mode == MODE.Sleep)
-        {
-            if(!mDriver.Device.info.Support.Sleep)
-            {
-                Log.w(TAG, "[ConverterCtrlRoomData] Mode - No Support (Sleep) !!! (" + String.format("%02X", Mode) + ")");
-                return null;
-            }
-        }
-        else if(Mode == MODE.Reservation)
-        {
-            if(!mDriver.Device.info.Support.Reservation)
-            {
-                Log.w(TAG, "[ConverterCtrlRoomData] Mode - No Support (Reservation) !!! (" + String.format("%02X", Mode) + ")");
-                return null;
-            }
-        }
-
-        // 4. Check SetTemp
-        if(ctrlRoomData.SetTemp != 0)
-        {
-            int Temp = (int)(ctrlRoomData.SetTemp * 10);
-            int Remainder = Temp%10;
-            if(Remainder != 0)
-            {
-                if(Remainder != 5)
-                {
-                    Log.w(TAG, "[ConverterCtrlRoomData] SetTemp - Out Of Range !!! (" + String.format("%d", Remainder) + ")");
-                    return null;
-                }
-            }
-            if( !((ctrlRoomData.SetTemp >= (double)mDriver.Device.info.Support.MinSetTemp) && (ctrlRoomData.SetTemp <= (double)mDriver.Device.info.Support.MaxSetTemp)) )
-            {
-                Log.w(TAG, "[ConverterCtrlRoomData] SetTemp - Out Of Range !!!  (" + ctrlRoomData.SetTemp + ")");
-                return null;
-            }
-        }
-
-        // 5. Check Sleep
-        if(ctrlRoomData.Sleep.getSupportNUse())
-        {
-            if(!mDriver.Device.info.Support.Sleep)
-            {
-                Log.w(TAG, "[ConverterCtrlRoomData] Sleep - Not Support !!!");
-                return null;
-            }
-        }
-
-        // 6. Check Reservation
-        if(ctrlRoomData.Reservation.getSupportNUse())
-        {
-            if(!mDriver.Device.info.Support.Reservation)
-            {
-                Log.w(TAG, "[ConverterCtrlRoomData] Reservation - Not Support !!!");
-                return null;
-            }
-        }
-
-        // 7. Make Paket
-
-        byte [] ReqData = new byte [8];
-        for(int i=0 ; i<ReqData.length ; i++) ReqData[i] = 0x00;
-        int Index = 0;
-
-        // 제어할 방번호
-        ReqData[Index++] = (byte)(RoomIndex+1);
-
-        // 운전모드
-        boolean IdleSet = false;
-        if(HEATINGOFF_NOSET_OUTTING)
-        {
-            if((Mode == MODE.Outing) || (Mode == MODE.OutingRelease))
-            {
-                if(mDriver.Device.Room[RoomIndex].Mode == MODE.HeatingOFF) IdleSet = true;
-            }
-        }
-        if(IdleSet) ReqData[Index++] = MODE.Idle;
-        else ReqData[Index++] = ctrlRoomData.Mode;
-
-        // 설정온도
-        if(ctrlRoomData.SetTemp != 0)
-        {
-            byte bTemp = (byte)ctrlRoomData.SetTemp;
-            int Temp = (int)(ctrlRoomData.SetTemp * 10);
-            int Remainder = Temp%10;
-            if(Remainder != 0) bTemp |= BIT6;
-
-            ReqData[Index++] = bTemp;
-        }
-        else Index++;
-
-        // 취침 운전 설정값
-        ReqData[Index++] = ctrlRoomData.Sleep.getByte();
-
-        // 예약운전
-        if(ctrlRoomData.Reservation.getSupportNUse())
-        {
-            ReqData[Index++] = 0x01;
-
-            byte [] ReservationData = ctrlRoomData.Reservation.getByte();
-            for(int i=0 ; i<3 ; i++)
-                ReqData[Index++] = ReservationData[i];
-        }
-        else
-        {
-            Index += 4;
-        }
-
-        return ReqData;
-    }
-
-    /**
-     * {@link #Send_GetEachRoomStatus(byte)}<br>
-     * {@link #Send_SetEachRoomStatus(byte, CtrlRoomData)}<br>
-     * 메소드의 응답 공통부분 메소드이다.
-     *
-     * @param RoomIndex - (byte) 요청 방인덱스
-     * @param Reply      - (byte []) 응답 Byte 배열
-     *
-     * @return (RoomData) null - Error , Not null - OK
-     */
-    private RoomData GetEachRoomStatus_RepParsing(byte RoomIndex, byte [] Reply)
-    {
-        // 1. 수신데이터 파싱
-        //     1.1. Default Check
-        if(Reply == null)
-        {
-            DeviceLog("[GetEachRoomStatus_RepParsing] Reply is null");
-            return null;
-        }
-        if(Reply.length != 10)
-        {
-            Log.w(TAG, "[GetEachRoomStatus_RepParsing] Reply.length  fail ... " + Reply.length);
-            return null;
-        }
-
-        int index = 0;
-        byte data = 0x00;
-        byte data2 = 0x00;
-        //     1.2. Details Data Check
-        //          - D1 : 응답 방번호
-        data = Reply[index++];
-        if( (data & (byte)(BIT4 | BIT5 | BIT6)) != 0x00 )
-        {
-            // 미사용 비트'0' 확인
-            Log.w(TAG, "[GetEachRoomStatus_RepParsing] D1 (ReplyRoomNumber) : Unused Bit Set !!! " + String.format("0x%02X", data));
-            return null;
-        }
-        if((byte)(data & (byte)(~BIT7)) != (byte)(RoomIndex+1))
-        {
-            // 요청방 응답방 번호 일치여부
-            Log.w(TAG, "[GetEachRoomStatus_RepParsing] D1 (ReplyRoomNumber) :  Rsp Rep Data Different !!! " + "(Rsp:" + (byte)(RoomIndex+1) + ", Rep:" + data + ")");
-            return null;
-        }
-        if((byte)(data & BIT7) != 0x00)
-        {
-            // 요청방의 존재여부 체크
-            Log.w(TAG, "[GetEachRoomStatus_RepParsing] D1 (ReplyRoomNumber) :  Not Supported Room !!! " + "(RoomNumber:" + (byte)(RoomIndex+1) + ")");
-            return null;
-        }
-        //          - D2 : 운전모드 및 밸브상태
-        data = Reply[index++];
-        if( (data & (byte)(BIT5 | BIT6 | BIT7)) != 0x00 )
-        {
-            // 미사용 비트'0' 확인
-            Log.w(TAG, "[GetEachRoomStatus_RepParsing] D2 (Mode) : Unused Bit Set !!! " + String.format("0x%02X", data));
-            return null;
-        }
-        byte Mode = (byte)(data & (byte)(BIT0 | BIT1 | BIT2 | BIT3));
-        if(MODE.CheckGetMode(Mode) == false)
-        {
-            // 운전모드 범위확인
-            Log.w(TAG, "[GetEachRoomStatus_RepParsing] D2 (Mode) : Out of Range !!!" + String.format("0x%02X", Mode));
-            return null;
-        }
-
-        //          - D3 : 설정온도
-        data = Reply[index++];
-        if( (data & (byte)(BIT7)) != 0x00 )
-        {
-            // 미사용 비트'0' 확인
-            Log.w(TAG, "[GetEachRoomStatus_RepParsing] D3 (SetTemp) : Unused Bit Set !!! " + String.format("0x%02X", data));
-            return null;
-        }
-        data2 = (byte)(data & (byte)(BIT0 | BIT1 | BIT2 | BIT3 | BIT4 | BIT5));
-        if( !((data2 >= SETTEMP_MIN_LOW) && (data2 <= SETTEMP_MAX_HI)) )
-        {
-            // 설정온도 범위체크
-            Log.w(TAG, "[GetEachRoomStatus_RepParsing] D3 (SetTemp) : Out of Range !!! " + String.format("0x%02X", data2));
-            return null;
-        }
-
-        //          - D4 ~ D5 : 현재온도
-        data = Reply[index++];
-        data2 = Reply[index++];
-        double NowTemp = Converter2ByteToDoubleP1(data, data2);
-        if( !((NowTemp >= NOWTEMP_MIN) && (NowTemp <= NOWTEMP_MAX)) )
-        {
-            // 현재온도 범위체크
-            Log.w(TAG, "[GetEachRoomStatus_RepParsing] D5~D6 (NowTemp) : Out of Range !!! " + NowTemp);
-            return null;
-        }
-
-        //          - D6 : 에러코드
-        data = Reply[index++];
-        /*if( (data & (byte)(BIT6)) != 0x00 )
-        {
-            // 미사용 비트'0' 확인
-            Log.w(TAG, "[GetEachRoomStatus_RepParsing] D7 (ErrorCode) : Unused Bit Set !!! " + String.format("0x%02X", data));
-            return null;
-        }*/
-        
-        //          - D7 : 취침운전 설정값
-        data = Reply[index++];
-        if(data != 0x00)
-        {
-            if ( (byte)(data & (byte)(BIT0 | BIT1 | BIT2 | BIT3 | BIT4)) > (byte)0x13)
-            {
-                Log.w(TAG, "[GetEachRoomStatus_RepParsing] D8 (Sleep Time) : Out of Range !!! " + String.format("0x%02X", data));
-                return null;
-            }
-            if ((( (data >> 5) & (byte)(BIT5 | BIT6 | BIT7)) >> 5) > 0x03)
-            {
-                Log.w(TAG, "[GetEachRoomStatus_RepParsing] D8 (Sleep Temp) : Out of Range !!! " + String.format("0x%02X", data));
-                return null;
-            }
-        }
-
-        //          - D8~D10 : 예약설정 정보
-
-        // 2. Data return
-        index = 0;
-        data = 0x00;
-        RoomData roomData = new RoomData();
-
-        //          - D1 : 응답 방번호
-        index++;
-
-        //          - D2 : 운전모드 및 밸브상태
-        data = Reply[index++];
-        roomData.Mode = Mode;
-        if((data & BIT4) != 0x00) roomData.bValveStatus = true;
-        else roomData.bValveStatus = false;
-
-        //          - D3 : 설정온도
-        double dTemp = 0;
-        data = Reply[index++];
-        dTemp = (double)getInt( (byte)(data & (byte) (BIT0 | BIT1 | BIT2 | BIT3 | BIT4 | BIT5)));
-        if((data & BIT6) != 0x00) dTemp += (double)0.5;
-        roomData.SetTemp = Double.parseDouble(String.format("%.1f", dTemp));
-
-        //          - D4 ~ D5 : 현재온도
-        index++;
-        index++;
-        roomData.NowTemp = NowTemp;
-
-        //          - D6 : 에러코드
-        data = Reply[index++];
-        roomData.Error.setByte(data);
-
-        //          - D7 : 취침운전 설정값
-        data = Reply[index++];
-        if(data != 0x00) roomData.Sleep.setByte(data);
-
-
-        //          - D8~D10 : 예약설정 정보
-        if(mDriver.Device.info.Support.Reservation)
-        {
-            byte [] ReservationData = new byte[3];
-            ReservationData[0] = Reply[index++];
-            ReservationData[1] = Reply[index++];
-            ReservationData[2] = Reply[index++];
-            roomData.Reservation.setByte(ReservationData);
-        }
-
-        return roomData;
-    }
-
-    /**
-     * 전체방 상태 요청 응답.
-     *
-     * @return (AllRoomData) null - Error , Not null - OK
-     */
-    private AllRoomData Send_GetAllRoomStatus()
-    {
-        DeviceLog("[Send_GetAllRoomStatus] Start");
-
-        // 1. In 파라미터 확인
-
-        // 2. 패킷 데이터 만들기
-        byte [] ReqData = null;
-
-        // 3. 데이터 전송 및 응답
-        byte [] Reply = SendNRead_Variable( (byte)(DEVICE_ADDRESS), CMDList.Req.GetAllRoomStatus, ReqData);
-
-        // 4. 수신데이터 파싱
-        AllRoomData allRoomData = GetAllRoomStatus_RepParsing(Reply);
-        if(allRoomData == null)
-        {
-            DeviceLog("[Send_GetAllRoomStatus] Reply is null");
-            AddDoCount(false);
-            return null;
-        }
-        AddDoCount(true);
-
-        return allRoomData;
-    }
-
-    /**
-     * 전체방 상태 제어 응답.
-     *
-     * @param TimeSet    - (boolean) 현재시간 설정여부 (true:설정, false:미설정)
-     * @param ChangeMode - (byte)    변경할 모드
-     * @param RoomCount  - (byte)    변경할 방개수
-     *
-     * @return (AllRoomData) null - Error , Not null - OK
-     */
-    private AllRoomData Send_SetAllRoomStatus(boolean TimeSet, byte ChangeMode, byte RoomCount)
-    {
-        DeviceLog("[Send_SetAllRoomStatus] Start (" + TimeSet + " / " + ChangeMode + ")");
-
-        // 1. In 파라미터 확인
-        if(!MODE.CheckSetMode(ChangeMode))
-        {
-            Log.w(TAG, "[Send_SetAllRoomStatus] (ChangeMode) Request Param Out Of Range !!!" + String.format("0x%02X", ChangeMode));
-            return null;
-        }
-        if(ChangeMode != MODE.Idle)
-        {
-            if((RoomCount <= 0) || (RoomCount > mDriver.Device.info.RoomCount))
-            {
-                Log.w(TAG, "[Send_SetAllRoomStatus] (RoomCount) Request Param Out Of Range !!!" + String.format("0x%02X", RoomCount));
-                return null;
-            }
-        }
-
-        // 2. 패킷 데이터 만들기
-        byte [] ReqData = new byte [7];
-        for(byte i=0 ; i<ReqData.length ; i++) ReqData[i] = 0x00;
-
-        int index = 0;
-        if(TimeSet)
-        {
-            Calendar cal = new GregorianCalendar();
-            ReqData[index++] = 0x01;
-            ReqData[index++] = (byte) cal.get(Calendar.HOUR_OF_DAY);
-            ReqData[index++] = (byte) cal.get(Calendar.MINUTE);
-
-        }
-        else
-        {
-            ReqData[index++] = 0x00;
-            ReqData[index++] = 0x00;
-            ReqData[index++] = 0x00;
-        }
-
-        if(ChangeMode != MODE.Idle)
-        {
-            byte [] ModeArray = new byte [8];
-            for(byte i=0 ; i<ModeArray.length ; i++) ModeArray[i] = MODE.Idle;
-
-            for(byte i=0 ; i<RoomCount ; i++)
-            {
-                boolean IdleSet = false;
-                if(HEATINGOFF_NOSET_OUTTING)
-                {
-                    if( (ChangeMode == MODE.Outing) ||
-                            (ChangeMode == MODE.OutingRelease) )
-                    {
-                        if(mDriver.Device.Room[i].Mode == MODE.HeatingOFF) IdleSet = true;
-                    }
-                }
-
-                if(!IdleSet)
-                {
-                    ModeArray[i] = ChangeMode;
-                }
-            }
-
-            byte RoomIndex = 0;
-            byte Temp = 0;
-
-            for(int i=0 ; i<4 ; i++)
-            {
-                Temp = (byte)ModeArray[RoomIndex++];
-                Temp |= (byte)(((byte)ModeArray[RoomIndex++] << 4) & (byte)0xF0);
-                ReqData[index++] = Temp;
-            }
-        }
-        else
-        {
-            ReqData[index++] = 0x00;
-            ReqData[index++] = 0x00;
-            ReqData[index++] = 0x00;
-            ReqData[index++] = 0x00;
-        }
-
-        // 3. 데이터 전송 및 응답
-        byte [] Reply = SendNRead_Variable( (byte)(DEVICE_ADDRESS), CMDList.Req.SetAllRoomStatus, ReqData);
-
-        // 4. 수신데이터 파싱
-        AllRoomData allRoomData = GetAllRoomStatus_RepParsing(Reply);
-        if(allRoomData == null)
-        {
-            DeviceLog("[Send_SetAllRoomStatus] Reply is null");
-            AddDoCount(false);
-            return null;
-        }
-        AddDoCount(true);
-
-        return allRoomData;
-    }
-
-    /**
-     * 전체방 제어 명령을 통하여 현재 시간만 셋팅하는 경우
-     *
-     * @return - (boolean) true : 성공 , false : 실패
-     */
-    private boolean Send_NowTimeSet()
-    {
-        AllRoomData allRoomData = Send_SetAllRoomStatus(true, (byte)0x00, (byte)0x00);
-        if(allRoomData == null)
-        {
-            AddDoCount(false);
-            return false;
-        }
-        AddDoCount(true);
-
-        return true;
-    }
-
-    /**
-     * {@link #Send_GetAllRoomStatus()} <br>
-     * {@link #Send_SetAllRoomStatus(boolean, byte, byte)} <br>
-     *
-     * 메소드의 응답 공통부분 메소드이다.
-     *
-     * @param Reply      - (byte []) 응답 Byte 배열
-     *
-     * @return (AllRoomData) null - Error , Not null - OK
-     */
-    private AllRoomData GetAllRoomStatus_RepParsing(byte [] Reply)
-    {
-        // 1. 수신데이터 파싱
-        //     1.1. Default Check
-        if(Reply == null)
-        {
-            DeviceLog("[GetAllRoomStatus_RepParsing] Reply is null");
-            return null;
-        }
-        if(Reply.length < (3+4))
-        {
-            // 최소사이즈는 기본 3byte + 방1개 4byte = 7byte 이다.
-            Log.w(TAG, "[GetAllRoomStatus_RepParsing] Reply.length  fail #1... " + Reply.length);
-            return null;
-        }
-        byte RoomCount = Reply[2];
-        if( !((RoomCount >= ROOM_COUNT_LOW) && (RoomCount <= ROOM_COUNT_HI)) )
-        {
-            // 방개수 범위체크
-            Log.w(TAG, "[GetAllRoomStatus_RepParsing] RoomCount  Out Of Range !!! " + RoomCount);
-            return null;
-        }
-        if(Reply.length != (int) (3+(RoomCount*4)))
-        {
-            // 방개수에 따른 가변데이터 비교
-            Log.w(TAG, "[GetAllRoomStatus_RepParsing] Reply.length  fail #2... " + "(length:" +Reply.length + " / RoomCount:" + RoomCount + ")");
-            return null;
-        }
-        byte data = 0x00;
-        byte data2 = 0x00;
-        int index = 0;
-        //          - D1 : 현재시간 (시)
-        data = Reply[index++];
-        if((data > 23) || (data < 0))
-        {
-            Log.w(TAG, "[GetAllRoomStatus_RepParsing] D1 (Time Hour) : Out of Range !!! " + String.format("0x%02X", data));
-            return null;
-        }
-        //          - D2 : 현재시간 (분)
-        data = Reply[index++];
-        if((data > 59) || (data < 0))
-        {
-            Log.w(TAG, "[GetAllRoomStatus_RepParsing] D2 (Time Min) : Out of Range !!! " + String.format("0x%02X", data));
-            return null;
-        }
-
-        index++;
-        for(byte i=0 ; i<RoomCount ; i++)
-        {
-            //          - D1+X : 운전모드 및 밸브상태
-            data = Reply[index++];
-            if( (data & (byte)(BIT5 | BIT6 | BIT7)) != 0x00 )
-            {
-                // 미사용 비트'0' 확인
-                Log.w(TAG, "[GetAllRoomStatus_RepParsing] D" + index + " (Mode) : Unused Bit Set !!! " + String.format("0x%02X", data));
-                return null;
-            }
-            data2 = (byte)(data & (byte)(BIT0 | BIT1 | BIT2 | BIT3));
-            if(MODE.CheckGetMode(data2) == false)
-            {
-                // 운전모드 범위확인
-                Log.w(TAG, "[GetAllRoomStatus_RepParsing] D" + index + " (Mode) : Out of Range !!!" + String.format("0x%02X", data2));
-                return null;
-            }
-
-            //          - D2+X : 설정온도
-            data = Reply[index++];
-            if( (data & (byte)(BIT7)) != 0x00 )
-            {
-                // 미사용 비트'0' 확인
-                Log.w(TAG, "[GetAllRoomStatus_RepParsing] D" + index + " (SetTemp) : Unused Bit Set !!! " + String.format("0x%02X", data));
-                return null;
-            }
-            data2 = (byte)(data & (byte)(BIT0 | BIT1 | BIT2 | BIT3 | BIT4 | BIT5));
-            if( !((data2 >= SETTEMP_MIN_LOW) && (data2 <= SETTEMP_MAX_HI)) )
-            {
-                // 설정온도 범위체크
-                Log.w(TAG, "[GetAllRoomStatus_RepParsing] D" + index + " (SetTemp) : Out of Range !!! " + String.format("0x%02X", data2));
-                return null;
-            }
-
-            //          - D3+X ~ D4+X : 현재온도
-            data = Reply[index++];
-            data2 = Reply[index++];
-            double NowTemp = Converter2ByteToDoubleP1(data, data2);
-            if( !((NowTemp >= NOWTEMP_MIN) && (NowTemp <= NOWTEMP_MAX)) )
-            {
-                // 현재온도 범위체크
-                Log.w(TAG, "[GetAllRoomStatus_RepParsing] D" + (index-1) + " ~ D" + index + " (NowTemp) : Out of Range !!! " + NowTemp);
-                return null;
-            }
-        }
-
-
-        // 2. Data return
-
-        //[광주 무등한 임대세대 전용 기능]
-        if((mDriver.bFixRoomCountUse == true) && (mDriver.FixRoomCount >= ROOM_COUNT_LOW) && (mDriver.FixRoomCount <= ROOM_COUNT_HI))
-        {
-            /**
-             * [광주 무등산 임대세대 전용 기능]
-             임대세대는 에너지미터가 3개인데 벨브가 2개인 현장임
-             문제점:난방 제어화면에서 방이 3개로 나옴
-             해결:방개수 3개로 알려주면 강제로 2개로 설정함
-             필요사항:단지서버에서 온도조절기 회로수를 2개로 설정하면 됨
-             * **/
-            RoomCount = (byte) mDriver.FixRoomCount;
-        }
-
-        index = 0;
-        data = 0x00;
-        AllRoomData allRoomData = new AllRoomData(RoomCount);
-
-        index = 3;
-        for(byte i=0 ; i<RoomCount ; i++)
-        {
-            //          - D2 : 운전모드 및 밸브상태
-            data = Reply[index++];
-            allRoomData.Room[i].Mode = (byte)(data & (byte)(BIT0 | BIT1 | BIT2 | BIT3));
-            if((data & BIT4) != 0x00) allRoomData.Room[i].bValveStatus = true;
-            else allRoomData.Room[i].bValveStatus = false;
-
-            //          - D3 : 설정온도
-            double dTemp = 0;
-            data = Reply[index++];
-            dTemp = (double)getInt( (byte)(data & (byte) (BIT0 | BIT1 | BIT2 | BIT3 | BIT4 | BIT5)));
-            if((data & BIT6) != 0x00) dTemp += (double)0.5;
-            allRoomData.Room[i].SetTemp = Double.parseDouble(String.format("%.1f", dTemp));
-
-            //          - D4 ~ D5 : 현재온도
-            data = Reply[index++];
-            data2 = Reply[index++];
-            allRoomData.Room[i].NowTemp = Converter2ByteToDoubleP1(data, data2);
-        }
-
-        return allRoomData;
-    }
-
-    /**
-     * 보일러 상태 요청 응답.
-     *
-     * @return (BoilerData) null - Error , Not null - OK
-     */
-    private BoilerData Send_GetBoilerStatus()
-    {
-        DeviceLog("[Send_GetBoilerStatus] Start");
-
-        // 1. In 파라미터 확인
-
-        // 2. 패킷 데이터 만들기
-        byte [] ReqData = null;
-
-        // 3. 데이터 전송 및 응답
-        byte [] Reply = SendNRead_Variable( (byte)(DEVICE_ADDRESS), CMDList.Req.GetBoilerStatus, ReqData);
-
-        // 4. 수신데이터 파싱
-        BoilerData boilerData = BoilerStatus_ReplyParsing(Reply);
-        if(boilerData == null)
-        {
-            DeviceLog("[Send_GetBoilerStatus] Reply is null");
-            AddDoCount(false);
-            return null;
-        }
-        AddDoCount(true);
-
-        return boilerData;
-    }
-
-    /**
-     * 보일러 제어 요청 응답.
-     *
-     * @return (BoilerData) null - Error , Not null - OK
-     */
-    private BoilerData Send_SetBoilerStatus(byte HeatingWaterTemp, byte HotWaterTemp)
-    {
-        DeviceLog("[Send_SetBoilerStatus] Start (" + HeatingWaterTemp + ", " + HotWaterTemp + ")");
-
-        // 1. In 파라미터 확인
-        //      난방수 설정온도
-        if(HeatingWaterTemp != 0x00)
-        {
-            byte HeatingWaterTempMIN = mDriver.Boiler.HeatingWater.MinSetTemp;
-            byte HeatingWaterTempMAX = mDriver.Boiler.HeatingWater.MaxSetTemp;
-            if (HeatingWaterTempMIN == 0) HeatingWaterTempMIN = BOILER_HEAT_WATER_MIN;
-            if (HeatingWaterTempMAX == 0) HeatingWaterTempMAX = BOILER_HEAT_WATER_MAX;
-            if ((HeatingWaterTemp < HeatingWaterTempMIN) || (HeatingWaterTemp > HeatingWaterTempMAX))
-            {
-                Log.w(TAG, "[Send_SetBoilerStatus] (HeatingWaterTemp) Request Param Out Of Range !!!" + String.format("0x%02X", HeatingWaterTemp));
-                return null;
-            }
-        }
-        //      온수 설정온도
-        if(HotWaterTemp != 0x00)
-        {
-            byte HotWaterTempMIN = mDriver.Boiler.HotWater.MinSetTemp;
-            byte HotWaterTempMAX = mDriver.Boiler.HotWater.MaxSetTemp;
-            if (HotWaterTempMIN == 0) HotWaterTempMIN = BOILER_HOT_WATER_MIN;
-            if (HotWaterTempMAX == 0) HotWaterTempMAX = BOILER_HOT_WATER_MAX;
-            if ((HotWaterTemp < HotWaterTempMIN) || (HotWaterTemp > HotWaterTempMAX))
-            {
-                Log.w(TAG, "[Send_SetBoilerStatus] (HotWaterTemp) Request Param Out Of Range !!!" + String.format("0x%02X", HotWaterTemp));
-                return null;
-            }
-        }
-
-        // 2. 패킷 데이터 만들기
-        byte [] ReqData = new byte [] { HeatingWaterTemp, HotWaterTemp };
-
-        // 3. 데이터 전송 및 응답
-        byte [] Reply = SendNRead_Variable( (byte)(DEVICE_ADDRESS), CMDList.Req.SetBoilerStatus, ReqData);
-
-        // 4. 수신데이터 파싱
-        BoilerData boilerData = BoilerStatus_ReplyParsing(Reply);
-        if(boilerData == null)
-        {
-            DeviceLog("[Send_SetBoilerStatus] Reply is null");
-            AddDoCount(false);
-            return null;
-        }
-        AddDoCount(true);
-
-        return boilerData;
-    }
-
-    /**
-     * {@link #Send_GetBoilerStatus()} <br>
-     * {@link #Send_SetBoilerStatus(byte, byte)} <br>
-     *
-     * 메소드의 응답 공통부분 메소드이다.
-     *
-     * @param Reply      - (byte []) 응답 Byte 배열
-     *
-     * @return (BoilerData) null - Error , Not null - OK
-     */
-    private BoilerData BoilerStatus_ReplyParsing(byte [] Reply)
-    {
-        // 1. 수신데이터 파싱
-        //     1.1. Default Check
-        if(Reply == null)
-        {
-            DeviceLog("[BoilerStatus_ReplyParsing] Reply is null");
-            return null;
-        }
-        if(Reply.length != 8)
-        {
-            // 길이 체크
-            Log.w(TAG, "[BoilerStatus_ReplyParsing] Reply.length  fail ... " + Reply.length);
-            return null;
-        }
-
-
-        byte data = 0x00;
-        int index = 0;
-
-        //          - D1 : 보일러모드
-        data = Reply[index++];
-        if ((data & (byte)(BIT6 | BIT7)) != 0x00)
-        {
-            // 미사용 비트'0' 확인
-            Log.w(TAG, "[BoilerStatus_ReplyParsing] D1 (Mode) : Unused Bit Set !!! " + String.format("0x%02X", data));
-            return null;
-        }
-        //     동파방지모드
-        switch (data & (byte)(BIT0 | BIT1))
-        {
-            case 0x01:      // 가동
-            case 0x02:      // 정지
-                break;
-            default:
-                Log.w(TAG, "[BoilerStatus_ReplyParsing] D1 (FrostProtectMode) : Out of Range !!! " + String.format("0x%02X", data));
-                return null;
-        }
-        //     난방수 설정온도 단위
-        switch ((data>>2) & (byte)(BIT0 | BIT1))
-        {
-            case 0x00:      // 1℃ 단위
-            case 0x01:      // 5℃ 단위
-                break;
-            default:
-                Log.w(TAG, "[BoilerStatus_ReplyParsing] D1 (HeatingWater) : Out of Range !!! " + String.format("0x%02X", data));
-                return null;
-        }
-        //     온수 설정온도 단위
-        switch ((data>>4) & (byte)(BIT0 | BIT1))
-        {
-            case 0x00:      // 1℃ 단위
-            case 0x01:      // 5℃ 단위
-                break;
-            default:
-                Log.w(TAG, "[BoilerStatus_ReplyParsing] D1 (HotWater) : Out of Range !!! " + String.format("0x%02X", data));
-                return null;
-        }
-        byte MinTemp = 0;
-        byte MaxTemp = 0;
-        //          - D2 : 난방수 최저 설정온도 (30도~89도)
-        MinTemp = Reply[index++];
-        if( !((MinTemp >= BOILER_HEAT_WATER_MIN) && (MinTemp <= (BOILER_HEAT_WATER_MAX-1))) )
-        {
-            Log.w(TAG, "[BoilerStatus_ReplyParsing] D2 (HeatingWater.MinSetTemp) : Out of Range !!! " + String.format("0x%02X", MinTemp));
-            return null;
-        }
-        //          - D3 : 난방수 최저 설정온도 (30도~89도)
-        MaxTemp = Reply[index++];
-        if( !((MaxTemp >= (BOILER_HEAT_WATER_MIN+1)) && (MaxTemp <= BOILER_HEAT_WATER_MAX)) )
-        {
-            Log.w(TAG, "[BoilerStatus_ReplyParsing] D3 (HeatingWater.MaxSetTemp) : Out of Range !!! " + String.format("0x%02X", MaxTemp));
-            return null;
-        }
-        //          - 예외상황 : 최저 설정온도가 최대설정온도보다 높을수는 없음
-        if (MinTemp > MaxTemp)
-        {
-            Log.w(TAG, "[BoilerStatus_ReplyParsing] D2~D3:HeatingWater The MinTemp is Higher!!!  Out of Range (MinTemp : " + MinTemp + ", MaxTemp : " + MaxTemp + ")");
-            return null;
-        }
-        //          - D4 : 난방수 설정온도 (MinTemp ~ MaxTemp)
-        data = Reply[index++];
-        if ((data < MinTemp) || (data > MaxTemp))
-        {
-            Log.w(TAG, "[BoilerStatus_ReplyParsing] D4 (HeatingWater.SetTemp) : Out of Range !!! " + "(Min:" + MinTemp + " / " + "Max:" + MaxTemp + " / Set:" + data + ")");
-            return null;
-        }
-
-        //          - D5 : 온수 최저 설정온도 (30도~89도)
-        MinTemp = Reply[index++];
-        if( !((MinTemp >= BOILER_HOT_WATER_MIN) && (MinTemp <= (BOILER_HOT_WATER_MAX-1))) )
-        {
-            Log.w(TAG, "[BoilerStatus_ReplyParsing] D5 (HotWater.MinSetTemp) : Out of Range !!! " + String.format("0x%02X", MinTemp));
-            return null;
-        }
-        //          - D6 : 온수 최저 설정온도 (30도~89도)
-        MaxTemp = Reply[index++];
-        if( !((MaxTemp >= (BOILER_HOT_WATER_MIN+1)) && (MaxTemp <= BOILER_HOT_WATER_MAX)) )
-        {
-            Log.w(TAG, "[BoilerStatus_ReplyParsing] D6 (HotWater.MaxSetTemp) : Out of Range !!! " + String.format("0x%02X", MaxTemp));
-            return null;
-        }
-        //          - 예외상황 : 최저 설정온도가 최대설정온도보다 높을수는 없음
-        if (MinTemp > MaxTemp)
-        {
-            Log.w(TAG, "[BoilerStatus_ReplyParsing] D5~D6:HotWater The MinTemp is Higher!!!  Out of Range (MinTemp : " + MinTemp + ", MaxTemp : " + MaxTemp + ")");
-            return null;
-        }
-        //          - D7 : 온수 설정온도 (MinTemp ~ MaxTemp)
-        data = Reply[index++];
-        if ((data < MinTemp) || (data > MaxTemp))
-        {
-            Log.w(TAG, "[BoilerStatus_ReplyParsing] D7 (HotWater.SetTemp) : Out of Range !!! " + "(Min:" + MinTemp + " / " + "Max:" + MaxTemp + " / Set:" + data + ")");
-            return null;
-        }
-
-        //      - D8 : 보일러 에러코드
-        //data = Reply[index++];
-
-
-        // 2. Data return
-        index = 0;
-        BoilerData boilerData = new BoilerData();
-
-        data = Reply[index++];
-        if( (byte)(data & (byte)(BIT0 | BIT1)) == (byte)0x01) boilerData.bFrostProtectMode = true;
-        else boilerData.bFrostProtectMode = false;
-        if( (byte)(data & (byte)(BIT2 | BIT3)) == (byte)0x00) boilerData.HeatingWater.bSetTempUnit5 = false;
-        else boilerData.HeatingWater.bSetTempUnit5 = true;
-        if( (byte)(data & (byte)(BIT4 | BIT5)) == (byte)0x00) boilerData.HotWater.bSetTempUnit5 = false;
-        else boilerData.HotWater.bSetTempUnit5 = true;
-
-        boilerData.HeatingWater.MinSetTemp = Reply[index++];
-        boilerData.HeatingWater.MaxSetTemp = Reply[index++];
-        boilerData.HeatingWater.SetTemp    = Reply[index++];
-
-        boilerData.HotWater.MinSetTemp = Reply[index++];
-        boilerData.HotWater.MaxSetTemp = Reply[index++];
-        boilerData.HotWater.SetTemp    = Reply[index++];
-
-        boilerData.ErrorCode = Reply[index++];
-
-        return boilerData;
-    }
-
-    /**
-     * 특화기능 상태 요청 응답.
-     *
-     * @return (SpecialFuncData) null - Error , Not null - OK
-     */
-    private SpecialFuncData Send_GetSpecialFuncStatus()
-    {
-        DeviceLog("[Send_GetSpecialFuncStatus] Start");
-
-        // 1. In 파라미터 확인
-
-        // 2. 패킷 데이터 만들기
-        byte [] ReqData = null;
-
-        // 3. 데이터 전송 및 응답
-        byte [] Reply = SendNRead_Variable( (byte)(DEVICE_ADDRESS), CMDList.Req.GetSpecialFuncStatus, ReqData);
-
-        // 4. 수신데이터 파싱
-        SpecialFuncData specialFuncData = SpecialFunc_ReplyParsing(Reply);
-        if(specialFuncData == null)
-        {
-            DeviceLog("[Send_GetSpecialFuncStatus] Reply is null");
-            AddDoCount(false);
-            return null;
-        }
-        AddDoCount(true);
-
-        return specialFuncData;
-    }
-
-    /**
-     * 특화기능 제어 요청 응답.
-     *
-     * @return (SpecialFuncData) null - Error , Not null - OK
-     */
-    private SpecialFuncData Send_SetSpecialFuncStatus(boolean bSetOutsideTemp, int OutsideTemp, byte AiMode)
-    {
-        DeviceLog("[Send_SetSpecialFuncStatus] Start");
-
-        // 1. In 파라미터 확인
-        if(bSetOutsideTemp)
-        {
-            if (OutsideTemp > 60)
-            {
-                Log.w(TAG, "[Send_SetSpecialFuncStatus] - OutsideTemp Out of Range 1 (" + OutsideTemp + ")");
-                return null;
-            }
-            if (OutsideTemp < -60)
-            {
-                Log.w(TAG, "[Send_SetSpecialFuncStatus] - OutsideTemp Out of Range 2 (" + OutsideTemp + ")");
-                return null;
-            }
-        }
-        if( (AiMode != SpecialFuncData.AIMODE.Idle) &&
-                (AiMode != SpecialFuncData.AIMODE.ON) &&
-                (AiMode != SpecialFuncData.AIMODE.OFF) )
-        {
-            Log.w(TAG, "[Send_SetSpecialFuncStatus] - AiMode Out of Range !!! (" + String.format("0x%02X", AiMode) + ")");
-            return null;
-        }
-
-        // 2. 패킷 데이터 만들기
-        byte [] ReqData = new byte [5];
-        for(int i=0 ; i<ReqData.length ; i++) ReqData[i] = 0x00;
-
-        if(bSetOutsideTemp)
-        {
-            ReqData[0] = 0x01;
-
-            byte Temp = 0x00;
-            if (OutsideTemp >= 0)
-            {
-                // 0도 ~ +60도
-                Temp = (byte)OutsideTemp;
-            }
-            else
-            {
-                // -1도 ~ -60도
-                OutsideTemp = (~OutsideTemp) + 1;       // 음수를 양수로 변환
-                Temp = (byte)OutsideTemp;               // 온도넣기
-                Temp |= BIT7;                           // 음수표시
-            }
-            ReqData[1] = Temp;
-        }
-
-        ReqData[2] = AiMode;
-
-        // 3. 데이터 전송 및 응답
-        byte [] Reply = SendNRead_Variable( (byte)(DEVICE_ADDRESS), CMDList.Req.SetSpecialFuncStatus, ReqData);
-
-        // 4. 수신데이터 파싱
-        SpecialFuncData specialFuncData = SpecialFunc_ReplyParsing(Reply);
-        if(specialFuncData == null)
-        {
-            DeviceLog("[Send_SetSpecialFuncStatus] Reply is null");
-            AddDoCount(false);
-            return null;
-        }
-        AddDoCount(true);
-
-        return specialFuncData;
-    }
-
-    /**
-     * {@link #Send_GetSpecialFuncStatus()} <br>
-     * {@link #Send_SetSpecialFuncStatus(boolean, int, byte)} <br>
-     *
-     * 메소드의 응답 공통부분 메소드이다.
-     *
-     * @param Reply      - (byte []) 응답 Byte 배열
-     *
-     * @return (SpecialFuncData) null - Error , Not null - OK
-     */
-    private SpecialFuncData SpecialFunc_ReplyParsing(byte [] Reply)
-    {
-        // 1. 수신데이터 파싱
-        //     1.1. Default Check
-        if(Reply == null)
-        {
-            DeviceLog("[SpecialFunc_ReplyParsing] Reply is null");
-            return null;
-        }
-        if(Reply.length != 4)
-        {
-            // 길이 체크
-            Log.w(TAG, "[SpecialFunc_ReplyParsing] Reply.length  fail ... " + Reply.length);
-            return null;
-        }
-
-        byte data = 0x00;
-        byte data2 = 0x00;
-        int index = 0;
-
-        //          - D1 : 외기온도
-        data = Reply[index++];
-        data2 = (byte)(data & (byte)(BIT5 | BIT4 | BIT3 | BIT2 | BIT1 | BIT0));
-        if (data2 > 60)
-        {
-            // 온도범위체크
-
-            Log.w(TAG, "[SpecialFunc_ReplyParsing] D1 (OutsideTemp) : Out Of Range !!! " + String.format("0x%02X", data2));
-            return null;
-        }
-
-        //          - D2 : 인공지능모드
-        data = Reply[index++];
-        if( (data != SpecialFuncData.AIMODE.ON) &&
-                (data != SpecialFuncData.AIMODE.OFF) )
-        {
-            Log.w(TAG, "[SpecialFunc_ReplyParsing] D2 (AI Mode) : Out Of Range !!! " + String.format("0x%02X", data));
-            return null;
-        }
-
-        // 2. Data return
-        index = 0;
-        SpecialFuncData specialFuncData = new SpecialFuncData();
-
-        data = Reply[index++];
-        double OutsideTemp = (double)(data & (byte)(BIT5 | BIT4 | BIT3 | BIT2 | BIT1 | BIT0));
-        if((data & BIT6) != 0x00) OutsideTemp += 0.5;
-        if((data & BIT7) != 0x00) OutsideTemp *= -1;
-        specialFuncData.OutsideTemp = OutsideTemp;
-
-        data = Reply[index++];
-        specialFuncData.Mode = data;
-
-        return specialFuncData;
-    }
-
-    /** 명령어 리스트 */
-    public static class CMDList
-    {
-        /** 요청 */
-        public static final class Req
-        {
-            /////////////////////////////////////////////////////////
-            // Board
-            /////////////////////////////////////////////////////////
-            /** 기기 상태 읽기 요청 */
-            public final static byte GetDeviceInfo        = 0x01;
-
-            /////////////////////////////////////////////////////////
-            // 개별방
-            /////////////////////////////////////////////////////////
-            /** 각방 상태 요청 */
-            public final static byte GetEachRoomStatus    = 0x11;
-            /** 각방 제어 요청 */
-            public final static byte SetEachRoomStatus    = 0x12;
-
-            /////////////////////////////////////////////////////////
-            // 전체방
-            /////////////////////////////////////////////////////////
-            /** 전체방 상태 요청 */
-            public final static byte GetAllRoomStatus     = 0x21;
-            /** 전체방 제어 요청 */
-            public final static byte SetAllRoomStatus     = 0x22;
-
-            /////////////////////////////////////////////////////////
-            // 보일러
-            /////////////////////////////////////////////////////////
-            /** 보일러 상태 요청 */
-            public final static byte GetBoilerStatus      = 0x31;
-            /** 보일러 제어 요청 */
-            public final static byte SetBoilerStatus      = 0x32;
-
-            /////////////////////////////////////////////////////////
-            // 특화기능
-            /////////////////////////////////////////////////////////
-            /** 특화기능 상태 요청 */
-            public final static byte GetSpecialFuncStatus = 0x41;
-            /** 특화기능 제어 요청 */
-            public final static byte SetSpecialFuncStatus = 0x42;
-        }
-    }
-
-    /**
-     * 현재온도 동기화<br>
-     * DB에 저장되어있는 날씨 정보를 가져와서 밸브제어기에 현재온도를 전송한다.
-     *
-     * @return (int) - >=0 : 성공, <0 : 실패
-     */
-    private int OutsideTempUpdate()
-    {
-        DeviceLog("OutsideTempUpdate");
-
-        try
-        {
-            WallpadStatusData DBMGR = new WallpadStatusData(ServiceMain.svcContext);
-            String[] WeatherVer = DBMGR.GetWeatherVer().split(define.DEVCTR_DATA_SPLITER);
-            WeatherTable WeatherTBL = DBMGR.GetWeatherTableController();
-            WeatherTBL.GetWeatherList();
-            DBMGR.closeDB();
-            String[] weatherdate = WeatherVer[0].split("[.]");
-            if (weatherdate.length < 4 || WeatherVer.length < 3)
-            {
-                Log.w(TAG, "[OutsideTempUpdate] length Error (" + "weatherdate.length:" + weatherdate.length + " , WeatherVer.length:" + WeatherVer.length + ")");
-                return -1;
-            }
-
-            Calendar cal = new GregorianCalendar();
-            int month = cal.get(Calendar.MONTH)+1;
-            int date  = cal.get(Calendar.DAY_OF_MONTH);
-
-            int WeatherMonth =  Integer.parseInt(weatherdate[1]);
-            int WeatherDate  =  Integer.parseInt(weatherdate[2]);
-            if( (WeatherMonth == month) && (WeatherDate == date) )
-            {
-                String TempStr = WeatherVer[5];
-                int Temp = 0;
-
-                if (TempStr==null)
-                {
-                    Log.w(TAG, "[OutsideTempUpdate] TempStr is null");
-                    return -4;
-                }
-
-                try
-                {
-                    Temp = Integer.parseInt(TempStr);
-                }
-                catch (RuntimeException re) {
-                    LogUtil.errorLogInfo("", TAG, re);
-                    return -5;
-                }
-                catch (Exception e) {
-                    Log.e(TAG, "[Exception Error] OutsideTempUpdate - Temp Converter");
-                    //e.printStackTrace();
-                    LogUtil.errorLogInfo("", TAG, e);
-                    return -5;
-                }
-
-                if( !((Temp <= 60) && (Temp >= -60)) )
-                {
-                    Log.w(TAG, "[OutsideTempUpdate] Temp  Out Of Range !!! (" + Temp + ")");
-                    return -6;
-                }
-
-                SpecialFuncData specialFuncData = Send_SetSpecialFuncStatus(true, Temp, SpecialFuncData.AIMODE.Idle);
-                if(specialFuncData == null)
-                {
-                    Log.w(TAG, "[OutsideTempUpdate] Send_SetSpecialFuncStatus  ret null!!!");
-                    return -7;
-                }
-
-                return 0;
-            }
-            else
-            {
-                Log.w(TAG, "[OutsideTempUpdate] Month/Date Not Equals (Weather : " + WeatherMonth + "-" + WeatherDate + " / Calendar:" + month + "-" + date + ")");
-                return -3;
-            }
-        }
-        catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-            return -2;
-        }
-        catch (Exception e) {
-            Log.e(TAG, "[Exception Error] OutsideTempUpdate");
-            //e.printStackTrace();
-            LogUtil.errorLogInfo("", TAG, e);
-            return -2;
-        }
-    }
-
-    /**
-     * 기기정보 데이터를 업데이트 한다.
-     *
-     * @param info  - (Info) 업데이트할 각방데이터
-     *
-     * @return (boolean) 데이터 변경여부 (true:변경 , false:미변경)
-     */
-    private boolean UpdateVariables(Info info)
-    {
-        if(info == null) return false;
-        if(mDriver.Device.info == null) return false;
-
-        Info DriverInfo = mDriver.Device.info;
-        boolean bChanged = false;
-        long ErrorCode = 0;
-        if(DriverInfo.RoomCount != info.RoomCount) { bChanged = true; ErrorCode |= 0x1; }
-        if(DriverInfo.Vender != info.Vender)       { bChanged = true; ErrorCode |= 0x2; }
-
-        if(DriverInfo.FwVer_Year != info.FwVer_Year) { bChanged = true; ErrorCode |= 0x4; }
-        if(DriverInfo.FwVer_Month != info.FwVer_Month) { bChanged = true; ErrorCode |= 0x8; }
-        if(DriverInfo.FwVer_Day != info.FwVer_Day) { bChanged = true; ErrorCode |= 0x10; }
-        if(DriverInfo.FwVer_Number != info.FwVer_Number) { bChanged = true; ErrorCode |= 0x20; }
-
-        if(DriverInfo.ProtocolVer_Main != info.ProtocolVer_Main) { bChanged = true; ErrorCode |= 0x40; }
-        if(DriverInfo.ProtocolVer_Sub != info.ProtocolVer_Sub) { bChanged = true; ErrorCode |= 0x80; }
-
-        if(DriverInfo.Support.MinSetTemp != info.Support.MinSetTemp) { bChanged = true; ErrorCode |= 0x100; }
-        if(DriverInfo.Support.MaxSetTemp != info.Support.MaxSetTemp) { bChanged = true; ErrorCode |= 0x200; }
-        if(DriverInfo.Support.SetTempPoint05 != info.Support.SetTempPoint05) { bChanged = true; ErrorCode |= 0x400; }
-        if(DriverInfo.Support.Outing != info.Support.Outing) { bChanged = true; ErrorCode |= 0x800; }
-        if(DriverInfo.Support.Sleep != info.Support.Sleep) { bChanged = true; ErrorCode |= 0x1000; }
-        if(DriverInfo.Support.Reservation != info.Support.Reservation) { bChanged = true; ErrorCode |= 0x2000; }
-        if(DriverInfo.Support.Pause != info.Support.Pause) { bChanged = true; ErrorCode |= 0x4000; }
-        if(DriverInfo.Support.AI != info.Support.AI) { bChanged = true; ErrorCode |= 0x8000; }
-        if(DriverInfo.Support.OutsideTempUse != info.Support.OutsideTempUse) { bChanged = true; ErrorCode |= 0x10000; }
-        if(DriverInfo.Support.Boiler != info.Support.Boiler) { bChanged = true; ErrorCode |= 0x20000; }
-
-        if(bChanged)
-        {
-            Log.i(TAG, "*****************************************************");
-            Log.i(TAG, "Warning !!!!  Device Change - Info Change... " + String.format("[%08X]", ErrorCode));
-            Log.i(TAG, "*****************************************************");
-
-            mDriver = new Driver();
-            mDriver.Device.info = info;
-        }
-
-        return bChanged;
-    }
-
-    /**
-     * 각방 데이터를 업데이트 한다.
-     *
-     * @param RoomIndex - (byte) 요청 방인덱스
-     * @param roomData  - (RoomData) 업데이트할 각방데이터
-     *
-     * @return (boolean) 데이터 변경여부 (true:변경 , false:미변경)
-     */
-    private boolean UpdateVariables(byte RoomIndex, HeatingV2.RoomData roomData)
-    {
-        if(mDriver.Device.Room == null) return false;
-        if(mDriver.Device.Room.length <= (int)RoomIndex) return false;
-        if(roomData == null) return false;
-
-        boolean bChanged = false;
-        HeatingV2.RoomData DriverRoomData = mDriver.Device.Room[RoomIndex];
-
-        ////////////////////////////////////////////////////////////////////////////
-        // 예약운전 시간 월패드 저장모드
-        ////////////////////////////////////////////////////////////////////////////
-        if (MODE_RESERVATION_SET_WALLPAD_SAVE == true)
-        {
-            if (DriverRoomData.Mode == MODE.Reservation)
-            {
-                // 예약운전 일시, 예약 스케쥴러가 다를경우
-                if (DriverRoomData.Reservation.getInt() != roomData.Reservation.getInt())
-                {
-                    // 스케쥴러 셋팅
-                    Log.i(TAG, "+++++++++++++++++++++++++++++++++++++++++++++++++++");
-                    Log.i(TAG, "UpdateVariables - EachRoom - Send_ReservationSettingInfo - RoomNumber:"
-                            + (byte)(RoomIndex+1) + " / Restore");
-                    Log.i(TAG, "+++++++++++++++++++++++++++++++++++++++++++++++++++");
-                    Send_ReservationSettingInfo(RoomIndex, false, false);
-                }
-            }
-            else
-            {
-                // 예약운전 아닐시, 예약셋팅값이 있을 경우
-                if (roomData.Reservation.getInt() != 0)
-                {
-                    // 초기화로 다시 셋팅
-                    Log.i(TAG, "+++++++++++++++++++++++++++++++++++++++++++++++++++");
-                    Log.i(TAG, "UpdateVariables - EachRoom - Send_ReservationSettingInfo - RoomNumber:"
-                            + (byte)(RoomIndex+1) + " / Reset!!!");
-                    Log.i(TAG, "+++++++++++++++++++++++++++++++++++++++++++++++++++");
-
-                    boolean bPauseRelease = false;
-                    if (roomData.Mode != MODE.Pause) bPauseRelease = true;
-                    Send_ReservationSettingInfo(RoomIndex, true, bPauseRelease);
-                }
-            }
-
-            // 통신으로 응답받은 예약스케쥴은 저장된값으로 변경함.
-            roomData.Reservation.setInt(DriverRoomData.Reservation.getInt());
-        }
-        ////////////////////////////////////////////////////////////////////////////
-
-
-        // 데이터 비교
-        if(DriverRoomData.Mode != roomData.Mode) 
-        {
-        	Log.i(TAG, "[UpdateVariables - room] - change true #1");
-        	bChanged = true;
-        }
-        if(DriverRoomData.bValveStatus != roomData.bValveStatus) 
-        {
-        	Log.i(TAG, "[UpdateVariables - room] - change true #2");
-        	bChanged = true;
-        }
-        if(DriverRoomData.SetTemp != roomData.SetTemp)
-        {
-        	Log.i(TAG, "[UpdateVariables - room] - change true #3");
-        	bChanged = true;
-        }
-        if(DriverRoomData.NowTemp != roomData.NowTemp)
-        {
-        	Log.i(TAG, "[UpdateVariables - room] - change true #4");
-        	bChanged = true;
-        }
-        if(DriverRoomData.Error.getByte() != roomData.Error.getByte())
-        {
-        	Log.i(TAG, "[UpdateVariables - room] - change true #5");
-        	
-        	Log.i(TAG, "OLD =====================");
-        	Log.i(TAG, DriverRoomData.Error.ToDebugString());
-        	Log.i(TAG, "NEW =====================");
-        	Log.i(TAG, roomData.Error.ToDebugString());
-        	
-        	
-        	bChanged = true;
-        }
-        
-        if(!bChanged)
-        {
-            if(mDriver.Device.info.Support.Sleep)
-            {
-                if(DriverRoomData.Sleep.getByte() != roomData.Sleep.getByte()) bChanged = true;
-            }
-            if(mDriver.Device.info.Support.Reservation)
-            {
-                byte [] Old = DriverRoomData.Reservation.getByte();
-                byte [] New = roomData.Reservation.getByte();
-                if((Old != null) && (New != null))
-                {
-                    for(int i=0 ; i<Old.length ; i++)
-                    {
-                        if(Old[i] != New[i]) { bChanged = true; break; }
-                    }
-                }
-            }
-        }
-
-        if(bChanged)
-        {
-            DeviceLog("OLD =====================");
-            DeviceLog(DriverRoomData.ToDebugString(RoomIndex));
-            DeviceLog("NEW =====================");
-            DeviceLog(roomData.ToDebugString(RoomIndex));
-            
-            CheckLeakError(roomData);
-            mDriver.Device.Room[RoomIndex] = roomData;
-            StatusChanged(RoomIndex);
-            DeviceLog("UpdateVariables !!!! *************************************** " + "RoomData - " + (byte)(RoomIndex+1));
-        }
-
-        return bChanged;
-    }
-
-    /**
-     * 전체방 데이터를 업데이트 한다.
-     *
-     * @param allRoomData  - (AllRoomData) 업데이트할 전체방데이터
-     *
-     * @return (boolean) 데이터 변경여부 (true:변경 , false:미변경)
-     */
-    private boolean UpdateVariables(AllRoomData allRoomData)
-    {
-        if(allRoomData == null) return false;
-
-        ////////////////////////////////////////////////////////////////////////////
-        // 예약운전 시간 월패드 저장모드
-        ////////////////////////////////////////////////////////////////////////////
-        if (MODE_RESERVATION_SET_WALLPAD_SAVE == true)
-        {
-            for (byte RoomIndex = 0; RoomIndex < allRoomData.RoomCount ; RoomIndex++)
-            {
-                RoomData DriverRoomData = mDriver.Device.Room[RoomIndex];
-
-                if ((allRoomData.Room[RoomIndex].Mode == MODE.Reservation) && (DriverRoomData.Mode != MODE.Reservation))
-                {
-                    // 새로운상태가 예약운전, 이전상태가 예약운전 아님일시
-
-                    // 스케쥴러 셋팅
-                    Log.i(TAG, "+++++++++++++++++++++++++++++++++++++++++++++++++++");
-                    Log.i(TAG, "UpdateVariables - AllRoom - Send_ReservationSettingInfo - RoomNumber:"
-                            + (byte)(RoomIndex+1) + " / Restore");
-                    Log.i(TAG, "+++++++++++++++++++++++++++++++++++++++++++++++++++");
-                    Send_ReservationSettingInfo(RoomIndex, false, false);
-                }
-                else if ((allRoomData.Room[RoomIndex].Mode != MODE.Reservation) && (DriverRoomData.Mode == MODE.Reservation))
-                {
-                    // 새로운상태가 예약운전아님, 이전상태가 예약운전 일시
-
-                    // 초기화로 다시 셋팅
-                    Log.i(TAG, "+++++++++++++++++++++++++++++++++++++++++++++++++++");
-                    Log.i(TAG, "UpdateVariables - AllRoom - Send_ReservationSettingInfo - RoomNumber:"
-                            + (byte)(RoomIndex+1) + " / Reset!!!");
-                    Log.i(TAG, "+++++++++++++++++++++++++++++++++++++++++++++++++++");
-
-                    boolean bPauseRelease = false;
-                    if (allRoomData.Room[RoomIndex].Mode != MODE.Pause) bPauseRelease = true;
-                    Send_ReservationSettingInfo(RoomIndex, true, bPauseRelease);
-                }
-            }
-        }
-        ////////////////////////////////////////////////////////////////////////////
-
-        if(mDriver.Device.info.RoomCount != allRoomData.RoomCount)
-        {
-            Log.w(TAG, "*****************************************************");
-            Log.w(TAG, "Warning !!!!  Device Change - RoomCount Change... (OLD:" + mDriver.Device.info.RoomCount + " / NOW:" + allRoomData.RoomCount + ")");
-            Log.w(TAG, "*****************************************************");
-
-            mDriver = new Driver();
-            return true;
-        }
-
-        boolean bChanged = false;
-        byte RoomIndex = define.DEVICE_ALL_OR_NOTHING;
-        boolean bAllRoomChanged = false;
-
-        for(byte i=0 ; i<allRoomData.RoomCount ; i++)
-        {
-            boolean bRoomChangedCheck = false;
-            if(mDriver.Device.Room[i].bValveStatus != allRoomData.Room[i].bValveStatus)
-            {
-                mDriver.Device.Room[i].bValveStatus = allRoomData.Room[i].bValveStatus;
-                bChanged = true;
-                bRoomChangedCheck = true;
-            }
-            if(mDriver.Device.Room[i].Mode != allRoomData.Room[i].Mode)
-            {
-                mDriver.Device.Room[i].Mode = allRoomData.Room[i].Mode;
-                bChanged = true;
-                bRoomChangedCheck = true;
-            }
-            if(mDriver.Device.Room[i].NowTemp != allRoomData.Room[i].NowTemp)
-            {
-                mDriver.Device.Room[i].NowTemp = allRoomData.Room[i].NowTemp;
-                bChanged = true;
-                bRoomChangedCheck = true;
-            }
-            if(mDriver.Device.Room[i].SetTemp != allRoomData.Room[i].SetTemp)
-            {
-                mDriver.Device.Room[i].SetTemp = allRoomData.Room[i].SetTemp;
-                bChanged = true;
-                bRoomChangedCheck = true;
-            }
-            if(bRoomChangedCheck)
-            {
-                if(RoomIndex == define.DEVICE_ALL_OR_NOTHING) RoomIndex = i;
-                else bAllRoomChanged = true;
-            }
-        }
-
-        if(bChanged)
-        {
-            if(bAllRoomChanged) StatusChanged(define.DEVICE_ALL_OR_NOTHING);
-            else StatusChanged(RoomIndex);
-            DeviceLog("UpdateVariables !!!! *************************************** " + "AllRoomData");
-        }
-
-        return bChanged;
-    }
-
-    /**
-     * 보일러 데이터를 업데이트 한다.
-     *
-     * @param boilerData - (BoilerData) 업데이트할 보일러데이터
-     *
-     * @return (boolean) 데이터 변경여부 (true:변경 , false:미변경)
-     */
-    private boolean UpdateVariables(BoilerData boilerData)
-    {
-        if(!mDriver.Device.info.Support.Boiler) return false;
-        if(boilerData == null) return false;
-        if(mDriver.Boiler == null) return false;
-
-        boolean bChanged = false;
-
-        if(mDriver.Boiler.bFrostProtectMode != boilerData.bFrostProtectMode) bChanged = true;
-        if(mDriver.Boiler.ErrorCode != boilerData.ErrorCode) bChanged = true;
-
-        if(mDriver.Boiler.HeatingWater.bSetTempUnit5 != boilerData.HeatingWater.bSetTempUnit5) bChanged = true;
-        if(mDriver.Boiler.HeatingWater.SetTemp != boilerData.HeatingWater.SetTemp) bChanged = true;
-        if(mDriver.Boiler.HeatingWater.MaxSetTemp != boilerData.HeatingWater.MaxSetTemp) bChanged = true;
-        if(mDriver.Boiler.HeatingWater.MinSetTemp != boilerData.HeatingWater.MinSetTemp) bChanged = true;
-
-        if(mDriver.Boiler.HotWater.bSetTempUnit5 != boilerData.HotWater.bSetTempUnit5) bChanged = true;
-        if(mDriver.Boiler.HotWater.SetTemp != boilerData.HotWater.SetTemp) bChanged = true;
-        if(mDriver.Boiler.HotWater.MaxSetTemp != boilerData.HotWater.MaxSetTemp) bChanged = true;
-        if(mDriver.Boiler.HotWater.MinSetTemp != boilerData.HotWater.MinSetTemp) bChanged = true;
-
-        if(bChanged)
-        {
-            mDriver.Boiler = boilerData;
-            StatusChanged(REFRESH_IDX.BOILER);
-            DeviceLog("UpdateVariables !!!! *************************************** " + "BoilerData");
-            DeviceLog(mDriver.Boiler.ToDebugString());
-        }
-
-        return bChanged;
-    }
-
-    /**
-     * 특화기능 데이터를 업데이트 한다.
-     *
-     * @param specialFuncData - (SpecialFuncData) 업데이트할 특화기능데이터
-     *
-     * @return (boolean) 데이터 변경여부 (true:변경 , false:미변경)
-     */
-    private boolean UpdateVariables(SpecialFuncData specialFuncData)
-    {
-        if(!mDriver.Device.info.Support.AI) return false;
-        if(specialFuncData == null) return false;
-        if(mDriver.SpecialFunc == null) return false;
-
-        boolean bChanged = false;
-
-        if(mDriver.SpecialFunc.Mode != specialFuncData.Mode) bChanged = true;
-        if(mDriver.SpecialFunc.OutsideTemp != specialFuncData.OutsideTemp) bChanged = true;
-
-        if(bChanged)
-        {
-            mDriver.SpecialFunc = specialFuncData;
-            StatusChanged(REFRESH_IDX.SPECIALFUNC);
-            DeviceLog("UpdateVariables !!!! *************************************** " + "SpecialFuncData");
-            DeviceLog(mDriver.SpecialFunc.ToDebugString());
-        }
-
-        return bChanged;
-    }
-
-    /**
-     * 모드 설정값의 범위를 체크한다.
-     *
-     * @param Mode - (byte) 범위체크할 모드
-     *
-     * @return (int) - >=0 : 성공, <0 : 실패
-     */
-    private int CheckSetMode(byte Mode)
-    {
-        if(!MODE.CheckSetMode(Mode))
-        {
-            DeviceLog("[CheckSetMode]" + "[Mode] Out Of Range (" + Mode + ")");
-            return -1;
-        }
-
-        if((Mode == MODE.Outing) ||
-                (Mode == MODE.OutingRelease) )
-        {
-            if(!mDriver.Device.info.Support.Outing)
-            {
-                DeviceLog("[CheckSetMode]" + "[Mode] Out Of Range - Error  Not Support Outing  (" + Mode + ")");
-                return -2;
-            }
-        }
-        else if(Mode == MODE.Sleep)
-        {
-            if(!mDriver.Device.info.Support.Sleep)
-            {
-                DeviceLog("[CheckSetMode]" + "[Mode] Out Of Range - Error  Not Support Sleep  (" + Mode + ")");
-                return -3;
-            }
-        }
-        else if(Mode == MODE.Reservation)
-        {
-            if(!mDriver.Device.info.Support.Reservation)
-            {
-                DeviceLog("[CheckSetMode]" + "[Mode] Out Of Range - Error  Not Support Reservation  (" + Mode + ")");
-                return -4;
-            }
-        }
-        else if((Mode == MODE.Pause) ||
-                (Mode == MODE.PauseRelease) )
-        {
-            if(!mDriver.Device.info.Support.Pause)
-            {
-                DeviceLog("[CheckSetMode]" + "[Mode] Out Of Range - Error  Not Support Pause  (" + Mode + ")");
-                return -5;
-            }
-        }
-
-        return 0;
-    }
-
-    /**
-     * 설정온도 소수점 0.5 도 존재 유무를 판별한다.
-     *
-     * @param n - (double) 값
-     *
-     * @return  - (boolean) true : 있음 , false : 없음
-     */
-    private boolean PointExist(double n)
-    {
-        double FilterData = Double.parseDouble(String.format("%.1f", n));
-        int IntValue = (int)FilterData;
-        double Point = FilterData - IntValue;
-
-        if(Point >= 0.5) return true;
-        return false;
-    }
-
-    /**
-     * double Type 의 온도를 프로토콜에서 사용하여 Byte 온도로 변환한다.
-     *
-     * @param n - (double) 온도
-     *
-     * @return (byte) 변환된 온도
-     */
-    private byte ConverterTemp(double n)
-    {
-        byte ByteTemp = (byte) n;
-        if(PointExist(n)) ByteTemp |= BIT6;
-        return ByteTemp;
-    }
-
-    ///////////////////////////////////////////////////////////////////////
-    // DB
-    ///////////////////////////////////////////////////////////////////////
-    /**
-     * 예약스케쥴 데이터를 DB에서 로딩한다.
-     *
-     * @return (boolean) true:성공 , false:실패)
-     */
-    private boolean LoadReservationData()
-    {
-        DeviceLog("[LoadReservationData] START !!!");
-        try
-        {
-            WallpadStatusData DBMGR = new WallpadStatusData(ServiceMain.svcContext);
-            String[] Data = DBMGR.GetWallPADData("HEAT_RESERVE").split(":");
-            DBMGR.closeDB();
-            if(Data == null)
-            {
-                Log.w(TAG, "[LoadReservationData] GetWallPADData - Data is null !!!");
-                return false;
-            }
-
-            if(Data.length != 8)
-            {
-                Log.w(TAG, "[LoadReservationData] Data length Not Match !!! (len:" + Data.length + " / Data:" + Data + ")");
-                DeleteReservationData();
-                return false;
-            }
-
-            for(byte i=0 ; i<mDriver.Device.info.RoomCount ; i++)
-            {
-                mDriver.Device.Room[i].Reservation.setInt(Integer.parseInt(Data[i]));
-                DeviceLog("Room" + (byte)(i+1) + " : " + mDriver.Device.Room[i].Reservation.ToDebugString());
-            }
-        }
-        catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-            return false;
-        }
-        catch (Exception e) {
-            Log.e(TAG, "[LoadReservationData] Exception Error");
-            //e.printStackTrace();
-            LogUtil.errorLogInfo("", TAG, e);
-            return false;
-        }
-
-        DeviceLog("[LoadReservationData] OK !!!");
-        return true;
-    }
-
-    /**
-     * 예약스케쥴 데이터를 DB에 저장한다.
-     *
-     * @return (boolean) true:성공 , false:실패)
-     */
-    private boolean SaveReservationData()
-    {
-        DeviceLog("[SaveReservationData] START !!!");
-
-        try
-        {
-            String Data = null;
-
-            for(byte i=0 ; i<8 ; i++)
-            {
-                if(i<mDriver.Device.info.RoomCount)
-                {
-                    if(i==0) Data = mDriver.Device.Room[i].Reservation.getInt() + ":";
-                    else     Data += mDriver.Device.Room[i].Reservation.getInt() + ":";
-
-                    DeviceLog("Room" + (byte)(i+1) + " : " + mDriver.Device.Room[i].Reservation.ToDebugString());
-                }
-                else
-                {
-                    Data += "0:";
-                }
-            }
-
-            wallpaddbmgr DBMGR = new wallpaddbmgr(ServiceMain.svcContext);
-            DBMGR.UpdateWallPADData("HEAT_RESERVE", Data);
-            DBMGR.closeDB();
-            DeviceLog("HEAT_RESERVE [" + Data + "]");
-        }
-        catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-            return false;
-        }
-        catch (Exception e) {
-            Log.e(TAG, "[SaveReservationData] Exception Error");
-            //e.printStackTrace();
-            LogUtil.errorLogInfo("", TAG, e);
-            return false;
-        }
-
-        DeviceLog("[SaveReservationData] OK !!!");
-        return true;
-    }
-
-    /**
-     * 예약스케쥴 데이터를 DB에 초기화한다.
-     *
-     * @return (boolean) true:성공 , false:실패)
-     */
-    public boolean DeleteReservationData()
-    {
-        DeviceLog("[DeleteReservationData] START !!!");
-
-        try
-        {
-            wallpaddbmgr DBMGR = new wallpaddbmgr(ServiceMain.svcContext);
-            DBMGR.UpdateWallPADData("HEAT_RESERVE", "0:0:0:0:0:0:0:0");
-            DBMGR.closeDB();
-            DeviceLog("HEAT_RESERVE [" + "0:0:0:0:0:0:0:0" + "]");
-        }
-        catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-            return false;
-        }
-        catch (Exception e) {
-            Log.e(TAG, "[DeleteReservationData] Exception Error");
-            //e.printStackTrace();
-            LogUtil.errorLogInfo("", TAG, e);
-            return false;
-        }
-
-        DeviceLog("[DeleteReservationData] OK !!!");
-        return true;
-    }
-
-    /**
-     * 예약운전 월패드 예약 저장기능 사용여부 판단
-     *
-     * @param info
-     */
-    @SuppressWarnings("unused")
-    private void CheckInfoReservationSaveMode(Info info) {
-        // 1. 모델명 비교 (GLE일 경우에만 수행한다)
-        if (!Version.getGatewayUsage()) return;
-        if (USE_RESERVATION_SET_WALLPAD_SAVE == false) return;
-        Log.d(TAG, "[CheckInfoReservationSaveMode] Start !!!");
-
-        // 2. Info 정보로 하여 월패드예약저장기능 사용여부 판단
-        boolean ChangeModeReservationSetWallPadSave = false;
-        if (info.Vender == 0x01)                    // 제조사 : 한에너지 (0x01)
-        {
-            if ((info.FwVer_Year   == 13) &&        // 펌웨어 Build Date (2013 년 5월 30일 - 1)
-                    (info.FwVer_Month  == 5) &&
-                    (info.FwVer_Day    == 30) &&
-                    (info.FwVer_Number == 1))
-            {
-                ChangeModeReservationSetWallPadSave = true;
-            }
-        }
-
-        // 3. 셋팅여부 판단
-        boolean ReSetting = false;
-        if ((ModeReservationFirstCheck == false) ||
-                (MODE_RESERVATION_SET_WALLPAD_SAVE != ChangeModeReservationSetWallPadSave) )
-        {
-            ModeReservationFirstCheck = true;
-            if(ChangeModeReservationSetWallPadSave) Log.d(TAG, "[[[[ MODE_RESERVATION_SET_WALLPAD_SAVE  -  ON  !!!! ]]]]");
-            else                                    Log.d(TAG, "[[[[ MODE_RESERVATION_SET_WALLPAD_SAVE  -  OFF !!!! ]]]]");
-
-            MODE_RESERVATION_SET_WALLPAD_SAVE = ChangeModeReservationSetWallPadSave;
-
-            ReSetting = true;
-        }
-
-        // 4. 셋팅
-        if (ReSetting == true)
-        {
-            if(MODE_RESERVATION_SET_WALLPAD_SAVE == true)
-            {
-                boolean bRet = LoadReservationData();
-                Log.d(TAG, "LoadReservationData = " + bRet);
-                if (bRet == false)
-                {
-                    for(byte i=0 ; i<mDriver.Device.info.RoomCount ; i++)
-                    {
-                        mDriver.Device.Room[i].Reservation.setInt(0);
-                    }
-
-                    bRet = SaveReservationData();
-                    Log.d(TAG, "SaveReservationData = " + bRet);
-                }
-            }
-            else
-            {
-                boolean bRet = DeleteReservationData();
-                Log.d(TAG, "DeleteReservationData = " + bRet);
-            }
-        }
-    }
-    
-    /**
-     * 세대 누수감지 처리
-     * @param roomData 
-     * **/
-    private void CheckLeakError(RoomData roomData)
-    {
-        if(roomData == null)
-        {
-            return;
-        }
-        if (mDriver.Device.info.Support.Leak == true)
-        {
-            if (roomData.Error.bLeak == true)
-            {
-                long currentTimeMillis = 0;
-                currentTimeMillis = System.currentTimeMillis();
-                if(Math.abs(currentTimeMillis - mDriver.Polling.LeakTimeTickCount) > 5000)
-                {                   
-                    mDriver.Polling.LeakTimeTickCount = currentTimeMillis;
-                    
-                    DeviceLog("[CheckLeakError] Check Alaram Status !!!");
-                    WallpadStatusData wdb = new WallpadStatusData(ServiceMain.svcContext);
-                    int alarmState = wdb.GetAlarmStatus();
-                    wdb.closeDB();
-                    if (alarmState == WallpadStatusData.ALARM_ARISE || alarmState == WallpadStatusData.ALARM_STOP)
-                    {
-                        // 알람화면이 현재 실행중이면 스킵
-                    }
-                    else
-                    {
-                        DeviceLog("[CheckLeakError] Send Leak Alaram !!!");
-                        Send_AlertBR(5);
-                    }
-                }
-            }
-        }
-    }
-    /**
-     * 알람 BR 송신
-     * 
-     * @param kind - (int) 알람종류
-     */
-    private void Send_AlertBR(int kind)
-    {
-        Log.d(TAG, "Send_AlertBR kind - " + kind);
-        Intent intent = new Intent();
-        intent.setAction("WALLPAD_ALERT");
-        intent.putExtra("KIND", kind);
-        ServiceMain.svcContext.sendBroadcast(intent);   
-    }
-}
+/*
+ * Copyright (C) 2014 Android WallPad Project
+ *
+ * FileName  : HeatingV2_Controller.java
+ * Project   : Android WallPad Project
+ * Company   : HDC I-CONTROLS ( www.icontrols.co.kr )
+ * Author    : Kang Sang Ho  , lairu@icontrols.co.kr
+ */
+
+package com.artncore.wallpaddevservice.driver;
+
+import java.util.Calendar;
+import java.util.GregorianCalendar;
+
+import kr.co.icontrols.wallpadsupport.Version;
+import android.annotation.SuppressLint;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.util.Log;
+
+import com.artncore.WallPadDataMgr.WallpadStatusData;
+import com.artncore.WallPadDataMgr.WallpadStatusData.WeatherTable;
+import com.artncore.WallPadDataMgr.wallpaddbmgr;
+import com.artncore.commons.APIErrorCode;
+import com.artncore.commons.DataClasses.HeatingV2;
+import com.util.LogUtil;
+import com.artncore.commons.define;
+import com.artncore.commons.DataClasses.HeatingV2.*;
+import com.artncore.wallpaddevservice.ServiceMain;
+
+
+/**
+ * 난방V2의 드라이버 모듈이다.
+ */
+@SuppressLint("HandlerLeak")
+public class HeatingV2_Controller extends DeviceManager {
+    private final static String TAG = "HeatingV2_Driver";
+
+    private final byte DEVICE_ADDRESS  = (byte) 0x28;
+
+    /** 예약운전 시간 월패드 저장모드 사용유무 (true:사용, false:미사용) */
+    private final boolean USE_RESERVATION_SET_WALLPAD_SAVE = true;
+    /** (주의 : 설정값아님 값 false 에서 변경하지말것) 예약운전 시간 월패드 저장모드 (초기 부팅시 2013/05/30 일경우 활성화) */
+    private boolean MODE_RESERVATION_SET_WALLPAD_SAVE = false;
+    private boolean ModeReservationFirstCheck = false;
+
+    /** 난방OFF일시 외출/외출해제 운전모드 변경하지않음 */
+    private final boolean HEATINGOFF_NOSET_OUTTING  = true;
+
+    /** 초기 기기 검색 횟수  */
+    private final int MAX_SEARCH_COUNT   = 3;
+
+    /** 시간동기화 주기 (분단위) */
+    private final long NOW_TIME_SINK_TICK = (long) (60  * TIME_MINUTE);
+
+    /** 외기온도 전송 전송주기 (분단위) - 2012 디지털특기시방 문서상으로는 최소 1시간이다. */
+    private final long OUTSIDETEMP_SEND_TIME_TICK = (long) (30 * TIME_MINUTE);
+
+    /** 기기정보 변경체크 주기 (분단위)*/
+    private final long INFO_CHECK_TIME_TICK = (long) (5  * TIME_MINUTE);
+
+    /////////////////////////////////////////////////////////
+    // 기본 지원 방개수
+    /////////////////////////////////////////////////////////
+    /** 지원 방개수 (하한값) */
+    private final byte ROOM_COUNT_LOW  = (byte) 1;
+    /** 지원 방개수 (상한값) */
+    private final byte ROOM_COUNT_HI   = (byte) 8;
+
+    /////////////////////////////////////////////////////////
+    // 현재온도 범위
+    /////////////////////////////////////////////////////////
+    /** 지원 최저설정온도 (하한값) */
+    private final double NOWTEMP_MIN  = (double) 0.0;
+    private final double NOWTEMP_MAX  = (double) 60.0;
+
+    /////////////////////////////////////////////////////////
+    // 설정온도 범위
+    /////////////////////////////////////////////////////////
+    /** 지원 최저설정온도 (하한값) */
+    private final byte SETTEMP_MIN_LOW  = (byte) 5;
+    /** 지원 최저설정온도 (상한값) */
+    private final byte SETTEMP_MIN_HI   = (byte) 20;
+    /** 지원 최대설정온도 (하한값) */
+    private final byte SETTEMP_MAX_LOW  = (byte) 21;
+    /** 지원 최대설정온도 (상한값) */
+    private final byte SETTEMP_MAX_HI   = (byte) 50;
+
+    /////////////////////////////////////////////////////////
+    // 보일러 설정온도 범위
+    /////////////////////////////////////////////////////////
+    /** 보일러 난방수 최소 설정온도 */
+    private final byte BOILER_HEAT_WATER_MIN = 30;
+    /** 보일러 난방수 최대 설정온도 */
+    private final byte BOILER_HEAT_WATER_MAX = 90;
+    /** 보일러 온수   최소 설정온도 */
+    private final byte BOILER_HOT_WATER_MIN  = 30;
+    /** 보일러 온수   최대 설정온도*/
+    private final byte BOILER_HOT_WATER_MAX  = 90;
+
+
+    /** Refresh 시 사용되는 index 를 정의한다. */
+    public final static class REFRESH_IDX
+    {
+        /** 방1 */
+        public final static byte ROOM1 = 0;
+        /** 방2 */
+        public final static byte ROOM2 = 1;
+        /** 방3 */
+        public final static byte ROOM3 = 2;
+        /** 방4 */
+        public final static byte ROOM4 = 3;
+        /** 방5 */
+        public final static byte ROOM5 = 4;
+        /** 방6 */
+        public final static byte ROOM6 = 5;
+        /** 방7 */
+        public final static byte ROOM7 = 6;
+        /** 방8 */
+        public final static byte ROOM8 = 7;
+
+        /** 기기 정보 */
+        public final static byte INFO        = 100;
+        /** 보일러 정보 */
+        public final static byte BOILER      = 101;
+        /** 특화기능 */
+        public final static byte SPECIALFUNC = 102;
+    }
+
+    private int mModelType = Version.MODEL_TYPE.OTHER;
+
+    private class Driver
+    {
+        private PollingList Polling;
+
+        private HeatingV2 Device;
+
+        private BoilerData Boiler;
+
+        private SpecialFuncData SpecialFunc;
+
+        public boolean bFixRoomCountUse;
+        public int FixRoomCount;
+
+        private Driver()
+        {
+            Polling = new PollingList();
+            Device = new HeatingV2();
+            Boiler = null;
+            SpecialFunc = null;
+            bFixRoomCountUse = false;
+            FixRoomCount = 0;
+        }
+
+        /** Polling 관련 */
+        private class PollingList
+        {
+            private final class STATUS
+            {
+                /** 초기화 과정 */
+                public final static byte First = 0;
+                /** 초기화 타임아웃 */
+                public final static byte FirstTimeOut = 1;
+                /** 평상시 */
+                public final static byte Normal = 2;
+                /** 지정방 상태조회 */
+                public final static byte FixRoom = 3;
+                /** 보일러 상태조회 */
+                public final static byte Boiler = 4;
+                /** 특화기능 상태조회 */
+                public final static byte SpecialFunc = 5;
+            }
+
+            public byte Status;
+            public int SearchTryCount;
+            public byte RoomIndex;
+            public long InfoCheckTimeTickCount;
+            public long NowTimeSetTickCount;
+            public long OutsideTempSetTickCount;
+            public boolean bOutsideTempDateNotSet;
+            public long LeakTimeTickCount;
+            
+            private PollingList()
+            {
+                Status = STATUS.First;
+                SearchTryCount = 0;
+                RoomIndex = 1;
+
+                InfoCheckTimeTickCount = 0;
+                NowTimeSetTickCount = 0;
+                OutsideTempSetTickCount = 0;
+                bOutsideTempDateNotSet = false;
+            }
+
+            public void NowTimeSetTickCountReset()
+            {
+                NowTimeSetTickCount = 0;
+            }
+        }
+    }
+
+    private Driver mDriver = null;
+
+
+    /**
+     * 생성자
+     */
+    public HeatingV2_Controller()
+    {
+        /** 로그 초기상태 */
+        log_sw = false;
+
+        /** 모델정보 가져오기 */
+        mModelType = Version.getModelType();
+
+        /** 통신성공률 변수 초기화 */
+        super.CommDataGeneration(1);
+
+        /** 드라이버 변수 초기화 */
+        mDriver = new Driver();
+
+        /** 현장 별 특화기능 DB정보 읽어오기 */
+        int [] TempGet_FixRoom_Info = ServiceMain.dataBaseLoader.data.wallpadDeviceSet.Heating_FixRoomCount;
+        if(TempGet_FixRoom_Info != null)
+        {
+            if(TempGet_FixRoom_Info[0] == 1)
+            {
+                mDriver.bFixRoomCountUse = true;
+                if((TempGet_FixRoom_Info[1] >= ROOM_COUNT_LOW) && (TempGet_FixRoom_Info[1] <= ROOM_COUNT_HI))
+                {
+                    mDriver.FixRoomCount = TempGet_FixRoom_Info[1];
+                }
+                else
+                {
+                    Log.w(TAG, "[TempGet_FixRoom_Info] TempGet_FixRoom_Info[1](Room Count) : Out of Range !!! " + String.format("0x%02X", TempGet_FixRoom_Info[1]));
+                    mDriver.bFixRoomCountUse = false;
+                }
+            }
+            else
+            {
+                mDriver.bFixRoomCountUse = false;
+            }
+        }
+
+
+        /** BroadcastReceiver Registration*/
+        Device_BrRegistration();
+    }
+
+    private boolean Device_BrRegistration() {
+        DeviceLog("Device_BrRegistration - Start");
+
+        try {
+            if ((ServiceMain.dataBaseLoader.data.wallpadDeviceSet.Get_ZeroEnergyHouse) || (ServiceMain.dataBaseLoader.data.wallpadDeviceSet.Get_IntegratedSwitchInfo) || Version.getGatewayUsage()) {
+                IntentFilter filter = new IntentFilter();
+                DeviceLog("Device_BrRegistration - filter.addAction - " + define.NOTIFY_ACNAME);
+                filter.addAction(define.NOTIFY_ACNAME);
+
+                ServiceMain.svcContext.registerReceiver(mWallPadNotifyBR, filter);
+                return true;
+            }
+        } catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+            return false;
+        } catch (Exception e) {
+            Log.e(TAG, "[Device_BrRegistration] Exception Error");
+            //e.printStackTrace();
+            LogUtil.errorLogInfo("", TAG, e);
+            return false;
+        }
+
+        return false;
+    }
+
+    @Override
+    public void DeviceLog(String msg)
+    {
+        if (!log_sw) return;
+        Log.d(TAG, msg);
+    }
+
+    /**
+     * BroadcastReceiver
+     */
+    private BroadcastReceiver mWallPadNotifyBR = new BroadcastReceiver()
+    {
+        public void onReceive(Context context, Intent intent)
+        {
+            String acname = intent.getAction();
+
+            DeviceLog("Receive Notify BR ["+ acname + "]");
+
+            if(mDriver.Polling.Status != Driver.PollingList.STATUS.Normal) return;
+
+            if (acname.equals(define.NOTIFY_ACNAME))
+            {
+                int kind = intent.getIntExtra("KIND", 0);
+                DeviceLog("Receive Notify BR "+ define.NOTIFY_ACNAME + " : " + kind);
+                switch (kind)
+                {
+                    case define.NOTIFY_SYSTEMTIMESETTED:
+                        Log.d(TAG, "[NOTIFY_SYSTEMTIMESETTED] - HeatingV2 Time Reset !!!");
+                        mDriver.Polling.NowTimeSetTickCountReset();
+
+                        if(mDriver.Polling.bOutsideTempDateNotSet)
+                        {
+                            mDriver.Polling.bOutsideTempDateNotSet = false;
+                            mDriver.Polling.OutsideTempSetTickCount = 0;
+                        }
+                        break;
+                }
+            }
+        }
+    };
+
+    /**
+     * 로딩후 처음 폴링 시퀀스
+     */
+    @Override
+    protected void do_boot()
+    {
+    }
+
+    /**
+     * do_ctr : 폴링스케쥴러
+     */
+    @Override
+    protected void do_ctr()
+    {
+        DeviceLog("Polling ");
+
+        /* [[ First & FirstTimeOut ]]
+         * 초기 디바이스정보  검색 */
+        if ((mDriver.Polling.Status == Driver.PollingList.STATUS.First) || (mDriver.Polling.Status == Driver.PollingList.STATUS.FirstTimeOut)) {
+            if (mDriver.Polling.Status == Driver.PollingList.STATUS.First) {
+                if (mDriver.Polling.SearchTryCount++ > MAX_SEARCH_COUNT) {
+                    mDriver.Polling.Status = Driver.PollingList.STATUS.FirstTimeOut;
+
+                    Log.i(TAG, "--------------------------------------------------");
+                    Log.i(TAG, "SearchDevice Fail... FirstTimeOut ");
+                    Log.i(TAG, "--------------------------------------------------");
+
+                    ServiceMain.deviceInitChecker.Remove(super.DeviceName);
+                }
+            }
+
+            Info info = Send_GetDeviceInfo();
+            if (info != null) {
+                mDriver.Device.info = info;
+                mDriver.Device.SetRoomCount(info.RoomCount);
+
+                Log.i(TAG, mDriver.Device.info.ToDebugString());
+
+                CheckInfoReservationSaveMode(info);
+
+                mDriver.Polling.Status = Driver.PollingList.STATUS.Normal;
+
+                mDriver.Polling.InfoCheckTimeTickCount = System.currentTimeMillis();
+
+                if (mDriver.Device.info.Support.Boiler) {
+                    Sleep(100);
+
+                    BoilerData boilerData = Send_GetBoilerStatus();
+                    if(boilerData != null) mDriver.Boiler = boilerData;
+                }
+
+                if (mDriver.Device.info.Support.AI) {
+                    Sleep(100);
+
+                    SpecialFuncData specialFuncData = Send_GetSpecialFuncStatus();
+                    if(specialFuncData != null) mDriver.SpecialFunc = specialFuncData;
+                }
+
+                ServiceMain.deviceInitChecker.Remove(super.DeviceName);
+            }
+        }
+
+        /* [[ Normal & FixRoom & Boiler & SpecialFunc ]]
+         * 평상시 */
+        else if ((mDriver.Polling.Status == Driver.PollingList.STATUS.Normal)
+                || (mDriver.Polling.Status == Driver.PollingList.STATUS.FixRoom)
+                || (mDriver.Polling.Status == Driver.PollingList.STATUS.Boiler)
+                || (mDriver.Polling.Status == Driver.PollingList.STATUS.SpecialFunc))
+        {
+            long currentTimeMillis = 0;
+
+            /*
+             * 기기정보 변동 체크
+             */
+            currentTimeMillis = System.currentTimeMillis();
+            if (Math.abs(currentTimeMillis - mDriver.Polling.InfoCheckTimeTickCount) > INFO_CHECK_TIME_TICK) {
+                Info info = Send_GetDeviceInfo();
+                if (info != null) {
+                    if (UpdateVariables(info)) return;
+                }
+                mDriver.Polling.InfoCheckTimeTickCount = currentTimeMillis;
+                Sleep(100);
+            }
+
+            /*
+             * 현재 시간 동기화
+             * 당사 에너지미터 적용여부에 따라 시간정보 전송 방식이 변경 됨
+             * 에너지미터 적용시: NOW_TIME_SINK_MINUTE 시간 마다 동기화 (1시간으로 설정되어 있음)
+             * 그외: 최초 1회만 동기화, 시간정보 변경시 동기화
+             */
+            if (Version.getGatewayUsage()
+                    || (ServiceMain.dataBaseLoader.data.wallpadDeviceSet.Get_ZeroEnergyHouse)
+                    || (ServiceMain.dataBaseLoader.data.wallpadDeviceSet.Get_IntegratedSwitchInfo)
+                    || (mDriver.Polling.NowTimeSetTickCount == 0))
+            {
+                currentTimeMillis = System.currentTimeMillis();
+                if (Math.abs(currentTimeMillis - mDriver.Polling.NowTimeSetTickCount) > NOW_TIME_SINK_TICK) {
+                    mDriver.Polling.NowTimeSetTickCount = currentTimeMillis;
+                    boolean bRet = Send_NowTimeSet();
+                    Log.d(TAG, "NowTimeSet : Result = " + bRet);
+                    Sleep(100);
+                }
+            }
+
+//            /*
+//             * 현재 시간 동기화
+//             * GLE 의 경우 현재시간을 NOW_TIME_SINK_MINUTE 시간 마다 동기화
+//             * GLE 가 아닐경우 최초 1회 동기화
+//             */
+//            if ((mModelType == Version.MODEL_TYPE.IHN_1020GL)
+//                    || (ServiceMain.dataBaseLoader.data.wallpadDeviceSet.Get_ZeroEnergyHouse == true)
+//                    || (ServiceMain.dataBaseLoader.data.wallpadDeviceSet.Get_IntegratedSwitchInfo == true)
+//                    || (mDriver.Polling.NowTimeSetTickCount == 0)
+//                    || (mModelType == Version.MODEL_TYPE.IHN_D101)
+//                    || (mModelType == Version.MODEL_TYPE.IHN_1010GL)
+//                    || mModelType == Version.MODEL_TYPE.IHN_D101K)
+//            {
+//                currentTimeMillis = System.currentTimeMillis();
+//                if (Math.abs(currentTimeMillis - mDriver.Polling.NowTimeSetTickCount) > NOW_TIME_SINK_TICK) {
+//                    mDriver.Polling.NowTimeSetTickCount = currentTimeMillis;
+//                    boolean bRet = Send_NowTimeSet();
+//                    Log.d(TAG, "NowTimeSet : Result = " + bRet);
+//                    Sleep(100);
+//                }
+//            }
+
+            /*
+             * 외기온도 사용시 외기온도 일정시간마다 전송
+             * Info 상으로 외기온도를 요구하며, iMap에서 외기온도를 1회이상 셋팅하였을 경우
+             * 본 기능은 GLE에만 적용되는 기능임.
+             */
+            if (Version.getGatewayUsage() || ServiceMain.dataBaseLoader.data.wallpadDeviceSet.Get_IntegratedSwitchInfo) {
+                if (mDriver.Device.info.Support.OutsideTempUse) {
+                    currentTimeMillis = System.currentTimeMillis();
+                    if (Math.abs(currentTimeMillis - mDriver.Polling.OutsideTempSetTickCount) > OUTSIDETEMP_SEND_TIME_TICK) {
+                        mDriver.Polling.OutsideTempSetTickCount = currentTimeMillis;
+                        int Ret = OutsideTempUpdate();
+                        if (Ret == -3) {
+                            // 날짜가 일치하지 않아 외기온도 설정을 못하였을 경우 시간이 설정되면 재설정 할수있도록 플레그 설정함.
+                            mDriver.Polling.bOutsideTempDateNotSet = true;
+                        }
+                        Log.d(TAG, "OutsideTempUpdate : Result = " + Ret);
+                        Sleep(100);
+                    }
+                }
+            }
+
+            // 전체방 조회를 1회한다.
+            AllRoomData allRoomData = Send_GetAllRoomStatus();
+            if (allRoomData != null) UpdateVariables(allRoomData);
+            Sleep(100);
+
+            /////////////////////////////////////////////////////////////////////////////////////////
+            // 폴링 모드별 처리
+            /////////////////////////////////////////////////////////////////////////////////////////
+
+            // Normal : 각방 상태 가져오기 (1개씩 순차적)
+            if (mDriver.Polling.Status == Driver.PollingList.STATUS.Normal) {
+                RoomData roomData = Send_GetEachRoomStatus(mDriver.Polling.RoomIndex);
+                if(roomData != null) UpdateVariables(mDriver.Polling.RoomIndex, roomData);
+
+                if(++mDriver.Polling.RoomIndex >= mDriver.Device.info.RoomCount) mDriver.Polling.RoomIndex = 0;
+            }
+
+            // FixRoom : 지정방 상태 가져오기
+            else if (mDriver.Polling.Status == Driver.PollingList.STATUS.FixRoom) {
+                RoomData roomData = Send_GetEachRoomStatus(mDriver.Polling.RoomIndex);
+                if(roomData != null) UpdateVariables(mDriver.Polling.RoomIndex, roomData);
+            }
+            // Boiler : 보일러 상태 가져오기
+            else if (mDriver.Polling.Status == Driver.PollingList.STATUS.Boiler) {
+                BoilerData boilerData = Send_GetBoilerStatus();
+                if(boilerData != null) UpdateVariables(boilerData);
+            }
+            // SpecialFunc : 특화기능 상태 가져오기
+            else if (mDriver.Polling.Status == Driver.PollingList.STATUS.SpecialFunc) {
+                SpecialFuncData specialFuncData = Send_GetSpecialFuncStatus();
+                if(specialFuncData != null) UpdateVariables(specialFuncData);
+            }
+        }
+        else {
+            mDriver = new Driver();
+        }
+    }
+
+    /** 방개수를 반환한다. */
+    public byte GetRoomCount() {
+        if (mDriver == null) return 0;
+        return mDriver.Device.info.RoomCount;
+    }
+
+    /**
+     * (프로토콜 데이터 반환)<br>
+     * 각 방의 운전모드를 프로토콜 데이터로 반환한다.
+     *
+     * @param RoomIndex - (byte) 요청 방 인덱스
+     *
+     * @return (byte) 운전모드
+     */
+    public byte GetRoomMode(int RoomIndex) {
+        byte retMode = HeatingV2.MODE.HeatingOFF;
+        if (mDriver == null) return retMode;
+        try {
+            if ((RoomIndex < 0) || (RoomIndex >= mDriver.Device.info.RoomCount)) return retMode;
+            retMode = mDriver.Device.Room[RoomIndex].Mode;
+        } catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+        } catch (Exception e) {
+            Log.e(TAG, "[GetRoomMode] Exception Error");
+            //e.printStackTrace();
+            LogUtil.errorLogInfo("", TAG, e);
+        }
+        return retMode;
+    }
+
+    /**
+     * (프로토콜 데이터 반환)<br>
+     * 각 방의 현재온도를 프로토콜 데이터로 반환한다.
+     *
+     * @param RoomIndex - (byte) 요청 방 인덱스
+     *
+     * @return (byte) 현재온도
+     */
+    public byte GetRoomNowTemp(int RoomIndex) {
+        byte retNowTemp = 0x00;
+        if (mDriver == null) return retNowTemp;
+        try {
+            if ((RoomIndex < 0) || (RoomIndex >= mDriver.Device.info.RoomCount)) return retNowTemp;
+            retNowTemp = ConverterTemp(mDriver.Device.Room[RoomIndex].NowTemp);
+        } catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+        } catch (Exception e) {
+            Log.e(TAG, "[GetRoomNowTemp] Exception Error");
+            //e.printStackTrace();
+            LogUtil.errorLogInfo("", TAG, e);
+        }
+        return retNowTemp;
+    }
+
+    /**
+     * (프로토콜 데이터 반환)<br>
+     * 각 방의 설정온도를 프로토콜 데이터로 반환한다.
+     *
+     * @param RoomIndex - (byte) 요청 방 인덱스
+     *
+     * @return (byte) 설정온도
+     */
+    public byte GetRoomSetTemp(int RoomIndex) {
+        byte retSetTemp = 0x00;
+        if (mDriver == null) return retSetTemp;
+        try {
+            if ((RoomIndex < 0) || (RoomIndex >= mDriver.Device.info.RoomCount)) return retSetTemp;
+            retSetTemp = ConverterTemp(mDriver.Device.Room[RoomIndex].SetTemp);
+        } catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+        } catch (Exception e) {
+            Log.e(TAG, "[GetRoomSetTemp] Exception Error");
+            //e.printStackTrace();
+            LogUtil.errorLogInfo("", TAG, e);
+        }
+        return retSetTemp;
+    }
+    
+    /**
+     * (프로토콜 데이터 반환)<br>
+     * 각 방의 밸브상태를 프로토콜 데이터로 반환한다.
+     * 
+     * @param RoomIndex - (int) 요청 방 인덱스
+     * 
+     * @return (String) 밸브상태
+     */
+    public String GetRoomValve(int RoomIndex) {
+    	boolean retMode = false;
+    	
+    	if (mDriver == null) return null;
+        try {
+            if ((RoomIndex < 0) || (RoomIndex >= mDriver.Device.info.RoomCount)) return null;
+            retMode = mDriver.Device.Room[RoomIndex].bValveStatus;
+        } catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+        } catch (Exception e) {
+            Log.e(TAG, "[GetRoomValve] Exception Error");
+            //e.printStackTrace();
+            LogUtil.errorLogInfo("", TAG, e);
+        }
+        return retMode + "";
+    }
+    
+    /**
+     * NoSink 제어
+     *
+     * @param StrArg
+     *
+     * @return
+     */
+    public String NoSinkCtrl(String StrArg) {
+        DeviceLog("[NoSinkCtrl] Start");
+
+        // 1. 디바이스 초기화시 에러리턴
+        if ((mDriver.Polling.Status == Driver.PollingList.STATUS.First) || (mDriver.Polling.Status == Driver.PollingList.STATUS.FirstTimeOut)) {
+            Log.w(TAG, "[NoSinkCtrl] - Not Yet !!!");
+            return "FAIL;" + APIErrorCode.DEVICEISNOTREADY;
+        }
+
+        CtrDevFormat ctrDevFormat = GetCtrDevParamParsing(StrArg, 5);
+        if (ctrDevFormat.ret != APIErrorCode.C_SUCCESS) {
+            Log.w(TAG, "[NoSinkCtrl] GetCtrDevParamParsing Error (ret:" + ctrDevFormat.ret + ")");
+            return "FAIL;" + APIErrorCode.DEFAULT_PARSING_ERR;
+        }
+
+        //////////////////////////////////////////////////////////
+        // Refresh : 데이터 갱신 (No Sink)
+        //////////////////////////////////////////////////////////
+        if (ctrDevFormat.CmdStr!=null && ctrDevFormat.CmdStr.equals("Refresh")) {
+            byte Index         = ctrDevFormat.param[0];
+
+            DeviceLog("[Refresh] Index : " + String.format("0x%02X", Index));
+
+            // 각방
+            if ((Index >= REFRESH_IDX.ROOM1) && (Index <= REFRESH_IDX.ROOM8)) {
+                return RefreshResult_Room(Index);
+            }
+            // 기기정보
+            else if (Index == REFRESH_IDX.INFO) {
+                return RefreshResult_Info();
+            }
+            // 보일러
+            else if (Index == REFRESH_IDX.BOILER) {
+                if(!mDriver.Device.info.Support.Boiler)
+                {
+                    Log.w(TAG, "[NoSinkCtrl] - Refresh : BOILER - Not Support Boiler !!!");
+                    return SHMem.retVal = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
+                }
+                return RefreshResult_Boiler();
+            }
+            // 특화기능
+            else if(Index == REFRESH_IDX.SPECIALFUNC)
+            {
+                if(!mDriver.Device.info.Support.AI)
+                {
+                    Log.w(TAG, "[NoSinkCtrl] - Refresh : SPECIALFUNC - Not Support AI !!!");
+                    return SHMem.retVal = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
+                }
+                return RefreshResult_SpecialFunc();
+            }
+            else
+            {
+                return "FAIL;" + APIErrorCode.INVALIDPARAMETER;
+            }
+        }
+
+        return "FAIL;" + APIErrorCode.UNKNOWNCOMMAND;
+    }
+
+    /**
+     * do_ctrEmm : 싱크 제어
+     */
+    @Override
+    @SuppressLint("DefaultLocale")
+    protected String do_ctrEmm(DeviceCtrSHMem SHMem)
+    {
+        DeviceLog("[do_ctrEmm] Start");
+        DeviceLog("cmd    : " + SHMem.cmd);
+        DeviceLog("StrArg : " + SHMem.StrArg);
+
+        // 1. 디바이스 초기화시 에러리턴
+        if( (mDriver.Polling.Status == Driver.PollingList.STATUS.First) ||
+                (mDriver.Polling.Status == Driver.PollingList.STATUS.FirstTimeOut) )
+        {
+            Log.w(TAG, "[do_ctrEmm] - Not Yet !!!");
+            return SHMem.retVal = "FAIL;" + APIErrorCode.DEVICEISNOTREADY;
+        }
+
+        CtrDevFormat ctrDevFormat = GetCtrDevParamParsing(SHMem.StrArg, 5);
+        if(ctrDevFormat.ret != APIErrorCode.C_SUCCESS)
+        {
+            Log.w(TAG, "[do_ctrEmm] GetCtrDevParamParsing Error (ret:" + ctrDevFormat.ret + ")");
+            return SHMem.retVal = "FAIL;" + APIErrorCode.DEFAULT_PARSING_ERR;
+        }
+
+        if(ctrDevFormat.CmdStr!=null)
+        {
+            //////////////////////////////////////////////////////////
+            // Refresh : 데이터 갱신 (Sink)
+            //////////////////////////////////////////////////////////
+            if(ctrDevFormat.CmdStr.equals("Refresh"))
+            {
+                byte Index    = ctrDevFormat.param[0];
+                SHMem.retVal = "FAIL;" + APIErrorCode.DEVICEISNORESPONSE;
+
+                // 전체방
+                if(Index == define.DEVICE_ALL_OR_NOTHING)
+                {
+                    byte i=0;
+                    for(i=0 ; i<mDriver.Device.info.RoomCount ; i++)
+                    {
+                        RoomData roomData = Send_GetEachRoomStatus(i);
+                        if(roomData != null)
+                        {
+                            mDriver.Device.Room[i] = roomData;
+                        }
+                        else break;
+                    }
+                    if(i == mDriver.Device.info.RoomCount)
+                    {
+                        SHMem.retVal = "SUCCESS";
+                    }
+                    else
+                    {
+                        SHMem.retVal = "FAIL;" + APIErrorCode.DEVICEISNORESPONSE;
+                    }
+                }
+                // 각방
+                else if((Index >= REFRESH_IDX.ROOM1) && (Index <= REFRESH_IDX.ROOM8))
+                {
+                    RoomData roomData = Send_GetEachRoomStatus(Index);
+                    if(roomData != null)
+                    {
+                        mDriver.Device.Room[Index] = roomData;
+                        SHMem.retVal = RefreshResult_Room(Index);
+                    }
+                }
+                // 보일러
+                else if(Index == REFRESH_IDX.BOILER)
+                {
+                    if(!mDriver.Device.info.Support.Boiler)
+                    {
+                        Log.w(TAG, "[do_ctrEmm] - Refresh : BOILER - Not Support Boiler !!!");
+                        return SHMem.retVal = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
+                    }
+                    BoilerData Boiler = Send_GetBoilerStatus();
+                    if(Boiler != null)
+                    {
+                        mDriver.Boiler = Boiler;
+                        SHMem.retVal = RefreshResult_Boiler();
+                    }
+                }
+                // 특화기능
+                else if(Index == REFRESH_IDX.SPECIALFUNC)
+                {
+                    if(!mDriver.Device.info.Support.AI)
+                    {
+                        Log.w(TAG, "[do_ctrEmm] - Refresh : SPECIALFUNC - Not Support AI !!!");
+                        return SHMem.retVal = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
+                    }
+                    SpecialFuncData SpecialFunc = Send_GetSpecialFuncStatus();
+                    if(SpecialFunc != null)
+                    {
+                        mDriver.SpecialFunc = SpecialFunc;
+                        SHMem.retVal = RefreshResult_SpecialFunc();
+                    }
+                }
+                else
+                {
+                    SHMem.retVal = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
+                }
+                return SHMem.retVal;
+            }
+            ///////////////////////////////////////////////////////////////
+            // SetPollingMode : 폴링상태 변경
+            ///////////////////////////////////////////////////////////////
+            if(ctrDevFormat.CmdStr.equals("SetPollingMode"))
+            {
+                // 1. Param Check
+                byte ChangePollingMode = ctrDevFormat.param[0];
+                byte RoomIndex         = ctrDevFormat.param[1];
+
+                if( !((ChangePollingMode == Driver.PollingList.STATUS.Normal)  ||
+                        (ChangePollingMode == Driver.PollingList.STATUS.FixRoom) ||
+                        (ChangePollingMode == Driver.PollingList.STATUS.Boiler)  ||
+                        (ChangePollingMode == Driver.PollingList.STATUS.SpecialFunc)) )
+                {
+                    Log.w(TAG, "[do_ctrEmm -> SetPollingMode]" + "[ChangePollingMode] Out Of Range (" + ChangePollingMode + ")");
+                    return SHMem.retVal = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
+                }
+                if(ChangePollingMode == Driver.PollingList.STATUS.FixRoom)
+                {
+                    if( (RoomIndex < 0) || (RoomIndex >= mDriver.Device.info.RoomCount) )
+                    {
+                        Log.w(TAG, "[do_ctrEmm -> SetPollingMode]" + "[RoomIndex] Out Of Range (" + RoomIndex + ")");
+                        return SHMem.retVal = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
+                    }
+                }
+
+                // 2. Doing
+                mDriver.Polling.Status = ChangePollingMode;
+                if(ChangePollingMode == Driver.PollingList.STATUS.FixRoom)
+                {
+                    mDriver.Polling.RoomIndex = RoomIndex;
+                }
+                else mDriver.Polling.RoomIndex = 0;
+
+                return SHMem.retVal = "SUCCESS";
+            }
+
+            ///////////////////////////////////////////////////////////////
+            // SetEachRoomStatus : 각방 제어 (운전모드 및 설정온도 변경)
+            ///////////////////////////////////////////////////////////////
+            else if(ctrDevFormat.CmdStr.equals("SetEachRoomStatus"))
+            {
+                // 1. Param Check
+                byte RoomIndex    = ctrDevFormat.param[0];
+                byte Mode         = ctrDevFormat.param[1];
+                byte Temp         = ctrDevFormat.param[2];
+                byte TempPoint    = ctrDevFormat.param[3];
+
+                //      1.1. RoomIndex
+                if( (RoomIndex < 0) || (RoomIndex >= mDriver.Device.info.RoomCount) )
+                {
+                    Log.w(TAG, "[do_ctrEmm -> SetEachRoomStatus]" + "[RoomIndex] Out Of Range (" + RoomIndex + ")");
+                    return SHMem.retVal = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
+                }
+
+                //      1.2. Mode
+                int ret = CheckSetMode(Mode);
+                if(ret < 0)
+                {
+                    Log.w(TAG, "[do_ctrEmm -> SetEachRoomStatus]" + "[Mode] Out Of Range (" + ret + ")");
+                    return SHMem.retVal = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
+                }
+
+                //      1.3. Temp & TempPoint
+                if(Temp != 0x00)
+                {
+                    if( (Temp < mDriver.Device.info.Support.MinSetTemp) || (Temp > mDriver.Device.info.Support.MaxSetTemp) )
+                    {
+                        Log.w(TAG, "[do_ctrEmm -> SetEachRoomStatus]" + "[Temp] Out Of Range - (" + Temp + ")");
+                        return SHMem.retVal = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
+                    }
+
+                    if( !((TempPoint == 0x00) || (TempPoint == 0x01)) )
+                    {
+                        Log.w(TAG, "[do_ctrEmm -> SetEachRoomStatus]" + "[TempPoint] Out Of Range - (" + TempPoint + ")");
+                        return SHMem.retVal = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
+                    }
+                    //                if(TempPoint == 0x01)
+                    //                {
+                    //                    if(!mDriver.Device.info.Support.SetTempPoint05)
+                    //                    {
+                    //                        Log.w(TAG, "[do_ctrEmm -> SetEachRoomStatus]" + "[TempPoint] Out Of Range - Error  Not Support SetTempPoint05  (" + TempPoint + ")");
+                    //                        return SHMem.retVal = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
+                    //                    }
+                    //                }
+                }
+
+                // 2. Make Packet Data
+                CtrlRoomData ctrlRoomData = new CtrlRoomData();
+
+                ctrlRoomData.Mode = Mode;
+
+                ctrlRoomData.SetTemp = (double) Temp;
+                if(mDriver.Device.info.Support.SetTempPoint05)
+                {
+                    if(TempPoint == 0x01) ctrlRoomData.SetTemp += 0.5;
+                }
+
+                // 3. Doing
+                RoomData roomData = Send_SetEachRoomStatus(RoomIndex, ctrlRoomData);
+                if(roomData == null)
+                    return SHMem.retVal = "FAIL;" + APIErrorCode.DEVICEISNORESPONSE;
+
+                UpdateVariables(RoomIndex, roomData);
+
+                return SHMem.retVal = "SUCCESS";
+            }
+
+            ///////////////////////////////////////////////////////////////
+            // SetAllRoomStatus : 전체방 제어 (운전모드 변경)
+            ///////////////////////////////////////////////////////////////
+            else if(ctrDevFormat.CmdStr.equals("SetAllRoomStatus"))
+            {
+                // 1. Param Check
+                byte Mode         = ctrDevFormat.param[0];
+
+                //      1.2. Mode
+                int ret = CheckSetMode(Mode);
+                if(ret < 0)
+                {
+                    Log.w(TAG, "[do_ctrEmm -> SetAllRoomStatus]" + "[Mode] Out Of Range (" + ret + ")");
+                    return SHMem.retVal = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
+                }
+
+                // 2. Make Packet Data
+
+                // 3. Doing
+                AllRoomData allRoomData = Send_SetAllRoomStatus(false, Mode, mDriver.Device.info.RoomCount);
+                if(allRoomData == null)
+                    return SHMem.retVal = "FAIL;" + APIErrorCode.DEVICEISNORESPONSE;
+
+                UpdateVariables(allRoomData);
+
+                return SHMem.retVal = "SUCCESS";
+            }
+
+            ///////////////////////////////////////////////////////////////
+            // SetSleep : 취침설정 변경
+            ///////////////////////////////////////////////////////////////
+            else if(ctrDevFormat.CmdStr.equals("SetSleep"))
+            {
+                // 0. Mode Check
+                if(!mDriver.Device.info.Support.Sleep)
+                {
+                    Log.w(TAG, "[do_ctrEmm -> SetSleep]" + "Not Support Sleep");
+                    return SHMem.retVal = "FAIL;" + APIErrorCode.NOT_SUPPORT;
+                }
+
+                // 1. Param Check
+                byte RoomIndex         = ctrDevFormat.param[0];
+                byte setTemp           = ctrDevFormat.param[1];
+                byte setTime           = ctrDevFormat.param[2];
+
+                //      1.1. RoomIndex
+                if( (RoomIndex < 0) || (RoomIndex >= mDriver.Device.info.RoomCount) )
+                {
+                    Log.w(TAG, "[do_ctrEmm -> SetSleep]" + "[RoomIndex] Out Of Range (" + RoomIndex + ")");
+                    return SHMem.retVal = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
+                }
+
+                // 2. Make Packet Data
+                CtrlRoomData ctrlRoomData = new CtrlRoomData();
+
+                if(!ctrlRoomData.Sleep.setTemp(setTemp))
+                {
+                    Log.w(TAG, "[do_ctrEmm -> SetSleep]" + "[setTemp] Out Of Range (" + setTemp + ")");
+                    return SHMem.retVal = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
+                }
+                if(!ctrlRoomData.Sleep.setTime(setTime))
+                {
+                    Log.w(TAG, "[do_ctrEmm -> SetSleep]" + "[setTime] Out Of Range (" + setTime + ")");
+                    return SHMem.retVal = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
+                }
+
+                // 3. Doing
+                RoomData roomData = Send_SetEachRoomStatus(RoomIndex, ctrlRoomData);
+                if(roomData == null)
+                    return SHMem.retVal = "FAIL;" + APIErrorCode.DEVICEISNORESPONSE;
+
+                UpdateVariables(RoomIndex, roomData);
+
+                return SHMem.retVal = "SUCCESS";
+            }
+
+            ///////////////////////////////////////////////////////////////
+            // SetReservation : 예약설정변경
+            ///////////////////////////////////////////////////////////////
+            else if(ctrDevFormat.CmdStr.equals("SetReservation"))
+            {
+                // 0. Mode Check
+                if(!mDriver.Device.info.Support.Reservation)
+                {
+                    Log.w(TAG, "[do_ctrEmm -> SetReservation]" + "Not Support Reservation");
+                    return SHMem.retVal = "FAIL;" + APIErrorCode.NOT_SUPPORT;
+                }
+
+                // 1. Param Check
+                byte RoomIndex         = ctrDevFormat.param[0];
+
+                //      1.1. RoomIndex
+                if( (RoomIndex < 0) || (RoomIndex >= mDriver.Device.info.RoomCount) )
+                {
+                    Log.w(TAG, "[do_ctrEmm -> SetEachRoomStatus]" + "[RoomIndex] Out Of Range (" + RoomIndex + ")");
+                    return SHMem.retVal = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
+                }
+
+                // 2. Make Packet Data
+                byte [] DataBuffer = new byte[3];
+                DataBuffer[0] = ctrDevFormat.param[1];
+                DataBuffer[1] = ctrDevFormat.param[2];
+                DataBuffer[2] = ctrDevFormat.param[3];
+
+                CtrlRoomData ctrlRoomData = new CtrlRoomData();
+                ctrlRoomData.Reservation.setByte(DataBuffer);
+
+                ////////////////////////////////////////////////////////////////////////////
+                // 예약운전 시간 월패드 저장모드
+                ////////////////////////////////////////////////////////////////////////////
+                boolean bSend = false;
+                if(MODE_RESERVATION_SET_WALLPAD_SAVE == true)
+                {
+                    mDriver.Device.Room[RoomIndex].Reservation.setByte(DataBuffer);
+
+                    SaveReservationData();
+
+                    if (mDriver.Device.Room[RoomIndex].Mode == MODE.Reservation)
+                    {
+                        ctrlRoomData.Reservation.setByte(DataBuffer);
+                        bSend = true;
+                    }
+                }
+                else
+                {
+                    ctrlRoomData.Reservation.setByte(DataBuffer);
+                    bSend = true;
+                }
+
+                // 3. Doing
+                if(bSend)
+                {
+                    RoomData roomData = Send_SetEachRoomStatus(RoomIndex, ctrlRoomData);
+                    if(roomData == null)
+                        return SHMem.retVal = "FAIL;" + APIErrorCode.DEVICEISNORESPONSE;
+
+                    UpdateVariables(RoomIndex, roomData);
+                }
+
+                return SHMem.retVal = "SUCCESS";
+            }
+
+            ///////////////////////////////////////////////////////////////
+            // 보일러 설정 변경
+            ///////////////////////////////////////////////////////////////
+            else if(ctrDevFormat.CmdStr.equals("SetBoiler"))
+            {
+                // 0. Mode Check
+                if(!mDriver.Device.info.Support.Boiler)
+                {
+                    Log.w(TAG, "[do_ctrEmm -> SetBoiler]" + "Not Support Boiler");
+                    return SHMem.retVal = "FAIL;" + APIErrorCode.NOT_SUPPORT;
+                }
+                if(mDriver.Boiler == null)
+                {
+                    Log.w(TAG, "[do_ctrEmm -> SetBoiler]" + "mDriver.Boiler is null !!!");
+                    return SHMem.retVal = "FAIL;" + APIErrorCode.DEVICEISNOTREADY;
+                }
+
+                byte HeatingWaterTemp     = ctrDevFormat.param[0];
+                byte HotWaterTemp         = ctrDevFormat.param[1];
+
+                // 2. Param Check & Doing
+                BoilerData Boiler = Send_SetBoilerStatus(HeatingWaterTemp, HotWaterTemp);
+                if(Boiler == null)
+                    return SHMem.retVal = "FAIL;" + APIErrorCode.DEVICEISNORESPONSE;
+
+                UpdateVariables(Boiler);
+
+                return SHMem.retVal = "SUCCESS";
+            }
+        }
+
+
+        return SHMem.retVal = "UNKNOWNCMD";
+    }
+
+    /**
+     * Info 에 대한 응답포멧 정의
+     *
+     * @return (String) "SUCCESS; ..." 성공 , "FAIL; ... " 실패
+     */
+    private String RefreshResult_Info()
+    {
+        String result = null;
+
+        DeviceLog("GetRefreshResultInfo call : ");
+
+        // 1. Check Polling Status
+        if( (mDriver.Polling.Status == Driver.PollingList.STATUS.First) ||
+                (mDriver.Polling.Status == Driver.PollingList.STATUS.FirstTimeOut) )
+        {
+            result = "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
+            return result;
+        }
+
+        // 2. Param Range Check
+
+        // 3. Make Return String Format
+        try
+        {
+            if(mDriver.Device == null)                   return "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
+            if(mDriver.Device.info == null)              return "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
+
+            /*
+             * [Format]
+             *
+             * SUCCESS       - (String) 성공
+             *
+             * RoomCount        - (byte) 방개수(범위 : 1~6)
+             *
+             * Vender           - (byte) 벤더
+             *
+             * FwVer_Year       - (byte) 펌웨어 빌드버전 (년)
+             * FwVer_Month      - (byte) 펌웨어 빌드버전 (월)
+             * FwVer_Day        - (byte) 펌웨어 빌드버전 (일)
+             * FwVer_Number     - (byte) 펌웨어 빌드버전 (순번)
+             *
+             * ProtocolVer_Main - (byte) 프로토콜 지원 버전 (상위)
+             * ProtocolVer_Sub  - (byte) 프로토콜 지원 버전 (하위)
+             *
+             * Support.MinSetTemp - (byte) 지원하는 최저설정온도 (범위 : 5도 ~ 20도)
+             * Support.MaxSetTemp - (byte) 지원하는 최대설정온도 (범위 : 21도 ~ 40도)
+             *
+             * Support.SetTempPoint05 - (boolean) 설정온도 단위          (ture : 0.5도단위, false : 1도단위)
+             * Support.Outing         - (boolean) 외출기능 지원여부   (ture : 지원, false : 미지원)
+             * Support.Sleep          - (boolean) 취침기능 지원여부    (ture : 지원, false : 미지원)
+             * Support.Reservation    - (boolean) 예약기능 지원여부    (ture : 지원, false : 미지원)
+             * Support.Pause          - (boolean) 일시정지 지원여부    (ture : 지원, false : 미지원)
+             *
+             * Support.AI             - (boolean) 인공지능 지원여부    (ture : 지원, false : 미지원)
+             * Support.OutsideTempUse - (boolean) 외기온도 사용여부    (ture : 사용, false : 미사용)
+             * Support.Boiler         - (boolean) 보일러 지원여부       (ture : 지원, false : 미지원)
+             */
+            Info info = mDriver.Device.info;
+
+            result = APIErrorCode.SUCCESS + ";";
+
+            result += info.RoomCount + ";" +
+            
+                      info.Vender + ";" +
+                      
+                      info.FwVer_Year + ";" +
+                      info.FwVer_Month + ";" +
+                      info.FwVer_Day + ";" +
+                      info.FwVer_Number + ";" +
+                      
+                      info.ProtocolVer_Main + ";" +
+                      info.ProtocolVer_Sub + ";" +
+                      
+                      info.Support.MinSetTemp + ";" +
+                      info.Support.MaxSetTemp + ";" +
+
+                      info.Support.SetTempPoint05 + ";" +
+                      info.Support.Outing + ";" +
+                      info.Support.Sleep + ";" +
+                      info.Support.Reservation + ";" +
+                      info.Support.Pause + ";" +
+                      
+                      info.Support.AI + ";" +
+                      info.Support.OutsideTempUse + ";" +
+                      info.Support.Boiler + ";" +
+                      info.Support.Leak + ";";
+        }
+        catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+            result = "FAIL;"+APIErrorCode.EXCEPTION;
+        }
+        catch (Exception e) {
+            Log.e(TAG, "[Exception Error] RefreshResult_Info");
+            //e.printStackTrace();
+            LogUtil.errorLogInfo("", TAG, e);
+            result = "FAIL;"+APIErrorCode.EXCEPTION;
+        }
+        DeviceLog(" GetRefreshResultInfo return : "+result);
+
+        return result;
+    }
+
+    /**
+     * Refresh 에 대한 응답포멧 정의
+     *
+     * param (byte) Index - 방 인덱스 (범위 : 0 ~ 7)
+     *
+     * @return (String) "SUCCESS; ..." 성공 , "FAIL; ... " 실패
+     */
+    private String RefreshResult_Room(byte Index)
+    {
+        String result = null;
+
+        DeviceLog("RefreshResult_Room call : ");
+
+        // 1. Check Polling Status
+        if( (mDriver.Polling.Status == Driver.PollingList.STATUS.First) ||
+                (mDriver.Polling.Status == Driver.PollingList.STATUS.FirstTimeOut) )
+        {
+            result = "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
+            return result;
+        }
+
+        // 2. Param Range Check
+        if(!(Index >= 0 && Index <= mDriver.Device.info.RoomCount))
+        {
+            result = "FAIL;"+APIErrorCode.INVALIDPARAMETER;
+            return result;
+        }
+
+        // 3. Make Return String Format
+        try
+        {
+            if(mDriver.Device == null)                   return "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
+            if(mDriver.Device.Room == null)              return "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
+            if(mDriver.Device.Room.length <= (int)Index) return "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
+            if(mDriver.Device.Room[Index] == null)       return "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
+
+            /*
+             * [Format]
+             *
+             * SUCCESS       - (String) 성공
+             *
+             * RequestIndex  - (byte)   요청 인덱스
+             *
+             * Mode          - (byte)    운전모드 (true : 설치 ,false : 미설치)
+             * bValveStatus  - (boolean) 밸브상태 ( ture : 열림, false : 닫힘 )
+             * SetTemp       - (double)  설정온도 ( 0.5도 혹은 1도 단위)
+             * NowTemp       - (double)  현재온도 ( 0.5도 혹은 1도 단위)
+             * Error         - (byte)    에러코드
+             *
+             * SLEEP         - (byte) 취침운전
+             *
+             * RESERVATION   - (int) 예약스케쥴
+             */
+            RoomData Room = mDriver.Device.Room[Index];
+
+            result = APIErrorCode.SUCCESS + ";";
+
+            result += Index + ";";
+
+            result += Room.Mode + ";" +
+                    Room.bValveStatus + ";" +
+                    Room.SetTemp + ";" +
+                    Room.NowTemp + ";" +
+                    Room.Error.getByte() + ";" +
+
+                    Room.Sleep.getByte() + ";" +
+
+                    Room.Reservation.getInt() + ";";
+        }
+        catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+            result = "FAIL;"+APIErrorCode.EXCEPTION;
+        }
+        catch (Exception e) {
+            Log.e(TAG, "[Exception Error] RefreshResult_Room");
+            //e.printStackTrace();
+            LogUtil.errorLogInfo("", TAG, e);
+            result = "FAIL;"+APIErrorCode.EXCEPTION;
+        }
+        DeviceLog(" RefreshResult_Room return : "+result);
+
+        return result;
+    }
+
+
+    /**
+     * 보일러 Refresh 에 대한 응답포멧 정의
+     *
+     * param (byte) Index - 방 인덱스 (범위 : 0 ~ 7)
+     *
+     * @return (String) "SUCCESS; ..." 성공 , "FAIL; ... " 실패
+     */
+    private String RefreshResult_Boiler()
+    {
+        String result = null;
+
+        DeviceLog("RefreshResult_Boiler call : ");
+
+        // 1. Check Polling Status
+        if( (mDriver.Polling.Status == Driver.PollingList.STATUS.First) ||
+                (mDriver.Polling.Status == Driver.PollingList.STATUS.FirstTimeOut) )
+        {
+            result = "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
+            return result;
+        }
+
+        // 2. Param Range Check
+
+        // 3. Make Return String Format
+        try
+        {
+            if(mDriver == null)                   return "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
+            if(mDriver.Boiler == null)            return "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
+
+            /*
+             * [Format]
+             *
+             * SUCCESS       - (String) 성공
+             *
+             * bFrostProtectMode - (boolean) 동파방지모드 (true : 가동, false : 정지)
+             * ErrorCode         - (byte) 에러코드 (0x00 정상 , 0x00 아닐경우 에러코드
+             *
+             * HeatingWater.bSetTempUnit5 - (boolean) 난방수  설정온도 단위 (false : 1도단위 , true : 5도 단위)
+             * HeatingWater.SetTemp       - (byte) 난방수  설정온도
+             * HeatingWater.MinSetTemp    - (byte) 난방수  최저 설정온도
+             * HeatingWater.MaxSetTemp    - (byte) 난방수  최대 설정온도
+             *
+             * HotWater.bSetTempUnit5 - (boolean) 온수  설정온도 단위 (false : 1도단위 , true : 5도 단위)
+             * HotWater.SetTemp       - (byte) 온수  설정온도
+             * HotWater.MinSetTemp    - (byte) 온수  최저 설정온도
+             * HotWater.MaxSetTemp    - (byte) 온수  최대 설정온도
+             */
+            BoilerData Boiler = mDriver.Boiler;
+
+            result = APIErrorCode.SUCCESS + ";";
+
+            result += Boiler.bFrostProtectMode + ";" +
+                    Boiler.ErrorCode + ";" +
+
+                    Boiler.HeatingWater.bSetTempUnit5 + ";" +
+                    Boiler.HeatingWater.SetTemp + ";" +
+                    Boiler.HeatingWater.MinSetTemp + ";" +
+                    Boiler.HeatingWater.MaxSetTemp + ";" +
+
+                    Boiler.HotWater.bSetTempUnit5 + ";" +
+                    Boiler.HotWater.SetTemp + ";" +
+                    Boiler.HotWater.MinSetTemp + ";" +
+                    Boiler.HotWater.MaxSetTemp + ";";
+        }
+        catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+            result = "FAIL;"+APIErrorCode.EXCEPTION;
+        }
+        catch (Exception e) {
+            Log.e(TAG, "[Exception Error] RefreshResult_Boiler");
+            //e.printStackTrace();
+            LogUtil.errorLogInfo("", TAG, e);
+            result = "FAIL;"+APIErrorCode.EXCEPTION;
+        }
+        DeviceLog(" RefreshResult_Boiler return : "+result);
+
+        return result;
+    }
+
+    /**
+     * 특화기능 Refresh 에 대한 응답포멧 정의
+     *
+     * param (byte) Index - 방 인덱스 (범위 : 0 ~ 7)
+     *
+     * @return (String) "SUCCESS; ..." 성공 , "FAIL; ... " 실패
+     */
+    private String RefreshResult_SpecialFunc()
+    {
+        String result = null;
+
+        DeviceLog("RefreshResult_SpecialFunc call : ");
+
+        // 1. Check Polling Status
+        if( (mDriver.Polling.Status == Driver.PollingList.STATUS.First) ||
+                (mDriver.Polling.Status == Driver.PollingList.STATUS.FirstTimeOut) )
+        {
+            result = "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
+            return result;
+        }
+
+        // 2. Param Range Check
+
+        // 3. Make Return String Format
+        try
+        {
+            if(mDriver == null)                   return "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
+            if(mDriver.SpecialFunc == null)       return "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
+
+            /*
+             * [Format]
+             *
+             * SUCCESS       - (String) 성공
+             *
+             * Mode        - (byte) 인공지능 동작모드
+             * OutsideTemp - (double) 설정된 외기온도
+             */
+            SpecialFuncData SpecialFunc = mDriver.SpecialFunc;
+
+            result = APIErrorCode.SUCCESS + ";";
+
+            result += SpecialFunc.Mode + ";" +
+                    SpecialFunc.OutsideTemp + ";";
+        }
+        catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+            result = "FAIL;"+APIErrorCode.EXCEPTION;
+        }
+        catch (Exception e) {
+            Log.e(TAG, "[Exception Error] RefreshResult_SpecialFunc");
+            //e.printStackTrace();
+            LogUtil.errorLogInfo("", TAG, e);
+            result = "FAIL;"+APIErrorCode.EXCEPTION;
+        }
+        DeviceLog(" RefreshResult_SpecialFunc return : "+result);
+
+        return result;
+    }
+
+    /**
+     * 보드 상태 읽기 요청 응답.
+     *
+     * @return (Info) null - Error , Not null - OK
+     */
+    private Info Send_GetDeviceInfo()
+    {
+        DeviceLog("[Send_GetDeviceInfo] Start");
+
+        // 1. In 파라미터 확인
+
+        // 2. 패킷 데이터 만들기
+        byte [] ReqData = null;
+
+        // 3. 데이터 전송 및 응답
+        byte [] Reply = SendNRead_Variable( (byte)(DEVICE_ADDRESS), CMDList.Req.GetDeviceInfo, ReqData);
+
+        // 4. 수신데이터 파싱
+        Info info = GetDeviceInfo_RepParsing(Reply);
+        if(info == null)
+        {
+            DeviceLog("[Send_GetDeviceInfo] Reply is null");
+            AddDoCount(false);
+            return null;
+        }
+        AddDoCount(true);
+
+        return info;
+    }
+
+    /**
+     * {@link #Send_GetDeviceInfo()}<br>
+     * 메소드의 응답 공통부분 메소드이다.
+     *
+     * @param Reply      - (byte []) 응답 Byte 배열
+     *
+     * @return (Info) null - Error , Not null - OK
+     */
+    private Info GetDeviceInfo_RepParsing(byte [] Reply)
+    {
+        // 1. 수신데이터 파싱
+        //     1.1. Default Check
+        if(Reply == null)
+        {
+            DeviceLog("[GetDeviceInfo_RepParsing] Reply is null");
+            return null;
+        }
+        if(Reply.length != 12)
+        {
+            Log.w(TAG, "[GetDeviceInfo_RepParsing] Reply.length  fail ... " + Reply.length);
+            return null;
+        }
+        //     1.2. Details Data Check
+        //         - D1 : 설치된 방 개수 X’01’ ~ X’08’
+        if( !((Reply[0] >= ROOM_COUNT_LOW) && (Reply[0] <= ROOM_COUNT_HI)) )
+        {
+            Log.w(TAG, "[GetDeviceInfo_RepParsing] D1 (RoomCount) : Out of Range !!! " + String.format("0x%02X", Reply[0]));
+            return null;
+        }
+        //         - D2 : 기본 기능 정보
+        if( (Reply[1] & (byte)(BIT5 | BIT6 | BIT7)) != 0x00 )
+        {
+            Log.w(TAG, "[GetDeviceInfo_RepParsing] D2 (DefultFuncInfo) : Unused Bit Set !!! " + String.format("0x%02X", Reply[1]));
+            return null;
+        }
+        //         - D3 : 특화 기능 정보
+        if( (Reply[2] & (byte)( BIT4 | BIT5 | BIT6 | BIT7)) != 0x00 )
+        {
+            Log.w(TAG, "[GetDeviceInfo_RepParsing] D3 (SpecialFuncInfo) : Unused Bit Set !!! " + String.format("0x%02X", Reply[2]));
+            return null;
+        }
+        //         - D4 : 지원하는 최저 설정온도
+        if( !((Reply[3] >= SETTEMP_MIN_LOW) && (Reply[3] <= SETTEMP_MIN_HI)) )
+        {
+            Log.w(TAG, "[GetDeviceInfo_RepParsing] D4 (MinTemp) : Out of Range !!! " + String.format("0x%02X", Reply[3]));
+            return null;
+        }
+        //         - D5 : 지원하는 최대 설정온도
+        if( !((Reply[4] >= SETTEMP_MAX_LOW) && (Reply[4] <= SETTEMP_MAX_HI)) )
+        {
+            Log.w(TAG, "[GetDeviceInfo_RepParsing] D5 (MaxTemp) : Out of Range !!! " + String.format("0x%02X", Reply[4]));
+            return null;
+        }
+        //         - D6 : 제조사 구분정보
+        if( !(Reply[5] >= 0x01) )
+        {
+            Log.w(TAG, "[GetDeviceInfo_RepParsing] D6 (Manufacturer) : Out of Range !!! " + String.format("0x%02X", Reply[5]));
+            return null;
+        }
+        //         - D7 : 펌웨어 Build Date (Year)
+        //         - D8 : 펌웨어 Build Date (Month)
+        if( !((Reply[7] >= 0x01) && (Reply[7] <= 0x0C)) )
+        {
+            Log.w(TAG, "[GetDeviceInfo_RepParsing] D8 (FW Build Data - Month) :  Out of Range !!! " + String.format("0x%02X", Reply[7]));
+            return null;
+        }
+        //         - D9 : 펌웨어 Build Date (Day)
+        if( !((Reply[8] >= 0x01) && (Reply[8] <= 0x1F)) )
+        {
+            Log.w(TAG, "[GetDeviceInfo_RepParsing] D9 (FW Build Data - Day) : Out of Range !!! " + String.format("0x%02X", Reply[8]));
+            return null;
+        }
+        //         - D10 : 펌웨어 Build Date (Number)
+        //         - D11 : Protocol 버전정보 (Main)
+        //         - D12 : Protocol 버전정보 (Sub)
+
+        // 2. Data return
+        Info info = new Info();
+        int index = 0;
+        byte data = 0;
+
+        //         - D1 : 설치된 방 개수 X’01’ ~ X’08’
+        if((mDriver.bFixRoomCountUse == true) && (mDriver.FixRoomCount >= ROOM_COUNT_LOW) && (mDriver.FixRoomCount <= ROOM_COUNT_HI))
+        {
+            /**
+             * [광주 무등산 임대세대 전용 기능]
+             임대세대는 에너지미터가 3개인데 벨브가 2개인 현장임
+             문제점:난방 제어화면에서 방이 3개로 나옴
+             해결:방개수 3개로 알려주면 강제로 2개로 설정함
+             필요사항:단지서버에서 온도조절기 회로수를 2개로 설정하면 됨
+             * **/
+            info.RoomCount = (byte) mDriver.FixRoomCount;
+            index++;
+            Log.w(TAG, "[GetDeviceInfo_RepParsing] info.RoomCount (Room Count) will be fixed : " + String.format("0x%02X", info.RoomCount));
+        }
+        else
+        {
+            info.RoomCount = Reply[index++];
+        }
+
+
+        //         - D2 : 기본 기능 정보
+        data = Reply[index++];
+        if((data & BIT0) != 0x00) info.Support.SetTempPoint05 = true;
+        else info.Support.SetTempPoint05 = false;
+        if((data & BIT1) != 0x00) info.Support.Outing = true;
+        else info.Support.Outing = false;
+        if((data & BIT2) != 0x00) info.Support.Sleep = true;
+        else info.Support.Sleep = false;
+        if((data & BIT3) != 0x00) info.Support.Reservation = true;
+        else info.Support.Reservation = false;
+        if((data & BIT4) != 0x00) info.Support.Pause = true;
+        else info.Support.Pause = false;
+
+        //         - D3 : 특화 기능 정보
+        data = Reply[index++];
+        if((data & BIT0) != 0x00) info.Support.AI = true;
+        else info.Support.AI = false;
+        if((data & BIT1) != 0x00) info.Support.OutsideTempUse = true;
+        else info.Support.OutsideTempUse = false;
+        if((data & BIT2) != 0x00) info.Support.Boiler = true;
+        else info.Support.Boiler = false;
+        if((data & BIT3) != 0x00) info.Support.Leak = true;
+        else info.Support.Leak = false;
+        
+        //         - D4 : 지원하는 최저 설정온도
+        info.Support.MinSetTemp = Reply[index++];
+        //         - D5 : 지원하는 최대 설정온도
+        info.Support.MaxSetTemp = Reply[index++];
+        //         - D6 : 제조사 구분정보
+        info.Vender           = Reply[index++];
+        //         - D7 : 펌웨어 Build Date (Year)
+        info.FwVer_Year       = Reply[index++];
+        //         - D8 : 펌웨어 Build Date (Month)
+        info.FwVer_Month      = Reply[index++];
+        //         - D9 : 펌웨어 Build Date (Day)
+        info.FwVer_Day        = Reply[index++];
+        //         - D10 : 펌웨어 Build Date (Number)
+        info.FwVer_Number     = Reply[index++];
+        //         - D11 : Protocol 버전정보 (Main)
+        info.ProtocolVer_Main = Reply[index++];
+        //         - D12 : Protocol 버전정보 (Sub)
+        info.ProtocolVer_Sub  = Reply[index++];
+
+        return info;
+    }
+
+    /**
+     * 각방 상태 요청 응답.
+     *
+     * @param RoomIndex - (byte) 요청 방인덱스
+     *
+     * @return (RoomData) null - Error , Not null - OK
+     */
+    private RoomData Send_GetEachRoomStatus(byte RoomIndex)
+    {
+        DeviceLog("[Send_GetEachRoomStatus] Start");
+
+        // 1. In 파라미터 확인
+        //         - D1 : 요청할 방번호
+        if( !((RoomIndex >= (ROOM_COUNT_LOW-1)) && (RoomIndex <= (ROOM_COUNT_HI-1))) )
+        {
+            Log.w(TAG, "[Send_GetEachRoomStatus] (RoomIndex) Request Param Out Of Range !!! " + RoomIndex);
+            return null;
+        }
+
+        // 2. 패킷 데이터 만들기
+        byte [] ReqData = new byte [] { (byte)(RoomIndex+1) };
+
+        // 3. 데이터 전송 및 응답
+        byte [] Reply = SendNRead_Variable( (byte)(DEVICE_ADDRESS), CMDList.Req.GetEachRoomStatus, ReqData);
+
+        // 4. 수신데이터 파싱
+        RoomData roomData = GetEachRoomStatus_RepParsing(RoomIndex, Reply);
+        if(roomData == null)
+        {
+            DeviceLog("[Send_GetEachRoomStatus] Reply is null");
+            AddDoCount(false);
+            return null;
+        }
+        AddDoCount(true);
+
+        return roomData;
+    }
+
+    /**
+     * 각방 제어 요청 응답.
+     *
+     * @param RoomIndex    - (byte) 제어할 방인덱스
+     * @param ctrlRoomData  - (CtrlRoomData) 제어 데이터 클래스
+     *
+     * @return (RoomData) null - Error , Not null - OK
+     */
+    private RoomData Send_SetEachRoomStatus(byte RoomIndex, CtrlRoomData ctrlRoomData)
+    {
+        DeviceLog("[Send_SetEachRoomStatus] Start");
+
+        // 1. In 파라미터 확인
+        //         - D1 : 요청할 방번호
+        if( !((RoomIndex >= (ROOM_COUNT_LOW-1)) && (RoomIndex <= (ROOM_COUNT_HI-1))) )
+        {
+            Log.w(TAG, "[Send_SetEachRoomStatus] (RoomIndex) Request Param Out Of Range !!!" + String.format("0x%02X", RoomIndex));
+            return null;
+        }
+
+        // 2. 패킷 데이터 만들기
+        byte [] ReqData = ConverterCtrlRoomData(RoomIndex, ctrlRoomData);
+        if(ReqData == null)
+        {
+            Log.w(TAG, "[Send_SetEachRoomStatus] ConverterCtrlRoomData null return");
+            return null;
+        }
+
+        // 3. 데이터 전송 및 응답
+        byte [] Reply = SendNRead_Variable( (byte)(DEVICE_ADDRESS), CMDList.Req.SetEachRoomStatus, ReqData);
+
+        // 4. 수신데이터 파싱
+        RoomData roomData = GetEachRoomStatus_RepParsing(RoomIndex, Reply);
+        if(roomData == null)
+        {
+            DeviceLog("[Send_SetEachRoomStatus] Reply is null");
+            AddDoCount(false);
+            return null;
+        }
+        AddDoCount(true);
+
+        return roomData;
+    }
+
+    /////////////////////////////////////////////////////////////////////
+    // 각방제어 명령을 통하여 예약운전스케쥴만 제어할 경우
+    // RoomNumber : 방번호, bReset (ture : 초기화, false : 복구), bPauseRelease (true : 일시정지 명령사용, false : 사용)
+    /////////////////////////////////////////////////////////////////////
+    private boolean Send_ReservationSettingInfo(byte RoomIndex, boolean bReset, boolean bPauseRelease)
+    {
+        // 제어 명령생성
+        CtrlRoomData ctrlRoomData = new CtrlRoomData();
+
+        int u32Temp = 0;
+        if (bReset == true)
+        {
+            if (bPauseRelease) ctrlRoomData.Mode = MODE.Pause;
+        }
+        else
+        {
+            u32Temp = mDriver.Device.Room[RoomIndex].Reservation.getInt();
+        }
+        ctrlRoomData.Reservation.setInt(u32Temp);
+
+        // 전송
+        RoomData roomData = Send_SetEachRoomStatus(RoomIndex, ctrlRoomData);
+        if (roomData == null) roomData = Send_SetEachRoomStatus(RoomIndex, ctrlRoomData);
+
+        if (bReset == true)
+        {
+            if (bPauseRelease)
+            {
+                Sleep(100);
+
+                ctrlRoomData.Mode = MODE.PauseRelease;
+                roomData = Send_SetEachRoomStatus(RoomIndex, ctrlRoomData);
+                if (roomData == null) roomData = Send_SetEachRoomStatus(RoomIndex, ctrlRoomData);
+            }
+        }
+
+        return true;
+    }
+
+
+    /**
+     * 각방 제어 요청 데이터 변환
+     *
+     * @param RoomIndex   - (byte) 요청할 방인덱스
+     * @param ctrlRoomData - (CtrlRoomData) 제어용 클래스
+     *
+     * @return (byte []) null - Error , Not null - OK
+     */
+    private byte [] ConverterCtrlRoomData(byte RoomIndex, CtrlRoomData ctrlRoomData)
+    {
+        // 1. Check RoomNumber
+        if((RoomIndex < 0) || (RoomIndex >= mDriver.Device.info.RoomCount))
+        {
+            Log.w(TAG, "[ConverterCtrlRoomData] RoomIndex - Out Of Range !!! " + RoomIndex);
+            return null;
+        }
+
+        // 2. Check CtrlRoomData Class
+        if(ctrlRoomData == null)
+        {
+            Log.w(TAG, "[ConverterCtrlRoomData] ctrlRoomData is null !!!");
+            return null;
+        }
+
+        // 3. Check Mode
+        byte Mode = ctrlRoomData.Mode;
+        if(!MODE.CheckSetMode(Mode))
+        {
+            Log.w(TAG, "[ConverterCtrlRoomData] Mode - Out Of Range !!! (" + String.format("%02X", Mode) + ")");
+            return null;
+        }
+
+        if((Mode == MODE.Outing) || (Mode == MODE.OutingRelease))
+        {
+            if(!mDriver.Device.info.Support.Outing)
+            {
+                Log.w(TAG, "[ConverterCtrlRoomData] Mode - No Support (Outing) !!! (" + String.format("%02X", Mode) + ")");
+                return null;
+            }
+        }
+        else if((Mode == MODE.Pause) || (Mode == MODE.PauseRelease))
+        {
+            if(!mDriver.Device.info.Support.Pause)
+            {
+                Log.w(TAG, "[ConverterCtrlRoomData] Mode - No Support (Pause) !!! (" + String.format("%02X", Mode) + ")");
+                return null;
+            }
+        }
+        else if(Mode == MODE.Sleep)
+        {
+            if(!mDriver.Device.info.Support.Sleep)
+            {
+                Log.w(TAG, "[ConverterCtrlRoomData] Mode - No Support (Sleep) !!! (" + String.format("%02X", Mode) + ")");
+                return null;
+            }
+        }
+        else if(Mode == MODE.Reservation)
+        {
+            if(!mDriver.Device.info.Support.Reservation)
+            {
+                Log.w(TAG, "[ConverterCtrlRoomData] Mode - No Support (Reservation) !!! (" + String.format("%02X", Mode) + ")");
+                return null;
+            }
+        }
+
+        // 4. Check SetTemp
+        if(ctrlRoomData.SetTemp != 0)
+        {
+            int Temp = (int)(ctrlRoomData.SetTemp * 10);
+            int Remainder = Temp%10;
+            if(Remainder != 0)
+            {
+                if(Remainder != 5)
+                {
+                    Log.w(TAG, "[ConverterCtrlRoomData] SetTemp - Out Of Range !!! (" + String.format("%d", Remainder) + ")");
+                    return null;
+                }
+            }
+            if( !((ctrlRoomData.SetTemp >= (double)mDriver.Device.info.Support.MinSetTemp) && (ctrlRoomData.SetTemp <= (double)mDriver.Device.info.Support.MaxSetTemp)) )
+            {
+                Log.w(TAG, "[ConverterCtrlRoomData] SetTemp - Out Of Range !!!  (" + ctrlRoomData.SetTemp + ")");
+                return null;
+            }
+        }
+
+        // 5. Check Sleep
+        if(ctrlRoomData.Sleep.getSupportNUse())
+        {
+            if(!mDriver.Device.info.Support.Sleep)
+            {
+                Log.w(TAG, "[ConverterCtrlRoomData] Sleep - Not Support !!!");
+                return null;
+            }
+        }
+
+        // 6. Check Reservation
+        if(ctrlRoomData.Reservation.getSupportNUse())
+        {
+            if(!mDriver.Device.info.Support.Reservation)
+            {
+                Log.w(TAG, "[ConverterCtrlRoomData] Reservation - Not Support !!!");
+                return null;
+            }
+        }
+
+        // 7. Make Paket
+
+        byte [] ReqData = new byte [8];
+        for(int i=0 ; i<ReqData.length ; i++) ReqData[i] = 0x00;
+        int Index = 0;
+
+        // 제어할 방번호
+        ReqData[Index++] = (byte)(RoomIndex+1);
+
+        // 운전모드
+        boolean IdleSet = false;
+        if(HEATINGOFF_NOSET_OUTTING)
+        {
+            if((Mode == MODE.Outing) || (Mode == MODE.OutingRelease))
+            {
+                if(mDriver.Device.Room[RoomIndex].Mode == MODE.HeatingOFF) IdleSet = true;
+            }
+        }
+        if(IdleSet) ReqData[Index++] = MODE.Idle;
+        else ReqData[Index++] = ctrlRoomData.Mode;
+
+        // 설정온도
+        if(ctrlRoomData.SetTemp != 0)
+        {
+            byte bTemp = (byte)ctrlRoomData.SetTemp;
+            int Temp = (int)(ctrlRoomData.SetTemp * 10);
+            int Remainder = Temp%10;
+            if(Remainder != 0) bTemp |= BIT6;
+
+            ReqData[Index++] = bTemp;
+        }
+        else Index++;
+
+        // 취침 운전 설정값
+        ReqData[Index++] = ctrlRoomData.Sleep.getByte();
+
+        // 예약운전
+        if(ctrlRoomData.Reservation.getSupportNUse())
+        {
+            ReqData[Index++] = 0x01;
+
+            byte [] ReservationData = ctrlRoomData.Reservation.getByte();
+            for(int i=0 ; i<3 ; i++)
+                ReqData[Index++] = ReservationData[i];
+        }
+        else
+        {
+            Index += 4;
+        }
+
+        return ReqData;
+    }
+
+    /**
+     * {@link #Send_GetEachRoomStatus(byte)}<br>
+     * {@link #Send_SetEachRoomStatus(byte, CtrlRoomData)}<br>
+     * 메소드의 응답 공통부분 메소드이다.
+     *
+     * @param RoomIndex - (byte) 요청 방인덱스
+     * @param Reply      - (byte []) 응답 Byte 배열
+     *
+     * @return (RoomData) null - Error , Not null - OK
+     */
+    private RoomData GetEachRoomStatus_RepParsing(byte RoomIndex, byte [] Reply)
+    {
+        // 1. 수신데이터 파싱
+        //     1.1. Default Check
+        if(Reply == null)
+        {
+            DeviceLog("[GetEachRoomStatus_RepParsing] Reply is null");
+            return null;
+        }
+        if(Reply.length != 10)
+        {
+            Log.w(TAG, "[GetEachRoomStatus_RepParsing] Reply.length  fail ... " + Reply.length);
+            return null;
+        }
+
+        int index = 0;
+        byte data = 0x00;
+        byte data2 = 0x00;
+        //     1.2. Details Data Check
+        //          - D1 : 응답 방번호
+        data = Reply[index++];
+        if( (data & (byte)(BIT4 | BIT5 | BIT6)) != 0x00 )
+        {
+            // 미사용 비트'0' 확인
+            Log.w(TAG, "[GetEachRoomStatus_RepParsing] D1 (ReplyRoomNumber) : Unused Bit Set !!! " + String.format("0x%02X", data));
+            return null;
+        }
+        if((byte)(data & (byte)(~BIT7)) != (byte)(RoomIndex+1))
+        {
+            // 요청방 응답방 번호 일치여부
+            Log.w(TAG, "[GetEachRoomStatus_RepParsing] D1 (ReplyRoomNumber) :  Rsp Rep Data Different !!! " + "(Rsp:" + (byte)(RoomIndex+1) + ", Rep:" + data + ")");
+            return null;
+        }
+        if((byte)(data & BIT7) != 0x00)
+        {
+            // 요청방의 존재여부 체크
+            Log.w(TAG, "[GetEachRoomStatus_RepParsing] D1 (ReplyRoomNumber) :  Not Supported Room !!! " + "(RoomNumber:" + (byte)(RoomIndex+1) + ")");
+            return null;
+        }
+        //          - D2 : 운전모드 및 밸브상태
+        data = Reply[index++];
+        if( (data & (byte)(BIT5 | BIT6 | BIT7)) != 0x00 )
+        {
+            // 미사용 비트'0' 확인
+            Log.w(TAG, "[GetEachRoomStatus_RepParsing] D2 (Mode) : Unused Bit Set !!! " + String.format("0x%02X", data));
+            return null;
+        }
+        byte Mode = (byte)(data & (byte)(BIT0 | BIT1 | BIT2 | BIT3));
+        if(MODE.CheckGetMode(Mode) == false)
+        {
+            // 운전모드 범위확인
+            Log.w(TAG, "[GetEachRoomStatus_RepParsing] D2 (Mode) : Out of Range !!!" + String.format("0x%02X", Mode));
+            return null;
+        }
+
+        //          - D3 : 설정온도
+        data = Reply[index++];
+        if( (data & (byte)(BIT7)) != 0x00 )
+        {
+            // 미사용 비트'0' 확인
+            Log.w(TAG, "[GetEachRoomStatus_RepParsing] D3 (SetTemp) : Unused Bit Set !!! " + String.format("0x%02X", data));
+            return null;
+        }
+        data2 = (byte)(data & (byte)(BIT0 | BIT1 | BIT2 | BIT3 | BIT4 | BIT5));
+        if( !((data2 >= SETTEMP_MIN_LOW) && (data2 <= SETTEMP_MAX_HI)) )
+        {
+            // 설정온도 범위체크
+            Log.w(TAG, "[GetEachRoomStatus_RepParsing] D3 (SetTemp) : Out of Range !!! " + String.format("0x%02X", data2));
+            return null;
+        }
+
+        //          - D4 ~ D5 : 현재온도
+        data = Reply[index++];
+        data2 = Reply[index++];
+        double NowTemp = Converter2ByteToDoubleP1(data, data2);
+        if( !((NowTemp >= NOWTEMP_MIN) && (NowTemp <= NOWTEMP_MAX)) )
+        {
+            // 현재온도 범위체크
+            Log.w(TAG, "[GetEachRoomStatus_RepParsing] D5~D6 (NowTemp) : Out of Range !!! " + NowTemp);
+            return null;
+        }
+
+        //          - D6 : 에러코드
+        data = Reply[index++];
+        /*if( (data & (byte)(BIT6)) != 0x00 )
+        {
+            // 미사용 비트'0' 확인
+            Log.w(TAG, "[GetEachRoomStatus_RepParsing] D7 (ErrorCode) : Unused Bit Set !!! " + String.format("0x%02X", data));
+            return null;
+        }*/
+        
+        //          - D7 : 취침운전 설정값
+        data = Reply[index++];
+        if(data != 0x00)
+        {
+            if ( (byte)(data & (byte)(BIT0 | BIT1 | BIT2 | BIT3 | BIT4)) > (byte)0x13)
+            {
+                Log.w(TAG, "[GetEachRoomStatus_RepParsing] D8 (Sleep Time) : Out of Range !!! " + String.format("0x%02X", data));
+                return null;
+            }
+            if ((( (data >> 5) & (byte)(BIT5 | BIT6 | BIT7)) >> 5) > 0x03)
+            {
+                Log.w(TAG, "[GetEachRoomStatus_RepParsing] D8 (Sleep Temp) : Out of Range !!! " + String.format("0x%02X", data));
+                return null;
+            }
+        }
+
+        //          - D8~D10 : 예약설정 정보
+
+        // 2. Data return
+        index = 0;
+        data = 0x00;
+        RoomData roomData = new RoomData();
+
+        //          - D1 : 응답 방번호
+        index++;
+
+        //          - D2 : 운전모드 및 밸브상태
+        data = Reply[index++];
+        roomData.Mode = Mode;
+        if((data & BIT4) != 0x00) roomData.bValveStatus = true;
+        else roomData.bValveStatus = false;
+
+        //          - D3 : 설정온도
+        double dTemp = 0;
+        data = Reply[index++];
+        dTemp = (double)getInt( (byte)(data & (byte) (BIT0 | BIT1 | BIT2 | BIT3 | BIT4 | BIT5)));
+        if((data & BIT6) != 0x00) dTemp += (double)0.5;
+        roomData.SetTemp = Double.parseDouble(String.format("%.1f", dTemp));
+
+        //          - D4 ~ D5 : 현재온도
+        index++;
+        index++;
+        roomData.NowTemp = NowTemp;
+
+        //          - D6 : 에러코드
+        data = Reply[index++];
+        roomData.Error.setByte(data);
+
+        //          - D7 : 취침운전 설정값
+        data = Reply[index++];
+        if(data != 0x00) roomData.Sleep.setByte(data);
+
+
+        //          - D8~D10 : 예약설정 정보
+        if(mDriver.Device.info.Support.Reservation)
+        {
+            byte [] ReservationData = new byte[3];
+            ReservationData[0] = Reply[index++];
+            ReservationData[1] = Reply[index++];
+            ReservationData[2] = Reply[index++];
+            roomData.Reservation.setByte(ReservationData);
+        }
+
+        return roomData;
+    }
+
+    /**
+     * 전체방 상태 요청 응답.
+     *
+     * @return (AllRoomData) null - Error , Not null - OK
+     */
+    private AllRoomData Send_GetAllRoomStatus()
+    {
+        DeviceLog("[Send_GetAllRoomStatus] Start");
+
+        // 1. In 파라미터 확인
+
+        // 2. 패킷 데이터 만들기
+        byte [] ReqData = null;
+
+        // 3. 데이터 전송 및 응답
+        byte [] Reply = SendNRead_Variable( (byte)(DEVICE_ADDRESS), CMDList.Req.GetAllRoomStatus, ReqData);
+
+        // 4. 수신데이터 파싱
+        AllRoomData allRoomData = GetAllRoomStatus_RepParsing(Reply);
+        if(allRoomData == null)
+        {
+            DeviceLog("[Send_GetAllRoomStatus] Reply is null");
+            AddDoCount(false);
+            return null;
+        }
+        AddDoCount(true);
+
+        return allRoomData;
+    }
+
+    /**
+     * 전체방 상태 제어 응답.
+     *
+     * @param TimeSet    - (boolean) 현재시간 설정여부 (true:설정, false:미설정)
+     * @param ChangeMode - (byte)    변경할 모드
+     * @param RoomCount  - (byte)    변경할 방개수
+     *
+     * @return (AllRoomData) null - Error , Not null - OK
+     */
+    private AllRoomData Send_SetAllRoomStatus(boolean TimeSet, byte ChangeMode, byte RoomCount)
+    {
+        DeviceLog("[Send_SetAllRoomStatus] Start (" + TimeSet + " / " + ChangeMode + ")");
+
+        // 1. In 파라미터 확인
+        if(!MODE.CheckSetMode(ChangeMode))
+        {
+            Log.w(TAG, "[Send_SetAllRoomStatus] (ChangeMode) Request Param Out Of Range !!!" + String.format("0x%02X", ChangeMode));
+            return null;
+        }
+        if(ChangeMode != MODE.Idle)
+        {
+            if((RoomCount <= 0) || (RoomCount > mDriver.Device.info.RoomCount))
+            {
+                Log.w(TAG, "[Send_SetAllRoomStatus] (RoomCount) Request Param Out Of Range !!!" + String.format("0x%02X", RoomCount));
+                return null;
+            }
+        }
+
+        // 2. 패킷 데이터 만들기
+        byte [] ReqData = new byte [7];
+        for(byte i=0 ; i<ReqData.length ; i++) ReqData[i] = 0x00;
+
+        int index = 0;
+        if(TimeSet)
+        {
+            Calendar cal = new GregorianCalendar();
+            ReqData[index++] = 0x01;
+            ReqData[index++] = (byte) cal.get(Calendar.HOUR_OF_DAY);
+            ReqData[index++] = (byte) cal.get(Calendar.MINUTE);
+
+        }
+        else
+        {
+            ReqData[index++] = 0x00;
+            ReqData[index++] = 0x00;
+            ReqData[index++] = 0x00;
+        }
+
+        if(ChangeMode != MODE.Idle)
+        {
+            byte [] ModeArray = new byte [8];
+            for(byte i=0 ; i<ModeArray.length ; i++) ModeArray[i] = MODE.Idle;
+
+            for(byte i=0 ; i<RoomCount ; i++)
+            {
+                boolean IdleSet = false;
+                if(HEATINGOFF_NOSET_OUTTING)
+                {
+                    if( (ChangeMode == MODE.Outing) ||
+                            (ChangeMode == MODE.OutingRelease) )
+                    {
+                        if(mDriver.Device.Room[i].Mode == MODE.HeatingOFF) IdleSet = true;
+                    }
+                }
+
+                if(!IdleSet)
+                {
+                    ModeArray[i] = ChangeMode;
+                }
+            }
+
+            byte RoomIndex = 0;
+            byte Temp = 0;
+
+            for(int i=0 ; i<4 ; i++)
+            {
+                Temp = (byte)ModeArray[RoomIndex++];
+                Temp |= (byte)(((byte)ModeArray[RoomIndex++] << 4) & (byte)0xF0);
+                ReqData[index++] = Temp;
+            }
+        }
+        else
+        {
+            ReqData[index++] = 0x00;
+            ReqData[index++] = 0x00;
+            ReqData[index++] = 0x00;
+            ReqData[index++] = 0x00;
+        }
+
+        // 3. 데이터 전송 및 응답
+        byte [] Reply = SendNRead_Variable( (byte)(DEVICE_ADDRESS), CMDList.Req.SetAllRoomStatus, ReqData);
+
+        // 4. 수신데이터 파싱
+        AllRoomData allRoomData = GetAllRoomStatus_RepParsing(Reply);
+        if(allRoomData == null)
+        {
+            DeviceLog("[Send_SetAllRoomStatus] Reply is null");
+            AddDoCount(false);
+            return null;
+        }
+        AddDoCount(true);
+
+        return allRoomData;
+    }
+
+    /**
+     * 전체방 제어 명령을 통하여 현재 시간만 셋팅하는 경우
+     *
+     * @return - (boolean) true : 성공 , false : 실패
+     */
+    private boolean Send_NowTimeSet()
+    {
+        AllRoomData allRoomData = Send_SetAllRoomStatus(true, (byte)0x00, (byte)0x00);
+        if(allRoomData == null)
+        {
+            AddDoCount(false);
+            return false;
+        }
+        AddDoCount(true);
+
+        return true;
+    }
+
+    /**
+     * {@link #Send_GetAllRoomStatus()} <br>
+     * {@link #Send_SetAllRoomStatus(boolean, byte, byte)} <br>
+     *
+     * 메소드의 응답 공통부분 메소드이다.
+     *
+     * @param Reply      - (byte []) 응답 Byte 배열
+     *
+     * @return (AllRoomData) null - Error , Not null - OK
+     */
+    private AllRoomData GetAllRoomStatus_RepParsing(byte [] Reply)
+    {
+        // 1. 수신데이터 파싱
+        //     1.1. Default Check
+        if(Reply == null)
+        {
+            DeviceLog("[GetAllRoomStatus_RepParsing] Reply is null");
+            return null;
+        }
+        if(Reply.length < (3+4))
+        {
+            // 최소사이즈는 기본 3byte + 방1개 4byte = 7byte 이다.
+            Log.w(TAG, "[GetAllRoomStatus_RepParsing] Reply.length  fail #1... " + Reply.length);
+            return null;
+        }
+        byte RoomCount = Reply[2];
+        if( !((RoomCount >= ROOM_COUNT_LOW) && (RoomCount <= ROOM_COUNT_HI)) )
+        {
+            // 방개수 범위체크
+            Log.w(TAG, "[GetAllRoomStatus_RepParsing] RoomCount  Out Of Range !!! " + RoomCount);
+            return null;
+        }
+        if(Reply.length != (int) (3+(RoomCount*4)))
+        {
+            // 방개수에 따른 가변데이터 비교
+            Log.w(TAG, "[GetAllRoomStatus_RepParsing] Reply.length  fail #2... " + "(length:" +Reply.length + " / RoomCount:" + RoomCount + ")");
+            return null;
+        }
+        byte data = 0x00;
+        byte data2 = 0x00;
+        int index = 0;
+        //          - D1 : 현재시간 (시)
+        data = Reply[index++];
+        if((data > 23) || (data < 0))
+        {
+            Log.w(TAG, "[GetAllRoomStatus_RepParsing] D1 (Time Hour) : Out of Range !!! " + String.format("0x%02X", data));
+            return null;
+        }
+        //          - D2 : 현재시간 (분)
+        data = Reply[index++];
+        if((data > 59) || (data < 0))
+        {
+            Log.w(TAG, "[GetAllRoomStatus_RepParsing] D2 (Time Min) : Out of Range !!! " + String.format("0x%02X", data));
+            return null;
+        }
+
+        index++;
+        for(byte i=0 ; i<RoomCount ; i++)
+        {
+            //          - D1+X : 운전모드 및 밸브상태
+            data = Reply[index++];
+            if( (data & (byte)(BIT5 | BIT6 | BIT7)) != 0x00 )
+            {
+                // 미사용 비트'0' 확인
+                Log.w(TAG, "[GetAllRoomStatus_RepParsing] D" + index + " (Mode) : Unused Bit Set !!! " + String.format("0x%02X", data));
+                return null;
+            }
+            data2 = (byte)(data & (byte)(BIT0 | BIT1 | BIT2 | BIT3));
+            if(MODE.CheckGetMode(data2) == false)
+            {
+                // 운전모드 범위확인
+                Log.w(TAG, "[GetAllRoomStatus_RepParsing] D" + index + " (Mode) : Out of Range !!!" + String.format("0x%02X", data2));
+                return null;
+            }
+
+            //          - D2+X : 설정온도
+            data = Reply[index++];
+            if( (data & (byte)(BIT7)) != 0x00 )
+            {
+                // 미사용 비트'0' 확인
+                Log.w(TAG, "[GetAllRoomStatus_RepParsing] D" + index + " (SetTemp) : Unused Bit Set !!! " + String.format("0x%02X", data));
+                return null;
+            }
+            data2 = (byte)(data & (byte)(BIT0 | BIT1 | BIT2 | BIT3 | BIT4 | BIT5));
+            if( !((data2 >= SETTEMP_MIN_LOW) && (data2 <= SETTEMP_MAX_HI)) )
+            {
+                // 설정온도 범위체크
+                Log.w(TAG, "[GetAllRoomStatus_RepParsing] D" + index + " (SetTemp) : Out of Range !!! " + String.format("0x%02X", data2));
+                return null;
+            }
+
+            //          - D3+X ~ D4+X : 현재온도
+            data = Reply[index++];
+            data2 = Reply[index++];
+            double NowTemp = Converter2ByteToDoubleP1(data, data2);
+            if( !((NowTemp >= NOWTEMP_MIN) && (NowTemp <= NOWTEMP_MAX)) )
+            {
+                // 현재온도 범위체크
+                Log.w(TAG, "[GetAllRoomStatus_RepParsing] D" + (index-1) + " ~ D" + index + " (NowTemp) : Out of Range !!! " + NowTemp);
+                return null;
+            }
+        }
+
+
+        // 2. Data return
+
+        //[광주 무등한 임대세대 전용 기능]
+        if((mDriver.bFixRoomCountUse == true) && (mDriver.FixRoomCount >= ROOM_COUNT_LOW) && (mDriver.FixRoomCount <= ROOM_COUNT_HI))
+        {
+            /**
+             * [광주 무등산 임대세대 전용 기능]
+             임대세대는 에너지미터가 3개인데 벨브가 2개인 현장임
+             문제점:난방 제어화면에서 방이 3개로 나옴
+             해결:방개수 3개로 알려주면 강제로 2개로 설정함
+             필요사항:단지서버에서 온도조절기 회로수를 2개로 설정하면 됨
+             * **/
+            RoomCount = (byte) mDriver.FixRoomCount;
+        }
+
+        index = 0;
+        data = 0x00;
+        AllRoomData allRoomData = new AllRoomData(RoomCount);
+
+        index = 3;
+        for(byte i=0 ; i<RoomCount ; i++)
+        {
+            //          - D2 : 운전모드 및 밸브상태
+            data = Reply[index++];
+            allRoomData.Room[i].Mode = (byte)(data & (byte)(BIT0 | BIT1 | BIT2 | BIT3));
+            if((data & BIT4) != 0x00) allRoomData.Room[i].bValveStatus = true;
+            else allRoomData.Room[i].bValveStatus = false;
+
+            //          - D3 : 설정온도
+            double dTemp = 0;
+            data = Reply[index++];
+            dTemp = (double)getInt( (byte)(data & (byte) (BIT0 | BIT1 | BIT2 | BIT3 | BIT4 | BIT5)));
+            if((data & BIT6) != 0x00) dTemp += (double)0.5;
+            allRoomData.Room[i].SetTemp = Double.parseDouble(String.format("%.1f", dTemp));
+
+            //          - D4 ~ D5 : 현재온도
+            data = Reply[index++];
+            data2 = Reply[index++];
+            allRoomData.Room[i].NowTemp = Converter2ByteToDoubleP1(data, data2);
+        }
+
+        return allRoomData;
+    }
+
+    /**
+     * 보일러 상태 요청 응답.
+     *
+     * @return (BoilerData) null - Error , Not null - OK
+     */
+    private BoilerData Send_GetBoilerStatus()
+    {
+        DeviceLog("[Send_GetBoilerStatus] Start");
+
+        // 1. In 파라미터 확인
+
+        // 2. 패킷 데이터 만들기
+        byte [] ReqData = null;
+
+        // 3. 데이터 전송 및 응답
+        byte [] Reply = SendNRead_Variable( (byte)(DEVICE_ADDRESS), CMDList.Req.GetBoilerStatus, ReqData);
+
+        // 4. 수신데이터 파싱
+        BoilerData boilerData = BoilerStatus_ReplyParsing(Reply);
+        if(boilerData == null)
+        {
+            DeviceLog("[Send_GetBoilerStatus] Reply is null");
+            AddDoCount(false);
+            return null;
+        }
+        AddDoCount(true);
+
+        return boilerData;
+    }
+
+    /**
+     * 보일러 제어 요청 응답.
+     *
+     * @return (BoilerData) null - Error , Not null - OK
+     */
+    private BoilerData Send_SetBoilerStatus(byte HeatingWaterTemp, byte HotWaterTemp)
+    {
+        DeviceLog("[Send_SetBoilerStatus] Start (" + HeatingWaterTemp + ", " + HotWaterTemp + ")");
+
+        // 1. In 파라미터 확인
+        //      난방수 설정온도
+        if(HeatingWaterTemp != 0x00)
+        {
+            byte HeatingWaterTempMIN = mDriver.Boiler.HeatingWater.MinSetTemp;
+            byte HeatingWaterTempMAX = mDriver.Boiler.HeatingWater.MaxSetTemp;
+            if (HeatingWaterTempMIN == 0) HeatingWaterTempMIN = BOILER_HEAT_WATER_MIN;
+            if (HeatingWaterTempMAX == 0) HeatingWaterTempMAX = BOILER_HEAT_WATER_MAX;
+            if ((HeatingWaterTemp < HeatingWaterTempMIN) || (HeatingWaterTemp > HeatingWaterTempMAX))
+            {
+                Log.w(TAG, "[Send_SetBoilerStatus] (HeatingWaterTemp) Request Param Out Of Range !!!" + String.format("0x%02X", HeatingWaterTemp));
+                return null;
+            }
+        }
+        //      온수 설정온도
+        if(HotWaterTemp != 0x00)
+        {
+            byte HotWaterTempMIN = mDriver.Boiler.HotWater.MinSetTemp;
+            byte HotWaterTempMAX = mDriver.Boiler.HotWater.MaxSetTemp;
+            if (HotWaterTempMIN == 0) HotWaterTempMIN = BOILER_HOT_WATER_MIN;
+            if (HotWaterTempMAX == 0) HotWaterTempMAX = BOILER_HOT_WATER_MAX;
+            if ((HotWaterTemp < HotWaterTempMIN) || (HotWaterTemp > HotWaterTempMAX))
+            {
+                Log.w(TAG, "[Send_SetBoilerStatus] (HotWaterTemp) Request Param Out Of Range !!!" + String.format("0x%02X", HotWaterTemp));
+                return null;
+            }
+        }
+
+        // 2. 패킷 데이터 만들기
+        byte [] ReqData = new byte [] { HeatingWaterTemp, HotWaterTemp };
+
+        // 3. 데이터 전송 및 응답
+        byte [] Reply = SendNRead_Variable( (byte)(DEVICE_ADDRESS), CMDList.Req.SetBoilerStatus, ReqData);
+
+        // 4. 수신데이터 파싱
+        BoilerData boilerData = BoilerStatus_ReplyParsing(Reply);
+        if(boilerData == null)
+        {
+            DeviceLog("[Send_SetBoilerStatus] Reply is null");
+            AddDoCount(false);
+            return null;
+        }
+        AddDoCount(true);
+
+        return boilerData;
+    }
+
+    /**
+     * {@link #Send_GetBoilerStatus()} <br>
+     * {@link #Send_SetBoilerStatus(byte, byte)} <br>
+     *
+     * 메소드의 응답 공통부분 메소드이다.
+     *
+     * @param Reply      - (byte []) 응답 Byte 배열
+     *
+     * @return (BoilerData) null - Error , Not null - OK
+     */
+    private BoilerData BoilerStatus_ReplyParsing(byte [] Reply)
+    {
+        // 1. 수신데이터 파싱
+        //     1.1. Default Check
+        if(Reply == null)
+        {
+            DeviceLog("[BoilerStatus_ReplyParsing] Reply is null");
+            return null;
+        }
+        if(Reply.length != 8)
+        {
+            // 길이 체크
+            Log.w(TAG, "[BoilerStatus_ReplyParsing] Reply.length  fail ... " + Reply.length);
+            return null;
+        }
+
+
+        byte data = 0x00;
+        int index = 0;
+
+        //          - D1 : 보일러모드
+        data = Reply[index++];
+        if ((data & (byte)(BIT6 | BIT7)) != 0x00)
+        {
+            // 미사용 비트'0' 확인
+            Log.w(TAG, "[BoilerStatus_ReplyParsing] D1 (Mode) : Unused Bit Set !!! " + String.format("0x%02X", data));
+            return null;
+        }
+        //     동파방지모드
+        switch (data & (byte)(BIT0 | BIT1))
+        {
+            case 0x01:      // 가동
+            case 0x02:      // 정지
+                break;
+            default:
+                Log.w(TAG, "[BoilerStatus_ReplyParsing] D1 (FrostProtectMode) : Out of Range !!! " + String.format("0x%02X", data));
+                return null;
+        }
+        //     난방수 설정온도 단위
+        switch ((data>>2) & (byte)(BIT0 | BIT1))
+        {
+            case 0x00:      // 1℃ 단위
+            case 0x01:      // 5℃ 단위
+                break;
+            default:
+                Log.w(TAG, "[BoilerStatus_ReplyParsing] D1 (HeatingWater) : Out of Range !!! " + String.format("0x%02X", data));
+                return null;
+        }
+        //     온수 설정온도 단위
+        switch ((data>>4) & (byte)(BIT0 | BIT1))
+        {
+            case 0x00:      // 1℃ 단위
+            case 0x01:      // 5℃ 단위
+                break;
+            default:
+                Log.w(TAG, "[BoilerStatus_ReplyParsing] D1 (HotWater) : Out of Range !!! " + String.format("0x%02X", data));
+                return null;
+        }
+        byte MinTemp = 0;
+        byte MaxTemp = 0;
+        //          - D2 : 난방수 최저 설정온도 (30도~89도)
+        MinTemp = Reply[index++];
+        if( !((MinTemp >= BOILER_HEAT_WATER_MIN) && (MinTemp <= (BOILER_HEAT_WATER_MAX-1))) )
+        {
+            Log.w(TAG, "[BoilerStatus_ReplyParsing] D2 (HeatingWater.MinSetTemp) : Out of Range !!! " + String.format("0x%02X", MinTemp));
+            return null;
+        }
+        //          - D3 : 난방수 최저 설정온도 (30도~89도)
+        MaxTemp = Reply[index++];
+        if( !((MaxTemp >= (BOILER_HEAT_WATER_MIN+1)) && (MaxTemp <= BOILER_HEAT_WATER_MAX)) )
+        {
+            Log.w(TAG, "[BoilerStatus_ReplyParsing] D3 (HeatingWater.MaxSetTemp) : Out of Range !!! " + String.format("0x%02X", MaxTemp));
+            return null;
+        }
+        //          - 예외상황 : 최저 설정온도가 최대설정온도보다 높을수는 없음
+        if (MinTemp > MaxTemp)
+        {
+            Log.w(TAG, "[BoilerStatus_ReplyParsing] D2~D3:HeatingWater The MinTemp is Higher!!!  Out of Range (MinTemp : " + MinTemp + ", MaxTemp : " + MaxTemp + ")");
+            return null;
+        }
+        //          - D4 : 난방수 설정온도 (MinTemp ~ MaxTemp)
+        data = Reply[index++];
+        if ((data < MinTemp) || (data > MaxTemp))
+        {
+            Log.w(TAG, "[BoilerStatus_ReplyParsing] D4 (HeatingWater.SetTemp) : Out of Range !!! " + "(Min:" + MinTemp + " / " + "Max:" + MaxTemp + " / Set:" + data + ")");
+            return null;
+        }
+
+        //          - D5 : 온수 최저 설정온도 (30도~89도)
+        MinTemp = Reply[index++];
+        if( !((MinTemp >= BOILER_HOT_WATER_MIN) && (MinTemp <= (BOILER_HOT_WATER_MAX-1))) )
+        {
+            Log.w(TAG, "[BoilerStatus_ReplyParsing] D5 (HotWater.MinSetTemp) : Out of Range !!! " + String.format("0x%02X", MinTemp));
+            return null;
+        }
+        //          - D6 : 온수 최저 설정온도 (30도~89도)
+        MaxTemp = Reply[index++];
+        if( !((MaxTemp >= (BOILER_HOT_WATER_MIN+1)) && (MaxTemp <= BOILER_HOT_WATER_MAX)) )
+        {
+            Log.w(TAG, "[BoilerStatus_ReplyParsing] D6 (HotWater.MaxSetTemp) : Out of Range !!! " + String.format("0x%02X", MaxTemp));
+            return null;
+        }
+        //          - 예외상황 : 최저 설정온도가 최대설정온도보다 높을수는 없음
+        if (MinTemp > MaxTemp)
+        {
+            Log.w(TAG, "[BoilerStatus_ReplyParsing] D5~D6:HotWater The MinTemp is Higher!!!  Out of Range (MinTemp : " + MinTemp + ", MaxTemp : " + MaxTemp + ")");
+            return null;
+        }
+        //          - D7 : 온수 설정온도 (MinTemp ~ MaxTemp)
+        data = Reply[index++];
+        if ((data < MinTemp) || (data > MaxTemp))
+        {
+            Log.w(TAG, "[BoilerStatus_ReplyParsing] D7 (HotWater.SetTemp) : Out of Range !!! " + "(Min:" + MinTemp + " / " + "Max:" + MaxTemp + " / Set:" + data + ")");
+            return null;
+        }
+
+        //      - D8 : 보일러 에러코드
+        //data = Reply[index++];
+
+
+        // 2. Data return
+        index = 0;
+        BoilerData boilerData = new BoilerData();
+
+        data = Reply[index++];
+        if( (byte)(data & (byte)(BIT0 | BIT1)) == (byte)0x01) boilerData.bFrostProtectMode = true;
+        else boilerData.bFrostProtectMode = false;
+        if( (byte)(data & (byte)(BIT2 | BIT3)) == (byte)0x00) boilerData.HeatingWater.bSetTempUnit5 = false;
+        else boilerData.HeatingWater.bSetTempUnit5 = true;
+        if( (byte)(data & (byte)(BIT4 | BIT5)) == (byte)0x00) boilerData.HotWater.bSetTempUnit5 = false;
+        else boilerData.HotWater.bSetTempUnit5 = true;
+
+        boilerData.HeatingWater.MinSetTemp = Reply[index++];
+        boilerData.HeatingWater.MaxSetTemp = Reply[index++];
+        boilerData.HeatingWater.SetTemp    = Reply[index++];
+
+        boilerData.HotWater.MinSetTemp = Reply[index++];
+        boilerData.HotWater.MaxSetTemp = Reply[index++];
+        boilerData.HotWater.SetTemp    = Reply[index++];
+
+        boilerData.ErrorCode = Reply[index++];
+
+        return boilerData;
+    }
+
+    /**
+     * 특화기능 상태 요청 응답.
+     *
+     * @return (SpecialFuncData) null - Error , Not null - OK
+     */
+    private SpecialFuncData Send_GetSpecialFuncStatus()
+    {
+        DeviceLog("[Send_GetSpecialFuncStatus] Start");
+
+        // 1. In 파라미터 확인
+
+        // 2. 패킷 데이터 만들기
+        byte [] ReqData = null;
+
+        // 3. 데이터 전송 및 응답
+        byte [] Reply = SendNRead_Variable( (byte)(DEVICE_ADDRESS), CMDList.Req.GetSpecialFuncStatus, ReqData);
+
+        // 4. 수신데이터 파싱
+        SpecialFuncData specialFuncData = SpecialFunc_ReplyParsing(Reply);
+        if(specialFuncData == null)
+        {
+            DeviceLog("[Send_GetSpecialFuncStatus] Reply is null");
+            AddDoCount(false);
+            return null;
+        }
+        AddDoCount(true);
+
+        return specialFuncData;
+    }
+
+    /**
+     * 특화기능 제어 요청 응답.
+     *
+     * @return (SpecialFuncData) null - Error , Not null - OK
+     */
+    private SpecialFuncData Send_SetSpecialFuncStatus(boolean bSetOutsideTemp, int OutsideTemp, byte AiMode)
+    {
+        DeviceLog("[Send_SetSpecialFuncStatus] Start");
+
+        // 1. In 파라미터 확인
+        if(bSetOutsideTemp)
+        {
+            if (OutsideTemp > 60)
+            {
+                Log.w(TAG, "[Send_SetSpecialFuncStatus] - OutsideTemp Out of Range 1 (" + OutsideTemp + ")");
+                return null;
+            }
+            if (OutsideTemp < -60)
+            {
+                Log.w(TAG, "[Send_SetSpecialFuncStatus] - OutsideTemp Out of Range 2 (" + OutsideTemp + ")");
+                return null;
+            }
+        }
+        if( (AiMode != SpecialFuncData.AIMODE.Idle) &&
+                (AiMode != SpecialFuncData.AIMODE.ON) &&
+                (AiMode != SpecialFuncData.AIMODE.OFF) )
+        {
+            Log.w(TAG, "[Send_SetSpecialFuncStatus] - AiMode Out of Range !!! (" + String.format("0x%02X", AiMode) + ")");
+            return null;
+        }
+
+        // 2. 패킷 데이터 만들기
+        byte [] ReqData = new byte [5];
+        for(int i=0 ; i<ReqData.length ; i++) ReqData[i] = 0x00;
+
+        if(bSetOutsideTemp)
+        {
+            ReqData[0] = 0x01;
+
+            byte Temp = 0x00;
+            if (OutsideTemp >= 0)
+            {
+                // 0도 ~ +60도
+                Temp = (byte)OutsideTemp;
+            }
+            else
+            {
+                // -1도 ~ -60도
+                OutsideTemp = (~OutsideTemp) + 1;       // 음수를 양수로 변환
+                Temp = (byte)OutsideTemp;               // 온도넣기
+                Temp |= BIT7;                           // 음수표시
+            }
+            ReqData[1] = Temp;
+        }
+
+        ReqData[2] = AiMode;
+
+        // 3. 데이터 전송 및 응답
+        byte [] Reply = SendNRead_Variable( (byte)(DEVICE_ADDRESS), CMDList.Req.SetSpecialFuncStatus, ReqData);
+
+        // 4. 수신데이터 파싱
+        SpecialFuncData specialFuncData = SpecialFunc_ReplyParsing(Reply);
+        if(specialFuncData == null)
+        {
+            DeviceLog("[Send_SetSpecialFuncStatus] Reply is null");
+            AddDoCount(false);
+            return null;
+        }
+        AddDoCount(true);
+
+        return specialFuncData;
+    }
+
+    /**
+     * {@link #Send_GetSpecialFuncStatus()} <br>
+     * {@link #Send_SetSpecialFuncStatus(boolean, int, byte)} <br>
+     *
+     * 메소드의 응답 공통부분 메소드이다.
+     *
+     * @param Reply      - (byte []) 응답 Byte 배열
+     *
+     * @return (SpecialFuncData) null - Error , Not null - OK
+     */
+    private SpecialFuncData SpecialFunc_ReplyParsing(byte [] Reply)
+    {
+        // 1. 수신데이터 파싱
+        //     1.1. Default Check
+        if(Reply == null)
+        {
+            DeviceLog("[SpecialFunc_ReplyParsing] Reply is null");
+            return null;
+        }
+        if(Reply.length != 4)
+        {
+            // 길이 체크
+            Log.w(TAG, "[SpecialFunc_ReplyParsing] Reply.length  fail ... " + Reply.length);
+            return null;
+        }
+
+        byte data = 0x00;
+        byte data2 = 0x00;
+        int index = 0;
+
+        //          - D1 : 외기온도
+        data = Reply[index++];
+        data2 = (byte)(data & (byte)(BIT5 | BIT4 | BIT3 | BIT2 | BIT1 | BIT0));
+        if (data2 > 60)
+        {
+            // 온도범위체크
+
+            Log.w(TAG, "[SpecialFunc_ReplyParsing] D1 (OutsideTemp) : Out Of Range !!! " + String.format("0x%02X", data2));
+            return null;
+        }
+
+        //          - D2 : 인공지능모드
+        data = Reply[index++];
+        if( (data != SpecialFuncData.AIMODE.ON) &&
+                (data != SpecialFuncData.AIMODE.OFF) )
+        {
+            Log.w(TAG, "[SpecialFunc_ReplyParsing] D2 (AI Mode) : Out Of Range !!! " + String.format("0x%02X", data));
+            return null;
+        }
+
+        // 2. Data return
+        index = 0;
+        SpecialFuncData specialFuncData = new SpecialFuncData();
+
+        data = Reply[index++];
+        double OutsideTemp = (double)(data & (byte)(BIT5 | BIT4 | BIT3 | BIT2 | BIT1 | BIT0));
+        if((data & BIT6) != 0x00) OutsideTemp += 0.5;
+        if((data & BIT7) != 0x00) OutsideTemp *= -1;
+        specialFuncData.OutsideTemp = OutsideTemp;
+
+        data = Reply[index++];
+        specialFuncData.Mode = data;
+
+        return specialFuncData;
+    }
+
+    /** 명령어 리스트 */
+    public static class CMDList
+    {
+        /** 요청 */
+        public static final class Req
+        {
+            /////////////////////////////////////////////////////////
+            // Board
+            /////////////////////////////////////////////////////////
+            /** 기기 상태 읽기 요청 */
+            public final static byte GetDeviceInfo        = 0x01;
+
+            /////////////////////////////////////////////////////////
+            // 개별방
+            /////////////////////////////////////////////////////////
+            /** 각방 상태 요청 */
+            public final static byte GetEachRoomStatus    = 0x11;
+            /** 각방 제어 요청 */
+            public final static byte SetEachRoomStatus    = 0x12;
+
+            /////////////////////////////////////////////////////////
+            // 전체방
+            /////////////////////////////////////////////////////////
+            /** 전체방 상태 요청 */
+            public final static byte GetAllRoomStatus     = 0x21;
+            /** 전체방 제어 요청 */
+            public final static byte SetAllRoomStatus     = 0x22;
+
+            /////////////////////////////////////////////////////////
+            // 보일러
+            /////////////////////////////////////////////////////////
+            /** 보일러 상태 요청 */
+            public final static byte GetBoilerStatus      = 0x31;
+            /** 보일러 제어 요청 */
+            public final static byte SetBoilerStatus      = 0x32;
+
+            /////////////////////////////////////////////////////////
+            // 특화기능
+            /////////////////////////////////////////////////////////
+            /** 특화기능 상태 요청 */
+            public final static byte GetSpecialFuncStatus = 0x41;
+            /** 특화기능 제어 요청 */
+            public final static byte SetSpecialFuncStatus = 0x42;
+        }
+    }
+
+    /**
+     * 현재온도 동기화<br>
+     * DB에 저장되어있는 날씨 정보를 가져와서 밸브제어기에 현재온도를 전송한다.
+     *
+     * @return (int) - >=0 : 성공, <0 : 실패
+     */
+    private int OutsideTempUpdate()
+    {
+        DeviceLog("OutsideTempUpdate");
+
+        try
+        {
+            WallpadStatusData DBMGR = new WallpadStatusData(ServiceMain.svcContext);
+            String[] WeatherVer = DBMGR.GetWeatherVer().split(define.DEVCTR_DATA_SPLITER);
+            WeatherTable WeatherTBL = DBMGR.GetWeatherTableController();
+            WeatherTBL.GetWeatherList();
+            DBMGR.closeDB();
+            String[] weatherdate = WeatherVer[0].split("[.]");
+            if (weatherdate.length < 4 || WeatherVer.length < 3)
+            {
+                Log.w(TAG, "[OutsideTempUpdate] length Error (" + "weatherdate.length:" + weatherdate.length + " , WeatherVer.length:" + WeatherVer.length + ")");
+                return -1;
+            }
+
+            Calendar cal = new GregorianCalendar();
+            int month = cal.get(Calendar.MONTH)+1;
+            int date  = cal.get(Calendar.DAY_OF_MONTH);
+
+            int WeatherMonth =  Integer.parseInt(weatherdate[1]);
+            int WeatherDate  =  Integer.parseInt(weatherdate[2]);
+            if( (WeatherMonth == month) && (WeatherDate == date) )
+            {
+                String TempStr = WeatherVer[5];
+                int Temp = 0;
+
+                if (TempStr==null)
+                {
+                    Log.w(TAG, "[OutsideTempUpdate] TempStr is null");
+                    return -4;
+                }
+
+                try
+                {
+                    Temp = Integer.parseInt(TempStr);
+                }
+                catch (RuntimeException re) {
+                    LogUtil.errorLogInfo("", TAG, re);
+                    return -5;
+                }
+                catch (Exception e) {
+                    Log.e(TAG, "[Exception Error] OutsideTempUpdate - Temp Converter");
+                    //e.printStackTrace();
+                    LogUtil.errorLogInfo("", TAG, e);
+                    return -5;
+                }
+
+                if( !((Temp <= 60) && (Temp >= -60)) )
+                {
+                    Log.w(TAG, "[OutsideTempUpdate] Temp  Out Of Range !!! (" + Temp + ")");
+                    return -6;
+                }
+
+                SpecialFuncData specialFuncData = Send_SetSpecialFuncStatus(true, Temp, SpecialFuncData.AIMODE.Idle);
+                if(specialFuncData == null)
+                {
+                    Log.w(TAG, "[OutsideTempUpdate] Send_SetSpecialFuncStatus  ret null!!!");
+                    return -7;
+                }
+
+                return 0;
+            }
+            else
+            {
+                Log.w(TAG, "[OutsideTempUpdate] Month/Date Not Equals (Weather : " + WeatherMonth + "-" + WeatherDate + " / Calendar:" + month + "-" + date + ")");
+                return -3;
+            }
+        }
+        catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+            return -2;
+        }
+        catch (Exception e) {
+            Log.e(TAG, "[Exception Error] OutsideTempUpdate");
+            //e.printStackTrace();
+            LogUtil.errorLogInfo("", TAG, e);
+            return -2;
+        }
+    }
+
+    /**
+     * 기기정보 데이터를 업데이트 한다.
+     *
+     * @param info  - (Info) 업데이트할 각방데이터
+     *
+     * @return (boolean) 데이터 변경여부 (true:변경 , false:미변경)
+     */
+    private boolean UpdateVariables(Info info)
+    {
+        if(info == null) return false;
+        if(mDriver.Device.info == null) return false;
+
+        Info DriverInfo = mDriver.Device.info;
+        boolean bChanged = false;
+        long ErrorCode = 0;
+        if(DriverInfo.RoomCount != info.RoomCount) { bChanged = true; ErrorCode |= 0x1; }
+        if(DriverInfo.Vender != info.Vender)       { bChanged = true; ErrorCode |= 0x2; }
+
+        if(DriverInfo.FwVer_Year != info.FwVer_Year) { bChanged = true; ErrorCode |= 0x4; }
+        if(DriverInfo.FwVer_Month != info.FwVer_Month) { bChanged = true; ErrorCode |= 0x8; }
+        if(DriverInfo.FwVer_Day != info.FwVer_Day) { bChanged = true; ErrorCode |= 0x10; }
+        if(DriverInfo.FwVer_Number != info.FwVer_Number) { bChanged = true; ErrorCode |= 0x20; }
+
+        if(DriverInfo.ProtocolVer_Main != info.ProtocolVer_Main) { bChanged = true; ErrorCode |= 0x40; }
+        if(DriverInfo.ProtocolVer_Sub != info.ProtocolVer_Sub) { bChanged = true; ErrorCode |= 0x80; }
+
+        if(DriverInfo.Support.MinSetTemp != info.Support.MinSetTemp) { bChanged = true; ErrorCode |= 0x100; }
+        if(DriverInfo.Support.MaxSetTemp != info.Support.MaxSetTemp) { bChanged = true; ErrorCode |= 0x200; }
+        if(DriverInfo.Support.SetTempPoint05 != info.Support.SetTempPoint05) { bChanged = true; ErrorCode |= 0x400; }
+        if(DriverInfo.Support.Outing != info.Support.Outing) { bChanged = true; ErrorCode |= 0x800; }
+        if(DriverInfo.Support.Sleep != info.Support.Sleep) { bChanged = true; ErrorCode |= 0x1000; }
+        if(DriverInfo.Support.Reservation != info.Support.Reservation) { bChanged = true; ErrorCode |= 0x2000; }
+        if(DriverInfo.Support.Pause != info.Support.Pause) { bChanged = true; ErrorCode |= 0x4000; }
+        if(DriverInfo.Support.AI != info.Support.AI) { bChanged = true; ErrorCode |= 0x8000; }
+        if(DriverInfo.Support.OutsideTempUse != info.Support.OutsideTempUse) { bChanged = true; ErrorCode |= 0x10000; }
+        if(DriverInfo.Support.Boiler != info.Support.Boiler) { bChanged = true; ErrorCode |= 0x20000; }
+
+        if(bChanged)
+        {
+            Log.i(TAG, "*****************************************************");
+            Log.i(TAG, "Warning !!!!  Device Change - Info Change... " + String.format("[%08X]", ErrorCode));
+            Log.i(TAG, "*****************************************************");
+
+            mDriver = new Driver();
+            mDriver.Device.info = info;
+        }
+
+        return bChanged;
+    }
+
+    /**
+     * 각방 데이터를 업데이트 한다.
+     *
+     * @param RoomIndex - (byte) 요청 방인덱스
+     * @param roomData  - (RoomData) 업데이트할 각방데이터
+     *
+     * @return (boolean) 데이터 변경여부 (true:변경 , false:미변경)
+     */
+    private boolean UpdateVariables(byte RoomIndex, HeatingV2.RoomData roomData)
+    {
+        if(mDriver.Device.Room == null) return false;
+        if(mDriver.Device.Room.length <= (int)RoomIndex) return false;
+        if(roomData == null) return false;
+
+        boolean bChanged = false;
+        HeatingV2.RoomData DriverRoomData = mDriver.Device.Room[RoomIndex];
+
+        ////////////////////////////////////////////////////////////////////////////
+        // 예약운전 시간 월패드 저장모드
+        ////////////////////////////////////////////////////////////////////////////
+        if (MODE_RESERVATION_SET_WALLPAD_SAVE == true)
+        {
+            if (DriverRoomData.Mode == MODE.Reservation)
+            {
+                // 예약운전 일시, 예약 스케쥴러가 다를경우
+                if (DriverRoomData.Reservation.getInt() != roomData.Reservation.getInt())
+                {
+                    // 스케쥴러 셋팅
+                    Log.i(TAG, "+++++++++++++++++++++++++++++++++++++++++++++++++++");
+                    Log.i(TAG, "UpdateVariables - EachRoom - Send_ReservationSettingInfo - RoomNumber:"
+                            + (byte)(RoomIndex+1) + " / Restore");
+                    Log.i(TAG, "+++++++++++++++++++++++++++++++++++++++++++++++++++");
+                    Send_ReservationSettingInfo(RoomIndex, false, false);
+                }
+            }
+            else
+            {
+                // 예약운전 아닐시, 예약셋팅값이 있을 경우
+                if (roomData.Reservation.getInt() != 0)
+                {
+                    // 초기화로 다시 셋팅
+                    Log.i(TAG, "+++++++++++++++++++++++++++++++++++++++++++++++++++");
+                    Log.i(TAG, "UpdateVariables - EachRoom - Send_ReservationSettingInfo - RoomNumber:"
+                            + (byte)(RoomIndex+1) + " / Reset!!!");
+                    Log.i(TAG, "+++++++++++++++++++++++++++++++++++++++++++++++++++");
+
+                    boolean bPauseRelease = false;
+                    if (roomData.Mode != MODE.Pause) bPauseRelease = true;
+                    Send_ReservationSettingInfo(RoomIndex, true, bPauseRelease);
+                }
+            }
+
+            // 통신으로 응답받은 예약스케쥴은 저장된값으로 변경함.
+            roomData.Reservation.setInt(DriverRoomData.Reservation.getInt());
+        }
+        ////////////////////////////////////////////////////////////////////////////
+
+
+        // 데이터 비교
+        if(DriverRoomData.Mode != roomData.Mode) 
+        {
+        	Log.i(TAG, "[UpdateVariables - room] - change true #1");
+        	bChanged = true;
+        }
+        if(DriverRoomData.bValveStatus != roomData.bValveStatus) 
+        {
+        	Log.i(TAG, "[UpdateVariables - room] - change true #2");
+        	bChanged = true;
+        }
+        if(DriverRoomData.SetTemp != roomData.SetTemp)
+        {
+        	Log.i(TAG, "[UpdateVariables - room] - change true #3");
+        	bChanged = true;
+        }
+        if(DriverRoomData.NowTemp != roomData.NowTemp)
+        {
+        	Log.i(TAG, "[UpdateVariables - room] - change true #4");
+        	bChanged = true;
+        }
+        if(DriverRoomData.Error.getByte() != roomData.Error.getByte())
+        {
+        	Log.i(TAG, "[UpdateVariables - room] - change true #5");
+        	
+        	Log.i(TAG, "OLD =====================");
+        	Log.i(TAG, DriverRoomData.Error.ToDebugString());
+        	Log.i(TAG, "NEW =====================");
+        	Log.i(TAG, roomData.Error.ToDebugString());
+        	
+        	
+        	bChanged = true;
+        }
+        
+        if(!bChanged)
+        {
+            if(mDriver.Device.info.Support.Sleep)
+            {
+                if(DriverRoomData.Sleep.getByte() != roomData.Sleep.getByte()) bChanged = true;
+            }
+            if(mDriver.Device.info.Support.Reservation)
+            {
+                byte [] Old = DriverRoomData.Reservation.getByte();
+                byte [] New = roomData.Reservation.getByte();
+                if((Old != null) && (New != null))
+                {
+                    for(int i=0 ; i<Old.length ; i++)
+                    {
+                        if(Old[i] != New[i]) { bChanged = true; break; }
+                    }
+                }
+            }
+        }
+
+        if(bChanged)
+        {
+            DeviceLog("OLD =====================");
+            DeviceLog(DriverRoomData.ToDebugString(RoomIndex));
+            DeviceLog("NEW =====================");
+            DeviceLog(roomData.ToDebugString(RoomIndex));
+            
+            CheckLeakError(roomData);
+            mDriver.Device.Room[RoomIndex] = roomData;
+            StatusChanged(RoomIndex);
+            DeviceLog("UpdateVariables !!!! *************************************** " + "RoomData - " + (byte)(RoomIndex+1));
+        }
+
+        return bChanged;
+    }
+
+    /**
+     * 전체방 데이터를 업데이트 한다.
+     *
+     * @param allRoomData  - (AllRoomData) 업데이트할 전체방데이터
+     *
+     * @return (boolean) 데이터 변경여부 (true:변경 , false:미변경)
+     */
+    private boolean UpdateVariables(AllRoomData allRoomData)
+    {
+        if(allRoomData == null) return false;
+
+        ////////////////////////////////////////////////////////////////////////////
+        // 예약운전 시간 월패드 저장모드
+        ////////////////////////////////////////////////////////////////////////////
+        if (MODE_RESERVATION_SET_WALLPAD_SAVE == true)
+        {
+            for (byte RoomIndex = 0; RoomIndex < allRoomData.RoomCount ; RoomIndex++)
+            {
+                RoomData DriverRoomData = mDriver.Device.Room[RoomIndex];
+
+                if ((allRoomData.Room[RoomIndex].Mode == MODE.Reservation) && (DriverRoomData.Mode != MODE.Reservation))
+                {
+                    // 새로운상태가 예약운전, 이전상태가 예약운전 아님일시
+
+                    // 스케쥴러 셋팅
+                    Log.i(TAG, "+++++++++++++++++++++++++++++++++++++++++++++++++++");
+                    Log.i(TAG, "UpdateVariables - AllRoom - Send_ReservationSettingInfo - RoomNumber:"
+                            + (byte)(RoomIndex+1) + " / Restore");
+                    Log.i(TAG, "+++++++++++++++++++++++++++++++++++++++++++++++++++");
+                    Send_ReservationSettingInfo(RoomIndex, false, false);
+                }
+                else if ((allRoomData.Room[RoomIndex].Mode != MODE.Reservation) && (DriverRoomData.Mode == MODE.Reservation))
+                {
+                    // 새로운상태가 예약운전아님, 이전상태가 예약운전 일시
+
+                    // 초기화로 다시 셋팅
+                    Log.i(TAG, "+++++++++++++++++++++++++++++++++++++++++++++++++++");
+                    Log.i(TAG, "UpdateVariables - AllRoom - Send_ReservationSettingInfo - RoomNumber:"
+                            + (byte)(RoomIndex+1) + " / Reset!!!");
+                    Log.i(TAG, "+++++++++++++++++++++++++++++++++++++++++++++++++++");
+
+                    boolean bPauseRelease = false;
+                    if (allRoomData.Room[RoomIndex].Mode != MODE.Pause) bPauseRelease = true;
+                    Send_ReservationSettingInfo(RoomIndex, true, bPauseRelease);
+                }
+            }
+        }
+        ////////////////////////////////////////////////////////////////////////////
+
+        if(mDriver.Device.info.RoomCount != allRoomData.RoomCount)
+        {
+            Log.w(TAG, "*****************************************************");
+            Log.w(TAG, "Warning !!!!  Device Change - RoomCount Change... (OLD:" + mDriver.Device.info.RoomCount + " / NOW:" + allRoomData.RoomCount + ")");
+            Log.w(TAG, "*****************************************************");
+
+            mDriver = new Driver();
+            return true;
+        }
+
+        boolean bChanged = false;
+        byte RoomIndex = define.DEVICE_ALL_OR_NOTHING;
+        boolean bAllRoomChanged = false;
+
+        for(byte i=0 ; i<allRoomData.RoomCount ; i++)
+        {
+            boolean bRoomChangedCheck = false;
+            if(mDriver.Device.Room[i].bValveStatus != allRoomData.Room[i].bValveStatus)
+            {
+                mDriver.Device.Room[i].bValveStatus = allRoomData.Room[i].bValveStatus;
+                bChanged = true;
+                bRoomChangedCheck = true;
+            }
+            if(mDriver.Device.Room[i].Mode != allRoomData.Room[i].Mode)
+            {
+                mDriver.Device.Room[i].Mode = allRoomData.Room[i].Mode;
+                bChanged = true;
+                bRoomChangedCheck = true;
+            }
+            if(mDriver.Device.Room[i].NowTemp != allRoomData.Room[i].NowTemp)
+            {
+                mDriver.Device.Room[i].NowTemp = allRoomData.Room[i].NowTemp;
+                bChanged = true;
+                bRoomChangedCheck = true;
+            }
+            if(mDriver.Device.Room[i].SetTemp != allRoomData.Room[i].SetTemp)
+            {
+                mDriver.Device.Room[i].SetTemp = allRoomData.Room[i].SetTemp;
+                bChanged = true;
+                bRoomChangedCheck = true;
+            }
+            if(bRoomChangedCheck)
+            {
+                if(RoomIndex == define.DEVICE_ALL_OR_NOTHING) RoomIndex = i;
+                else bAllRoomChanged = true;
+            }
+        }
+
+        if(bChanged)
+        {
+            if(bAllRoomChanged) StatusChanged(define.DEVICE_ALL_OR_NOTHING);
+            else StatusChanged(RoomIndex);
+            DeviceLog("UpdateVariables !!!! *************************************** " + "AllRoomData");
+        }
+
+        return bChanged;
+    }
+
+    /**
+     * 보일러 데이터를 업데이트 한다.
+     *
+     * @param boilerData - (BoilerData) 업데이트할 보일러데이터
+     *
+     * @return (boolean) 데이터 변경여부 (true:변경 , false:미변경)
+     */
+    private boolean UpdateVariables(BoilerData boilerData)
+    {
+        if(!mDriver.Device.info.Support.Boiler) return false;
+        if(boilerData == null) return false;
+        if(mDriver.Boiler == null) return false;
+
+        boolean bChanged = false;
+
+        if(mDriver.Boiler.bFrostProtectMode != boilerData.bFrostProtectMode) bChanged = true;
+        if(mDriver.Boiler.ErrorCode != boilerData.ErrorCode) bChanged = true;
+
+        if(mDriver.Boiler.HeatingWater.bSetTempUnit5 != boilerData.HeatingWater.bSetTempUnit5) bChanged = true;
+        if(mDriver.Boiler.HeatingWater.SetTemp != boilerData.HeatingWater.SetTemp) bChanged = true;
+        if(mDriver.Boiler.HeatingWater.MaxSetTemp != boilerData.HeatingWater.MaxSetTemp) bChanged = true;
+        if(mDriver.Boiler.HeatingWater.MinSetTemp != boilerData.HeatingWater.MinSetTemp) bChanged = true;
+
+        if(mDriver.Boiler.HotWater.bSetTempUnit5 != boilerData.HotWater.bSetTempUnit5) bChanged = true;
+        if(mDriver.Boiler.HotWater.SetTemp != boilerData.HotWater.SetTemp) bChanged = true;
+        if(mDriver.Boiler.HotWater.MaxSetTemp != boilerData.HotWater.MaxSetTemp) bChanged = true;
+        if(mDriver.Boiler.HotWater.MinSetTemp != boilerData.HotWater.MinSetTemp) bChanged = true;
+
+        if(bChanged)
+        {
+            mDriver.Boiler = boilerData;
+            StatusChanged(REFRESH_IDX.BOILER);
+            DeviceLog("UpdateVariables !!!! *************************************** " + "BoilerData");
+            DeviceLog(mDriver.Boiler.ToDebugString());
+        }
+
+        return bChanged;
+    }
+
+    /**
+     * 특화기능 데이터를 업데이트 한다.
+     *
+     * @param specialFuncData - (SpecialFuncData) 업데이트할 특화기능데이터
+     *
+     * @return (boolean) 데이터 변경여부 (true:변경 , false:미변경)
+     */
+    private boolean UpdateVariables(SpecialFuncData specialFuncData)
+    {
+        if(!mDriver.Device.info.Support.AI) return false;
+        if(specialFuncData == null) return false;
+        if(mDriver.SpecialFunc == null) return false;
+
+        boolean bChanged = false;
+
+        if(mDriver.SpecialFunc.Mode != specialFuncData.Mode) bChanged = true;
+        if(mDriver.SpecialFunc.OutsideTemp != specialFuncData.OutsideTemp) bChanged = true;
+
+        if(bChanged)
+        {
+            mDriver.SpecialFunc = specialFuncData;
+            StatusChanged(REFRESH_IDX.SPECIALFUNC);
+            DeviceLog("UpdateVariables !!!! *************************************** " + "SpecialFuncData");
+            DeviceLog(mDriver.SpecialFunc.ToDebugString());
+        }
+
+        return bChanged;
+    }
+
+    /**
+     * 모드 설정값의 범위를 체크한다.
+     *
+     * @param Mode - (byte) 범위체크할 모드
+     *
+     * @return (int) - >=0 : 성공, <0 : 실패
+     */
+    private int CheckSetMode(byte Mode)
+    {
+        if(!MODE.CheckSetMode(Mode))
+        {
+            DeviceLog("[CheckSetMode]" + "[Mode] Out Of Range (" + Mode + ")");
+            return -1;
+        }
+
+        if((Mode == MODE.Outing) ||
+                (Mode == MODE.OutingRelease) )
+        {
+            if(!mDriver.Device.info.Support.Outing)
+            {
+                DeviceLog("[CheckSetMode]" + "[Mode] Out Of Range - Error  Not Support Outing  (" + Mode + ")");
+                return -2;
+            }
+        }
+        else if(Mode == MODE.Sleep)
+        {
+            if(!mDriver.Device.info.Support.Sleep)
+            {
+                DeviceLog("[CheckSetMode]" + "[Mode] Out Of Range - Error  Not Support Sleep  (" + Mode + ")");
+                return -3;
+            }
+        }
+        else if(Mode == MODE.Reservation)
+        {
+            if(!mDriver.Device.info.Support.Reservation)
+            {
+                DeviceLog("[CheckSetMode]" + "[Mode] Out Of Range - Error  Not Support Reservation  (" + Mode + ")");
+                return -4;
+            }
+        }
+        else if((Mode == MODE.Pause) ||
+                (Mode == MODE.PauseRelease) )
+        {
+            if(!mDriver.Device.info.Support.Pause)
+            {
+                DeviceLog("[CheckSetMode]" + "[Mode] Out Of Range - Error  Not Support Pause  (" + Mode + ")");
+                return -5;
+            }
+        }
+
+        return 0;
+    }
+
+    /**
+     * 설정온도 소수점 0.5 도 존재 유무를 판별한다.
+     *
+     * @param n - (double) 값
+     *
+     * @return  - (boolean) true : 있음 , false : 없음
+     */
+    private boolean PointExist(double n)
+    {
+        double FilterData = Double.parseDouble(String.format("%.1f", n));
+        int IntValue = (int)FilterData;
+        double Point = FilterData - IntValue;
+
+        if(Point >= 0.5) return true;
+        return false;
+    }
+
+    /**
+     * double Type 의 온도를 프로토콜에서 사용하여 Byte 온도로 변환한다.
+     *
+     * @param n - (double) 온도
+     *
+     * @return (byte) 변환된 온도
+     */
+    private byte ConverterTemp(double n)
+    {
+        byte ByteTemp = (byte) n;
+        if(PointExist(n)) ByteTemp |= BIT6;
+        return ByteTemp;
+    }
+
+    ///////////////////////////////////////////////////////////////////////
+    // DB
+    ///////////////////////////////////////////////////////////////////////
+    /**
+     * 예약스케쥴 데이터를 DB에서 로딩한다.
+     *
+     * @return (boolean) true:성공 , false:실패)
+     */
+    private boolean LoadReservationData()
+    {
+        DeviceLog("[LoadReservationData] START !!!");
+        try
+        {
+            WallpadStatusData DBMGR = new WallpadStatusData(ServiceMain.svcContext);
+            String[] Data = DBMGR.GetWallPADData("HEAT_RESERVE").split(":");
+            DBMGR.closeDB();
+            if(Data == null)
+            {
+                Log.w(TAG, "[LoadReservationData] GetWallPADData - Data is null !!!");
+                return false;
+            }
+
+            if(Data.length != 8)
+            {
+                Log.w(TAG, "[LoadReservationData] Data length Not Match !!! (len:" + Data.length + " / Data:" + Data + ")");
+                DeleteReservationData();
+                return false;
+            }
+
+            for(byte i=0 ; i<mDriver.Device.info.RoomCount ; i++)
+            {
+                mDriver.Device.Room[i].Reservation.setInt(Integer.parseInt(Data[i]));
+                DeviceLog("Room" + (byte)(i+1) + " : " + mDriver.Device.Room[i].Reservation.ToDebugString());
+            }
+        }
+        catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+            return false;
+        }
+        catch (Exception e) {
+            Log.e(TAG, "[LoadReservationData] Exception Error");
+            //e.printStackTrace();
+            LogUtil.errorLogInfo("", TAG, e);
+            return false;
+        }
+
+        DeviceLog("[LoadReservationData] OK !!!");
+        return true;
+    }
+
+    /**
+     * 예약스케쥴 데이터를 DB에 저장한다.
+     *
+     * @return (boolean) true:성공 , false:실패)
+     */
+    private boolean SaveReservationData()
+    {
+        DeviceLog("[SaveReservationData] START !!!");
+
+        try
+        {
+            String Data = null;
+
+            for(byte i=0 ; i<8 ; i++)
+            {
+                if(i<mDriver.Device.info.RoomCount)
+                {
+                    if(i==0) Data = mDriver.Device.Room[i].Reservation.getInt() + ":";
+                    else     Data += mDriver.Device.Room[i].Reservation.getInt() + ":";
+
+                    DeviceLog("Room" + (byte)(i+1) + " : " + mDriver.Device.Room[i].Reservation.ToDebugString());
+                }
+                else
+                {
+                    Data += "0:";
+                }
+            }
+
+            wallpaddbmgr DBMGR = new wallpaddbmgr(ServiceMain.svcContext);
+            DBMGR.UpdateWallPADData("HEAT_RESERVE", Data);
+            DBMGR.closeDB();
+            DeviceLog("HEAT_RESERVE [" + Data + "]");
+        }
+        catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+            return false;
+        }
+        catch (Exception e) {
+            Log.e(TAG, "[SaveReservationData] Exception Error");
+            //e.printStackTrace();
+            LogUtil.errorLogInfo("", TAG, e);
+            return false;
+        }
+
+        DeviceLog("[SaveReservationData] OK !!!");
+        return true;
+    }
+
+    /**
+     * 예약스케쥴 데이터를 DB에 초기화한다.
+     *
+     * @return (boolean) true:성공 , false:실패)
+     */
+    public boolean DeleteReservationData()
+    {
+        DeviceLog("[DeleteReservationData] START !!!");
+
+        try
+        {
+            wallpaddbmgr DBMGR = new wallpaddbmgr(ServiceMain.svcContext);
+            DBMGR.UpdateWallPADData("HEAT_RESERVE", "0:0:0:0:0:0:0:0");
+            DBMGR.closeDB();
+            DeviceLog("HEAT_RESERVE [" + "0:0:0:0:0:0:0:0" + "]");
+        }
+        catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+            return false;
+        }
+        catch (Exception e) {
+            Log.e(TAG, "[DeleteReservationData] Exception Error");
+            //e.printStackTrace();
+            LogUtil.errorLogInfo("", TAG, e);
+            return false;
+        }
+
+        DeviceLog("[DeleteReservationData] OK !!!");
+        return true;
+    }
+
+    /**
+     * 예약운전 월패드 예약 저장기능 사용여부 판단
+     *
+     * @param info
+     */
+    @SuppressWarnings("unused")
+    private void CheckInfoReservationSaveMode(Info info) {
+        // 1. 모델명 비교 (GLE일 경우에만 수행한다)
+        if (!Version.getGatewayUsage()) return;
+        if (USE_RESERVATION_SET_WALLPAD_SAVE == false) return;
+        Log.d(TAG, "[CheckInfoReservationSaveMode] Start !!!");
+
+        // 2. Info 정보로 하여 월패드예약저장기능 사용여부 판단
+        boolean ChangeModeReservationSetWallPadSave = false;
+        if (info.Vender == 0x01)                    // 제조사 : 한에너지 (0x01)
+        {
+            if ((info.FwVer_Year   == 13) &&        // 펌웨어 Build Date (2013 년 5월 30일 - 1)
+                    (info.FwVer_Month  == 5) &&
+                    (info.FwVer_Day    == 30) &&
+                    (info.FwVer_Number == 1))
+            {
+                ChangeModeReservationSetWallPadSave = true;
+            }
+        }
+
+        // 3. 셋팅여부 판단
+        boolean ReSetting = false;
+        if ((ModeReservationFirstCheck == false) ||
+                (MODE_RESERVATION_SET_WALLPAD_SAVE != ChangeModeReservationSetWallPadSave) )
+        {
+            ModeReservationFirstCheck = true;
+            if(ChangeModeReservationSetWallPadSave) Log.d(TAG, "[[[[ MODE_RESERVATION_SET_WALLPAD_SAVE  -  ON  !!!! ]]]]");
+            else                                    Log.d(TAG, "[[[[ MODE_RESERVATION_SET_WALLPAD_SAVE  -  OFF !!!! ]]]]");
+
+            MODE_RESERVATION_SET_WALLPAD_SAVE = ChangeModeReservationSetWallPadSave;
+
+            ReSetting = true;
+        }
+
+        // 4. 셋팅
+        if (ReSetting == true)
+        {
+            if(MODE_RESERVATION_SET_WALLPAD_SAVE == true)
+            {
+                boolean bRet = LoadReservationData();
+                Log.d(TAG, "LoadReservationData = " + bRet);
+                if (bRet == false)
+                {
+                    for(byte i=0 ; i<mDriver.Device.info.RoomCount ; i++)
+                    {
+                        mDriver.Device.Room[i].Reservation.setInt(0);
+                    }
+
+                    bRet = SaveReservationData();
+                    Log.d(TAG, "SaveReservationData = " + bRet);
+                }
+            }
+            else
+            {
+                boolean bRet = DeleteReservationData();
+                Log.d(TAG, "DeleteReservationData = " + bRet);
+            }
+        }
+    }
+    
+    /**
+     * 세대 누수감지 처리
+     * @param roomData 
+     * **/
+    private void CheckLeakError(RoomData roomData)
+    {
+        if(roomData == null)
+        {
+            return;
+        }
+        if (mDriver.Device.info.Support.Leak == true)
+        {
+            if (roomData.Error.bLeak == true)
+            {
+                long currentTimeMillis = 0;
+                currentTimeMillis = System.currentTimeMillis();
+                if(Math.abs(currentTimeMillis - mDriver.Polling.LeakTimeTickCount) > 5000)
+                {                   
+                    mDriver.Polling.LeakTimeTickCount = currentTimeMillis;
+                    
+                    DeviceLog("[CheckLeakError] Check Alaram Status !!!");
+                    WallpadStatusData wdb = new WallpadStatusData(ServiceMain.svcContext);
+                    int alarmState = wdb.GetAlarmStatus();
+                    wdb.closeDB();
+                    if (alarmState == WallpadStatusData.ALARM_ARISE || alarmState == WallpadStatusData.ALARM_STOP)
+                    {
+                        // 알람화면이 현재 실행중이면 스킵
+                    }
+                    else
+                    {
+                        DeviceLog("[CheckLeakError] Send Leak Alaram !!!");
+                        Send_AlertBR(5);
+                    }
+                }
+            }
+        }
+    }
+    /**
+     * 알람 BR 송신
+     * 
+     * @param kind - (int) 알람종류
+     */
+    private void Send_AlertBR(int kind)
+    {
+        Log.d(TAG, "Send_AlertBR kind - " + kind);
+        Intent intent = new Intent();
+        intent.setAction("WALLPAD_ALERT");
+        intent.putExtra("KIND", kind);
+        ServiceMain.svcContext.sendBroadcast(intent);   
+    }
+}

+ 2739 - 2739
WallPadDevService/src/main/java/com/artncore/wallpaddevservice/driver/MultiSwitch_Controller.java

@@ -1,2739 +1,2739 @@
-/*
- * Copyright (C) 2015 Android WallPad Project
- *
- * FileName  : MultiSwitch_Controller.java
- * Project   : Android WallPad Project
- * Company   : HDC I-CONTROLS ( www.icontrols.co.kr )
- * Author    : Kang Sang Ho  , lairu@icontrols.co.kr
- */
-
-package com.artncore.wallpaddevservice.driver;
-
-import java.net.InetAddress;
-import java.net.NetworkInterface;
-import java.util.Calendar;
-import java.util.Collections;
-import java.util.GregorianCalendar;
-import java.util.List;
-import java.util.regex.Pattern;
-
-import android.annotation.SuppressLint;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.Build;
-import android.util.Log;
-
-import com.artncore.WallPadDataMgr.WallpadStatusData;
-import com.artncore.WallPadDataMgr.wallpaddbmgr;
-import com.artncore.commons.APIErrorCode;
-import com.artncore.commons.DataClasses;
-import com.artncore.commons.DataClasses.MultiSwitch;
-import com.artncore.commons.define;
-import com.util.LogUtil;
-import com.artncore.wallpaddevservice.ServiceMain;
-
-import kr.co.icontrols.v40ioctl.V40IF;
-import kr.co.icontrols.wallpadsupport.Version;
-
-
-/**
- * 멀티스위치 의 드라이버 모듈이다.
- */
-@SuppressLint("HandlerLeak")
-public class MultiSwitch_Controller extends DeviceManager {
-    private final static String TAG = "MultiSwitch_Controller";
-
-    private final byte DEVICE_ADDRESS  = (byte) 0x51;
-
-    /** 최대 기기 개수 */
-    private final byte MAX_DEVICE_COUNT      = 8;
-
-    /** 최대 조명 개수 */
-    private final byte MAX_LIGHT_COUNT       = 8;
-
-    /** 최대 콘센트 개수 */
-    private final byte MAX_OUTLET_COUNT = 8;
-
-    /** 초기 기기 검색 횟수  */
-    private final int MAX_SEARCH_COUNT   = 3;
-
-    /** 시간 동기화 간격(분) */
-    private final long STATUS_SYNC_TICK   = (long)(10 * TIME_MINUTE);
-
-    /**
-     * 조명 ON/OFF 상태를 반환한다.
-     *
-     * @param Index    - (byte) 기기인덱스 (0~7)
-     * @param LightIdx - (byte) 조명인덱스 (0~7)
-     *
-     * @return (boolean) true:ON , false:OFF
-     */
-    public boolean getLightPower(byte Index, byte LightIdx) {
-        if (!DeviceIndexRangeCheck(Index)) return false;
-        try {
-            if (mDriver.Device[Index].device == null) return false;
-            if ((LightIdx < 0) || (LightIdx >= mDriver.Device[Index].device.hLightCnt)) return false;
-            return mDriver.Device[Index].device.getLightPower(LightIdx);
-        } catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-            return false;
-        } catch (Exception e) {
-            Log.e(TAG, "[Exception Error] getLightPower");
-            LogUtil.errorLogInfo("", TAG, e);//e.printStackTrace();
-            return false;
-        }
-    }
-
-    /**
-     * 조명 개수를 반환한다.
-     *
-     * @param Index - (byte) 기기인덱스 (0~7)
-     *
-     * @return (byte) 조명 개수
-     */
-    public byte getLightCnt(byte Index) {
-        if (!DeviceIndexRangeCheck(Index)) return 0x00;
-        try {
-            if (mDriver.Device[Index].device == null) return 0x00;
-            return mDriver.Device[Index].info.Support.hLightCnt;
-        } catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-            return 0x00;
-        } catch (Exception e) {
-            Log.e(TAG, "[Exception Error] getLightCnt");
-            LogUtil.errorLogInfo("", TAG, e);//e.printStackTrace();
-            return 0x00;
-        }
-    }
-
-    /** 멀티스위치 조명&콘센트 제어용 클래스 */
-    public class CtrlCmd {
-        public class Light {
-            public boolean OnOff;
-            public boolean Dim;
-            public byte DimLevel;
-            public byte Pattern;
-            private byte BatchOff;
-            public Light() {
-                OnOff = false;
-                Dim = false;
-                DimLevel = 0x00;
-                Pattern = 0x00;
-                BatchOff = 0x00;
-            }
-
-            public boolean setBatchOff(byte nBatchOff) {
-                if ((nBatchOff != 0x00) && (nBatchOff != MultiSwitch.BATCHOFF_STATUS.Set) && (nBatchOff != MultiSwitch.BATCHOFF_STATUS.Clr)) {
-                    Log.w(TAG, "[ControlCommand->Light->setBatchOff] Param Out Of Range " + String.format("%02X", nBatchOff));
-                    return false;
-                }
-                BatchOff = nBatchOff;
-                return true;
-            }
-
-            public byte [] getBytes() {
-                byte [] retBytes = new byte [3];
-                int index = 0;
-
-                byte ctrlOption = 0x00;
-                if (OnOff) ctrlOption |= BIT0;
-                if (Dim) ctrlOption |= BIT1;
-                Log.e(TAG, "[ControlCommand->Light] ctrlOption: " + String.format("%02X", ctrlOption));
-                retBytes[index++] = ctrlOption;
-                retBytes[index++] = Pattern;
-                retBytes[index++] = BatchOff;
-
-                return retBytes;
-            }
-        }
-
-        public class Outlet {
-            public class unitOutlet {
-                private byte OnOff;
-                private byte Mode;
-                public boolean CutOff;
-
-                public unitOutlet() {
-                    OnOff = 0x00;
-                    Mode  = 0x00;
-                    CutOff = false;
-                }
-
-                public boolean setOnOff (byte nOnOff) {
-                    if ((nOnOff != 0x00) && (nOnOff != MultiSwitch.OUTLET_STATUS.On) && (nOnOff != MultiSwitch.OUTLET_STATUS.Off)) {
-                        Log.w(TAG, "[ControlCommand->Concent->Con->setOnOff] Param Out Of Range " + String.format("%02X", nOnOff));
-                        return false;
-                    }
-                    OnOff = nOnOff;
-                    return true;
-                }
-
-                public boolean setMode (byte nMode) {
-                    if ((nMode != 0x00) && (nMode != MultiSwitch.OUTLET_MODE.Auto) && (nMode != MultiSwitch.OUTLET_MODE.Always)){
-                        Log.w(TAG, "[ControlCommand->Concent->Con->setMode] Param Out Of Range " + String.format("%02X", nMode));
-                        return false;
-                    }
-                    Mode = nMode;
-                    return true;
-                }
-
-                public byte getByte() {
-                    byte retByte = 0x00;
-
-                    retByte |= (byte)(OnOff & (BIT0 | BIT1));
-                    retByte |= (byte)((Mode << 4) & (BIT4 | BIT5));
-                    if (CutOff) retByte |= BIT6;
-
-                    return retByte;
-                }
-            }
-
-            public byte Count;
-            public unitOutlet[] unitOutlet;
-
-            public Outlet() {
-                Count = 0;
-                unitOutlet = null;
-            }
-
-            public boolean setCount(byte nCount){
-                if (nCount < 0) return false;
-
-                Count = nCount;
-                unitOutlet = new unitOutlet[nCount];
-                for (byte i = 0; i < nCount; i++) unitOutlet[i] = new unitOutlet();
-
-                return true;
-            }
-
-            public boolean setCon(int index, byte nOnOff, byte nMode, boolean nCutOff) {
-                if (unitOutlet == null) return false;
-                if (unitOutlet.length <= index) return false;
-
-                if (!unitOutlet[index].setOnOff(nOnOff)) return false;
-                if (!unitOutlet[index].setMode(nMode)) return false;
-                unitOutlet[index].CutOff = nCutOff;
-
-                return true;
-            }
-
-            public byte [] getBytes() {
-                if (Count <= 0) return new byte [] { 0x00 };
-                try {
-                    byte ContCount = 0;
-                    for (byte i = 0; i < Count; i++) {
-                        if (unitOutlet[i].getByte() != 0x00) ContCount++;
-                    }
-                    
-                    if (ContCount == 0) return new byte[] { 0x00 };
-
-                    byte[] retBytes = new byte [1 + (ContCount*2)];
-                    int index = 0;
-                    retBytes[index++] = ContCount;
-                    for (byte i = 0; i < Count; i++) {
-                        if (unitOutlet[i].getByte() != 0x00) {
-                            retBytes[index++] = (byte)(i+1);
-                            retBytes[index++] = unitOutlet[i].getByte();
-                        }
-                    }
-                    return retBytes;
-                } catch (RuntimeException re) {
-                    LogUtil.errorLogInfo("", TAG, re);
-                    return new byte [] { 0x00 };
-                } catch (Exception e) {
-                    Log.e(TAG, "[Exception Error] CtrlCmd -> Concent -> getBytes");
-                    LogUtil.errorLogInfo("", TAG, e);//e.printStackTrace();
-                    return new byte [] { 0x00 };
-                }
-            }
-        }
-
-        public Light light;
-        public Outlet outlet;
-
-        public CtrlCmd() {
-            light = new Light();
-            outlet = new Outlet();
-        }
-
-        public byte [] getBytes() {
-            byte[] lightBytes = light.getBytes();
-            byte[] concentBytes = outlet.getBytes();
-
-            if ((lightBytes == null) || (concentBytes == null)) {
-                Log.w(TAG, "[ControlCommand] getBytes - lightBytes or concentBytes  is null !!!");
-                return null;
-            }
-
-            byte [] retBytes = new byte [lightBytes.length + concentBytes.length + (light.Dim ? 1 : 0)];
-            Log.w(TAG, "[ControlCommand] getBytes - retBytes.length: " + retBytes.length);
-            int index = 0;
-            int i = 0;
-            for (i = 0; i < lightBytes.length; i++) retBytes[index++] = lightBytes[i];
-            for (i = 0; i < concentBytes.length; i++) retBytes[index++] = concentBytes[i];
-            if (light.Dim) retBytes[index++] = light.DimLevel;
-
-            return retBytes;
-        }
-    }
-
-    /** 드라이버 내부 변수 */
-    public class Driver {
-        private PollingList Polling;
-
-        private MultiSwitch[] Device;
-
-        private boolean bDeviceFirstNotify;
-
-        private long [] TimeSyncTick;
-
-        public Driver() {
-            Polling = new PollingList();
-
-            Device = new MultiSwitch [MAX_DEVICE_COUNT];
-            for (int i = 0; i < MAX_DEVICE_COUNT ; i++) Device[i] = new MultiSwitch();
-
-            bDeviceFirstNotify = false;
-
-            TimeSyncTick = new long [MAX_DEVICE_COUNT];
-            for(int i=0 ; i<MAX_DEVICE_COUNT ; i++) TimeSyncTick[i] = 0;
-        }
-
-        /** Polling 관련 */
-        private class PollingList {
-            private final class STATUS {
-                /** 초기화 과정 */
-                public final static byte First = 0;
-                /** 초기화 타임아웃 */
-                public final static byte FirstTimeOut = 1;
-                /** 평상시 */
-                public final static byte Normal = 2;
-            }
-
-            private final class ALLCTRL {
-                /** 없음 */
-                public final static byte Idle         = 0;
-                /** 일괄소등 설정 */
-                public final static byte BatchOff_Set = 1;
-                /** 일괄소등 해제 */
-                public final static byte BatchOff_Clr = 2;
-            }
-
-            public byte CurrentAddress;
-            public byte Status;
-            public byte SearchDeviceCount;
-            public int SearchTryCount;
-            public boolean SearchEnd;
-            public byte AllCtrl;
-
-            private PollingList() {
-                CurrentAddress = 0;
-                Status = STATUS.First;
-                SearchDeviceCount = 0;
-                SearchTryCount = 0;
-                SearchEnd = false;
-                AllCtrl = ALLCTRL.Idle;
-            }
-
-            public void SetStatus(byte ChangeStatus) {
-                switch (ChangeStatus) {
-                    case STATUS.First:
-                        Status = ChangeStatus;
-                        CurrentAddress = 0;
-                        SearchDeviceCount = 0;
-                        SearchTryCount = 0;
-                        SearchEnd = false;
-                        break;
-
-                    case STATUS.FirstTimeOut:
-                        Status = ChangeStatus;
-                        break;
-
-                    case STATUS.Normal:
-                        Status = ChangeStatus;
-                        break;
-
-                    default:
-                        break;
-                }
-            }
-        }
-    }
-
-    private Driver mDriver = null;
-
-    private DriverInterOpAPI driverInterOpAPI;
-
-    /**
-     * 생성자
-     */
-    public MultiSwitch_Controller() {
-        /* 로그 초기상태 */
-//        log_sw = true;
-//        SerialLog = true;
-
-        /* 드라이버 내부 변수 초기화 */
-        mDriver = new Driver();
-
-//        /* BR registerReceiver (일괄소등 수신용) */
-//        IntentFilter filter = new IntentFilter();
-//        filter.addAction(define.NOTIFY_ACNAME);
-//        ServiceMain.svcContext.registerReceiver(mWallPadNotifyBR, filter);
-    }
-
-    @Override
-    public void DeviceLog(String msg) {
-        if (!log_sw) return;
-        Log.d(TAG, msg);
-    }
-
-    private boolean registerDeviceBR() {
-        DeviceLog("registerDeviceBR - Start");
-
-        if (mDriver == null) return false;
-        if (mDriver.Polling.Status != Driver.PollingList.STATUS.Normal) return false;
-
-        IntentFilter filter = new IntentFilter();
-        /* BR registerReceiver (일괄소등 수신용) */
-        filter.addAction(define.NOTIFY_ACNAME);
-        /* BR registerReceiver (에어컨 상태 수신용) */
-        driverInterOpAPI.setAirconRegBR(define.DRIVER_AIRCON_BR);
-        filter.addAction(define.DRIVER_AIRCON_BR);
-        ServiceMain.svcContext.registerReceiver(mWallPadNotifyBR, filter);
-        DeviceLog("registerDeviceBR - OK");
-
-        return true;
-    }
-
-    /**
-     * BroadcastReceiver
-     */
-    private BroadcastReceiver mWallPadNotifyBR = new BroadcastReceiver() {
-        public void onReceive(Context context, Intent intent) {
-            String strActionNamr = intent.getAction();
-
-            DeviceLog("Receive Notify BR ["+ strActionNamr + "]");
-
-            if (strActionNamr.equals(define.NOTIFY_ACNAME)) {
-                int kind = intent.getIntExtra("KIND", 0);
-                DeviceLog("Receive Notify BR "+ define.NOTIFY_ACNAME + " : " + kind);
-
-                switch (kind) {
-                    case define.NOTIFY_ALL_LIGHT_OFF:
-                        if (!((mDriver.Polling.Status == Driver.PollingList.STATUS.First) || (mDriver.Polling.Status == Driver.PollingList.STATUS.FirstTimeOut))) {
-                            // 일괄소등 설정 (조명 OFF)
-                            mDriver.Polling.AllCtrl = Driver.PollingList.ALLCTRL.BatchOff_Set;
-                        }
-                        break;
-
-                    case define.NOTIFY_ALL_LIGHT_ON:
-                        if (!((mDriver.Polling.Status == Driver.PollingList.STATUS.First) || (mDriver.Polling.Status == Driver.PollingList.STATUS.FirstTimeOut))) {
-                            // 일괄소등 해제 (조명 ON)
-                            mDriver.Polling.AllCtrl = Driver.PollingList.ALLCTRL.BatchOff_Clr;
-                        }
-                        break;
-
-                    case define.NOTIFY_DEVICE_INIT_COMPLETION:
-                        getEntireAIrconData();
-                        break;
-                }
-            }
-            else if (strActionNamr.equals(define.DRIVER_AIRCON_BR)) {
-                getEntireAIrconData();
-            }
-        }
-    };
-
-    private int getEntireAIrconData() {
-        try {
-            Log.i(TAG, "[getEntireAIrconData]");
-            if (ServiceMain.systemAircon_controller == null) return -1;
-
-            DataClasses.SystemAircon.AirconUnitData[] airconUnitData = ServiceMain.systemAircon_controller.getEntireAirconStatus();
-//            if (airconUnitData != null) Log.e(TAG, "[getEntireAIrconData] airconUnitData is not null airconUnitData.length [" + airconUnitData.length +"]");
-//            else Log.e(TAG, "[getEntireAIrconData] airconUnitData is null airconUnitData.length [" + airconUnitData.length + "]");
-
-
-            for (int i = 0; i < mDriver.Device.length; i++) {
-                MultiSwitch.Device.AirconData airconData = new MultiSwitch.Device.AirconData(mDriver.Device[i].info.Support.hAirconCtrlCnt);
-                for (int j = 0; j < mDriver.Device[i].info.Support.hAirconCtrlCnt; j++) {
-                    for (int k = 0; k < airconUnitData.length; k++) {
-                        if (mDriver.Device[i].info.Support.hAirconCtrlID[j] == airconUnitData[k].hInsideID) {
-                            // 멀티스위치에서 제어하는 에어컨 ID
-                            airconData.hInsideID[j] = airconUnitData[k].hInsideID;
-                            if (j == 0) {
-                                // 에어컨 상태정보는 빠른ID의 정보만 저장한다.
-                                airconData.conversionAirconStatus(airconUnitData[k]);
-                            }
-                        }
-                    }
-                    mDriver.Device[i].device.airconData = airconData;
-                }
-            }
-
-//            Log.i(TAG, "[getEntireAIrconData] ========== driver check start!! ==========");
-//            for (int i = 0; i < mDriver.Device.length; i++) {
-//                if (mDriver.Device[i].info.Support.bAirconCtrl) Log.i(TAG, mDriver.Device[i].device.airconData.ToDebugString((byte) i));
-//            }
-//            Log.i(TAG, "[getEntireAIrconData] ========== driver check end!! ==========");
-
-            return 0;
-        } catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-        } catch (Exception e) {
-            Log.e(TAG, "[Exception] getEntireAIrconData()");
-            LogUtil.errorLogInfo("", TAG, e);//e.printStackTrace();
-        }
-        return -99;
-    }
-
-    /**
-     * 로딩후 처음 폴링 시퀀스
-     */
-    @Override
-    protected void do_boot() {
-        driverInterOpAPI = new DriverInterOpAPI(MainHandler);
-    }
-
-    ///////////////////////////////////////////////////////////////////////////////////////////////
-    // Polling
-    ///////////////////////////////////////////////////////////////////////////////////////////////
-    /**
-     * do_ctr : 폴링스케쥴러
-     */
-    @Override
-    protected void do_ctr() {
-        DeviceLog("Polling ");
-
-        /* [[ First ]]
-         * 초기 디바이스정보 및 최대 ADDRESS 검색 */
-        if (mDriver.Polling.Status == Driver.PollingList.STATUS.First) {
-            // 1. 디바이스 검색
-            byte MaxDeviceID = 0;
-            for (byte DeviceIdx = 0; DeviceIdx < MAX_DEVICE_COUNT; DeviceIdx++) {
-                MultiSwitch.Info info = Send_GetDeviceInfo(DeviceIdx);
-                if (info != null) {
-                    MaxDeviceID = (byte) (DeviceIdx+1);
-                    if (info.Support.bV2CMDUsage) {
-                        info = sendGetDeviceInfoV2(DeviceIdx, info);
-                    }
-                    mDriver.Device[DeviceIdx].info = info;
-                    mDriver.Device[DeviceIdx].setBasicInfo(info.Support.hLightCnt, info.Support.hOutletCnt);
-                    if (info.Support.bAirconCtrl) mDriver.Device[DeviceIdx].setAirconInfo(info.Support.hAirconCtrlCnt, info.Support.hAirconCtrlID);
-                    Log.i(TAG, "SearchDevice     DeviceNum = " + (byte)(DeviceIdx+1) + "      OK!!!");
-
-                    Log.i(TAG, mDriver.Device[DeviceIdx].info.ToDebugString(DeviceIdx));
-                    Log.i(TAG, mDriver.Device[DeviceIdx].info.Support.ToDebugString(DeviceIdx));
-                }
-                else {
-                    Log.i(TAG, "SearchDevice     DeviceNum = " + (byte)(DeviceIdx+1) + "      Fail...");
-                }
-            }
-
-            // 2. 가장 높은 ID 저장
-            if (MaxDeviceID > mDriver.Polling.SearchDeviceCount) mDriver.Polling.SearchDeviceCount = MaxDeviceID;
-
-            // 3. 검색 횟수 체크
-            if (++mDriver.Polling.SearchTryCount >= MAX_SEARCH_COUNT) {
-                if (mDriver.Polling.SearchDeviceCount != 0) {
-                    mDriver.Polling.SearchEnd = true;
-                    mDriver.Polling.SetStatus(Driver.PollingList.STATUS.Normal);
-                    registerDeviceBR();
-                    Log.i(TAG, "First - Search Device END - SearchDeviceCount : " + mDriver.Polling.SearchDeviceCount);
-
-                    super.CommDataGeneration(mDriver.Polling.SearchDeviceCount);
-
-                    ServiceMain.deviceInitChecker.Remove(super.DeviceName);
-                }
-                else {
-                    mDriver.Polling.SetStatus(Driver.PollingList.STATUS.FirstTimeOut);
-
-                    Log.i(TAG, "--------------------------------------------------");
-                    Log.i(TAG, "SearchDevice Fail... FirstTimeOut ");
-                    Log.i(TAG, "--------------------------------------------------");
-
-                    ServiceMain.deviceInitChecker.Remove(super.DeviceName);
-                }
-            }
-        }
-
-        /* [[ FirstTimeOut ]]
-         * 초기 디바이스 검색하지못함. */
-        else if (mDriver.Polling.Status == Driver.PollingList.STATUS.FirstTimeOut) {
-            MultiSwitch.Info info = Send_GetDeviceInfo(mDriver.Polling.CurrentAddress);
-            if (info != null) {
-                if (info.Support.bV2CMDUsage) {
-                    info = sendGetDeviceInfoV2(mDriver.Polling.CurrentAddress, info);
-                }
-                mDriver.Device[mDriver.Polling.CurrentAddress].info = info;
-                mDriver.Device[mDriver.Polling.CurrentAddress].setBasicInfo(info.Support.hLightCnt, info.Support.hOutletCnt);
-                if (info.Support.bAirconCtrl) mDriver.Device[mDriver.Polling.CurrentAddress].setAirconInfo(info.Support.hAirconCtrlCnt, info.Support.hAirconCtrlID);
-                mDriver.Polling.SearchDeviceCount = (byte) (mDriver.Polling.CurrentAddress + 1);
-            }
-
-            if (++mDriver.Polling.CurrentAddress >= MAX_DEVICE_COUNT) {
-                mDriver.Polling.CurrentAddress = 0;
-
-                if (mDriver.Polling.SearchDeviceCount != 0) {
-                    mDriver.Polling.SearchEnd = true;
-                    mDriver.Polling.SetStatus(Driver.PollingList.STATUS.Normal);
-                    registerDeviceBR();
-
-                    Log.i(TAG, "FirstTimeOut - Search Device END - SearchDeviceCount : " + mDriver.Polling.SearchDeviceCount);
-                }
-            }
-        }
-
-        /* [[ Normal ]]
-         * 평상시 */
-        else if (mDriver.Polling.Status == Driver.PollingList.STATUS.Normal) {
-            if (mDriver.Polling.SearchEnd) {
-                mDriver.Polling.SearchEnd = false;
-
-                int DeviceCount = mDriver.Polling.SearchDeviceCount;
-
-                if (!super.getCommCNTGeneration()) super.CommDataGeneration(DeviceCount);
-
-                for (byte DeviceIdx = 0; DeviceIdx < DeviceCount; DeviceIdx++) {
-                    DeviceLog(mDriver.Device[DeviceIdx].info.ToDebugString(DeviceIdx));
-                }
-            }
-
-            // 전체 명령 처리
-            if (mDriver.Polling.AllCtrl != Driver.PollingList.ALLCTRL.Idle) {
-                CtrlCmd ctrlCmd = new CtrlCmd();
-
-                // 일괄소등 설정
-                if (mDriver.Polling.AllCtrl == Driver.PollingList.ALLCTRL.BatchOff_Set) {
-                    ctrlCmd.light.setBatchOff(MultiSwitch.BATCHOFF_STATUS.Set);
-                }
-
-                // 일괄소등 해제
-                else if (mDriver.Polling.AllCtrl == Driver.PollingList.ALLCTRL.BatchOff_Clr) {
-                    ctrlCmd.light.setBatchOff(MultiSwitch.BATCHOFF_STATUS.Clr);
-                }
-                else {
-                    Log.w(TAG, "[do_ctr] AllCtrl Out Of Range !!! (AllCtrl:" + mDriver.Polling.AllCtrl + ")");
-                    mDriver.Polling.AllCtrl = Driver.PollingList.ALLCTRL.Idle;
-                    return;
-                }
-
-                byte TempAllCtrlStatus = mDriver.Polling.AllCtrl;
-
-                MultiSwitch.Device device;
-                for (byte i=0 ; i<mDriver.Polling.SearchDeviceCount ; i++) {
-                    if (mDriver.Device[i].info.Support.bV2CMDUsage) device = sendSetLightConcentStatusV2(i, ctrlCmd);
-                    else device = Send_SetLightConcentStatus(i, ctrlCmd);
-
-                    if (device != null) {
-                        UpdateVariables(i, device, false);
-                    }
-                    else
-                    {
-                        Log.w(TAG, "[do_ctr] AllCtrl:" + mDriver.Polling.AllCtrl + ", DeviceIdx:" + i + "   Ctrl Fail ... !!!");
-                    }
-                }
-
-                //전체제어중 전체제어명령어 다시 수신되었을 경우는 예외처리
-                if (TempAllCtrlStatus == mDriver.Polling.AllCtrl) {
-                    mDriver.Polling.AllCtrl = Driver.PollingList.ALLCTRL.Idle;
-                }
-            }
-            // 상태 가져오기
-            else {
-                byte CurrentAddress = mDriver.Polling.CurrentAddress;
-                if (mDriver.Device[CurrentAddress].info.Install) {
-                    if (mDriver.Device[CurrentAddress].info.Support.bTimeSync) {
-                        //시간정보 사용함 인 경우 처리
-                        long currentTimeMillis = 0;
-                        currentTimeMillis = System.currentTimeMillis();
-                        if (Math.abs(currentTimeMillis - mDriver.TimeSyncTick[CurrentAddress]) > STATUS_SYNC_TICK) {
-                            //시간정보를 보내줘야 할 순서 확인
-                            mDriver.TimeSyncTick[CurrentAddress] = currentTimeMillis;
-
-                            //시간 전송
-                            MultiSwitch.Device device = Send_Time(CurrentAddress);
-                            if (device != null) {
-                                boolean bNotify = false;
-                                if (!mDriver.bDeviceFirstNotify) {
-                                    if (CurrentAddress == 0) {
-                                        bNotify = true;
-                                        mDriver.bDeviceFirstNotify = true;
-                                    }
-                                }
-                                UpdateVariables(CurrentAddress, device, bNotify);
-                            }
-                        }
-                        else {
-                            //평상시 폴링
-                            MultiSwitch.Device device;
-                            if (mDriver.Device[CurrentAddress].info.Support.bV2CMDUsage) device = sendGetDeviceStatusV2(CurrentAddress);
-                            else device = Send_GetLightConcentStatus(CurrentAddress);
-
-                            if (device != null && device.ctrlReq.bAircon && mDriver.Device[CurrentAddress].info.Support.bV2CMDUsage) {
-                                sendCtrlReqACKV2(CurrentAddress, (byte) 0x01);
-                                for (int i = 0; i < mDriver.Device[CurrentAddress].info.Support.hAirconCtrlID.length; i++) {
-                                    Log.e(TAG, device.ctrlReq.ToDebugString(CurrentAddress));
-                                    int nResult = driverInterOpAPI.ctrlAircon(ServiceMain.MSG_DEV_CTR, mDriver.Device[CurrentAddress].info.Support.hAirconCtrlID[i], device.ctrlReq.hAirconCtrlOption, device.ctrlReq.hAirconStatus, device.ctrlReq.hSetTemper);
-                                    Log.e(TAG, "Aircon Ctrl -> nResult [" + nResult + "]");
-                                }
-                            }
-
-                            if (device != null) {
-                                boolean bNotify = false;
-                                if (!mDriver.bDeviceFirstNotify) {
-                                    if (CurrentAddress == 0) {
-                                        bNotify = true;
-                                        mDriver.bDeviceFirstNotify = true;
-                                    }
-                                }
-                                UpdateVariables(CurrentAddress, device, bNotify);
-                            }
-                        }
-                    }
-                    else {
-                        //시간정보 사용안함 때 평상시 폴링
-                        MultiSwitch.Device device;
-                        if (mDriver.Device[CurrentAddress].info.Support.bV2CMDUsage) {
-                            device = sendGetDeviceStatusV2(CurrentAddress);
-                            if (device != null && device.ctrlReq.bAircon && mDriver.Device[CurrentAddress].info.Support.bV2CMDUsage) {
-                                sendCtrlReqACKV2(CurrentAddress, (byte) 0x01);
-                                for (int i = 0; i < mDriver.Device[CurrentAddress].info.Support.hAirconCtrlID.length; i++) {
-                                    driverInterOpAPI.ctrlAircon(ServiceMain.MSG_DEV_CTR, mDriver.Device[CurrentAddress].info.Support.hAirconCtrlID[i], device.ctrlReq.hAirconCtrlOption, device.ctrlReq.hAirconStatus, device.ctrlReq.hSetTemper);
-                                }
-                            }
-                        }
-                        else device = Send_GetLightConcentStatus(CurrentAddress);
-
-                        if (device != null) {
-                            boolean bNotify = false;
-                            if (!mDriver.bDeviceFirstNotify) {
-                                if (CurrentAddress == 0) {
-                                    bNotify = true;
-                                    mDriver.bDeviceFirstNotify = true;
-                                }
-                            }
-                            UpdateVariables(CurrentAddress, device, bNotify);
-                        }
-                    }
-                }
-                else {
-                    MultiSwitch.Info info = Send_GetDeviceInfo(CurrentAddress);
-                    if (info != null) {
-                        if (info.Support.bV2CMDUsage) {
-                            info = sendGetDeviceInfoV2(CurrentAddress, info);
-                        }
-                        mDriver.Device[CurrentAddress].info = info;
-                        mDriver.Device[CurrentAddress].setBasicInfo(info.Support.hLightCnt, info.Support.hOutletCnt);
-                        if (info.Support.bAirconCtrl) mDriver.Device[CurrentAddress].setAirconInfo(info.Support.hAirconCtrlCnt, info.Support.hAirconCtrlID);
-                        AddDoCount(CurrentAddress, true);
-                    }
-                    else {
-                        AddDoCount(CurrentAddress, false);
-                    }
-                }
-
-                if (++mDriver.Polling.CurrentAddress >= mDriver.Polling.SearchDeviceCount) mDriver.Polling.CurrentAddress = 0;
-            }
-        }
-        else {
-            mDriver = new Driver();
-        }
-    }
-
-    ///////////////////////////////////////////////////////////////////////////////////////////////
-    // Ctrl
-    ///////////////////////////////////////////////////////////////////////////////////////////////
-    /**
-     * NoSink 제어
-     *
-     * @param StrArg
-     *
-     * @return
-     */
-    public String NoSinkCtrl(String StrArg) {
-        DeviceLog("[NoSinkCtrl] Start");
-
-        // 1. 디바이스 초기화시 에러리턴
-        if ((mDriver.Polling.Status == Driver.PollingList.STATUS.First) || (mDriver.Polling.Status == Driver.PollingList.STATUS.FirstTimeOut)) {
-            Log.w(TAG, "[NoSinkCtrl] - Not Yet !!!");
-            return "FAIL;" + APIErrorCode.DEVICEISNOTREADY;
-        }
-
-        CtrDevFormat ctrDevFormat = GetCtrDevParamParsing(StrArg, 5);
-        if (ctrDevFormat.ret != APIErrorCode.C_SUCCESS) {
-            Log.w(TAG, "[NoSinkCtrl] GetCtrDevParamParsing Error (ret:" + ctrDevFormat.ret + ")");
-            return "FAIL;" + APIErrorCode.DEFAULT_PARSING_ERR;
-        }
-
-        if (ctrDevFormat.CmdStr!=null) {
-            //////////////////////////////////////////////////////////
-            // Refresh : 데이터 갱신 (No Sink)
-            //////////////////////////////////////////////////////////
-            if (ctrDevFormat.CmdStr.equals("Refresh")) {
-                byte Index         = ctrDevFormat.param[0];
-                DeviceLog("[Refresh] Index : " + String.format("0x%02X", Index));
-                return RefreshResult(Index);
-            }
-
-            //////////////////////////////////////////////////////////
-            // GetDeviceCount : 기기 개수 가져오기 (No Sink)
-            //////////////////////////////////////////////////////////
-            else if (ctrDevFormat.CmdStr.equals("GetDeviceCount")) {
-                DeviceLog("[GetDeviceCount]");
-                return RefreshResult_GetDeviceCount();
-            }
-        }
-
-        return "FAIL;" + APIErrorCode.UNKNOWNCOMMAND;
-    }
-
-    /**
-     * do_ctrEmm : 싱크 제어
-     */
-    @Override
-    @SuppressLint("DefaultLocale")
-    protected String do_ctrEmm(DeviceCtrSHMem SHMem) {
-        DeviceLog("[do_ctrEmm] Start");
-        DeviceLog("cmd    : " + SHMem.cmd);
-        DeviceLog("StrArg : " + SHMem.StrArg);
-
-        // 1. 디바이스 초기화시 에러리턴
-        if ((mDriver.Polling.Status == Driver.PollingList.STATUS.First) || (mDriver.Polling.Status == Driver.PollingList.STATUS.FirstTimeOut)) {
-            Log.w(TAG, "[do_ctrEmm] - Not Yet !!!");
-            return SHMem.retVal = "FAIL;" + APIErrorCode.DEVICEISNOTREADY;
-        }
-
-        CtrDevFormat ctrDevFormat = GetCtrDevParamParsing(SHMem.StrArg, 5);
-        if (ctrDevFormat.ret != APIErrorCode.C_SUCCESS) {
-            Log.w(TAG, "[do_ctrEmm] GetCtrDevParamParsing Error (ret:" + ctrDevFormat.ret + ")");
-            return SHMem.retVal = "FAIL;" + APIErrorCode.DEFAULT_PARSING_ERR;
-        }
-
-        if (ctrDevFormat.CmdStr!=null) {
-            //////////////////////////////////////////////////////////
-            // Refresh : 데이터 갱신 (Sink)
-            //
-            // [0] Index    - 기기인덱스 (0~7)
-            //////////////////////////////////////////////////////////
-            if (ctrDevFormat.CmdStr.equals("Refresh")) {
-                try {
-                    byte Index    = ctrDevFormat.param[0];
-
-                    // 1. 범위체크
-                    //     1.1. Index
-                    if (!DeviceIndexRangeCheck(Index)) {
-                        Log.w(TAG, "[do_ctrEmm -> Refresh] Param : Index - Out Of Range !!! (Index:" + Index + ")");
-                        return SHMem.retVal = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
-                    }
-
-                    // 2. Doing
-                    MultiSwitch.Device device;
-                    if (mDriver.Device[Index].info.Support.bV2CMDUsage) device = sendGetDeviceStatusV2(Index);
-                    else device = Send_GetLightConcentStatus(Index);
-
-                    if (device != null && device.ctrlReq.bAircon && mDriver.Device[Index].info.Support.bV2CMDUsage) {
-                        sendCtrlReqACKV2(Index, (byte) 0x01);
-                        for (int i = 0; i < mDriver.Device[Index].info.Support.hAirconCtrlID.length; i++) {
-                            driverInterOpAPI.ctrlAircon(ServiceMain.MSG_DEV_CTR, mDriver.Device[Index].info.Support.hAirconCtrlID[i], device.ctrlReq.hAirconCtrlOption, device.ctrlReq.hAirconStatus, device.ctrlReq.hSetTemper);
-                        }
-                    }
-
-                    if (device != null) {
-                        UpdateVariables(Index, device, false);
-                        SHMem.retVal = RefreshResult(Index);
-                    }
-                    else {
-                        SHMem.retVal = "FAIL;" + APIErrorCode.DEVICEISNORESPONSE;
-                    }
-                    return SHMem.retVal;
-                } catch (RuntimeException re) {
-                    LogUtil.errorLogInfo("", TAG, re);
-                    return SHMem.retVal = "FAIL;" + APIErrorCode.EXCEPTION;
-                } catch (Exception e) {
-                    Log.e(TAG, "[Exception Error] do_ctrEmm -> Refresh");
-                    //e.printStackTrace();
-                    LogUtil.errorLogInfo("", TAG, e);
-                    return SHMem.retVal = "FAIL;" + APIErrorCode.EXCEPTION;
-                }
-            }
-
-            ///////////////////////////////////////////////////////////////
-            // SetLightOnOff : 조명 제어
-            //
-            // [0] Index    - 기기인덱스 (0~7)
-            // [1] LightIdx - 조명인덱스 (0~7, 0xFF:전체)
-            // [2] OnOff    - 0x00 : OFF, 0x01 : ON
-            ///////////////////////////////////////////////////////////////
-            else if (ctrDevFormat.CmdStr.equals("SetLightOnOff")) {
-                try {
-                    byte Index    = ctrDevFormat.param[0];
-                    byte LightIdx = ctrDevFormat.param[1];
-                    byte OnOff    = ctrDevFormat.param[2];
-
-                    // 1. 범위체크
-                    //     1.1. Index
-                    if (!DeviceIndexRangeCheck(Index)) {
-                        Log.w(TAG, "[do_ctrEmm -> SetLightOnOff] Param : Index - Out Of Range !!! (Index:" + Index + ")");
-                        return SHMem.retVal = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
-                    }
-
-                    if (!mDriver.Device[Index].info.Install) {
-                        Log.w(TAG, "[do_ctrEmm -> SetLightOnOff] Device [" + Index + "]  No Install !!!");
-                        return SHMem.retVal = "FAIL;" + APIErrorCode.DEVICEISNOTREADY;
-                    }
-
-                    //     1.2. LightIdx
-                    if (LightIdx != define.DEVICE_ALL_OR_NOTHING) {
-                        if ((LightIdx < 0) || (LightIdx >= MAX_LIGHT_COUNT)) {
-                            Log.w(TAG, "[do_ctrEmm -> SetLightOnOff] Param : LightIdx - Out Of Range #1 !!! (LightIdx:" + LightIdx + ")");
-                            return SHMem.retVal = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
-                        }
-                        else {
-                            if (LightIdx >= mDriver.Device[Index].info.Support.hLightCnt) {
-                                Log.w(TAG, "[do_ctrEmm -> SetLightOnOff] Param : LightIdx - Out Of Range #2 !!! (LightIdx:" + LightIdx + ")");
-                                return SHMem.retVal = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
-                            }
-                        }
-                    }
-
-                    //     1.3. OnOff
-                    if ((OnOff != 0x00) && (OnOff != 0x01)) {
-                        Log.w(TAG, "[do_ctrEmm -> SetLightOnOff] Param : OnOff - Out Of Range !!! (OnOff:" + OnOff + ")");
-                        return SHMem.retVal = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
-                    }
-
-                    // 2. Make Ctrl Command
-                    CtrlCmd ctrlCmd = new CtrlCmd();
-                    if (LightIdx == define.DEVICE_ALL_OR_NOTHING) ctrlCmd.light.Pattern = define.DEVICE_ALL_OR_NOTHING;
-                    else ctrlCmd.light.Pattern = super.BIT_ARRAY[LightIdx];
-
-                    if (OnOff == 0x00) ctrlCmd.light.OnOff = false;
-                    else ctrlCmd.light.OnOff = true;
-
-                    // 3. Doing
-                    MultiSwitch.Device device;
-                    if (mDriver.Device[Index].info.Support.bV2CMDUsage) device = sendSetLightConcentStatusV2(Index, ctrlCmd);
-                    else device = Send_SetLightConcentStatus(Index, ctrlCmd);
-
-                    if (device != null) {
-                        UpdateVariables(Index, device, false);
-                        SHMem.retVal = "SUCCESS";
-                    }
-                    else {
-                        SHMem.retVal = "FAIL;" + APIErrorCode.DEVICEISNORESPONSE;
-                    }
-                    return SHMem.retVal;
-                } catch (RuntimeException re) {
-                    LogUtil.errorLogInfo("", TAG, re);
-                    return SHMem.retVal = "FAIL;" + APIErrorCode.EXCEPTION;
-                } catch (Exception e) {
-                    Log.e(TAG, "[Exception Error] do_ctrEmm -> SetLightOnOff");
-                    //e.printStackTrace();
-                    LogUtil.errorLogInfo("", TAG, e);
-                    return SHMem.retVal = "FAIL;" + APIErrorCode.EXCEPTION;
-                }
-            }
-            ///////////////////////////////////////////////////////////////
-            // SetLightOnOff : 조명 제어
-            //
-            // [0] Index    - 기기인덱스 (0~7)
-            // [1] LightIdx - 조명인덱스 (0~7, 0xFF:전체)
-            // [2] OnOff    - 0x00 : OFF, 0x01 : ON
-            ///////////////////////////////////////////////////////////////
-            else if (ctrDevFormat.CmdStr.equals("SetLightDimV2")) {
-                try {
-                    byte Index    = ctrDevFormat.param[0];
-                    byte LightIdx = ctrDevFormat.param[1];
-                    byte DimLevel    = ctrDevFormat.param[2];
-
-                    if (!mDriver.Device[Index].info.Support.bV2CMDUsage) return SHMem.retVal = "FAIL;" + APIErrorCode.NOT_SUPPORT;
-
-                    // 1. 범위체크
-                    //     1.1. Index
-                    if (!DeviceIndexRangeCheck(Index)) {
-                        Log.w(TAG, "[do_ctrEmm -> SetLightDimV2] Param : Index - Out Of Range !!! (Index:" + Index + ")");
-                        return SHMem.retVal = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
-                    }
-
-                    if (!mDriver.Device[Index].info.Install) {
-                        Log.w(TAG, "[do_ctrEmm -> SetLightDimV2] Device [" + Index + "]  No Install !!!");
-                        return SHMem.retVal = "FAIL;" + APIErrorCode.DEVICEISNOTREADY;
-                    }
-
-                    //     1.2. LightIdx
-                    if (LightIdx != define.DEVICE_ALL_OR_NOTHING) {
-                        if ((LightIdx < 0) || (LightIdx >= MAX_LIGHT_COUNT)) {
-                            Log.w(TAG, "[do_ctrEmm -> SetLightDimV2] Param : LightIdx - Out Of Range #1 !!! (LightIdx:" + LightIdx + ")");
-                            return SHMem.retVal = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
-                        }
-                        else {
-                            if (LightIdx >= mDriver.Device[Index].info.Support.hLightCnt) {
-                                Log.w(TAG, "[do_ctrEmm -> SetLightDimV2] Param : LightIdx - Out Of Range #2 !!! (LightIdx:" + LightIdx + ")");
-                                return SHMem.retVal = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
-                            }
-                        }
-                    }
-
-                    //     1.3. Dim
-                    if (DimLevel < 1 && mDriver.Device[Index].info.Support.hDimLevel < DimLevel) {
-                        Log.w(TAG, "[do_ctrEmm -> SetLightDimV2] Param : DimLevel - Out Of Range !!! (DimLevel:" + DimLevel + ")");
-                        return SHMem.retVal = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
-                    }
-
-                    // 2. Make Ctrl Command
-                    CtrlCmd ctrlCmd = new CtrlCmd();
-                    if(LightIdx == define.DEVICE_ALL_OR_NOTHING) ctrlCmd.light.Pattern = define.DEVICE_ALL_OR_NOTHING;
-                    else ctrlCmd.light.Pattern = super.BIT_ARRAY[LightIdx];
-
-                    ctrlCmd.light.OnOff = mDriver.Device[Index].device.light[LightIdx].bPower;
-                    ctrlCmd.light.Dim = true;
-                    ctrlCmd.light.DimLevel = DimLevel;
-
-                    // 3. Doing
-                    MultiSwitch.Device device;
-                    device = sendSetLightConcentStatusV2(Index, ctrlCmd);
-
-                    if (device != null) {
-                        UpdateVariables(Index, device, false);
-                        SHMem.retVal = "SUCCESS";
-                    }
-                    else {
-                        SHMem.retVal = "FAIL;" + APIErrorCode.DEVICEISNORESPONSE;
-                    }
-                    return SHMem.retVal;
-                } catch (RuntimeException re) {
-                    LogUtil.errorLogInfo("", TAG, re);
-                    return SHMem.retVal = "FAIL;" + APIErrorCode.EXCEPTION;
-                } catch (Exception e) {
-                    Log.e(TAG, "[Exception Error] do_ctrEmm -> SetLightDimV2");
-                    //e.printStackTrace();
-                    LogUtil.errorLogInfo("", TAG, e);
-                    return SHMem.retVal = "FAIL;" + APIErrorCode.EXCEPTION;
-                }
-            }
-
-            ///////////////////////////////////////////////////////////////
-            // SetConcentOnOff : 콘센트 ON/OFF 제어
-            //
-            // [0] Index      - 기기인덱스 (0~7)
-            // [1] ConcentIdx - 콘센트인덱스 (0~7, 0xFF:전체)
-            // [2] OnOff    - 0x00 : OFF, 0x01 : ON
-            ///////////////////////////////////////////////////////////////
-            else if (ctrDevFormat.CmdStr.equals("SetConcentOnOff")) {
-                return SHMem.retVal = do_ctrEmm_SetConcent(ctrDevFormat.CmdStr, ctrDevFormat.param[0], ctrDevFormat.param[1], ctrDevFormat.param[2]);
-            }
-
-            ///////////////////////////////////////////////////////////////
-            // SetConcentMode : 콘센트 Mode 제어
-            //
-            // [0] Index      - 기기인덱스 (0~7)
-            // [1] ConcentIdx - 콘센트인덱스 (0~7, 0xFF:전체)
-            // [2] Mode       - 0x00 : 상시 Always, 0x01 : 자동 Auto
-            ///////////////////////////////////////////////////////////////
-            else if (ctrDevFormat.CmdStr.equals("SetConcentMode")) {
-                return SHMem.retVal = do_ctrEmm_SetConcent(ctrDevFormat.CmdStr, ctrDevFormat.param[0], ctrDevFormat.param[1], ctrDevFormat.param[2]);
-            }
-
-            ///////////////////////////////////////////////////////////////
-            // SetConcentCutOff : 콘센트 차단기준값 설정
-            //
-            // [0] Index      - 기기인덱스 (0~7)
-            // [1] ConcentIdx - 콘센트인덱스 (0~7, 0xFF:전체)
-            ///////////////////////////////////////////////////////////////
-            else if (ctrDevFormat.CmdStr.equals("SetConcentCutOff")) {
-                return SHMem.retVal = do_ctrEmm_SetConcent(ctrDevFormat.CmdStr, ctrDevFormat.param[0], ctrDevFormat.param[1], (byte)0x00);
-            }
-
-            ///////////////////////////////////////////////////////////////
-        }
-
-
-        return SHMem.retVal = "UNKNOWNCMD";
-    }
-
-    /**
-     * {@link #do_ctrEmm(DeviceCtrSHMem)} 의 콘센트 처리부분 Sub 함수이다.
-     *
-     * @param CmdStr      - (String) 명령어
-     * @param Index       - (byte) 기기 인덱스
-     * @param ConcentIdx  - (byte) 콘센트 인덱스
-     * @param OnOff       - (byte) ON/OFF Param
-     *
-     * @return (String) 결과
-     */
-    private String do_ctrEmm_SetConcent(String CmdStr, byte Index, byte ConcentIdx, byte OnOff) {
-        if (CmdStr == null) {
-            Log.w(TAG, "[do_ctrEmm_SetConcent] Param : CmdStr is null !!!");
-            return "FAIL;" + APIErrorCode.INVALIDPARAMETER;
-        }
-
-        try {
-            // 1. 범위체크
-            //     1.1. CmdStr
-            if (!( CmdStr.equals("SetConcentOnOff") || CmdStr.equals("SetConcentMode") || CmdStr.equals("SetConcentCutOff"))) {
-                Log.w(TAG, "[do_ctrEmm_SetConcent] Param : CmdStr - Out Of Range (CmdStr:" + CmdStr + ")");
-                return "FAIL;" + APIErrorCode.INVALIDPARAMETER;
-            }
-
-            //     1.2. Index
-            if (Index != define.DEVICE_ALL_OR_NOTHING) {
-                if (!DeviceIndexRangeCheck(Index)) {
-                    Log.w(TAG, "[do_ctrEmm -> SetConcentOnOff] Param : Index - Out Of Range !!! (Index:" + Index + ")");
-                    return "FAIL;" + APIErrorCode.INVALIDPARAMETER;
-                }
-
-                if (!mDriver.Device[Index].info.Install) {
-                    Log.w(TAG, "[do_ctrEmm -> SetConcentOnOff] Device [" + Index + "]  No Install !!!");
-                    return "FAIL;" + APIErrorCode.DEVICEISNOTREADY;
-                }
-            }
-
-            //     1.2. ConcentIdx
-            if (Index == define.DEVICE_ALL_OR_NOTHING) {
-                if (ConcentIdx != define.DEVICE_ALL_OR_NOTHING) {
-                    Log.w(TAG, "[do_ctrEmm -> SetConcentOnOff] Param : If the entire DeviceIndex ConcentIndex must be a whole.");
-                    return "FAIL;" + APIErrorCode.INVALIDPARAMETER;
-                }
-            }
-            else {
-                if (ConcentIdx != define.DEVICE_ALL_OR_NOTHING) {
-                    if ((ConcentIdx < 0) || (ConcentIdx >= MAX_OUTLET_COUNT)) {
-                        Log.w(TAG, "[do_ctrEmm -> SetConcentOnOff] Param : ConcentIdx - Out Of Range #1 !!! (ConcentIdx:" + ConcentIdx + ")");
-                        return "FAIL;" + APIErrorCode.INVALIDPARAMETER;
-                    }
-                    else {
-                        if (ConcentIdx >= mDriver.Device[Index].info.Support.hOutletCnt) {
-                            Log.w(TAG, "[do_ctrEmm -> SetConcentOnOff] Param : ConcentIdx - Out Of Range #1 !!! (ConcentIdx:" + ConcentIdx + ")");
-                            return SHMem.retVal = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
-                        }
-                    }
-                }
-            }
-
-            //     1.3. OnOff
-            if ((OnOff != 0x00) && (OnOff != 0x01)) {
-                Log.w(TAG, "[do_ctrEmm -> SetConcentOnOff] Param : OnOff - Out Of Range !!! (OnOff:" + OnOff + ")");
-                return SHMem.retVal = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
-            }
-
-            // 2. Make Ctrl Command
-            CtrlCmd ctrlCmd = null;
-            // 3. Doing
-            if (Index == define.DEVICE_ALL_OR_NOTHING) {
-                int FailCount = 0;
-                for (byte DeviceIdx = 0; DeviceIdx<mDriver.Polling.SearchDeviceCount; DeviceIdx++) {
-                    if (mDriver.Device[DeviceIdx].info.Support.hOutletCnt > 0) {
-                        ctrlCmd = MakeConcentCtrlCmd(CmdStr, DeviceIdx, ConcentIdx, OnOff);
-
-                        MultiSwitch.Device device;
-                        if (mDriver.Device[DeviceIdx].info.Support.bV2CMDUsage) device = sendSetLightConcentStatusV2(DeviceIdx, ctrlCmd);
-                        else device = Send_SetLightConcentStatus(DeviceIdx, ctrlCmd);
-
-                        if (device != null) {
-                            UpdateVariables(DeviceIdx, device, false);
-                        }
-                        else {
-                            FailCount++;
-                        }
-                    }
-                }
-
-                if (FailCount == 0) {
-                    return "SUCCESS";
-                }
-                else {
-                    return "FAIL;" + APIErrorCode.DEVICEISNORESPONSE;
-                }
-            }
-            else {
-                ctrlCmd = MakeConcentCtrlCmd(CmdStr, Index, ConcentIdx, OnOff);
-
-                MultiSwitch.Device device;
-                if (mDriver.Device[Index].info.Support.bV2CMDUsage) device = sendSetLightConcentStatusV2(Index, ctrlCmd);
-                else device = Send_SetLightConcentStatus(Index, ctrlCmd);
-
-                if (device != null) {
-                    UpdateVariables(Index, device, false);
-                    return "SUCCESS";
-                }
-                else {
-                    return "FAIL;" + APIErrorCode.DEVICEISNORESPONSE;
-                }
-            }
-        } catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-            return "FAIL;" + APIErrorCode.EXCEPTION;
-        } catch (Exception e) {
-            Log.e(TAG, "[Exception Error] do_ctrEmm_SetConcent - [" + CmdStr + "]");
-            //e.printStackTrace();            
-            LogUtil.errorLogInfo("", TAG, e);
-            return "FAIL;" + APIErrorCode.EXCEPTION;
-        }
-    }
-
-    /**
-     * {@link #do_ctrEmm_SetConcent(String, byte, byte, byte)} 의 콘센트 명령어 생성 Sub 함수이다.
-     *
-     * @param CmdStr      - (String) 명령어
-     * @param Index       - (byte) 기기 인덱스
-     * @param ConcentIdx  - (byte) 콘센트 인덱스
-     * @param OnOff       - (byte) ON/OFF Param
-     *
-     * @return (CtrlCmd) 명령어
-     */
-    private CtrlCmd MakeConcentCtrlCmd(String CmdStr, byte Index, byte ConcentIdx, byte OnOff) {
-        byte ConcentCount = mDriver.Device[Index].info.Support.hOutletCnt;
-        CtrlCmd ctrlCmd = new CtrlCmd();
-        ctrlCmd.outlet.setCount(ConcentCount);
-
-        if (CmdStr.equals("SetConcentOnOff")) {
-            if (ConcentIdx == define.DEVICE_ALL_OR_NOTHING) {
-                for (byte i = 0; i < ConcentCount; i++) {
-                    if (OnOff != 0x00) ctrlCmd.outlet.unitOutlet[i].setOnOff(MultiSwitch.OUTLET_STATUS.On);
-                    else ctrlCmd.outlet.unitOutlet[i].setOnOff(MultiSwitch.OUTLET_STATUS.Off);
-                }
-            }
-            else {
-                if (OnOff != 0x00) ctrlCmd.outlet.unitOutlet[ConcentIdx].setOnOff(MultiSwitch.OUTLET_STATUS.On);
-                else ctrlCmd.outlet.unitOutlet[ConcentIdx].setOnOff(MultiSwitch.OUTLET_STATUS.Off);
-            }
-        }
-        else if (CmdStr.equals("SetConcentMode")) {
-            if (ConcentIdx == define.DEVICE_ALL_OR_NOTHING) {
-                for (byte i = 0; i < ConcentCount; i++) {
-                    if (OnOff != 0x00) ctrlCmd.outlet.unitOutlet[i].setMode(MultiSwitch.OUTLET_MODE.Auto);
-                    else ctrlCmd.outlet.unitOutlet[i].setMode(MultiSwitch.OUTLET_MODE.Always);
-                }
-            }
-            else {
-                if (OnOff != 0x00) ctrlCmd.outlet.unitOutlet[ConcentIdx].setMode(MultiSwitch.OUTLET_MODE.Auto);
-                else ctrlCmd.outlet.unitOutlet[ConcentIdx].setMode(MultiSwitch.OUTLET_MODE.Always);
-            }
-        }
-        else if (CmdStr.equals("SetConcentCutOff")) {
-            if (ConcentIdx == define.DEVICE_ALL_OR_NOTHING) {
-                for(byte i=0 ; i<ConcentCount ; i++) ctrlCmd.outlet.unitOutlet[i].CutOff = true;
-            }
-            else {
-                ctrlCmd.outlet.unitOutlet[ConcentIdx].CutOff = true;
-            }
-        }
-        else return null;
-
-        return ctrlCmd;
-    }
-
-    /**
-     * 기기 인덱스의 범위체크를 한다.
-     *
-     * @param Index - (byte) 범위체크할 인덱스
-     *
-     * @return (boolean) 결과 - true : 정상, false : 에러
-     */
-    private boolean DeviceIndexRangeCheck(byte Index) {
-        try {
-            if ((Index < 0) || (Index >= mDriver.Polling.SearchDeviceCount)) return false;
-            return true;
-        } catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-            return false;
-        } catch (Exception e) {
-            Log.e(TAG, "[Exception Error] DeviceIndexRangeCheck");
-            //e.printStackTrace();            
-            LogUtil.errorLogInfo("", TAG, e);
-            return false;
-        }
-    }
-
-    ///////////////////////////////////////////////////////////////////////////////////////////////
-    // RefreshResult
-    ///////////////////////////////////////////////////////////////////////////////////////////////
-    /**
-     * Refresh 에 대한 응답포멧 정의
-     *
-     * @param Index - (byte) 기기 인덱스 (범위 : 0 ~ 3)
-     *
-     * @return (String) "SUCCESS; ..." 성공 , "FAIL; ... " 실패
-     */
-    private String RefreshResult(byte Index) {
-        String result = null;
-
-        DeviceLog("RefreshResult call : ");
-
-        // 1. Check Polling Status
-        if ((mDriver.Polling.Status == Driver.PollingList.STATUS.First) || (mDriver.Polling.Status == Driver.PollingList.STATUS.FirstTimeOut)) {
-            result = "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
-            return result;
-        }
-
-        // 2. Param Range Check
-        if (!(Index >= 0 && Index < mDriver.Polling.SearchDeviceCount)) {
-            result = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
-            return result;
-        }
-
-        // 3. Make Return String Format
-        try {
-            if (mDriver == null)                      return "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
-            if (mDriver.Device == null)               return "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
-            if (mDriver.Device[Index].info == null)   return "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
-            if (mDriver.Device[Index].device == null) return "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
-
-            /*
-             * [Format]
-             *
-             * SUCCESS;                         - (String) 성공
-             *
-             * RequestIndex;                            - (byte) 요청 인덱스
-             *
-             * [Info]
-             * Install                          - (boolean) 설치여부
-             * Vender                           - (byte) 벤더
-             * FwVer_Year                           - (byte) 펌웨어 빌드버전 (년)
-             * FwVer_Month                          - (byte) 펌웨어 빌드버전 (월)
-             * FwVer_Day                            - (byte) 펌웨어 빌드버전 (일)
-             * FwVer_Number                         - (byte) 펌웨어 빌드버전 (순번)
-             * ProtocolVer_Main                         - (byte) 프로토콜 지원 버전 (상위)
-             * ProtocolVer_Sub                          - (byte) 프로토콜 지원 버전 (하위)
-             *
-             * [SupportInfo]
-             * hLightCnt                            - (byte) 조명 개수
-             * hOutletCnt                           - (byte) 콘센트 개수
-             * bV2CMDUsage                          - (byte) V2 CMD 사용 여부
-             * bDim                         - (byte) 디밍 사용 여부
-             * hDimLevel                            - (byte) 디밍 레벨
-             * hDimEnabledCircuit                           - (byte) 디밍 지원 회로
-             * bAirconCtrl                          - (byte) 에어컨 제어 지원 여부 (멀티콘센트에서 월패드로 제어 요청)
-             * hAirconCtrlCnt                           - (byte) 에어컨 제어 개수
-             * hAirconCtrlID[]                          - (byte) 제어할 에어컨 ID (에어컨 제어 개수 만큼)
-             *
-             * [Device]
-             * 조명 정보
-             * 조명 개수 만큼
-             * {
-             *     bPower            - (byte) 상태
-             *     bDimUsage              - (byte) 모드
-             *     hDimLevel             - (double) 현재 소비전력
-             * }
-             * BatchOffStatus        - (byte) 일괄소등상태
-             *
-             * 콘센트 정보
-             * 콘센트 개수 만큼
-             * {
-             *     Status            - (byte) 상태
-             *     Mode              - (byte) 모드
-             *     NowPw             - (double) 현재 소비전력
-             *     CutOffVal         - (double) 대기전력 차단 기준값
-             * }
-             *
-             */
-
-//            Log.e(TAG, "[RefreshResult] =============== start 1 ===============");
-//            Log.w(TAG, mDriver.Device[Index].device.ToDebugString(Index));
-//            Log.e(TAG, "[RefreshResult] =============== end 1 ===============");
-
-            MultiSwitch Device = mDriver.Device[Index];
-//            Device.setBasicInfo(Device.info.Support.hLightCnt, Device.info.Support.hOutletCnt);
-
-//            Log.e(TAG, "[RefreshResult] =============== start 2 ===============");
-//            Log.w(TAG, Device.device.ToDebugString(Index));
-//            Log.e(TAG, "[RefreshResult] =============== end 2 ===============");
-
-            // 조명, 콘센트 클래스 초기화
-//            Device.setBasicInfo(mDriver.Device[Index].info.Support.hLightCnt, mDriver.Device[Index].info.Support.hOutletCnt);
-            // 에어컨 제어 클래스 초기화
-//            Device.setAirconInfo(mDriver.Device[Index].info.Support.hAirconCtrlCnt, mDriver.Device[Index].info.Support.hAirconCtrlID);
-
-            result = APIErrorCode.SUCCESS + ";";
-            result += Index + ";";
-
-            // Install
-            result += Device.info.Install + ";";
-            if (!Device.info.Install) return result;
-
-            // Info
-            result += Device.info.Vender + ";" +
-                    Device.info.FwVer_Year + ";" +
-                    Device.info.FwVer_Month + ";" +
-                    Device.info.FwVer_Day + ";" +
-                    Device.info.FwVer_Number + ";" +
-                    Device.info.ProtocolVer_Main + ";" +
-                    Device.info.ProtocolVer_Sub + ";";
-
-            //SupportInfo
-            result += Device.info.Support.hLightCnt + ";" +
-                    Device.info.Support.hOutletCnt + ";" +
-                    Device.info.Support.bV2CMDUsage + ";" +
-                    Device.info.Support.bDim + ";" +
-                    Device.info.Support.hDimLevel + ";" +
-                    Device.info.Support.hDimEnabledCircuit + ";" +
-                    Device.info.Support.bAirconCtrl + ";";
-            // 에어컨 제어 ID
-            if (Device.info.Support.bAirconCtrl) {
-                result += Device.info.Support.hAirconCtrlCnt + ";";
-                for (byte i = 0; i < Device.info.Support.hAirconCtrlCnt; i++) {
-                    result += Device.info.Support.hAirconCtrlID[i] + ";";
-                }
-            }
-
-            // 조명
-//            Log.e(TAG, "[RefreshResult] Device.device.hLightCnt: " + Device.device.hLightCnt);
-            result += Device.device.hLightCnt + ";";
-            for (byte i = 0; i < Device.device.hLightCnt; i++) {
-                result += Device.device.getLightPower(i) + ";";
-                result += Device.device.getLightDimUsage(i) + ";";
-                result += Device.device.getLightDimLevel(i) + ";";
-            }
-            result += Device.device.hBatchOffStatus + ";";
-
-            // 콘센트
-            result += Device.device.hOutletCnt + ";";
-            if (Device.device.hOutletCnt > 0) {
-                MultiSwitch.Device.Outlet outlet = null;
-                for (byte i = 0; i < Device.device.hOutletCnt; i++) {
-                    outlet = Device.device.getOutletStatus(i);
-                    if (outlet == null) {
-                        Log.e(TAG, "[RefreshResult] getOutletStatus is null !!!");
-                        return "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
-                    }
-                    result += outlet.Status + ";";
-                    result += outlet.Mode + ";";
-                    result += outlet.NowPw + ";";
-                    result += outlet.CutOffVal + ";";
-                }
-            }
-
-        } catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-            result = "FAIL;"+APIErrorCode.EXCEPTION;
-        } catch (Exception e) {
-            Log.e(TAG, "[Exception Error] RefreshResult");
-            //e.printStackTrace();
-            LogUtil.errorLogInfo("", TAG, e);
-            result = "FAIL;"+APIErrorCode.EXCEPTION;
-        }
-        DeviceLog("RefreshResult return : " + result);
-
-        return result;
-    }
-
-    /**
-     * GetDeviceCount 에 대한 응답포멧 정의
-     *
-     * @return (String) "SUCCESS; ..." 성공 , "FAIL; ... " 실패
-     */
-    private String RefreshResult_GetDeviceCount() {
-        String result = null;
-
-        DeviceLog("RefreshResult_GetDeviceCount call : ");
-
-        // 1. Check Polling Status
-        if ((mDriver.Polling.Status == Driver.PollingList.STATUS.First) || (mDriver.Polling.Status == Driver.PollingList.STATUS.FirstTimeOut)) {
-            result = "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
-            return result;
-        }
-
-        // 2. Param Range Check
-
-        // 3. Make Return String Format
-        try {
-            if (mDriver == null) return "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
-            if (mDriver.Polling == null) return "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
-
-            /*
-             * [Format]
-             *
-             * SUCCESS        - (String) 성공
-             *
-             * DeviceCount    - (byte) 기기개수
-             */
-            result = APIErrorCode.SUCCESS + ";";
-            result += mDriver.Polling.SearchDeviceCount + ";";
-        } catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-            result = "FAIL;"+APIErrorCode.EXCEPTION;
-        } catch (Exception e) {
-            Log.e(TAG, "[Exception Error] RefreshResult_GetDeviceCount");
-            //e.printStackTrace();            
-            LogUtil.errorLogInfo("", TAG, e);
-            result = "FAIL;"+APIErrorCode.EXCEPTION;
-        }
-        DeviceLog("RefreshResult_GetDeviceCount return : " + result);
-
-        return result;
-    }
-
-    ///////////////////////////////////////////////////////////////////////////////////////////////
-    // Protocol Command Send Func
-    ///////////////////////////////////////////////////////////////////////////////////////////////
-    /**
-     * 기기 상태 읽기 요청/응답
-     *
-     * @param DeviceIdx - (byte) 요청할 기기 인덱스
-     *
-     * @return (MultiSwitch.Info) 기기정보 null - Error , Not null - OK
-     */
-    private MultiSwitch.Info Send_GetDeviceInfo(byte DeviceIdx) {
-        DeviceLog("[Send_GetDeviceInfo] Start");
-
-        // 1. In 파라미터 확인
-        if ((DeviceIdx < 0) || (DeviceIdx >= MAX_DEVICE_COUNT)) {
-            Log.w(TAG, "[Send_GetDeviceInfo] param [DeviceIdx] Out of Range!!! " + DeviceIdx);
-            return null;
-        }
-
-        // 2. 패킷 데이터 만들기
-        byte[] ReqData = null;
-
-        // 3. 데이터 전송 및 응답
-        byte[] Reply = SendNRead_Variable((byte) (DEVICE_ADDRESS + DeviceIdx), CMDList.Req.GetDeviceInfo, ReqData);
-
-        // 4. 수신데이터 파싱
-        //     4.1. Default Check
-        if (Reply == null) {
-            DeviceLog("[Send_GetDeviceInfo] Reply is null");
-            return null;
-        }
-
-        if (Reply.length != 9) {
-            Log.w(TAG, "[Send_GetDeviceInfo] Reply.length  fail ... " + Reply.length);
-            return null;
-        }
-
-        byte data = 0x00;
-        int index = 0;
-
-        //     4.1. Details Data Check
-        //         - 설치된 조명 개수 X’00’ ~ X’08’
-        data = Reply[index++];
-        if (!((data >= 0x00) && (data <= MAX_LIGHT_COUNT))) {
-            Log.w(TAG, "[Send_GetDeviceInfo] LightCount -  Out of Range !!! " + ToByteString(data));
-            return null;
-        }
-
-        //         - 설치된 콘센트 개수 X’00’ ~ X’08’
-        data = Reply[index++];
-        if (!((data >= 0x00) && (data <= MAX_OUTLET_COUNT))) {
-            Log.w(TAG, "[Send_GetDeviceInfo] ConcentCount -  Out of Range !!! " + ToByteString(data));
-            return null;
-        }
-
-        //         - 제조사 구분정보 및 시간정보
-        data = Reply[index++];
-        if ((data & BIT7) != 0x00) {
-            data = (byte) (data & ~BIT7);
-        }
-
-        if (!(data >= 0x01)) {
-            Log.w(TAG, "[Send_GetDeviceInfo] Vender - Out of Range !!! " + ToByteString(data));
-            return null;
-        }
-
-        //         - 펌웨어 Build Date (Year)
-        data = Reply[index++];
-
-        //         - 펌웨어 Build Date (Month)
-        data = Reply[index++];
-        if (!((data >= 0x01) && (data <= 0x0C))) {
-            Log.w(TAG, "[Send_GetDeviceInfo] Build Date (Month) - Out of Range !!! " + ToByteString(data));
-            return null;
-        }
-
-        //         - 펌웨어 Build Date (Day)
-        data = Reply[index++];
-        if (!((data >= 0x01) && (data <= 0x1F))) {
-            Log.w(TAG, "[Send_GetDeviceInfo] Build Date (Day) - Out of Range !!! " + ToByteString(data));
-            return null;
-        }
-
-        // 5. Data return
-        MultiSwitch.Info info = new MultiSwitch.Info();
-        index = 0;
-
-        info.Install = true;
-        info.Support.hLightCnt       = Reply[index++];
-        info.Support.hOutletCnt     = Reply[index++];
-
-        /** Vendor And TimeShow **/
-        byte VendorData = Reply[index++];
-        if ((VendorData & BIT7) != 0x00) {
-            DeviceLog("[Send_GetDeviceInfo] bTimeSync is Enable!!!");
-            info.Support.bTimeSync = true;
-            VendorData = (byte) (VendorData & ~BIT7);
-        }
-        else {
-            info.Support.bTimeSync = false;
-        }
-
-        if ((VendorData & BIT6) != 0x00) {
-            DeviceLog("[Send_GetDeviceInfo] bV2CMDUsage is Enable!!!");
-            info.Support.bV2CMDUsage = true;
-            VendorData = (byte) (VendorData & ~BIT6);
-        }
-        else {
-            info.Support.bV2CMDUsage = false;
-        }
-
-        info.Vender           = VendorData;
-
-        info.FwVer_Year       = Reply[index++];
-        info.FwVer_Month      = Reply[index++];
-        info.FwVer_Day        = Reply[index++];
-        info.FwVer_Number     = Reply[index++];
-        info.ProtocolVer_Main = Reply[index++];
-        info.ProtocolVer_Sub  = Reply[index++];
-
-        try {
-            if (!Version.getGatewayUsage() || Version.getModelType() == Version.MODEL_TYPE.IHN_1010GL || Version.getModelType() == Version.MODEL_TYPE.IHN_1010GL_I
-                    || Version.getModelType() == Version.MODEL_TYPE.IHN_1010GL_I_2443ALT || Version.getModelType() == Version.MODEL_TYPE.IHN_1010GL_I_6410ALT) {
-                // 대외향 모델 + IHN-1010GL-I
-                WallpadStatusData SetData = new WallpadStatusData(ServiceMain.svcContext);
-                wallpaddbmgr.AddressSet addc = SetData.getAddressMGR();
-                if (!isSystemIPSet()) {
-                    Log.d(TAG, "[Send_GetDeviceInfo] The IP Address of OS is not set!");
-                }
-                else if (addc.Dong.equals("NONE") || addc.Ho.equals("NONE")) {
-                    Log.d(TAG, "[Send_GetDeviceInfo] The info. of resi. is not set! [primary db]");;
-                }
-                else {
-                    if (info.Support.hOutletCnt > 0) {
-                        boolean concentUse = SetData.Get_MultiSwitch_Concent_Use();
-                        Log.i(TAG, "[Send_GetDeviceInfo] concentUse [" + concentUse + "]");
-                        if (!concentUse) {
-                            SetData.Set_MultiSwitch_Concent_Use(true);
-                            Log.w(TAG, "[Send_GetDeviceInfo] ####### MultiSwitch Concent Use ---> Reboot #######");
-
-                            // 재부팅 설정 - 5초
-                            V40IF mV40IF = new V40IF();
-                            mV40IF.setV40Reboot(5);
-                        }
-                    }
-                }
-                SetData.closeDB();
-            }
-        } catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-        } catch (Exception me) {
-            //me.printStackTrace();
-            LogUtil.errorLogInfo("", TAG, me);
-        }
-
-
-        return info;
-    }
-
-    public boolean isSystemIPSet() {
-        try {
-            Log.i(TAG, "[isSystemIPSet] START!");
-
-            String strResult = "";
-            if (Build.VERSION.SDK_INT > 23) {
-                // Android 7
-                strResult = getIPAddress();
-            }
-            else {
-                // Android 6
-                if(NetworkInterface.getByName("eth0")!=null)
-                {
-                    String strNetInfo = NetworkInterface.getByName("eth0").toString();
-                    Log.i(TAG, "[isSystemIPSet] strNetInfo : " + strNetInfo + "]");
-                    strNetInfo.trim();
-
-                    String[] Parse_01 = strNetInfo.split("\\]");
-//            for (int i = 0; i < Parse_01.length; i++) {
-//                LOG_DEBUG("[getDeviceIPAddress] Parse_01[" + i + "] : " + Parse_01[i]);
-//            }
-
-                    String[] Parse_02 = Parse_01[Parse_01.length - 1].split("\\/");
-//            for (int i = 0; i < Parse_02.length; i++) {
-//                LOG_DEBUG("[getDeviceIPAddress] Parse_02[" + i + "] : " + Parse_02[i]);
-//            }
-
-                    strResult = Parse_02[1];
-                }
-
-            }
-
-            Log.i(TAG, "[isSystemIPSet] DONE! [IP Address : " + strResult + "]");
-
-            Pattern mPattern = Pattern.compile("^(([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.){3}([01]?\\d\\d?|2[0-4]\\d|25[0-5])$");
-
-            return mPattern.matcher(strResult).matches();
-
-        } catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-            return false;
-        }
-        catch (Exception e) {
-            Log.e(TAG, "[Exception] isSystemIPSet()");
-
-            LogUtil.errorLogInfo("", TAG, e);
-            return false;
-        }
-    }
-
-    public static String getIPAddress() {
-        try {
-            List<NetworkInterface> interfaces = Collections.list(NetworkInterface.getNetworkInterfaces());
-            for (NetworkInterface intf : interfaces) {
-                List<InetAddress> addrs = Collections.list(intf.getInetAddresses());
-                for (InetAddress addr : addrs) {
-                    if (!addr.isLoopbackAddress()) {
-                        String sAddr = addr.getHostAddress();
-                        //boolean isIPv4 = InetAddressUtils.isIPv4Address(sAddr);
-                        boolean isIPv4 = sAddr.indexOf(':')<0;
-
-                        if (isIPv4) return sAddr;
-                    }
-                }
-            }
-        } catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-        } catch (Exception e) {
-            Log.e(TAG, "[Exception] isSystemIPSet()");
-
-            LogUtil.errorLogInfo("", TAG, e);
-        }
-        return "";
-    }
-
-    /**
-     * 조명&콘센트 상태 요청/응답
-     *
-     * @param DeviceIdx - (byte) 요청할 기기 인덱스
-     *
-     * @return (MultiSwitch.Device) 기기상태 null - Error , Not null - OK
-     */
-    private MultiSwitch.Device Send_GetLightConcentStatus(byte DeviceIdx) {
-        DeviceLog("[Send_GetLightConcentStatus] Start");
-
-        // 1. In 파라미터 확인
-        if ((DeviceIdx < 0) || (DeviceIdx >= MAX_DEVICE_COUNT)) {
-            Log.w(TAG, "[Send_GetLightConcentStatus] param [DeviceIdx] Out of Range!!! " + DeviceIdx);
-            return null;
-        }
-
-        // 2. 패킷 데이터 만들기
-        byte[] ReqData = null;
-
-        // 3. 데이터 전송 및 응답
-        byte[] Reply = SendNRead_Variable((byte)(DEVICE_ADDRESS + DeviceIdx), CMDList.Req.GetLightConcentStatus, ReqData);
-
-        // 4. 수신데이터 파싱
-        MultiSwitch.Device device = ReplyParsing(Reply);
-        if (device == null) {
-            DeviceLog("[Send_GetLightConcentStatus] Reply is null");
-            AddDoCount(DeviceIdx, false);
-            return null;
-        }
-        AddDoCount(DeviceIdx, true);
-
-        return device;
-    }
-
-    /**
-     * 조명 콘센트 제어 요청/응답
-     *
-     * @param DeviceIdx - (byte) 요청할 기기 인덱스
-     * @param ctrlCmd   - (CtrlCmd) 제어 데이터 클래스
-     *
-     * @return (MultiSwitch.Device) 기기상태 null - Error , Not null - OK
-     */
-    private MultiSwitch.Device Send_SetLightConcentStatus(byte DeviceIdx, CtrlCmd ctrlCmd) {
-        DeviceLog("[Send_SetLightConcentStatus] Start");
-
-        // 1. In 파라미터 확인
-        if ((DeviceIdx < 0) || (DeviceIdx >= MAX_DEVICE_COUNT)) {
-            Log.w(TAG, "[Send_SetLightConcentStatus] param [DeviceIdx] Out of Range!!! " + DeviceIdx);
-            return null;
-        }
-
-        if (ctrlCmd == null) {
-            Log.w(TAG, "[Send_SetLightConcentStatus] param [ctrlCmd] is null !!!");
-            return null;
-        }
-
-        // 2. 패킷 데이터 만들기
-        byte [] ReqData = ctrlCmd.getBytes();
-        if (ReqData == null) {
-            Log.w(TAG, "[Send_SetLightConcentStatus] param [ctrlCmd.getBytes] is null !!!");
-            return null;
-        }
-
-        // 3. 데이터 전송 및 응답
-        byte[] Reply = SendNRead_Variable((byte)(DEVICE_ADDRESS + DeviceIdx), CMDList.Req.SetLightConcentStatus, ReqData);
-
-        // 4. 수신데이터 파싱
-        MultiSwitch.Device device = ReplyParsing(Reply);
-        if (device == null) {
-            DeviceLog("[Send_SetLightConcentStatus] Reply is null");
-            AddDoCount(DeviceIdx, false);
-            return null;
-        }
-        AddDoCount(DeviceIdx, true);
-
-        return device;
-    }
-
-    /**
-     * {@link #Send_GetLightConcentStatus(byte DeviceIdx)} <br>
-     * {@link #Send_SetLightConcentStatus(byte DeviceIdx, CtrlCmd ctrlCmd)} <br>
-     *
-     * 메소드의 응답 공통부분 메소드이다.
-     *
-     * @param Reply      - (byte []) 응답 Byte 배열
-     *
-     * @return (MultiSwitch.Device) 기기상태 null - Error , Not null - OK
-     */
-    private MultiSwitch.Device ReplyParsing(byte [] Reply) {
-        // 1. 수신데이터 파싱
-        //     1.1. Default Check
-        if (Reply == null) {
-            DeviceLog("[ReplyParsing] Reply is null");
-            return null;
-        }
-
-        //     데이터는 최소 4바이트 이상임.
-        if (Reply.length < 4) {
-            Log.w(TAG, "[ReplyParsing] Reply.length  fail #1 ... " + Reply.length);
-            return null;
-        }
-
-        int index = 0;
-        byte data = 0x00;
-        //     1.2. Details Data Check
-        //          - D1 : 설치된 조명 개수
-        data = Reply[index++];
-        if ((data > MAX_LIGHT_COUNT) || (data < 0)) {
-            Log.w(TAG, "[ReplyParsing] D1 (LightCount) : Out Of Range " + ToByteString(data));
-            return null;
-        }
-        byte LightCount = data;
-
-        //          - D2 : 조명 ON/OFF 상태
-        data = Reply[index++];
-
-        //          - D3 : 조명 일괄소등 상태
-        data = Reply[index++];
-        if (!MultiSwitch.BATCHOFF_STATUS.checkRange(data)) {
-            Log.w(TAG, "[ReplyParsing] D3 (BatchOffStatus) : Out Of Range " + ToByteString(data));
-            return null;
-        }
-
-        //          - D4 : 설치된 콘센트 개수
-        data = Reply[index++];
-        if ((data > MAX_OUTLET_COUNT) || (data < 0)) {
-            Log.w(TAG, "[ReplyParsing] D4 (ConcentCount) : Out Of Range " + ToByteString(data));
-            return null;
-        }
-
-        //           - 콘센트 개수에 따른 패킷 데이터 길이 체크
-        byte ConcentCount = data;
-        int CalcLength = (int)((ConcentCount * 5) + 4);
-        if (CalcLength != Reply.length) {
-            Log.w(TAG, "[ReplyParsing] Reply.length  fail #2... (CalcLength:" + CalcLength + ", Reply.length:" + Reply.length + ")");
-            return null;
-        }
-
-        if (ConcentCount > 0) {
-            for (byte i = 0; i < ConcentCount; i++) {
-                data = Reply[index++];
-
-                if (!MultiSwitch.OUTLET_STATUS.checkRange((byte)(data & (BIT0 | BIT1 | BIT2)))) {
-                    Log.w(TAG, "[ReplyParsing] CONCENT_STATUS.CheckRange fail... " + ToByteString(data) + " , i:" + i);
-                    return null;
-                }
-
-                if (!MultiSwitch.OUTLET_MODE.checkRange((byte)((data >> 4) & (BIT0 | BIT1)))) {
-                    Log.w(TAG, "[ReplyParsing] CONCENT_MODE.CheckRange fail... " + ToByteString(data) + " , i:" + i);
-                    return null;
-                }
-                index += 4;
-            }
-        }
-
-        // 2. Data return
-        index = 0;
-        data = 0x00;
-        MultiSwitch.Device device = new MultiSwitch.Device(LightCount, ConcentCount);
-
-        //          - D1 : 설치된 조명 개수
-        index++;
-
-        //          - D2 : 조명 ON/OFF 상태
-        data = Reply[index++];
-        for (byte i = 0; i < LightCount; i++) {
-            if ((data & BIT_ARRAY[i]) != 0x00) device.setLightPower(i, true);
-        }
-
-        //          - D3 : 조명 일괄소등 상태
-        data = Reply[index++];
-        device.hBatchOffStatus = data;
-
-        //          - D4 : 설치된 콘센트 개수
-        index++;
-
-        //          - D5 ~ 콘센트 상태
-        if (ConcentCount > 0) {
-            byte Hi, Low;
-            byte Status;
-            byte Mode;
-            double NowPw;
-            double CutOffVal;
-            for (byte i = 0; i < ConcentCount; i++) {
-                data = Reply[index++];
-
-                Status = (byte)(data & (BIT0 | BIT1 | BIT2));
-                Mode   = (byte)((data >> 4) & (BIT0 | BIT1));
-
-                Hi  = Reply[index++];
-                Low = Reply[index++];
-                NowPw = Converter2ByteToDoubleP1(Hi, Low);
-
-                Hi  = Reply[index++];
-                Low = Reply[index++];
-                CutOffVal = Converter2ByteToDoubleP1(Hi, Low);
-
-                device.setOutlet(i, Status, Mode, NowPw, CutOffVal);
-            }
-        }
-
-        return device;
-    }
-
-    /**
-     * 시간 정보 알림/응답
-     *
-     * @param DeviceIdx - (byte) 시간을 동기화할 기기 인덱스 (시간 정보 사용구분자가 true 인 경우에만 전송)
-     *
-     * @return (MultiSwitch.Device) 기기상태 null - Error , Not null - OK
-     */
-    private MultiSwitch.Device Send_Time(byte DeviceIdx) {
-        DeviceLog("[Send_Time] Start");
-
-        // 1. In 파라미터 확인
-        if ((DeviceIdx < 0) || (DeviceIdx >= MAX_DEVICE_COUNT)) {
-            Log.w(TAG, "[Send_Time] param [DeviceIdx] Out of Range!!! " + DeviceIdx);
-            return null;
-        }
-
-        // 2. 패킷 데이터 만들기
-        byte [] ReqData = new byte[6];
-        Calendar cal = new GregorianCalendar();
-        ReqData[0] = (byte) (cal.get(Calendar.YEAR) - 2000);
-        ReqData[1] = (byte) (cal.get(Calendar.MONTH) + 1);
-        ReqData[2] = (byte) cal.get(Calendar.DAY_OF_MONTH);
-        ReqData[3] = (byte) cal.get(Calendar.HOUR_OF_DAY);
-        ReqData[4] = (byte) cal.get(Calendar.MINUTE);
-        ReqData[5] = (byte) cal.get(Calendar.SECOND);
-
-        // 3. 데이터 전송 및 응답
-        byte [] Reply = SendNRead_Variable( (byte)(DEVICE_ADDRESS + DeviceIdx), CMDList.Req.SetTimeInfo, ReqData);
-
-        // 4. 수신데이터 파싱
-        MultiSwitch.Device device = ReplyParsing(Reply);
-        if (device == null) {
-            DeviceLog("[Send_Time] Reply is null");
-            AddDoCount(DeviceIdx, false);
-            return null;
-        }
-        AddDoCount(DeviceIdx, true);
-
-        return device;
-    }
-
-
-
-
-
-
-    /**
-     * 기기 상태 읽기 요청/응답 V2
-     *
-     * @param DeviceIdx - (byte) 요청할 기기 인덱스
-     *
-     * @return (MultiSwitch.Info) 기기정보 null - Error , Not null - OK
-     */
-    private MultiSwitch.Info sendGetDeviceInfoV2(byte DeviceIdx, MultiSwitch.Info mInfo) {
-        try {
-            DeviceLog("[Send_GetDeviceInfoV2] Start");
-
-            // 1. In 파라미터 확인
-            if ((DeviceIdx < 0) || (DeviceIdx >= MAX_DEVICE_COUNT)) {
-                Log.w(TAG, "[Send_GetDeviceInfoV2] param [DeviceIdx] Out of Range!!! " + DeviceIdx);
-                return null;
-            }
-
-            // 2. 패킷 데이터 만들기
-            byte [] ReqData = null;
-
-            // 3. 데이터 전송 및 응답
-            byte [] Reply = SendNRead_Variable((byte) (DEVICE_ADDRESS + DeviceIdx), CMDList.Req.GetDeviceInfoV2, ReqData);
-
-            // 4. 수신데이터 파싱
-            MultiSwitch.Info info = parsingReply_GetDeviceInfoV2(Reply, mInfo);
-
-            // 5. 수신데이터 파싱결과 확인
-            if (info == null) {
-                DeviceLog("[sendGetDeviceInfoV2] Reply is null");
-                AddDoCount(false);
-                return null;
-            }
-
-            AddDoCount(true);
-
-            // 4. 수신데이터 파싱
-            //     4.1. Default Check
-            if (Reply == null) {
-                DeviceLog("[Send_GetDeviceInfoV2] Reply is null");
-                return null;
-            }
-
-            return info;
-        } catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-            return null;
-        } catch (Exception e) {
-            Log.e(TAG, "[Exception] sendGetDeviceInfoV2()");
-            //e.printStackTrace();
-            LogUtil.errorLogInfo("", TAG, e);
-            return null;
-        }
-    }
-
-    /**
-     * 메소드의 응답 공통부분 메소드이다.
-     *
-     * @param ahReply      - (byte []) 응답 Byte 배열
-     *
-     * @return (Info) null - Error , Not null - OK
-     */
-    private MultiSwitch.Info parsingReply_GetDeviceInfoV2(byte[] ahReply, MultiSwitch.Info mInfo) {
-        try {
-            // 1. 수신데이터 파싱
-            //     1.1. Default Check
-            if (ahReply == null) {
-                DeviceLog("[parsingReply_GetDeviceInfoV2] ahReply is null");
-                return null;
-            }
-
-            MultiSwitch.Info mInfoV2 = new MultiSwitch.Info();
-
-            // 최소 데이터 길이 확인
-            if (ahReply.length < 2) {
-                Log.w(TAG, "[parsingReply_GetDeviceInfoV2] Minimum Reply.length  fail!! (must be longer than 2bytes!! ahReply.length:" + ahReply.length + ")");
-                return null;
-            }
-
-            //     1.2. Details Data Check
-            //         - D1 : 기능 제공 여부 1
-            if ((ahReply[0] & (byte)(BIT2 | BIT3 | BIT4 | BIT5 | BIT6 | BIT7)) != 0x00) {
-                Log.w(TAG, "[parsingReply_GetDeviceInfoV2] D1 (DefultFuncInfo) : Unused Bit Set !!! " + String.format("0x%02X", ahReply[0]));
-                return null;
-            }
-
-            // 조명 디밍 지원
-            if ((ahReply[0] & BIT0) != 0x00) mInfoV2.Support.bDim = true;
-            else mInfoV2.Support.bDim = false;
-
-            // 에어컨 제어
-            if ((ahReply[0] & BIT1) != 0x00) mInfoV2.Support.bAirconCtrl = true;
-            else mInfoV2.Support.bAirconCtrl = false;
-
-            //         - D2 : 기능 제공 여부 2
-            if ((ahReply[1] & (byte)(BIT0 | BIT1 | BIT2 | BIT3 | BIT4 | BIT5 | BIT6 | BIT7)) != 0x00) {
-                Log.w(TAG, "[parsingReply_GetDeviceInfoV2] D2 (DefultFuncInfo) : Unused Bit Set !!! " + String.format("0x%02X", ahReply[1]));
-                return null;
-            }
-
-            /** Data length check */
-            int nExpectLength = 2;   // D1, D2
-            int nAirconCnt = 0;   // 에어컨 제어시 제어 에어컨 개수
-            if (mInfoV2.Support.bDim) nExpectLength += 2;
-            if (mInfoV2.Support.bAirconCtrl) {
-                nAirconCnt = ahReply[nExpectLength];
-                nExpectLength += 1 + nAirconCnt;
-            }
-
-            if (ahReply.length != nExpectLength) {
-                Log.w(TAG, "[parsingReply_GetDeviceInfoV2] Reply.length  fail!! (nExpectLength:" + nExpectLength + ", ahReply.length:" + ahReply.length + ")");
-                return null;
-            }
-
-            // D3
-            int nIndex = 2;
-            byte data;
-            if (mInfoV2.Support.bDim) {
-                data = ahReply[nIndex++];
-                if (data < 0 || 100 < data) {
-                    Log.w(TAG, "[parsingReply_GetDeviceInfoV2] D" + (nIndex - 1) + " (DimLevel) - Out of range!! -> " + String.format("0x%02X", data));
-                    return null;
-                }
-                mInfoV2.Support.hDimLevel = data;
-                data = ahReply[nIndex++];
-                mInfoV2.Support.hDimEnabledCircuit = data;
-            }
-
-            if (mInfoV2.Support.bAirconCtrl) {
-                data = ahReply[nIndex++];
-                if (data < 1 || 15 < data) {
-                    Log.w(TAG, "[parsingReply_GetDeviceInfoV2] D" + (nIndex - 1) + " (AirconCnt) - Out of range!! -> " + String.format("0x%02X", data));
-                    return null;
-                }
-                mInfoV2.Support.hAirconCtrlCnt = data;
-                mInfoV2.Support.hAirconCtrlID = new byte[mInfoV2.Support.hAirconCtrlCnt];
-//                Log.w(TAG, "[parsingReply_GetDeviceInfoV2] mInfoV2.Support.hAirconCtrlCnt -> " + mInfoV2.Support.hAirconCtrlCnt);
-                for (int i = 0; i < mInfoV2.Support.hAirconCtrlCnt; i++) {
-                    data = ahReply[nIndex++];
-                    mInfoV2.Support.hAirconCtrlID[i] = data;
-//                    Log.w(TAG, "[parsingReply_GetDeviceInfoV2] mInfoV2.Support.hAirconCtrlID[" + i + "] = " + mInfoV2.Support.hAirconCtrlID[i]);
-                }
-            }
-
-            mInfo.Support.bDim = mInfoV2.Support.bDim;
-            mInfo.Support.hDimLevel = mInfoV2.Support.hDimLevel;
-            mInfo.Support.hDimEnabledCircuit = mInfoV2.Support.hDimEnabledCircuit;
-            mInfo.Support.bAirconCtrl = mInfoV2.Support.bAirconCtrl;
-            mInfo.Support.hAirconCtrlCnt = mInfoV2.Support.hAirconCtrlCnt;
-            mInfo.Support.hAirconCtrlID = mInfoV2.Support.hAirconCtrlID;
-
-            return mInfo;
-        } catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-            return null;
-        } catch (Exception e) {
-            Log.e(TAG, "[Exception] parsingReply_GetDeviceInfoV2(byte[] ahReply, MultiSwitch.Info mInfo)");
-            //e.printStackTrace();
-            LogUtil.errorLogInfo("", TAG, e);
-            return null;
-        }
-    }
-
-
-
-
-    /**
-     * 조명&콘센트 상태 요청/응답
-     *
-     * @param DeviceIdx - (byte) 요청할 기기 인덱스
-     *
-     * @return (MultiSwitch.Device) 기기상태 null - Error , Not null - OK
-     */
-    private MultiSwitch.Device sendGetDeviceStatusV2(byte DeviceIdx) {
-        try {
-//            DeviceLog("[sendGetDeviceStatusV2] Start DeviceIdx = [" + ToByteString(DeviceIdx) + "]");
-
-            // 1. In 파라미터 확인
-            if ((DeviceIdx < 0) || (DeviceIdx >= MAX_DEVICE_COUNT)) {
-                Log.w(TAG, "[sendGetDeviceStatusV2] param [DeviceIdx] Out of Range!!! " + DeviceIdx);
-                return null;
-            }
-
-            // 2. 패킷 데이터 만들기
-            byte [] ReqData = null;
-            if (mDriver.Device[DeviceIdx].info.Support.bAirconCtrl) {
-                // 2. 패킷 데이터 만들기
-                byte hOption = (byte) 0x00;
-                hOption |= BIT0;
-
-                if (mDriver.Device[DeviceIdx] == null) Log.e(TAG, "[sendGetDeviceStatusV2] mDriver.Device[" + ToByteString(DeviceIdx) + "] is null!!");
-
-                if (mDriver.Device[DeviceIdx].device.airconData == null) {
-                    Log.e(TAG, "[sendGetDeviceStatusV2] mDriver.Device[" + ToByteString(DeviceIdx) + "].device.airconData is null!!");
-                    ReqData = new byte[] {(byte) 0x00};
-                }
-                else {
-//                    Log.e(TAG, "[sendGetDeviceStatusV2] ===== driver aircon start =====");
-//                    Log.i(TAG, mDriver.Device[DeviceIdx].device.airconData.ToDebugString(DeviceIdx));
-//                    Log.e(TAG, "[sendGetDeviceStatusV2] ===== driver aircon end =====");
-
-                    MultiSwitch.Device.AirconData airconData = mDriver.Device[DeviceIdx].device.airconData;
-                    if (airconData == null) Log.e(TAG, "[sendGetDeviceStatusV2] airconData is null!!");
-
-//                    Log.e(TAG, "[sendGetDeviceStatusV2] ===== msg aircon start =====");
-//                    Log.i(TAG, airconData.ToDebugString(DeviceIdx));
-//                    Log.e(TAG, "[sendGetDeviceStatusV2] ===== msg aircon end =====");
-
-                    byte hAirSwing = (byte) 0x00;
-                    if (airconData.bAirSwing) hAirSwing = (byte) 0x01;
-
-                    byte hSetData = (byte) ((int) airconData.hPower + (airconData.hAirVol << 2) + (airconData.hMode << 4) + (hAirSwing << 7));
-
-                    ReqData = new byte[] {hOption, hSetData, airconData.hSetTemper, airconData.hCurrentTemper};
-                }
-            }
-
-            // 3. 데이터 전송 및 응답
-            byte [] Reply = SendNRead_Variable((byte)(DEVICE_ADDRESS + DeviceIdx), CMDList.Req.GetDeviceStatusV2, ReqData);
-
-            // 4. 수신데이터 파싱
-            MultiSwitch.Device device = parsingReply_GetDeviceStatusV2(DeviceIdx, Reply);
-            if (device == null) {
-                DeviceLog("[sendGetDeviceStatusV2] Reply is null");
-                AddDoCount(DeviceIdx, false);
-                return null;
-            }
-            AddDoCount(DeviceIdx, true);
-
-            return device;
-        } catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-            return null;
-        } catch (Exception e) {
-            Log.e(TAG, "[Exception] sendGetDeviceStatusV2(byte DeviceIdx)");
-            //e.printStackTrace();
-            LogUtil.errorLogInfo("", TAG, e);
-            return null;
-        }
-    }
-
-    /**
-     * {@link #Send_GetLightConcentStatus(byte DeviceIdx)} <br>
-     * {@link #Send_SetLightConcentStatus(byte DeviceIdx, CtrlCmd ctrlCmd)} <br>
-     *
-     * 메소드의 응답 공통부분 메소드이다.
-     *
-     * @param Reply      - (byte []) 응답 Byte 배열
-     *
-     * @return (MultiSwitch.Device) 기기상태 null - Error , Not null - OK
-     */
-    private MultiSwitch.Device parsingReply_GetDeviceStatusV2(byte DeviceIdx, byte[] Reply) {
-        try {
-            // 1. 수신데이터 파싱
-            //     1.1. Default Check
-            if (Reply == null) {
-                DeviceLog("[parsingReply_GetDeviceStatusV2] Reply is null");
-                return null;
-            }
-
-            //     데이터는 최소 4바이트 이상임.
-            if (Reply.length < 4) {
-                Log.w(TAG, "[parsingReply_GetDeviceStatusV2] Reply.length fail #1, Must be longer than 4bytes -> Received length: " + Reply.length);
-                return null;
-            }
-
-            int index = 0;
-            byte data = 0x00;
-            //     1.2. Details Data Check
-            //          - D1 : 설치된 조명 개수
-            data = Reply[index++];
-            if ((data > MAX_LIGHT_COUNT) || (data < 0)) {
-                Log.w(TAG, "[parsingReply_GetDeviceStatusV2] D1 (LightCount) : Out Of Range " + ToByteString(data));
-                return null;
-            }
-            byte LightCount = data;
-
-            //          - D2 : 조명 ON/OFF 상태
-            data = Reply[index++];
-
-            //          - D3 : 조명 일괄소등 상태
-            data = Reply[index++];
-            if (!MultiSwitch.BATCHOFF_STATUS.checkRange(data)) {
-                Log.w(TAG, "[parsingReply_GetDeviceStatusV2] D3 (BatchOffStatus) : Out Of Range " + ToByteString(data));
-                return null;
-            }
-
-            //          - Dn : 설치된 콘센트 개수
-            data = Reply[index++];
-            if ((data > MAX_OUTLET_COUNT) || (data < 0)) {
-                Log.w(TAG, "[parsingReply_GetDeviceStatusV2] D4 (OutletCount) : Out Of Range " + ToByteString(data));
-                return null;
-            }
-
-            //           - 콘센트 개수에 따른 패킷 데이터 길이 체크
-            byte OutletCount = data;
-            if (OutletCount > 0) {
-                for (byte i = 0; i < OutletCount; i++) {
-                    data = Reply[index++];
-
-                    if (!MultiSwitch.OUTLET_STATUS.checkRange((byte)(data & (BIT0 | BIT1 | BIT2)))) {
-                        Log.w(TAG, "[parsingReply_GetDeviceStatusV2] CONCENT_STATUS.CheckRange fail... " + ToByteString(data) + " , i:" + i);
-                        return null;
-                    }
-
-                    if (!MultiSwitch.OUTLET_STATUS.checkRange((byte)((data >> 4) & (BIT0 | BIT1)))) {
-                        Log.w(TAG, "[parsingReply_GetDeviceStatusV2] CONCENT_MODE.CheckRange fail... " + ToByteString(data) + " , i:" + i);
-                        return null;
-                    }
-                    index += 4;
-                }
-            }
-
-            // 디밍/에어컨 제어에 따른 데이터 길이 확인
-            int nDimCnt = 0;   // 디밍 조명 개수
-            if (mDriver.Device[DeviceIdx].info.Support.bDim) {
-                /** 디밍 지원 */
-                //          - Dn : 조명 디밍 지원 회로 정보
-                data = Reply[index++];
-                if (data == (byte) 0x00) {
-                    Log.w(TAG, "[parsingReply_GetDeviceStatusV2] D4 (nDimCnt) : Out Of Range " + ToByteString(data));
-                    return null;
-                }
-
-                nDimCnt = Integer.bitCount(data);
-
-                // 디밍 설정 단계
-                for (int i = 0; i < nDimCnt; i++) {
-                    data = Reply[index++];
-                    if (data < 0 && mDriver.Device[DeviceIdx].info.Support.hDimLevel < data) {
-                        Log.w(TAG, "[parsingReply_GetDeviceStatusV2] D4 (hDimLevel[" + i + "]) : Out Of Range: " + ToByteString(data) + ", Enabled dim level: " + mDriver.Device[DeviceIdx].info.Support.hDimLevel);
-                        return null;
-                    }
-                }
-            }
-
-            int nAirconDataLength = 0;
-            if (mDriver.Device[DeviceIdx].info.Support.bAirconCtrl) {
-                /** 에어컨 제어 지원 */
-                //          - Dn : 제어요청 기기 종류
-                data = Reply[index++];
-                if ((data & (byte)(BIT1 | BIT2 | BIT3 | BIT4 | BIT5 | BIT6 | BIT7)) != 0x00) {
-                    Log.w(TAG, "[parsingReply_GetDeviceStatusV2] D" + (index - 1) + " (Ctrl Type) : Unused Bit Set !!! " + String.format("0x%02X", data));
-                    return null;
-                }
-
-                if ((data & (byte)BIT0) != 0x00) {
-                    // 에어컨 제어 요청 있음
-                    // 에어컨 제어 개수 확인
-                    int nAirconIDsCnt = 0;
-                    // 제어 에어컨 ID 1
-                    data = Reply[index++];
-                    nAirconIDsCnt = Integer.bitCount(data);
-                    // 제어 에어컨 ID 2
-                    data = Reply[index++];
-                    nAirconIDsCnt += Integer.bitCount(data);
-                    // 개별 실내기 제어 선택 정보
-                    data = Reply[index++];
-                    if ((data & (byte)(BIT5 | BIT6 | BIT7)) != 0x00) {
-                        Log.w(TAG, "[parsingReply_GetDeviceStatusV2] D" + (index - 1) + " (Ctrl Type) : Unused Bit Set !!! " + String.format("0x%02X", data));
-                        return null;
-                    }
-
-                    // 에어컨 상태 제어
-                    //      1.2. Mode
-                    data = Reply[index++];
-
-                    byte hPower = (byte)(data & (byte) (BIT0 | BIT1));
-                    if (!DataClasses.SystemAircon.POWER.checkPowerRange(hPower)) {
-                        // on/off 상태 확인
-                        Log.w(TAG, "[parsingReply_GetDeviceStatusV2] (hPower) : Out of Range !!! -> " + String.format("0x%02X", hPower));
-                        return null;
-                    }
-
-                    byte hAirVol = (byte)((data >> 2) & (byte) (BIT0 | BIT1));
-                    if (!DataClasses.SystemAircon.AIRVOLUME.checkAirVolRange(hAirVol)) {
-                        // 풍량 범위확인
-                        Log.w(TAG, "[parsingReply_GetDeviceStatusV2] (hAirVol) : Out of Range !!! -> " + String.format("0x%02X", hAirVol));
-                        return null;
-                    }
-
-                    byte hMode = (byte)((data >> 4) & (byte) (BIT0 | BIT1 | BIT2));
-                    if (!DataClasses.SystemAircon.MODE.checkModeRange(hMode)) {
-                        // 운전모드 범위확인
-                        Log.w(TAG, "[parsingReply_GetDeviceStatusV2] (hMode) : Out of Range !!! -> " + String.format("0x%02X", hMode));
-                        return null;
-                    }
-
-                    //     1.4.1 check supported mode
-//                    if (!checkSupportedMode(hMode, DeviceIdx)) {
-//                        Log.w(TAG, "[parsingReply_GetDeviceStatusV2] (hMode) Not support !!! -> " + DataClasses.SystemAircon.MODE.ToDebugString(hMode));
-//                        return null;
-//                    }
-
-                    boolean bAirSwing = false;
-                    if ((data & BIT7) != 0x00) {
-                        // 풍향지원 여부 확인
-                        if (!mDriver.Device[DeviceIdx].device.airconData.bSupportAirSwing) {
-                            Log.w(TAG, "[parsingReply_GetDeviceStatusV2] (bAirSwing) : Out of Range !!! -> " + bAirSwing);
-                            return null;
-                        }
-                        bAirSwing = true;
-                    }
-                    else bAirSwing = false;
-                    
-                    data = Reply[index++];
-
-                    if (data != 0x00) {
-                        if (hMode == DataClasses.SystemAircon.MODE.Cooling) {
-                            if (data < mDriver.Device[DeviceIdx].device.airconData.hMinCoolSetTemper || mDriver.Device[DeviceIdx].device.airconData.hMaxCoolSetTemper < data) {
-                                Log.w(TAG, "[parsingReply_GetDeviceStatusV2] MODE.Cold -> hMinCoolSetTemper [" + mDriver.Device[DeviceIdx].device.airconData.hMinCoolSetTemper + "], hMaxCoolSetTemper [" + mDriver.Device[DeviceIdx].device.airconData.hMaxCoolSetTemper + "], hSetTemper Out Of Range !!! - (" + String.format("0x%02X", data) + ")");
-                                return null;
-                            }
-                        }
-                        else if (hMode == DataClasses.SystemAircon.MODE.Heating) {
-                            if (data < mDriver.Device[DeviceIdx].device.airconData.hMinHeatSetTemper || mDriver.Device[DeviceIdx].device.airconData.hMaxHeatSetTemper < data) {
-                                Log.w(TAG, "[parsingReply_GetDeviceStatusV2] MODE.Cold -> hMinHeatSetTemper [" + mDriver.Device[DeviceIdx].device.airconData.hMinHeatSetTemper + "], hMaxHeatSetTemper [" + mDriver.Device[DeviceIdx].device.airconData.hMaxHeatSetTemper + "], hSetTemper Out Of Range !!! - (" + String.format("0x%02X", data) + ")");
-                                return null;
-                            }
-                        }
-                    }
-
-                    if ((data & (byte)BIT0) != 0x00) nAirconDataLength = 5;
-                }
-                else {
-                    // 에어컨 제어 요청 없음
-                    nAirconDataLength = 1;
-                }
-
-            }
-
-            int nOutletDataLength = (int) (OutletCount * 5);
-            int nDimDataLength = (nDimCnt > 0) ? nDimCnt + 1 : 0;
-            int nExpectedLength = 4 + nOutletDataLength + nDimDataLength + nAirconDataLength;
-//            if (nExpectedLength != Reply.length) {
-//                Log.w(TAG, "[parsingReply_GetDeviceStatusV2] Reply.length fail #2 (nExpectedLength:" + nExpectedLength + ", Reply.length:" + Reply.length + ")");
-//                Log.w(TAG, "[parsingReply_GetDeviceStatusV2] nOutletDataLength [" + nOutletDataLength + "], nDimDataLength [" + nDimDataLength + "], nAirconDataLength [" + nAirconDataLength + "]");
-//                return null;
-//            }
-
-            // 2. Data return
-            index = 0;
-            data = 0x00;
-//            Log.w(TAG, "[parsingReply_GetDeviceStatusV2] LightCount [" + LightCount + "], OutletCount [" + OutletCount + "]");
-            MultiSwitch.Device device = new MultiSwitch.Device(LightCount, OutletCount);
-
-//            Log.w(TAG, "[parsingReply_GetDeviceStatusV2] new hLightCnt [" + device.hLightCnt + "], hOutletCnt [" + device.hOutletCnt + "]");
-            //          - D1 : 설치된 조명 개수
-            index++;
-
-            //          - D2 : 조명 ON/OFF 상태
-            data = Reply[index++];
-            for (byte i = 0; i < LightCount; i++) {
-                if ((data & BIT_ARRAY[i]) != 0x00) device.setLightPower(i, true);
-            }
-
-            //          - D3 : 조명 일괄소등 상태
-            data = Reply[index++];
-            device.hBatchOffStatus = data;
-
-            //          - D4 : 설치된 콘센트 개수
-            index++;
-
-            //          - D5 ~ 콘센트 상태
-            if (OutletCount > 0) {
-                byte Hi, Low;
-                byte Status;
-                byte Mode;
-                double NowPw;
-                double CutOffVal;
-                for (byte i = 0; i < OutletCount; i++) {
-                    data = Reply[index++];
-
-                    Status = (byte)(data & (BIT0 | BIT1 | BIT2));
-                    Mode   = (byte)((data >> 4) & (BIT0 | BIT1));
-
-                    Hi  = Reply[index++];
-                    Low = Reply[index++];
-                    NowPw = Converter2ByteToDoubleP1(Hi, Low);
-
-                    Hi  = Reply[index++];
-                    Low = Reply[index++];
-                    CutOffVal = Converter2ByteToDoubleP1(Hi, Low);
-
-                    device.setOutlet(i, Status, Mode, NowPw, CutOffVal);
-                }
-            }
-
-            // 조명 디밍 정보
-            if (mDriver.Device[DeviceIdx].info.Support.bDim) {
-                data = Reply[index++];
-                for (byte i = 0; i < LightCount; i++) {
-                    if ((data & BIT_ARRAY[i]) != 0x00) device.setLightDimUsage(i, true);
-                }
-
-                for (int i = 0; i < device.hLightCnt; i++) {
-                    if (device.getLightDimUsage(i)) device.setLightDimLevel(i, Reply[index++]);
-                }
-            }
-
-            if (mDriver.Device[DeviceIdx].info.Support.bAirconCtrl) {
-                device.ctrlReq = new MultiSwitch.Device.CtrlReq((byte) 16);   // 에어컨 ID 필드 -> 추후 확인
-            }
-
-            // 에어컨 제어 정보
-            if (mDriver.Device[DeviceIdx].info.Support.bAirconCtrl) {
-                device.airconData = new MultiSwitch.Device.AirconData(mDriver.Device[DeviceIdx].info.Support.hAirconCtrlCnt);
-                byte hCtrlReq = Reply[index++];
-                if ((hCtrlReq & (byte)BIT0) != 0x00) {
-                    device.ctrlReq.bAircon = true;
-
-                    index++;   // 에어컨 ID 필드(2Bytes) > 추후 확인
-                    index++;   // 에어컨 ID 필드(2Bytes) > 추후 확인
-                    
-                    data = Reply[index++];
-                    device.ctrlReq.hAirconCtrlOption = data;
-
-                    data = Reply[index++];
-                    device.ctrlReq.hAirconStatus = data;
-
-                    data = Reply[index++];
-                    device.ctrlReq.hSetTemper = data;
-                }
-                else {
-                    device.ctrlReq.bAircon = false;
-                }
-            }
-
-            // 에어컨 데이터를 넣어준다.
-            if (mDriver.Device[DeviceIdx].info.Support.bAirconCtrl) device.airconData.setAirconStatus(mDriver.Device[DeviceIdx].device.airconData);
-            else device.ctrlReq = new MultiSwitch.Device.CtrlReq((byte) 0x00);
-
-            return device;
-        } catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-            return null;
-        } catch (Exception e) {
-            Log.e(TAG, "[Exception] parsingReply_GetDeviceStatusV2(byte[] Reply)");
-            //e.printStackTrace();
-            LogUtil.errorLogInfo("", TAG, e);
-            return null;
-        }
-    }
-
-    /**
-     * 제어할 운전모드 지원여부 확인
-     * @param hMode
-     * @return true: 지원함, false: 지원안함
-     */
-    private boolean checkSupportedMode(byte hMode, byte DeviceIdx) {
-        try {
-            if (hMode == DataClasses.SystemAircon.MODE.Cooling && mDriver.Device[DeviceIdx].device.airconData.bSupportModeCooling) return true;
-            else if (hMode == DataClasses.SystemAircon.MODE.Dehumidify && mDriver.Device[DeviceIdx].device.airconData.bSupportModeDehumidify) return true;
-            else if (hMode == DataClasses.SystemAircon.MODE.Fan && mDriver.Device[DeviceIdx].device.airconData.bSupportModeFan) return true;
-            else if (hMode == DataClasses.SystemAircon.MODE.Heating && mDriver.Device[DeviceIdx].device.airconData.bSupportModeHeating) return true;
-            else if (hMode == DataClasses.SystemAircon.MODE.Auto) return true;   // 자동모드는 확인하지 않는다. (자동모드 값이 0인데, 사용하지 않을때도 0으로 보내므로 확인하면 안됨 (jeff, 2020.10.20)
-            else return false;
-        } catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-            return false;
-        } catch (Exception e) {
-            Log.e(TAG, "[Exception] checkSupportedMode(byte hMode, byte DeviceIdx)");
-            //e.printStackTrace();
-            LogUtil.errorLogInfo("", TAG, e);
-            return false;
-        }
-    }
-
-    /**
-     * 조명&콘센트 상태 요청/응답
-     *
-     * @param DeviceIdx - (byte) 요청할 기기 인덱스
-     *
-     * @return (MultiSwitch.Device) 기기상태 null - Error , Not null - OK
-     */
-    private MultiSwitch.Device sendCtrlReqACKV2(byte DeviceIdx, byte hCtrlType) {
-        try {
-            DeviceLog("[sendCtrlReqACKV2] Start");
-
-            // 1. In 파라미터 확인
-            if ((DeviceIdx < 0) || (DeviceIdx >= MAX_DEVICE_COUNT)) {
-                Log.w(TAG, "[sendCtrlReqACKV2] param [DeviceIdx] Out of Range!!! " + DeviceIdx);
-                return null;
-            }
-
-            // 2. 패킷 데이터 만들기
-            byte[] ReqData = { (byte)Integer.bitCount(hCtrlType), hCtrlType };
-
-            // 3. 데이터 전송 및 응답
-            byte[] Reply = SendNRead_Variable((byte)(DEVICE_ADDRESS + DeviceIdx), CMDList.Req.ACK_StatusV2, ReqData);
-
-            // 4. 수신데이터 파싱
-            MultiSwitch.Device device = parsingReply_GetDeviceStatusV2(DeviceIdx, Reply);
-            if (device == null) {
-                DeviceLog("[sendGetDeviceStatusV2] Reply is null");
-                AddDoCount(DeviceIdx, false);
-                return null;
-            }
-            AddDoCount(DeviceIdx, true);
-
-            return device;
-        } catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-            return null;
-        } catch (Exception e) {
-            Log.e(TAG, "[Exception] sendCtrlReqACKV2(byte DeviceIdx, byte hCtrlType)");
-            //e.printStackTrace();
-            LogUtil.errorLogInfo("", TAG, e);
-            return null;
-        }
-    }
-
-    /**
-     * 조명 콘센트 제어 요청/응답
-     *
-     * @param DeviceIdx - (byte) 요청할 기기 인덱스
-     * @param ctrlCmd   - (CtrlCmd) 제어 데이터 클래스
-     *
-     * @return (MultiSwitch.Device) 기기상태 null - Error , Not null - OK
-     */
-    private MultiSwitch.Device sendSetLightConcentStatusV2(byte DeviceIdx, CtrlCmd ctrlCmd) {
-        DeviceLog("[sendSetLightConcentStatusV2] Start");
-
-        // 1. In 파라미터 확인
-        if ((DeviceIdx < 0) || (DeviceIdx >= MAX_DEVICE_COUNT)) {
-            Log.w(TAG, "[sendSetLightConcentStatusV2] param [DeviceIdx] Out of Range!!! " + DeviceIdx);
-            return null;
-        }
-
-        if (ctrlCmd == null) {
-            Log.w(TAG, "[sendSetLightConcentStatusV2] param [ctrlCmd] is null !!!");
-            return null;
-        }
-
-        // 2. 패킷 데이터 만들기
-        byte [] ReqData = ctrlCmd.getBytes();
-        if (ReqData == null) {
-            Log.w(TAG, "[sendSetLightConcentStatusV2] param [ctrlCmd.getBytes] is null !!!");
-            return null;
-        }
-
-        // 3. 데이터 전송 및 응답
-        byte[] Reply = SendNRead_Variable((byte)(DEVICE_ADDRESS + DeviceIdx), CMDList.Req.SetDeviceStatusV2, ReqData);
-
-        // 4. 수신데이터 파싱
-        MultiSwitch.Device device = parsingReply_GetDeviceStatusV2(DeviceIdx, Reply);
-        if (device == null) {
-            DeviceLog("[sendSetLightConcentStatusV2] Reply is null");
-            AddDoCount(DeviceIdx, false);
-            return null;
-        }
-        AddDoCount(DeviceIdx, true);
-
-        return device;
-    }
-
-    ///////////////////////////////////////////////////////////////////////////////////////////////
-    // CMDList
-    ///////////////////////////////////////////////////////////////////////////////////////////////
-    /**
-     * 명령어 리스트
-     */
-    public static class CMDList {
-        public static final class Req {
-            /////////////////////////////////////////////////////////
-            // Board
-            /////////////////////////////////////////////////////////
-            /** 기기 정보 요청 */
-            public final static byte GetDeviceInfo              = 0x01;
-
-            /////////////////////////////////////////////////////////
-            // 상태
-            /////////////////////////////////////////////////////////
-            /** 조명 콘센트 상태 요청 */
-            public final static byte GetLightConcentStatus      = 0x11;
-
-            /////////////////////////////////////////////////////////
-            // 제어
-            /////////////////////////////////////////////////////////
-            /** 조명 콘센트 제어 요청 */
-            public final static byte SetLightConcentStatus      = 0x12;
-
-            /////////////////////////////////////////////////////////
-            // 시간정보 알림
-            /////////////////////////////////////////////////////////
-            /** 시간정보 알림 */
-            public final static byte SetTimeInfo                = 0x21;
-
-            /////////////////////////////////////////////////////////
-            // V2 CMD
-            /////////////////////////////////////////////////////////
-            /** 기기 정보 요청 V2 */
-            public final static byte GetDeviceInfoV2                = 0x31;
-
-            /** 기기 상태 요청 V2 */
-            public final static byte GetDeviceStatusV2                = 0x32;
-
-            /** 기기 제어 요청 수신 알림 V2 */
-            public final static byte ACK_StatusV2                = 0x33;
-
-            /** 기기 제어 요청 V2 */
-            public final static byte SetDeviceStatusV2                = 0x34;
-
-        }
-    }
-
-    ///////////////////////////////////////////////////////////////////////////////////////////////
-    // UpdateVariables
-    ///////////////////////////////////////////////////////////////////////////////////////////////
-    /**
-     * 데이터를 업데이트 한다.
-     *
-     * @param DeviceIdx - (byte) 업데이트할 디바이스 인덱스
-     * @param device    - (MultiSwitch.Device) 업데이트할 디바이스 데이터
-     * @param bNotify - (boolean) 알림 업데이트 (true:무조건 변경 알림, false:변경여부에 따라 알림)
-     *
-     * @return (boolean) 데이터 변경여부 (true:변경 , false:미변경)
-     */
-    private boolean UpdateVariables(byte DeviceIdx, MultiSwitch.Device device, boolean bNotify) {
-        // 1. Param Range Check
-        if (DeviceIdx < 0) return false;
-        if (DeviceIdx >= mDriver.Polling.SearchDeviceCount) return false;
-        if (mDriver.Device[DeviceIdx].device == null) return false;
-
-        // 2. Check
-        boolean bChanged = false;
-        MultiSwitch.Device OldDevice = mDriver.Device[DeviceIdx].device;
-
-        while (true) {
-            // LightCount
-            if (OldDevice.hLightCnt != device.hLightCnt) {
-                Log.w(TAG, "[UpdateVariables] Device Change !!! LightCount Difference !!!");
-                mDriver.Device[DeviceIdx].info.Install = false;
-                bChanged = true;
-                break;
-            }
-
-            // ConcentCount
-            if (OldDevice.hOutletCnt != device.hOutletCnt) {
-                Log.w(TAG, "[UpdateVariables] Device Change !!! ConcentCount Difference !!!");
-                mDriver.Device[DeviceIdx].info.Install = false;
-                bChanged = true;
-                break;
-            }
-
-            // LightOnOff
-            for (byte i = 0; i < OldDevice.hLightCnt; i++) {
-                if (OldDevice.getLightPower(i) != device.getLightPower(i)) { bChanged = true; break; }
-                if (OldDevice.getLightDimLevel(i) != device.getLightDimLevel(i)) { bChanged = true; break; }
-                if (OldDevice.getLightDimUsage(i) != device.getLightDimUsage(i)) { bChanged = true; break; }
-            }
-
-            if (bChanged) break;
-
-            // BatchOffStatus
-            if (OldDevice.hBatchOffStatus != device.hBatchOffStatus) { bChanged = true; break; }
-
-            // Concent
-            MultiSwitch.Device.Outlet oldOutlet;
-            MultiSwitch.Device.Outlet newOutlet;
-            for (byte i = 0; i < OldDevice.hOutletCnt; i++) {
-                oldOutlet = OldDevice.getOutletStatus(i);
-                newOutlet = device.getOutletStatus(i);
-                if (oldOutlet == null || newOutlet == null) continue;
-
-                if (oldOutlet.Status != newOutlet.Status) { bChanged = true; break; }
-                if (oldOutlet.Mode != newOutlet.Mode) { bChanged = true; break; }
-                if (oldOutlet.NowPw != newOutlet.NowPw) { bChanged = true; break; }
-                if (oldOutlet.CutOffVal != newOutlet.CutOffVal) { bChanged = true; break; }
-            }
-
-            if (bChanged) break;
-
-            break;
-        }
-
-        if (bChanged || bNotify) {
-            mDriver.Device[DeviceIdx].device = device;
-            StatusChanged(DeviceIdx);
-
-            DeviceLog("UpdateVariables !!!! ***************************************");
-            DeviceLog(device.ToDebugString(DeviceIdx));
-            return true;
-        }
-
-        return false;
-    }
-}
+/*
+ * Copyright (C) 2015 Android WallPad Project
+ *
+ * FileName  : MultiSwitch_Controller.java
+ * Project   : Android WallPad Project
+ * Company   : HDC I-CONTROLS ( www.icontrols.co.kr )
+ * Author    : Kang Sang Ho  , lairu@icontrols.co.kr
+ */
+
+package com.artncore.wallpaddevservice.driver;
+
+import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.GregorianCalendar;
+import java.util.List;
+import java.util.regex.Pattern;
+
+import android.annotation.SuppressLint;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Build;
+import android.util.Log;
+
+import com.artncore.WallPadDataMgr.WallpadStatusData;
+import com.artncore.WallPadDataMgr.wallpaddbmgr;
+import com.artncore.commons.APIErrorCode;
+import com.artncore.commons.DataClasses;
+import com.artncore.commons.DataClasses.MultiSwitch;
+import com.artncore.commons.define;
+import com.util.LogUtil;
+import com.artncore.wallpaddevservice.ServiceMain;
+
+import kr.co.icontrols.v40ioctl.V40IF;
+import kr.co.icontrols.wallpadsupport.Version;
+
+
+/**
+ * 멀티스위치 의 드라이버 모듈이다.
+ */
+@SuppressLint("HandlerLeak")
+public class MultiSwitch_Controller extends DeviceManager {
+    private final static String TAG = "MultiSwitch_Controller";
+
+    private final byte DEVICE_ADDRESS  = (byte) 0x51;
+
+    /** 최대 기기 개수 */
+    private final byte MAX_DEVICE_COUNT      = 8;
+
+    /** 최대 조명 개수 */
+    private final byte MAX_LIGHT_COUNT       = 8;
+
+    /** 최대 콘센트 개수 */
+    private final byte MAX_OUTLET_COUNT = 8;
+
+    /** 초기 기기 검색 횟수  */
+    private final int MAX_SEARCH_COUNT   = 3;
+
+    /** 시간 동기화 간격(분) */
+    private final long STATUS_SYNC_TICK   = (long)(10 * TIME_MINUTE);
+
+    /**
+     * 조명 ON/OFF 상태를 반환한다.
+     *
+     * @param Index    - (byte) 기기인덱스 (0~7)
+     * @param LightIdx - (byte) 조명인덱스 (0~7)
+     *
+     * @return (boolean) true:ON , false:OFF
+     */
+    public boolean getLightPower(byte Index, byte LightIdx) {
+        if (!DeviceIndexRangeCheck(Index)) return false;
+        try {
+            if (mDriver.Device[Index].device == null) return false;
+            if ((LightIdx < 0) || (LightIdx >= mDriver.Device[Index].device.hLightCnt)) return false;
+            return mDriver.Device[Index].device.getLightPower(LightIdx);
+        } catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+            return false;
+        } catch (Exception e) {
+            Log.e(TAG, "[Exception Error] getLightPower");
+            LogUtil.errorLogInfo("", TAG, e);//e.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+     * 조명 개수를 반환한다.
+     *
+     * @param Index - (byte) 기기인덱스 (0~7)
+     *
+     * @return (byte) 조명 개수
+     */
+    public byte getLightCnt(byte Index) {
+        if (!DeviceIndexRangeCheck(Index)) return 0x00;
+        try {
+            if (mDriver.Device[Index].device == null) return 0x00;
+            return mDriver.Device[Index].info.Support.hLightCnt;
+        } catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+            return 0x00;
+        } catch (Exception e) {
+            Log.e(TAG, "[Exception Error] getLightCnt");
+            LogUtil.errorLogInfo("", TAG, e);//e.printStackTrace();
+            return 0x00;
+        }
+    }
+
+    /** 멀티스위치 조명&콘센트 제어용 클래스 */
+    public class CtrlCmd {
+        public class Light {
+            public boolean OnOff;
+            public boolean Dim;
+            public byte DimLevel;
+            public byte Pattern;
+            private byte BatchOff;
+            public Light() {
+                OnOff = false;
+                Dim = false;
+                DimLevel = 0x00;
+                Pattern = 0x00;
+                BatchOff = 0x00;
+            }
+
+            public boolean setBatchOff(byte nBatchOff) {
+                if ((nBatchOff != 0x00) && (nBatchOff != MultiSwitch.BATCHOFF_STATUS.Set) && (nBatchOff != MultiSwitch.BATCHOFF_STATUS.Clr)) {
+                    Log.w(TAG, "[ControlCommand->Light->setBatchOff] Param Out Of Range " + String.format("%02X", nBatchOff));
+                    return false;
+                }
+                BatchOff = nBatchOff;
+                return true;
+            }
+
+            public byte [] getBytes() {
+                byte [] retBytes = new byte [3];
+                int index = 0;
+
+                byte ctrlOption = 0x00;
+                if (OnOff) ctrlOption |= BIT0;
+                if (Dim) ctrlOption |= BIT1;
+                Log.e(TAG, "[ControlCommand->Light] ctrlOption: " + String.format("%02X", ctrlOption));
+                retBytes[index++] = ctrlOption;
+                retBytes[index++] = Pattern;
+                retBytes[index++] = BatchOff;
+
+                return retBytes;
+            }
+        }
+
+        public class Outlet {
+            public class unitOutlet {
+                private byte OnOff;
+                private byte Mode;
+                public boolean CutOff;
+
+                public unitOutlet() {
+                    OnOff = 0x00;
+                    Mode  = 0x00;
+                    CutOff = false;
+                }
+
+                public boolean setOnOff (byte nOnOff) {
+                    if ((nOnOff != 0x00) && (nOnOff != MultiSwitch.OUTLET_STATUS.On) && (nOnOff != MultiSwitch.OUTLET_STATUS.Off)) {
+                        Log.w(TAG, "[ControlCommand->Concent->Con->setOnOff] Param Out Of Range " + String.format("%02X", nOnOff));
+                        return false;
+                    }
+                    OnOff = nOnOff;
+                    return true;
+                }
+
+                public boolean setMode (byte nMode) {
+                    if ((nMode != 0x00) && (nMode != MultiSwitch.OUTLET_MODE.Auto) && (nMode != MultiSwitch.OUTLET_MODE.Always)){
+                        Log.w(TAG, "[ControlCommand->Concent->Con->setMode] Param Out Of Range " + String.format("%02X", nMode));
+                        return false;
+                    }
+                    Mode = nMode;
+                    return true;
+                }
+
+                public byte getByte() {
+                    byte retByte = 0x00;
+
+                    retByte |= (byte)(OnOff & (BIT0 | BIT1));
+                    retByte |= (byte)((Mode << 4) & (BIT4 | BIT5));
+                    if (CutOff) retByte |= BIT6;
+
+                    return retByte;
+                }
+            }
+
+            public byte Count;
+            public unitOutlet[] unitOutlet;
+
+            public Outlet() {
+                Count = 0;
+                unitOutlet = null;
+            }
+
+            public boolean setCount(byte nCount){
+                if (nCount < 0) return false;
+
+                Count = nCount;
+                unitOutlet = new unitOutlet[nCount];
+                for (byte i = 0; i < nCount; i++) unitOutlet[i] = new unitOutlet();
+
+                return true;
+            }
+
+            public boolean setCon(int index, byte nOnOff, byte nMode, boolean nCutOff) {
+                if (unitOutlet == null) return false;
+                if (unitOutlet.length <= index) return false;
+
+                if (!unitOutlet[index].setOnOff(nOnOff)) return false;
+                if (!unitOutlet[index].setMode(nMode)) return false;
+                unitOutlet[index].CutOff = nCutOff;
+
+                return true;
+            }
+
+            public byte [] getBytes() {
+                if (Count <= 0) return new byte [] { 0x00 };
+                try {
+                    byte ContCount = 0;
+                    for (byte i = 0; i < Count; i++) {
+                        if (unitOutlet[i].getByte() != 0x00) ContCount++;
+                    }
+                    
+                    if (ContCount == 0) return new byte[] { 0x00 };
+
+                    byte[] retBytes = new byte [1 + (ContCount*2)];
+                    int index = 0;
+                    retBytes[index++] = ContCount;
+                    for (byte i = 0; i < Count; i++) {
+                        if (unitOutlet[i].getByte() != 0x00) {
+                            retBytes[index++] = (byte)(i+1);
+                            retBytes[index++] = unitOutlet[i].getByte();
+                        }
+                    }
+                    return retBytes;
+                } catch (RuntimeException re) {
+                    LogUtil.errorLogInfo("", TAG, re);
+                    return new byte [] { 0x00 };
+                } catch (Exception e) {
+                    Log.e(TAG, "[Exception Error] CtrlCmd -> Concent -> getBytes");
+                    LogUtil.errorLogInfo("", TAG, e);//e.printStackTrace();
+                    return new byte [] { 0x00 };
+                }
+            }
+        }
+
+        public Light light;
+        public Outlet outlet;
+
+        public CtrlCmd() {
+            light = new Light();
+            outlet = new Outlet();
+        }
+
+        public byte [] getBytes() {
+            byte[] lightBytes = light.getBytes();
+            byte[] concentBytes = outlet.getBytes();
+
+            if ((lightBytes == null) || (concentBytes == null)) {
+                Log.w(TAG, "[ControlCommand] getBytes - lightBytes or concentBytes  is null !!!");
+                return null;
+            }
+
+            byte [] retBytes = new byte [lightBytes.length + concentBytes.length + (light.Dim ? 1 : 0)];
+            Log.w(TAG, "[ControlCommand] getBytes - retBytes.length: " + retBytes.length);
+            int index = 0;
+            int i = 0;
+            for (i = 0; i < lightBytes.length; i++) retBytes[index++] = lightBytes[i];
+            for (i = 0; i < concentBytes.length; i++) retBytes[index++] = concentBytes[i];
+            if (light.Dim) retBytes[index++] = light.DimLevel;
+
+            return retBytes;
+        }
+    }
+
+    /** 드라이버 내부 변수 */
+    public class Driver {
+        private PollingList Polling;
+
+        private MultiSwitch[] Device;
+
+        private boolean bDeviceFirstNotify;
+
+        private long [] TimeSyncTick;
+
+        public Driver() {
+            Polling = new PollingList();
+
+            Device = new MultiSwitch [MAX_DEVICE_COUNT];
+            for (int i = 0; i < MAX_DEVICE_COUNT ; i++) Device[i] = new MultiSwitch();
+
+            bDeviceFirstNotify = false;
+
+            TimeSyncTick = new long [MAX_DEVICE_COUNT];
+            for(int i=0 ; i<MAX_DEVICE_COUNT ; i++) TimeSyncTick[i] = 0;
+        }
+
+        /** Polling 관련 */
+        private class PollingList {
+            private final class STATUS {
+                /** 초기화 과정 */
+                public final static byte First = 0;
+                /** 초기화 타임아웃 */
+                public final static byte FirstTimeOut = 1;
+                /** 평상시 */
+                public final static byte Normal = 2;
+            }
+
+            private final class ALLCTRL {
+                /** 없음 */
+                public final static byte Idle         = 0;
+                /** 일괄소등 설정 */
+                public final static byte BatchOff_Set = 1;
+                /** 일괄소등 해제 */
+                public final static byte BatchOff_Clr = 2;
+            }
+
+            public byte CurrentAddress;
+            public byte Status;
+            public byte SearchDeviceCount;
+            public int SearchTryCount;
+            public boolean SearchEnd;
+            public byte AllCtrl;
+
+            private PollingList() {
+                CurrentAddress = 0;
+                Status = STATUS.First;
+                SearchDeviceCount = 0;
+                SearchTryCount = 0;
+                SearchEnd = false;
+                AllCtrl = ALLCTRL.Idle;
+            }
+
+            public void SetStatus(byte ChangeStatus) {
+                switch (ChangeStatus) {
+                    case STATUS.First:
+                        Status = ChangeStatus;
+                        CurrentAddress = 0;
+                        SearchDeviceCount = 0;
+                        SearchTryCount = 0;
+                        SearchEnd = false;
+                        break;
+
+                    case STATUS.FirstTimeOut:
+                        Status = ChangeStatus;
+                        break;
+
+                    case STATUS.Normal:
+                        Status = ChangeStatus;
+                        break;
+
+                    default:
+                        break;
+                }
+            }
+        }
+    }
+
+    private Driver mDriver = null;
+
+    private DriverInterOpAPI driverInterOpAPI;
+
+    /**
+     * 생성자
+     */
+    public MultiSwitch_Controller() {
+        /* 로그 초기상태 */
+//        log_sw = true;
+//        SerialLog = true;
+
+        /* 드라이버 내부 변수 초기화 */
+        mDriver = new Driver();
+
+//        /* BR registerReceiver (일괄소등 수신용) */
+//        IntentFilter filter = new IntentFilter();
+//        filter.addAction(define.NOTIFY_ACNAME);
+//        ServiceMain.svcContext.registerReceiver(mWallPadNotifyBR, filter);
+    }
+
+    @Override
+    public void DeviceLog(String msg) {
+        if (!log_sw) return;
+        Log.d(TAG, msg);
+    }
+
+    private boolean registerDeviceBR() {
+        DeviceLog("registerDeviceBR - Start");
+
+        if (mDriver == null) return false;
+        if (mDriver.Polling.Status != Driver.PollingList.STATUS.Normal) return false;
+
+        IntentFilter filter = new IntentFilter();
+        /* BR registerReceiver (일괄소등 수신용) */
+        filter.addAction(define.NOTIFY_ACNAME);
+        /* BR registerReceiver (에어컨 상태 수신용) */
+        driverInterOpAPI.setAirconRegBR(define.DRIVER_AIRCON_BR);
+        filter.addAction(define.DRIVER_AIRCON_BR);
+        ServiceMain.svcContext.registerReceiver(mWallPadNotifyBR, filter);
+        DeviceLog("registerDeviceBR - OK");
+
+        return true;
+    }
+
+    /**
+     * BroadcastReceiver
+     */
+    private BroadcastReceiver mWallPadNotifyBR = new BroadcastReceiver() {
+        public void onReceive(Context context, Intent intent) {
+            String strActionNamr = intent.getAction();
+
+            DeviceLog("Receive Notify BR ["+ strActionNamr + "]");
+
+            if (strActionNamr.equals(define.NOTIFY_ACNAME)) {
+                int kind = intent.getIntExtra("KIND", 0);
+                DeviceLog("Receive Notify BR "+ define.NOTIFY_ACNAME + " : " + kind);
+
+                switch (kind) {
+                    case define.NOTIFY_ALL_LIGHT_OFF:
+                        if (!((mDriver.Polling.Status == Driver.PollingList.STATUS.First) || (mDriver.Polling.Status == Driver.PollingList.STATUS.FirstTimeOut))) {
+                            // 일괄소등 설정 (조명 OFF)
+                            mDriver.Polling.AllCtrl = Driver.PollingList.ALLCTRL.BatchOff_Set;
+                        }
+                        break;
+
+                    case define.NOTIFY_ALL_LIGHT_ON:
+                        if (!((mDriver.Polling.Status == Driver.PollingList.STATUS.First) || (mDriver.Polling.Status == Driver.PollingList.STATUS.FirstTimeOut))) {
+                            // 일괄소등 해제 (조명 ON)
+                            mDriver.Polling.AllCtrl = Driver.PollingList.ALLCTRL.BatchOff_Clr;
+                        }
+                        break;
+
+                    case define.NOTIFY_DEVICE_INIT_COMPLETION:
+                        getEntireAIrconData();
+                        break;
+                }
+            }
+            else if (strActionNamr.equals(define.DRIVER_AIRCON_BR)) {
+                getEntireAIrconData();
+            }
+        }
+    };
+
+    private int getEntireAIrconData() {
+        try {
+            Log.i(TAG, "[getEntireAIrconData]");
+            if (ServiceMain.systemAircon_controller == null) return -1;
+
+            DataClasses.SystemAircon.AirconUnitData[] airconUnitData = ServiceMain.systemAircon_controller.getEntireAirconStatus();
+//            if (airconUnitData != null) Log.e(TAG, "[getEntireAIrconData] airconUnitData is not null airconUnitData.length [" + airconUnitData.length +"]");
+//            else Log.e(TAG, "[getEntireAIrconData] airconUnitData is null airconUnitData.length [" + airconUnitData.length + "]");
+
+
+            for (int i = 0; i < mDriver.Device.length; i++) {
+                MultiSwitch.Device.AirconData airconData = new MultiSwitch.Device.AirconData(mDriver.Device[i].info.Support.hAirconCtrlCnt);
+                for (int j = 0; j < mDriver.Device[i].info.Support.hAirconCtrlCnt; j++) {
+                    for (int k = 0; k < airconUnitData.length; k++) {
+                        if (mDriver.Device[i].info.Support.hAirconCtrlID[j] == airconUnitData[k].hInsideID) {
+                            // 멀티스위치에서 제어하는 에어컨 ID
+                            airconData.hInsideID[j] = airconUnitData[k].hInsideID;
+                            if (j == 0) {
+                                // 에어컨 상태정보는 빠른ID의 정보만 저장한다.
+                                airconData.conversionAirconStatus(airconUnitData[k]);
+                            }
+                        }
+                    }
+                    mDriver.Device[i].device.airconData = airconData;
+                }
+            }
+
+//            Log.i(TAG, "[getEntireAIrconData] ========== driver check start!! ==========");
+//            for (int i = 0; i < mDriver.Device.length; i++) {
+//                if (mDriver.Device[i].info.Support.bAirconCtrl) Log.i(TAG, mDriver.Device[i].device.airconData.ToDebugString((byte) i));
+//            }
+//            Log.i(TAG, "[getEntireAIrconData] ========== driver check end!! ==========");
+
+            return 0;
+        } catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+        } catch (Exception e) {
+            Log.e(TAG, "[Exception] getEntireAIrconData()");
+            LogUtil.errorLogInfo("", TAG, e);//e.printStackTrace();
+        }
+        return -99;
+    }
+
+    /**
+     * 로딩후 처음 폴링 시퀀스
+     */
+    @Override
+    protected void do_boot() {
+        driverInterOpAPI = new DriverInterOpAPI(MainHandler);
+    }
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    // Polling
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+     * do_ctr : 폴링스케쥴러
+     */
+    @Override
+    protected void do_ctr() {
+        DeviceLog("Polling ");
+
+        /* [[ First ]]
+         * 초기 디바이스정보 및 최대 ADDRESS 검색 */
+        if (mDriver.Polling.Status == Driver.PollingList.STATUS.First) {
+            // 1. 디바이스 검색
+            byte MaxDeviceID = 0;
+            for (byte DeviceIdx = 0; DeviceIdx < MAX_DEVICE_COUNT; DeviceIdx++) {
+                MultiSwitch.Info info = Send_GetDeviceInfo(DeviceIdx);
+                if (info != null) {
+                    MaxDeviceID = (byte) (DeviceIdx+1);
+                    if (info.Support.bV2CMDUsage) {
+                        info = sendGetDeviceInfoV2(DeviceIdx, info);
+                    }
+                    mDriver.Device[DeviceIdx].info = info;
+                    mDriver.Device[DeviceIdx].setBasicInfo(info.Support.hLightCnt, info.Support.hOutletCnt);
+                    if (info.Support.bAirconCtrl) mDriver.Device[DeviceIdx].setAirconInfo(info.Support.hAirconCtrlCnt, info.Support.hAirconCtrlID);
+                    Log.i(TAG, "SearchDevice     DeviceNum = " + (byte)(DeviceIdx+1) + "      OK!!!");
+
+                    Log.i(TAG, mDriver.Device[DeviceIdx].info.ToDebugString(DeviceIdx));
+                    Log.i(TAG, mDriver.Device[DeviceIdx].info.Support.ToDebugString(DeviceIdx));
+                }
+                else {
+                    Log.i(TAG, "SearchDevice     DeviceNum = " + (byte)(DeviceIdx+1) + "      Fail...");
+                }
+            }
+
+            // 2. 가장 높은 ID 저장
+            if (MaxDeviceID > mDriver.Polling.SearchDeviceCount) mDriver.Polling.SearchDeviceCount = MaxDeviceID;
+
+            // 3. 검색 횟수 체크
+            if (++mDriver.Polling.SearchTryCount >= MAX_SEARCH_COUNT) {
+                if (mDriver.Polling.SearchDeviceCount != 0) {
+                    mDriver.Polling.SearchEnd = true;
+                    mDriver.Polling.SetStatus(Driver.PollingList.STATUS.Normal);
+                    registerDeviceBR();
+                    Log.i(TAG, "First - Search Device END - SearchDeviceCount : " + mDriver.Polling.SearchDeviceCount);
+
+                    super.CommDataGeneration(mDriver.Polling.SearchDeviceCount);
+
+                    ServiceMain.deviceInitChecker.Remove(super.DeviceName);
+                }
+                else {
+                    mDriver.Polling.SetStatus(Driver.PollingList.STATUS.FirstTimeOut);
+
+                    Log.i(TAG, "--------------------------------------------------");
+                    Log.i(TAG, "SearchDevice Fail... FirstTimeOut ");
+                    Log.i(TAG, "--------------------------------------------------");
+
+                    ServiceMain.deviceInitChecker.Remove(super.DeviceName);
+                }
+            }
+        }
+
+        /* [[ FirstTimeOut ]]
+         * 초기 디바이스 검색하지못함. */
+        else if (mDriver.Polling.Status == Driver.PollingList.STATUS.FirstTimeOut) {
+            MultiSwitch.Info info = Send_GetDeviceInfo(mDriver.Polling.CurrentAddress);
+            if (info != null) {
+                if (info.Support.bV2CMDUsage) {
+                    info = sendGetDeviceInfoV2(mDriver.Polling.CurrentAddress, info);
+                }
+                mDriver.Device[mDriver.Polling.CurrentAddress].info = info;
+                mDriver.Device[mDriver.Polling.CurrentAddress].setBasicInfo(info.Support.hLightCnt, info.Support.hOutletCnt);
+                if (info.Support.bAirconCtrl) mDriver.Device[mDriver.Polling.CurrentAddress].setAirconInfo(info.Support.hAirconCtrlCnt, info.Support.hAirconCtrlID);
+                mDriver.Polling.SearchDeviceCount = (byte) (mDriver.Polling.CurrentAddress + 1);
+            }
+
+            if (++mDriver.Polling.CurrentAddress >= MAX_DEVICE_COUNT) {
+                mDriver.Polling.CurrentAddress = 0;
+
+                if (mDriver.Polling.SearchDeviceCount != 0) {
+                    mDriver.Polling.SearchEnd = true;
+                    mDriver.Polling.SetStatus(Driver.PollingList.STATUS.Normal);
+                    registerDeviceBR();
+
+                    Log.i(TAG, "FirstTimeOut - Search Device END - SearchDeviceCount : " + mDriver.Polling.SearchDeviceCount);
+                }
+            }
+        }
+
+        /* [[ Normal ]]
+         * 평상시 */
+        else if (mDriver.Polling.Status == Driver.PollingList.STATUS.Normal) {
+            if (mDriver.Polling.SearchEnd) {
+                mDriver.Polling.SearchEnd = false;
+
+                int DeviceCount = mDriver.Polling.SearchDeviceCount;
+
+                if (!super.getCommCNTGeneration()) super.CommDataGeneration(DeviceCount);
+
+                for (byte DeviceIdx = 0; DeviceIdx < DeviceCount; DeviceIdx++) {
+                    DeviceLog(mDriver.Device[DeviceIdx].info.ToDebugString(DeviceIdx));
+                }
+            }
+
+            // 전체 명령 처리
+            if (mDriver.Polling.AllCtrl != Driver.PollingList.ALLCTRL.Idle) {
+                CtrlCmd ctrlCmd = new CtrlCmd();
+
+                // 일괄소등 설정
+                if (mDriver.Polling.AllCtrl == Driver.PollingList.ALLCTRL.BatchOff_Set) {
+                    ctrlCmd.light.setBatchOff(MultiSwitch.BATCHOFF_STATUS.Set);
+                }
+
+                // 일괄소등 해제
+                else if (mDriver.Polling.AllCtrl == Driver.PollingList.ALLCTRL.BatchOff_Clr) {
+                    ctrlCmd.light.setBatchOff(MultiSwitch.BATCHOFF_STATUS.Clr);
+                }
+                else {
+                    Log.w(TAG, "[do_ctr] AllCtrl Out Of Range !!! (AllCtrl:" + mDriver.Polling.AllCtrl + ")");
+                    mDriver.Polling.AllCtrl = Driver.PollingList.ALLCTRL.Idle;
+                    return;
+                }
+
+                byte TempAllCtrlStatus = mDriver.Polling.AllCtrl;
+
+                MultiSwitch.Device device;
+                for (byte i=0 ; i<mDriver.Polling.SearchDeviceCount ; i++) {
+                    if (mDriver.Device[i].info.Support.bV2CMDUsage) device = sendSetLightConcentStatusV2(i, ctrlCmd);
+                    else device = Send_SetLightConcentStatus(i, ctrlCmd);
+
+                    if (device != null) {
+                        UpdateVariables(i, device, false);
+                    }
+                    else
+                    {
+                        Log.w(TAG, "[do_ctr] AllCtrl:" + mDriver.Polling.AllCtrl + ", DeviceIdx:" + i + "   Ctrl Fail ... !!!");
+                    }
+                }
+
+                //전체제어중 전체제어명령어 다시 수신되었을 경우는 예외처리
+                if (TempAllCtrlStatus == mDriver.Polling.AllCtrl) {
+                    mDriver.Polling.AllCtrl = Driver.PollingList.ALLCTRL.Idle;
+                }
+            }
+            // 상태 가져오기
+            else {
+                byte CurrentAddress = mDriver.Polling.CurrentAddress;
+                if (mDriver.Device[CurrentAddress].info.Install) {
+                    if (mDriver.Device[CurrentAddress].info.Support.bTimeSync) {
+                        //시간정보 사용함 인 경우 처리
+                        long currentTimeMillis = 0;
+                        currentTimeMillis = System.currentTimeMillis();
+                        if (Math.abs(currentTimeMillis - mDriver.TimeSyncTick[CurrentAddress]) > STATUS_SYNC_TICK) {
+                            //시간정보를 보내줘야 할 순서 확인
+                            mDriver.TimeSyncTick[CurrentAddress] = currentTimeMillis;
+
+                            //시간 전송
+                            MultiSwitch.Device device = Send_Time(CurrentAddress);
+                            if (device != null) {
+                                boolean bNotify = false;
+                                if (!mDriver.bDeviceFirstNotify) {
+                                    if (CurrentAddress == 0) {
+                                        bNotify = true;
+                                        mDriver.bDeviceFirstNotify = true;
+                                    }
+                                }
+                                UpdateVariables(CurrentAddress, device, bNotify);
+                            }
+                        }
+                        else {
+                            //평상시 폴링
+                            MultiSwitch.Device device;
+                            if (mDriver.Device[CurrentAddress].info.Support.bV2CMDUsage) device = sendGetDeviceStatusV2(CurrentAddress);
+                            else device = Send_GetLightConcentStatus(CurrentAddress);
+
+                            if (device != null && device.ctrlReq.bAircon && mDriver.Device[CurrentAddress].info.Support.bV2CMDUsage) {
+                                sendCtrlReqACKV2(CurrentAddress, (byte) 0x01);
+                                for (int i = 0; i < mDriver.Device[CurrentAddress].info.Support.hAirconCtrlID.length; i++) {
+                                    Log.e(TAG, device.ctrlReq.ToDebugString(CurrentAddress));
+                                    int nResult = driverInterOpAPI.ctrlAircon(ServiceMain.MSG_DEV_CTR, mDriver.Device[CurrentAddress].info.Support.hAirconCtrlID[i], device.ctrlReq.hAirconCtrlOption, device.ctrlReq.hAirconStatus, device.ctrlReq.hSetTemper);
+                                    Log.e(TAG, "Aircon Ctrl -> nResult [" + nResult + "]");
+                                }
+                            }
+
+                            if (device != null) {
+                                boolean bNotify = false;
+                                if (!mDriver.bDeviceFirstNotify) {
+                                    if (CurrentAddress == 0) {
+                                        bNotify = true;
+                                        mDriver.bDeviceFirstNotify = true;
+                                    }
+                                }
+                                UpdateVariables(CurrentAddress, device, bNotify);
+                            }
+                        }
+                    }
+                    else {
+                        //시간정보 사용안함 때 평상시 폴링
+                        MultiSwitch.Device device;
+                        if (mDriver.Device[CurrentAddress].info.Support.bV2CMDUsage) {
+                            device = sendGetDeviceStatusV2(CurrentAddress);
+                            if (device != null && device.ctrlReq.bAircon && mDriver.Device[CurrentAddress].info.Support.bV2CMDUsage) {
+                                sendCtrlReqACKV2(CurrentAddress, (byte) 0x01);
+                                for (int i = 0; i < mDriver.Device[CurrentAddress].info.Support.hAirconCtrlID.length; i++) {
+                                    driverInterOpAPI.ctrlAircon(ServiceMain.MSG_DEV_CTR, mDriver.Device[CurrentAddress].info.Support.hAirconCtrlID[i], device.ctrlReq.hAirconCtrlOption, device.ctrlReq.hAirconStatus, device.ctrlReq.hSetTemper);
+                                }
+                            }
+                        }
+                        else device = Send_GetLightConcentStatus(CurrentAddress);
+
+                        if (device != null) {
+                            boolean bNotify = false;
+                            if (!mDriver.bDeviceFirstNotify) {
+                                if (CurrentAddress == 0) {
+                                    bNotify = true;
+                                    mDriver.bDeviceFirstNotify = true;
+                                }
+                            }
+                            UpdateVariables(CurrentAddress, device, bNotify);
+                        }
+                    }
+                }
+                else {
+                    MultiSwitch.Info info = Send_GetDeviceInfo(CurrentAddress);
+                    if (info != null) {
+                        if (info.Support.bV2CMDUsage) {
+                            info = sendGetDeviceInfoV2(CurrentAddress, info);
+                        }
+                        mDriver.Device[CurrentAddress].info = info;
+                        mDriver.Device[CurrentAddress].setBasicInfo(info.Support.hLightCnt, info.Support.hOutletCnt);
+                        if (info.Support.bAirconCtrl) mDriver.Device[CurrentAddress].setAirconInfo(info.Support.hAirconCtrlCnt, info.Support.hAirconCtrlID);
+                        AddDoCount(CurrentAddress, true);
+                    }
+                    else {
+                        AddDoCount(CurrentAddress, false);
+                    }
+                }
+
+                if (++mDriver.Polling.CurrentAddress >= mDriver.Polling.SearchDeviceCount) mDriver.Polling.CurrentAddress = 0;
+            }
+        }
+        else {
+            mDriver = new Driver();
+        }
+    }
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    // Ctrl
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+     * NoSink 제어
+     *
+     * @param StrArg
+     *
+     * @return
+     */
+    public String NoSinkCtrl(String StrArg) {
+        DeviceLog("[NoSinkCtrl] Start");
+
+        // 1. 디바이스 초기화시 에러리턴
+        if ((mDriver.Polling.Status == Driver.PollingList.STATUS.First) || (mDriver.Polling.Status == Driver.PollingList.STATUS.FirstTimeOut)) {
+            Log.w(TAG, "[NoSinkCtrl] - Not Yet !!!");
+            return "FAIL;" + APIErrorCode.DEVICEISNOTREADY;
+        }
+
+        CtrDevFormat ctrDevFormat = GetCtrDevParamParsing(StrArg, 5);
+        if (ctrDevFormat.ret != APIErrorCode.C_SUCCESS) {
+            Log.w(TAG, "[NoSinkCtrl] GetCtrDevParamParsing Error (ret:" + ctrDevFormat.ret + ")");
+            return "FAIL;" + APIErrorCode.DEFAULT_PARSING_ERR;
+        }
+
+        if (ctrDevFormat.CmdStr!=null) {
+            //////////////////////////////////////////////////////////
+            // Refresh : 데이터 갱신 (No Sink)
+            //////////////////////////////////////////////////////////
+            if (ctrDevFormat.CmdStr.equals("Refresh")) {
+                byte Index         = ctrDevFormat.param[0];
+                DeviceLog("[Refresh] Index : " + String.format("0x%02X", Index));
+                return RefreshResult(Index);
+            }
+
+            //////////////////////////////////////////////////////////
+            // GetDeviceCount : 기기 개수 가져오기 (No Sink)
+            //////////////////////////////////////////////////////////
+            else if (ctrDevFormat.CmdStr.equals("GetDeviceCount")) {
+                DeviceLog("[GetDeviceCount]");
+                return RefreshResult_GetDeviceCount();
+            }
+        }
+
+        return "FAIL;" + APIErrorCode.UNKNOWNCOMMAND;
+    }
+
+    /**
+     * do_ctrEmm : 싱크 제어
+     */
+    @Override
+    @SuppressLint("DefaultLocale")
+    protected String do_ctrEmm(DeviceCtrSHMem SHMem) {
+        DeviceLog("[do_ctrEmm] Start");
+        DeviceLog("cmd    : " + SHMem.cmd);
+        DeviceLog("StrArg : " + SHMem.StrArg);
+
+        // 1. 디바이스 초기화시 에러리턴
+        if ((mDriver.Polling.Status == Driver.PollingList.STATUS.First) || (mDriver.Polling.Status == Driver.PollingList.STATUS.FirstTimeOut)) {
+            Log.w(TAG, "[do_ctrEmm] - Not Yet !!!");
+            return SHMem.retVal = "FAIL;" + APIErrorCode.DEVICEISNOTREADY;
+        }
+
+        CtrDevFormat ctrDevFormat = GetCtrDevParamParsing(SHMem.StrArg, 5);
+        if (ctrDevFormat.ret != APIErrorCode.C_SUCCESS) {
+            Log.w(TAG, "[do_ctrEmm] GetCtrDevParamParsing Error (ret:" + ctrDevFormat.ret + ")");
+            return SHMem.retVal = "FAIL;" + APIErrorCode.DEFAULT_PARSING_ERR;
+        }
+
+        if (ctrDevFormat.CmdStr!=null) {
+            //////////////////////////////////////////////////////////
+            // Refresh : 데이터 갱신 (Sink)
+            //
+            // [0] Index    - 기기인덱스 (0~7)
+            //////////////////////////////////////////////////////////
+            if (ctrDevFormat.CmdStr.equals("Refresh")) {
+                try {
+                    byte Index    = ctrDevFormat.param[0];
+
+                    // 1. 범위체크
+                    //     1.1. Index
+                    if (!DeviceIndexRangeCheck(Index)) {
+                        Log.w(TAG, "[do_ctrEmm -> Refresh] Param : Index - Out Of Range !!! (Index:" + Index + ")");
+                        return SHMem.retVal = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
+                    }
+
+                    // 2. Doing
+                    MultiSwitch.Device device;
+                    if (mDriver.Device[Index].info.Support.bV2CMDUsage) device = sendGetDeviceStatusV2(Index);
+                    else device = Send_GetLightConcentStatus(Index);
+
+                    if (device != null && device.ctrlReq.bAircon && mDriver.Device[Index].info.Support.bV2CMDUsage) {
+                        sendCtrlReqACKV2(Index, (byte) 0x01);
+                        for (int i = 0; i < mDriver.Device[Index].info.Support.hAirconCtrlID.length; i++) {
+                            driverInterOpAPI.ctrlAircon(ServiceMain.MSG_DEV_CTR, mDriver.Device[Index].info.Support.hAirconCtrlID[i], device.ctrlReq.hAirconCtrlOption, device.ctrlReq.hAirconStatus, device.ctrlReq.hSetTemper);
+                        }
+                    }
+
+                    if (device != null) {
+                        UpdateVariables(Index, device, false);
+                        SHMem.retVal = RefreshResult(Index);
+                    }
+                    else {
+                        SHMem.retVal = "FAIL;" + APIErrorCode.DEVICEISNORESPONSE;
+                    }
+                    return SHMem.retVal;
+                } catch (RuntimeException re) {
+                    LogUtil.errorLogInfo("", TAG, re);
+                    return SHMem.retVal = "FAIL;" + APIErrorCode.EXCEPTION;
+                } catch (Exception e) {
+                    Log.e(TAG, "[Exception Error] do_ctrEmm -> Refresh");
+                    //e.printStackTrace();
+                    LogUtil.errorLogInfo("", TAG, e);
+                    return SHMem.retVal = "FAIL;" + APIErrorCode.EXCEPTION;
+                }
+            }
+
+            ///////////////////////////////////////////////////////////////
+            // SetLightOnOff : 조명 제어
+            //
+            // [0] Index    - 기기인덱스 (0~7)
+            // [1] LightIdx - 조명인덱스 (0~7, 0xFF:전체)
+            // [2] OnOff    - 0x00 : OFF, 0x01 : ON
+            ///////////////////////////////////////////////////////////////
+            else if (ctrDevFormat.CmdStr.equals("SetLightOnOff")) {
+                try {
+                    byte Index    = ctrDevFormat.param[0];
+                    byte LightIdx = ctrDevFormat.param[1];
+                    byte OnOff    = ctrDevFormat.param[2];
+
+                    // 1. 범위체크
+                    //     1.1. Index
+                    if (!DeviceIndexRangeCheck(Index)) {
+                        Log.w(TAG, "[do_ctrEmm -> SetLightOnOff] Param : Index - Out Of Range !!! (Index:" + Index + ")");
+                        return SHMem.retVal = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
+                    }
+
+                    if (!mDriver.Device[Index].info.Install) {
+                        Log.w(TAG, "[do_ctrEmm -> SetLightOnOff] Device [" + Index + "]  No Install !!!");
+                        return SHMem.retVal = "FAIL;" + APIErrorCode.DEVICEISNOTREADY;
+                    }
+
+                    //     1.2. LightIdx
+                    if (LightIdx != define.DEVICE_ALL_OR_NOTHING) {
+                        if ((LightIdx < 0) || (LightIdx >= MAX_LIGHT_COUNT)) {
+                            Log.w(TAG, "[do_ctrEmm -> SetLightOnOff] Param : LightIdx - Out Of Range #1 !!! (LightIdx:" + LightIdx + ")");
+                            return SHMem.retVal = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
+                        }
+                        else {
+                            if (LightIdx >= mDriver.Device[Index].info.Support.hLightCnt) {
+                                Log.w(TAG, "[do_ctrEmm -> SetLightOnOff] Param : LightIdx - Out Of Range #2 !!! (LightIdx:" + LightIdx + ")");
+                                return SHMem.retVal = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
+                            }
+                        }
+                    }
+
+                    //     1.3. OnOff
+                    if ((OnOff != 0x00) && (OnOff != 0x01)) {
+                        Log.w(TAG, "[do_ctrEmm -> SetLightOnOff] Param : OnOff - Out Of Range !!! (OnOff:" + OnOff + ")");
+                        return SHMem.retVal = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
+                    }
+
+                    // 2. Make Ctrl Command
+                    CtrlCmd ctrlCmd = new CtrlCmd();
+                    if (LightIdx == define.DEVICE_ALL_OR_NOTHING) ctrlCmd.light.Pattern = define.DEVICE_ALL_OR_NOTHING;
+                    else ctrlCmd.light.Pattern = super.BIT_ARRAY[LightIdx];
+
+                    if (OnOff == 0x00) ctrlCmd.light.OnOff = false;
+                    else ctrlCmd.light.OnOff = true;
+
+                    // 3. Doing
+                    MultiSwitch.Device device;
+                    if (mDriver.Device[Index].info.Support.bV2CMDUsage) device = sendSetLightConcentStatusV2(Index, ctrlCmd);
+                    else device = Send_SetLightConcentStatus(Index, ctrlCmd);
+
+                    if (device != null) {
+                        UpdateVariables(Index, device, false);
+                        SHMem.retVal = "SUCCESS";
+                    }
+                    else {
+                        SHMem.retVal = "FAIL;" + APIErrorCode.DEVICEISNORESPONSE;
+                    }
+                    return SHMem.retVal;
+                } catch (RuntimeException re) {
+                    LogUtil.errorLogInfo("", TAG, re);
+                    return SHMem.retVal = "FAIL;" + APIErrorCode.EXCEPTION;
+                } catch (Exception e) {
+                    Log.e(TAG, "[Exception Error] do_ctrEmm -> SetLightOnOff");
+                    //e.printStackTrace();
+                    LogUtil.errorLogInfo("", TAG, e);
+                    return SHMem.retVal = "FAIL;" + APIErrorCode.EXCEPTION;
+                }
+            }
+            ///////////////////////////////////////////////////////////////
+            // SetLightOnOff : 조명 제어
+            //
+            // [0] Index    - 기기인덱스 (0~7)
+            // [1] LightIdx - 조명인덱스 (0~7, 0xFF:전체)
+            // [2] OnOff    - 0x00 : OFF, 0x01 : ON
+            ///////////////////////////////////////////////////////////////
+            else if (ctrDevFormat.CmdStr.equals("SetLightDimV2")) {
+                try {
+                    byte Index    = ctrDevFormat.param[0];
+                    byte LightIdx = ctrDevFormat.param[1];
+                    byte DimLevel    = ctrDevFormat.param[2];
+
+                    if (!mDriver.Device[Index].info.Support.bV2CMDUsage) return SHMem.retVal = "FAIL;" + APIErrorCode.NOT_SUPPORT;
+
+                    // 1. 범위체크
+                    //     1.1. Index
+                    if (!DeviceIndexRangeCheck(Index)) {
+                        Log.w(TAG, "[do_ctrEmm -> SetLightDimV2] Param : Index - Out Of Range !!! (Index:" + Index + ")");
+                        return SHMem.retVal = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
+                    }
+
+                    if (!mDriver.Device[Index].info.Install) {
+                        Log.w(TAG, "[do_ctrEmm -> SetLightDimV2] Device [" + Index + "]  No Install !!!");
+                        return SHMem.retVal = "FAIL;" + APIErrorCode.DEVICEISNOTREADY;
+                    }
+
+                    //     1.2. LightIdx
+                    if (LightIdx != define.DEVICE_ALL_OR_NOTHING) {
+                        if ((LightIdx < 0) || (LightIdx >= MAX_LIGHT_COUNT)) {
+                            Log.w(TAG, "[do_ctrEmm -> SetLightDimV2] Param : LightIdx - Out Of Range #1 !!! (LightIdx:" + LightIdx + ")");
+                            return SHMem.retVal = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
+                        }
+                        else {
+                            if (LightIdx >= mDriver.Device[Index].info.Support.hLightCnt) {
+                                Log.w(TAG, "[do_ctrEmm -> SetLightDimV2] Param : LightIdx - Out Of Range #2 !!! (LightIdx:" + LightIdx + ")");
+                                return SHMem.retVal = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
+                            }
+                        }
+                    }
+
+                    //     1.3. Dim
+                    if (DimLevel < 1 && mDriver.Device[Index].info.Support.hDimLevel < DimLevel) {
+                        Log.w(TAG, "[do_ctrEmm -> SetLightDimV2] Param : DimLevel - Out Of Range !!! (DimLevel:" + DimLevel + ")");
+                        return SHMem.retVal = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
+                    }
+
+                    // 2. Make Ctrl Command
+                    CtrlCmd ctrlCmd = new CtrlCmd();
+                    if(LightIdx == define.DEVICE_ALL_OR_NOTHING) ctrlCmd.light.Pattern = define.DEVICE_ALL_OR_NOTHING;
+                    else ctrlCmd.light.Pattern = super.BIT_ARRAY[LightIdx];
+
+                    ctrlCmd.light.OnOff = mDriver.Device[Index].device.light[LightIdx].bPower;
+                    ctrlCmd.light.Dim = true;
+                    ctrlCmd.light.DimLevel = DimLevel;
+
+                    // 3. Doing
+                    MultiSwitch.Device device;
+                    device = sendSetLightConcentStatusV2(Index, ctrlCmd);
+
+                    if (device != null) {
+                        UpdateVariables(Index, device, false);
+                        SHMem.retVal = "SUCCESS";
+                    }
+                    else {
+                        SHMem.retVal = "FAIL;" + APIErrorCode.DEVICEISNORESPONSE;
+                    }
+                    return SHMem.retVal;
+                } catch (RuntimeException re) {
+                    LogUtil.errorLogInfo("", TAG, re);
+                    return SHMem.retVal = "FAIL;" + APIErrorCode.EXCEPTION;
+                } catch (Exception e) {
+                    Log.e(TAG, "[Exception Error] do_ctrEmm -> SetLightDimV2");
+                    //e.printStackTrace();
+                    LogUtil.errorLogInfo("", TAG, e);
+                    return SHMem.retVal = "FAIL;" + APIErrorCode.EXCEPTION;
+                }
+            }
+
+            ///////////////////////////////////////////////////////////////
+            // SetConcentOnOff : 콘센트 ON/OFF 제어
+            //
+            // [0] Index      - 기기인덱스 (0~7)
+            // [1] ConcentIdx - 콘센트인덱스 (0~7, 0xFF:전체)
+            // [2] OnOff    - 0x00 : OFF, 0x01 : ON
+            ///////////////////////////////////////////////////////////////
+            else if (ctrDevFormat.CmdStr.equals("SetConcentOnOff")) {
+                return SHMem.retVal = do_ctrEmm_SetConcent(ctrDevFormat.CmdStr, ctrDevFormat.param[0], ctrDevFormat.param[1], ctrDevFormat.param[2]);
+            }
+
+            ///////////////////////////////////////////////////////////////
+            // SetConcentMode : 콘센트 Mode 제어
+            //
+            // [0] Index      - 기기인덱스 (0~7)
+            // [1] ConcentIdx - 콘센트인덱스 (0~7, 0xFF:전체)
+            // [2] Mode       - 0x00 : 상시 Always, 0x01 : 자동 Auto
+            ///////////////////////////////////////////////////////////////
+            else if (ctrDevFormat.CmdStr.equals("SetConcentMode")) {
+                return SHMem.retVal = do_ctrEmm_SetConcent(ctrDevFormat.CmdStr, ctrDevFormat.param[0], ctrDevFormat.param[1], ctrDevFormat.param[2]);
+            }
+
+            ///////////////////////////////////////////////////////////////
+            // SetConcentCutOff : 콘센트 차단기준값 설정
+            //
+            // [0] Index      - 기기인덱스 (0~7)
+            // [1] ConcentIdx - 콘센트인덱스 (0~7, 0xFF:전체)
+            ///////////////////////////////////////////////////////////////
+            else if (ctrDevFormat.CmdStr.equals("SetConcentCutOff")) {
+                return SHMem.retVal = do_ctrEmm_SetConcent(ctrDevFormat.CmdStr, ctrDevFormat.param[0], ctrDevFormat.param[1], (byte)0x00);
+            }
+
+            ///////////////////////////////////////////////////////////////
+        }
+
+
+        return SHMem.retVal = "UNKNOWNCMD";
+    }
+
+    /**
+     * {@link #do_ctrEmm(DeviceCtrSHMem)} 의 콘센트 처리부분 Sub 함수이다.
+     *
+     * @param CmdStr      - (String) 명령어
+     * @param Index       - (byte) 기기 인덱스
+     * @param ConcentIdx  - (byte) 콘센트 인덱스
+     * @param OnOff       - (byte) ON/OFF Param
+     *
+     * @return (String) 결과
+     */
+    private String do_ctrEmm_SetConcent(String CmdStr, byte Index, byte ConcentIdx, byte OnOff) {
+        if (CmdStr == null) {
+            Log.w(TAG, "[do_ctrEmm_SetConcent] Param : CmdStr is null !!!");
+            return "FAIL;" + APIErrorCode.INVALIDPARAMETER;
+        }
+
+        try {
+            // 1. 범위체크
+            //     1.1. CmdStr
+            if (!( CmdStr.equals("SetConcentOnOff") || CmdStr.equals("SetConcentMode") || CmdStr.equals("SetConcentCutOff"))) {
+                Log.w(TAG, "[do_ctrEmm_SetConcent] Param : CmdStr - Out Of Range (CmdStr:" + CmdStr + ")");
+                return "FAIL;" + APIErrorCode.INVALIDPARAMETER;
+            }
+
+            //     1.2. Index
+            if (Index != define.DEVICE_ALL_OR_NOTHING) {
+                if (!DeviceIndexRangeCheck(Index)) {
+                    Log.w(TAG, "[do_ctrEmm -> SetConcentOnOff] Param : Index - Out Of Range !!! (Index:" + Index + ")");
+                    return "FAIL;" + APIErrorCode.INVALIDPARAMETER;
+                }
+
+                if (!mDriver.Device[Index].info.Install) {
+                    Log.w(TAG, "[do_ctrEmm -> SetConcentOnOff] Device [" + Index + "]  No Install !!!");
+                    return "FAIL;" + APIErrorCode.DEVICEISNOTREADY;
+                }
+            }
+
+            //     1.2. ConcentIdx
+            if (Index == define.DEVICE_ALL_OR_NOTHING) {
+                if (ConcentIdx != define.DEVICE_ALL_OR_NOTHING) {
+                    Log.w(TAG, "[do_ctrEmm -> SetConcentOnOff] Param : If the entire DeviceIndex ConcentIndex must be a whole.");
+                    return "FAIL;" + APIErrorCode.INVALIDPARAMETER;
+                }
+            }
+            else {
+                if (ConcentIdx != define.DEVICE_ALL_OR_NOTHING) {
+                    if ((ConcentIdx < 0) || (ConcentIdx >= MAX_OUTLET_COUNT)) {
+                        Log.w(TAG, "[do_ctrEmm -> SetConcentOnOff] Param : ConcentIdx - Out Of Range #1 !!! (ConcentIdx:" + ConcentIdx + ")");
+                        return "FAIL;" + APIErrorCode.INVALIDPARAMETER;
+                    }
+                    else {
+                        if (ConcentIdx >= mDriver.Device[Index].info.Support.hOutletCnt) {
+                            Log.w(TAG, "[do_ctrEmm -> SetConcentOnOff] Param : ConcentIdx - Out Of Range #1 !!! (ConcentIdx:" + ConcentIdx + ")");
+                            return SHMem.retVal = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
+                        }
+                    }
+                }
+            }
+
+            //     1.3. OnOff
+            if ((OnOff != 0x00) && (OnOff != 0x01)) {
+                Log.w(TAG, "[do_ctrEmm -> SetConcentOnOff] Param : OnOff - Out Of Range !!! (OnOff:" + OnOff + ")");
+                return SHMem.retVal = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
+            }
+
+            // 2. Make Ctrl Command
+            CtrlCmd ctrlCmd = null;
+            // 3. Doing
+            if (Index == define.DEVICE_ALL_OR_NOTHING) {
+                int FailCount = 0;
+                for (byte DeviceIdx = 0; DeviceIdx<mDriver.Polling.SearchDeviceCount; DeviceIdx++) {
+                    if (mDriver.Device[DeviceIdx].info.Support.hOutletCnt > 0) {
+                        ctrlCmd = MakeConcentCtrlCmd(CmdStr, DeviceIdx, ConcentIdx, OnOff);
+
+                        MultiSwitch.Device device;
+                        if (mDriver.Device[DeviceIdx].info.Support.bV2CMDUsage) device = sendSetLightConcentStatusV2(DeviceIdx, ctrlCmd);
+                        else device = Send_SetLightConcentStatus(DeviceIdx, ctrlCmd);
+
+                        if (device != null) {
+                            UpdateVariables(DeviceIdx, device, false);
+                        }
+                        else {
+                            FailCount++;
+                        }
+                    }
+                }
+
+                if (FailCount == 0) {
+                    return "SUCCESS";
+                }
+                else {
+                    return "FAIL;" + APIErrorCode.DEVICEISNORESPONSE;
+                }
+            }
+            else {
+                ctrlCmd = MakeConcentCtrlCmd(CmdStr, Index, ConcentIdx, OnOff);
+
+                MultiSwitch.Device device;
+                if (mDriver.Device[Index].info.Support.bV2CMDUsage) device = sendSetLightConcentStatusV2(Index, ctrlCmd);
+                else device = Send_SetLightConcentStatus(Index, ctrlCmd);
+
+                if (device != null) {
+                    UpdateVariables(Index, device, false);
+                    return "SUCCESS";
+                }
+                else {
+                    return "FAIL;" + APIErrorCode.DEVICEISNORESPONSE;
+                }
+            }
+        } catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+            return "FAIL;" + APIErrorCode.EXCEPTION;
+        } catch (Exception e) {
+            Log.e(TAG, "[Exception Error] do_ctrEmm_SetConcent - [" + CmdStr + "]");
+            //e.printStackTrace();            
+            LogUtil.errorLogInfo("", TAG, e);
+            return "FAIL;" + APIErrorCode.EXCEPTION;
+        }
+    }
+
+    /**
+     * {@link #do_ctrEmm_SetConcent(String, byte, byte, byte)} 의 콘센트 명령어 생성 Sub 함수이다.
+     *
+     * @param CmdStr      - (String) 명령어
+     * @param Index       - (byte) 기기 인덱스
+     * @param ConcentIdx  - (byte) 콘센트 인덱스
+     * @param OnOff       - (byte) ON/OFF Param
+     *
+     * @return (CtrlCmd) 명령어
+     */
+    private CtrlCmd MakeConcentCtrlCmd(String CmdStr, byte Index, byte ConcentIdx, byte OnOff) {
+        byte ConcentCount = mDriver.Device[Index].info.Support.hOutletCnt;
+        CtrlCmd ctrlCmd = new CtrlCmd();
+        ctrlCmd.outlet.setCount(ConcentCount);
+
+        if (CmdStr.equals("SetConcentOnOff")) {
+            if (ConcentIdx == define.DEVICE_ALL_OR_NOTHING) {
+                for (byte i = 0; i < ConcentCount; i++) {
+                    if (OnOff != 0x00) ctrlCmd.outlet.unitOutlet[i].setOnOff(MultiSwitch.OUTLET_STATUS.On);
+                    else ctrlCmd.outlet.unitOutlet[i].setOnOff(MultiSwitch.OUTLET_STATUS.Off);
+                }
+            }
+            else {
+                if (OnOff != 0x00) ctrlCmd.outlet.unitOutlet[ConcentIdx].setOnOff(MultiSwitch.OUTLET_STATUS.On);
+                else ctrlCmd.outlet.unitOutlet[ConcentIdx].setOnOff(MultiSwitch.OUTLET_STATUS.Off);
+            }
+        }
+        else if (CmdStr.equals("SetConcentMode")) {
+            if (ConcentIdx == define.DEVICE_ALL_OR_NOTHING) {
+                for (byte i = 0; i < ConcentCount; i++) {
+                    if (OnOff != 0x00) ctrlCmd.outlet.unitOutlet[i].setMode(MultiSwitch.OUTLET_MODE.Auto);
+                    else ctrlCmd.outlet.unitOutlet[i].setMode(MultiSwitch.OUTLET_MODE.Always);
+                }
+            }
+            else {
+                if (OnOff != 0x00) ctrlCmd.outlet.unitOutlet[ConcentIdx].setMode(MultiSwitch.OUTLET_MODE.Auto);
+                else ctrlCmd.outlet.unitOutlet[ConcentIdx].setMode(MultiSwitch.OUTLET_MODE.Always);
+            }
+        }
+        else if (CmdStr.equals("SetConcentCutOff")) {
+            if (ConcentIdx == define.DEVICE_ALL_OR_NOTHING) {
+                for(byte i=0 ; i<ConcentCount ; i++) ctrlCmd.outlet.unitOutlet[i].CutOff = true;
+            }
+            else {
+                ctrlCmd.outlet.unitOutlet[ConcentIdx].CutOff = true;
+            }
+        }
+        else return null;
+
+        return ctrlCmd;
+    }
+
+    /**
+     * 기기 인덱스의 범위체크를 한다.
+     *
+     * @param Index - (byte) 범위체크할 인덱스
+     *
+     * @return (boolean) 결과 - true : 정상, false : 에러
+     */
+    private boolean DeviceIndexRangeCheck(byte Index) {
+        try {
+            if ((Index < 0) || (Index >= mDriver.Polling.SearchDeviceCount)) return false;
+            return true;
+        } catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+            return false;
+        } catch (Exception e) {
+            Log.e(TAG, "[Exception Error] DeviceIndexRangeCheck");
+            //e.printStackTrace();            
+            LogUtil.errorLogInfo("", TAG, e);
+            return false;
+        }
+    }
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    // RefreshResult
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+     * Refresh 에 대한 응답포멧 정의
+     *
+     * @param Index - (byte) 기기 인덱스 (범위 : 0 ~ 3)
+     *
+     * @return (String) "SUCCESS; ..." 성공 , "FAIL; ... " 실패
+     */
+    private String RefreshResult(byte Index) {
+        String result = null;
+
+        DeviceLog("RefreshResult call : ");
+
+        // 1. Check Polling Status
+        if ((mDriver.Polling.Status == Driver.PollingList.STATUS.First) || (mDriver.Polling.Status == Driver.PollingList.STATUS.FirstTimeOut)) {
+            result = "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
+            return result;
+        }
+
+        // 2. Param Range Check
+        if (!(Index >= 0 && Index < mDriver.Polling.SearchDeviceCount)) {
+            result = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
+            return result;
+        }
+
+        // 3. Make Return String Format
+        try {
+            if (mDriver == null)                      return "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
+            if (mDriver.Device == null)               return "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
+            if (mDriver.Device[Index].info == null)   return "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
+            if (mDriver.Device[Index].device == null) return "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
+
+            /*
+             * [Format]
+             *
+             * SUCCESS;                         - (String) 성공
+             *
+             * RequestIndex;                            - (byte) 요청 인덱스
+             *
+             * [Info]
+             * Install                          - (boolean) 설치여부
+             * Vender                           - (byte) 벤더
+             * FwVer_Year                           - (byte) 펌웨어 빌드버전 (년)
+             * FwVer_Month                          - (byte) 펌웨어 빌드버전 (월)
+             * FwVer_Day                            - (byte) 펌웨어 빌드버전 (일)
+             * FwVer_Number                         - (byte) 펌웨어 빌드버전 (순번)
+             * ProtocolVer_Main                         - (byte) 프로토콜 지원 버전 (상위)
+             * ProtocolVer_Sub                          - (byte) 프로토콜 지원 버전 (하위)
+             *
+             * [SupportInfo]
+             * hLightCnt                            - (byte) 조명 개수
+             * hOutletCnt                           - (byte) 콘센트 개수
+             * bV2CMDUsage                          - (byte) V2 CMD 사용 여부
+             * bDim                         - (byte) 디밍 사용 여부
+             * hDimLevel                            - (byte) 디밍 레벨
+             * hDimEnabledCircuit                           - (byte) 디밍 지원 회로
+             * bAirconCtrl                          - (byte) 에어컨 제어 지원 여부 (멀티콘센트에서 월패드로 제어 요청)
+             * hAirconCtrlCnt                           - (byte) 에어컨 제어 개수
+             * hAirconCtrlID[]                          - (byte) 제어할 에어컨 ID (에어컨 제어 개수 만큼)
+             *
+             * [Device]
+             * 조명 정보
+             * 조명 개수 만큼
+             * {
+             *     bPower            - (byte) 상태
+             *     bDimUsage              - (byte) 모드
+             *     hDimLevel             - (double) 현재 소비전력
+             * }
+             * BatchOffStatus        - (byte) 일괄소등상태
+             *
+             * 콘센트 정보
+             * 콘센트 개수 만큼
+             * {
+             *     Status            - (byte) 상태
+             *     Mode              - (byte) 모드
+             *     NowPw             - (double) 현재 소비전력
+             *     CutOffVal         - (double) 대기전력 차단 기준값
+             * }
+             *
+             */
+
+//            Log.e(TAG, "[RefreshResult] =============== start 1 ===============");
+//            Log.w(TAG, mDriver.Device[Index].device.ToDebugString(Index));
+//            Log.e(TAG, "[RefreshResult] =============== end 1 ===============");
+
+            MultiSwitch Device = mDriver.Device[Index];
+//            Device.setBasicInfo(Device.info.Support.hLightCnt, Device.info.Support.hOutletCnt);
+
+//            Log.e(TAG, "[RefreshResult] =============== start 2 ===============");
+//            Log.w(TAG, Device.device.ToDebugString(Index));
+//            Log.e(TAG, "[RefreshResult] =============== end 2 ===============");
+
+            // 조명, 콘센트 클래스 초기화
+//            Device.setBasicInfo(mDriver.Device[Index].info.Support.hLightCnt, mDriver.Device[Index].info.Support.hOutletCnt);
+            // 에어컨 제어 클래스 초기화
+//            Device.setAirconInfo(mDriver.Device[Index].info.Support.hAirconCtrlCnt, mDriver.Device[Index].info.Support.hAirconCtrlID);
+
+            result = APIErrorCode.SUCCESS + ";";
+            result += Index + ";";
+
+            // Install
+            result += Device.info.Install + ";";
+            if (!Device.info.Install) return result;
+
+            // Info
+            result += Device.info.Vender + ";" +
+                    Device.info.FwVer_Year + ";" +
+                    Device.info.FwVer_Month + ";" +
+                    Device.info.FwVer_Day + ";" +
+                    Device.info.FwVer_Number + ";" +
+                    Device.info.ProtocolVer_Main + ";" +
+                    Device.info.ProtocolVer_Sub + ";";
+
+            //SupportInfo
+            result += Device.info.Support.hLightCnt + ";" +
+                    Device.info.Support.hOutletCnt + ";" +
+                    Device.info.Support.bV2CMDUsage + ";" +
+                    Device.info.Support.bDim + ";" +
+                    Device.info.Support.hDimLevel + ";" +
+                    Device.info.Support.hDimEnabledCircuit + ";" +
+                    Device.info.Support.bAirconCtrl + ";";
+            // 에어컨 제어 ID
+            if (Device.info.Support.bAirconCtrl) {
+                result += Device.info.Support.hAirconCtrlCnt + ";";
+                for (byte i = 0; i < Device.info.Support.hAirconCtrlCnt; i++) {
+                    result += Device.info.Support.hAirconCtrlID[i] + ";";
+                }
+            }
+
+            // 조명
+//            Log.e(TAG, "[RefreshResult] Device.device.hLightCnt: " + Device.device.hLightCnt);
+            result += Device.device.hLightCnt + ";";
+            for (byte i = 0; i < Device.device.hLightCnt; i++) {
+                result += Device.device.getLightPower(i) + ";";
+                result += Device.device.getLightDimUsage(i) + ";";
+                result += Device.device.getLightDimLevel(i) + ";";
+            }
+            result += Device.device.hBatchOffStatus + ";";
+
+            // 콘센트
+            result += Device.device.hOutletCnt + ";";
+            if (Device.device.hOutletCnt > 0) {
+                MultiSwitch.Device.Outlet outlet = null;
+                for (byte i = 0; i < Device.device.hOutletCnt; i++) {
+                    outlet = Device.device.getOutletStatus(i);
+                    if (outlet == null) {
+                        Log.e(TAG, "[RefreshResult] getOutletStatus is null !!!");
+                        return "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
+                    }
+                    result += outlet.Status + ";";
+                    result += outlet.Mode + ";";
+                    result += outlet.NowPw + ";";
+                    result += outlet.CutOffVal + ";";
+                }
+            }
+
+        } catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+            result = "FAIL;"+APIErrorCode.EXCEPTION;
+        } catch (Exception e) {
+            Log.e(TAG, "[Exception Error] RefreshResult");
+            //e.printStackTrace();
+            LogUtil.errorLogInfo("", TAG, e);
+            result = "FAIL;"+APIErrorCode.EXCEPTION;
+        }
+        DeviceLog("RefreshResult return : " + result);
+
+        return result;
+    }
+
+    /**
+     * GetDeviceCount 에 대한 응답포멧 정의
+     *
+     * @return (String) "SUCCESS; ..." 성공 , "FAIL; ... " 실패
+     */
+    private String RefreshResult_GetDeviceCount() {
+        String result = null;
+
+        DeviceLog("RefreshResult_GetDeviceCount call : ");
+
+        // 1. Check Polling Status
+        if ((mDriver.Polling.Status == Driver.PollingList.STATUS.First) || (mDriver.Polling.Status == Driver.PollingList.STATUS.FirstTimeOut)) {
+            result = "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
+            return result;
+        }
+
+        // 2. Param Range Check
+
+        // 3. Make Return String Format
+        try {
+            if (mDriver == null) return "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
+            if (mDriver.Polling == null) return "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
+
+            /*
+             * [Format]
+             *
+             * SUCCESS        - (String) 성공
+             *
+             * DeviceCount    - (byte) 기기개수
+             */
+            result = APIErrorCode.SUCCESS + ";";
+            result += mDriver.Polling.SearchDeviceCount + ";";
+        } catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+            result = "FAIL;"+APIErrorCode.EXCEPTION;
+        } catch (Exception e) {
+            Log.e(TAG, "[Exception Error] RefreshResult_GetDeviceCount");
+            //e.printStackTrace();            
+            LogUtil.errorLogInfo("", TAG, e);
+            result = "FAIL;"+APIErrorCode.EXCEPTION;
+        }
+        DeviceLog("RefreshResult_GetDeviceCount return : " + result);
+
+        return result;
+    }
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    // Protocol Command Send Func
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+     * 기기 상태 읽기 요청/응답
+     *
+     * @param DeviceIdx - (byte) 요청할 기기 인덱스
+     *
+     * @return (MultiSwitch.Info) 기기정보 null - Error , Not null - OK
+     */
+    private MultiSwitch.Info Send_GetDeviceInfo(byte DeviceIdx) {
+        DeviceLog("[Send_GetDeviceInfo] Start");
+
+        // 1. In 파라미터 확인
+        if ((DeviceIdx < 0) || (DeviceIdx >= MAX_DEVICE_COUNT)) {
+            Log.w(TAG, "[Send_GetDeviceInfo] param [DeviceIdx] Out of Range!!! " + DeviceIdx);
+            return null;
+        }
+
+        // 2. 패킷 데이터 만들기
+        byte[] ReqData = null;
+
+        // 3. 데이터 전송 및 응답
+        byte[] Reply = SendNRead_Variable((byte) (DEVICE_ADDRESS + DeviceIdx), CMDList.Req.GetDeviceInfo, ReqData);
+
+        // 4. 수신데이터 파싱
+        //     4.1. Default Check
+        if (Reply == null) {
+            DeviceLog("[Send_GetDeviceInfo] Reply is null");
+            return null;
+        }
+
+        if (Reply.length != 9) {
+            Log.w(TAG, "[Send_GetDeviceInfo] Reply.length  fail ... " + Reply.length);
+            return null;
+        }
+
+        byte data = 0x00;
+        int index = 0;
+
+        //     4.1. Details Data Check
+        //         - 설치된 조명 개수 X’00’ ~ X’08’
+        data = Reply[index++];
+        if (!((data >= 0x00) && (data <= MAX_LIGHT_COUNT))) {
+            Log.w(TAG, "[Send_GetDeviceInfo] LightCount -  Out of Range !!! " + ToByteString(data));
+            return null;
+        }
+
+        //         - 설치된 콘센트 개수 X’00’ ~ X’08’
+        data = Reply[index++];
+        if (!((data >= 0x00) && (data <= MAX_OUTLET_COUNT))) {
+            Log.w(TAG, "[Send_GetDeviceInfo] ConcentCount -  Out of Range !!! " + ToByteString(data));
+            return null;
+        }
+
+        //         - 제조사 구분정보 및 시간정보
+        data = Reply[index++];
+        if ((data & BIT7) != 0x00) {
+            data = (byte) (data & ~BIT7);
+        }
+
+        if (!(data >= 0x01)) {
+            Log.w(TAG, "[Send_GetDeviceInfo] Vender - Out of Range !!! " + ToByteString(data));
+            return null;
+        }
+
+        //         - 펌웨어 Build Date (Year)
+        data = Reply[index++];
+
+        //         - 펌웨어 Build Date (Month)
+        data = Reply[index++];
+        if (!((data >= 0x01) && (data <= 0x0C))) {
+            Log.w(TAG, "[Send_GetDeviceInfo] Build Date (Month) - Out of Range !!! " + ToByteString(data));
+            return null;
+        }
+
+        //         - 펌웨어 Build Date (Day)
+        data = Reply[index++];
+        if (!((data >= 0x01) && (data <= 0x1F))) {
+            Log.w(TAG, "[Send_GetDeviceInfo] Build Date (Day) - Out of Range !!! " + ToByteString(data));
+            return null;
+        }
+
+        // 5. Data return
+        MultiSwitch.Info info = new MultiSwitch.Info();
+        index = 0;
+
+        info.Install = true;
+        info.Support.hLightCnt       = Reply[index++];
+        info.Support.hOutletCnt     = Reply[index++];
+
+        /** Vendor And TimeShow **/
+        byte VendorData = Reply[index++];
+        if ((VendorData & BIT7) != 0x00) {
+            DeviceLog("[Send_GetDeviceInfo] bTimeSync is Enable!!!");
+            info.Support.bTimeSync = true;
+            VendorData = (byte) (VendorData & ~BIT7);
+        }
+        else {
+            info.Support.bTimeSync = false;
+        }
+
+        if ((VendorData & BIT6) != 0x00) {
+            DeviceLog("[Send_GetDeviceInfo] bV2CMDUsage is Enable!!!");
+            info.Support.bV2CMDUsage = true;
+            VendorData = (byte) (VendorData & ~BIT6);
+        }
+        else {
+            info.Support.bV2CMDUsage = false;
+        }
+
+        info.Vender           = VendorData;
+
+        info.FwVer_Year       = Reply[index++];
+        info.FwVer_Month      = Reply[index++];
+        info.FwVer_Day        = Reply[index++];
+        info.FwVer_Number     = Reply[index++];
+        info.ProtocolVer_Main = Reply[index++];
+        info.ProtocolVer_Sub  = Reply[index++];
+
+        try {
+            if (!Version.getGatewayUsage() || Version.getModelType() == Version.MODEL_TYPE.IHN_1010GL || Version.getModelType() == Version.MODEL_TYPE.IHN_1010GL_I
+                    || Version.getModelType() == Version.MODEL_TYPE.IHN_1010GL_I_2443ALT || Version.getModelType() == Version.MODEL_TYPE.IHN_1010GL_I_6410ALT) {
+                // 대외향 모델 + IHN-1010GL-I
+                WallpadStatusData SetData = new WallpadStatusData(ServiceMain.svcContext);
+                wallpaddbmgr.AddressSet addc = SetData.getAddressMGR();
+                if (!isSystemIPSet()) {
+                    Log.d(TAG, "[Send_GetDeviceInfo] The IP Address of OS is not set!");
+                }
+                else if (addc.Dong.equals("NONE") || addc.Ho.equals("NONE")) {
+                    Log.d(TAG, "[Send_GetDeviceInfo] The info. of resi. is not set! [primary db]");;
+                }
+                else {
+                    if (info.Support.hOutletCnt > 0) {
+                        boolean concentUse = SetData.Get_MultiSwitch_Concent_Use();
+                        Log.i(TAG, "[Send_GetDeviceInfo] concentUse [" + concentUse + "]");
+                        if (!concentUse) {
+                            SetData.Set_MultiSwitch_Concent_Use(true);
+                            Log.w(TAG, "[Send_GetDeviceInfo] ####### MultiSwitch Concent Use ---> Reboot #######");
+
+                            // 재부팅 설정 - 5초
+                            V40IF mV40IF = new V40IF();
+                            mV40IF.setV40Reboot(5);
+                        }
+                    }
+                }
+                SetData.closeDB();
+            }
+        } catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+        } catch (Exception me) {
+            //me.printStackTrace();
+            LogUtil.errorLogInfo("", TAG, me);
+        }
+
+
+        return info;
+    }
+
+    public boolean isSystemIPSet() {
+        try {
+            Log.i(TAG, "[isSystemIPSet] START!");
+
+            String strResult = "";
+            if (Build.VERSION.SDK_INT > 23) {
+                // Android 7
+                strResult = getIPAddress();
+            }
+            else {
+                // Android 6
+                if(NetworkInterface.getByName("eth0")!=null)
+                {
+                    String strNetInfo = NetworkInterface.getByName("eth0").toString();
+                    Log.i(TAG, "[isSystemIPSet] strNetInfo : " + strNetInfo + "]");
+                    strNetInfo.trim();
+
+                    String[] Parse_01 = strNetInfo.split("\\]");
+//            for (int i = 0; i < Parse_01.length; i++) {
+//                LOG_DEBUG("[getDeviceIPAddress] Parse_01[" + i + "] : " + Parse_01[i]);
+//            }
+
+                    String[] Parse_02 = Parse_01[Parse_01.length - 1].split("\\/");
+//            for (int i = 0; i < Parse_02.length; i++) {
+//                LOG_DEBUG("[getDeviceIPAddress] Parse_02[" + i + "] : " + Parse_02[i]);
+//            }
+
+                    strResult = Parse_02[1];
+                }
+
+            }
+
+            Log.i(TAG, "[isSystemIPSet] DONE! [IP Address : " + strResult + "]");
+
+            Pattern mPattern = Pattern.compile("^(([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.){3}([01]?\\d\\d?|2[0-4]\\d|25[0-5])$");
+
+            return mPattern.matcher(strResult).matches();
+
+        } catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+            return false;
+        }
+        catch (Exception e) {
+            Log.e(TAG, "[Exception] isSystemIPSet()");
+
+            LogUtil.errorLogInfo("", TAG, e);
+            return false;
+        }
+    }
+
+    public static String getIPAddress() {
+        try {
+            List<NetworkInterface> interfaces = Collections.list(NetworkInterface.getNetworkInterfaces());
+            for (NetworkInterface intf : interfaces) {
+                List<InetAddress> addrs = Collections.list(intf.getInetAddresses());
+                for (InetAddress addr : addrs) {
+                    if (!addr.isLoopbackAddress()) {
+                        String sAddr = addr.getHostAddress();
+                        //boolean isIPv4 = InetAddressUtils.isIPv4Address(sAddr);
+                        boolean isIPv4 = sAddr.indexOf(':')<0;
+
+                        if (isIPv4) return sAddr;
+                    }
+                }
+            }
+        } catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+        } catch (Exception e) {
+            Log.e(TAG, "[Exception] isSystemIPSet()");
+
+            LogUtil.errorLogInfo("", TAG, e);
+        }
+        return "";
+    }
+
+    /**
+     * 조명&콘센트 상태 요청/응답
+     *
+     * @param DeviceIdx - (byte) 요청할 기기 인덱스
+     *
+     * @return (MultiSwitch.Device) 기기상태 null - Error , Not null - OK
+     */
+    private MultiSwitch.Device Send_GetLightConcentStatus(byte DeviceIdx) {
+        DeviceLog("[Send_GetLightConcentStatus] Start");
+
+        // 1. In 파라미터 확인
+        if ((DeviceIdx < 0) || (DeviceIdx >= MAX_DEVICE_COUNT)) {
+            Log.w(TAG, "[Send_GetLightConcentStatus] param [DeviceIdx] Out of Range!!! " + DeviceIdx);
+            return null;
+        }
+
+        // 2. 패킷 데이터 만들기
+        byte[] ReqData = null;
+
+        // 3. 데이터 전송 및 응답
+        byte[] Reply = SendNRead_Variable((byte)(DEVICE_ADDRESS + DeviceIdx), CMDList.Req.GetLightConcentStatus, ReqData);
+
+        // 4. 수신데이터 파싱
+        MultiSwitch.Device device = ReplyParsing(Reply);
+        if (device == null) {
+            DeviceLog("[Send_GetLightConcentStatus] Reply is null");
+            AddDoCount(DeviceIdx, false);
+            return null;
+        }
+        AddDoCount(DeviceIdx, true);
+
+        return device;
+    }
+
+    /**
+     * 조명 콘센트 제어 요청/응답
+     *
+     * @param DeviceIdx - (byte) 요청할 기기 인덱스
+     * @param ctrlCmd   - (CtrlCmd) 제어 데이터 클래스
+     *
+     * @return (MultiSwitch.Device) 기기상태 null - Error , Not null - OK
+     */
+    private MultiSwitch.Device Send_SetLightConcentStatus(byte DeviceIdx, CtrlCmd ctrlCmd) {
+        DeviceLog("[Send_SetLightConcentStatus] Start");
+
+        // 1. In 파라미터 확인
+        if ((DeviceIdx < 0) || (DeviceIdx >= MAX_DEVICE_COUNT)) {
+            Log.w(TAG, "[Send_SetLightConcentStatus] param [DeviceIdx] Out of Range!!! " + DeviceIdx);
+            return null;
+        }
+
+        if (ctrlCmd == null) {
+            Log.w(TAG, "[Send_SetLightConcentStatus] param [ctrlCmd] is null !!!");
+            return null;
+        }
+
+        // 2. 패킷 데이터 만들기
+        byte [] ReqData = ctrlCmd.getBytes();
+        if (ReqData == null) {
+            Log.w(TAG, "[Send_SetLightConcentStatus] param [ctrlCmd.getBytes] is null !!!");
+            return null;
+        }
+
+        // 3. 데이터 전송 및 응답
+        byte[] Reply = SendNRead_Variable((byte)(DEVICE_ADDRESS + DeviceIdx), CMDList.Req.SetLightConcentStatus, ReqData);
+
+        // 4. 수신데이터 파싱
+        MultiSwitch.Device device = ReplyParsing(Reply);
+        if (device == null) {
+            DeviceLog("[Send_SetLightConcentStatus] Reply is null");
+            AddDoCount(DeviceIdx, false);
+            return null;
+        }
+        AddDoCount(DeviceIdx, true);
+
+        return device;
+    }
+
+    /**
+     * {@link #Send_GetLightConcentStatus(byte DeviceIdx)} <br>
+     * {@link #Send_SetLightConcentStatus(byte DeviceIdx, CtrlCmd ctrlCmd)} <br>
+     *
+     * 메소드의 응답 공통부분 메소드이다.
+     *
+     * @param Reply      - (byte []) 응답 Byte 배열
+     *
+     * @return (MultiSwitch.Device) 기기상태 null - Error , Not null - OK
+     */
+    private MultiSwitch.Device ReplyParsing(byte [] Reply) {
+        // 1. 수신데이터 파싱
+        //     1.1. Default Check
+        if (Reply == null) {
+            DeviceLog("[ReplyParsing] Reply is null");
+            return null;
+        }
+
+        //     데이터는 최소 4바이트 이상임.
+        if (Reply.length < 4) {
+            Log.w(TAG, "[ReplyParsing] Reply.length  fail #1 ... " + Reply.length);
+            return null;
+        }
+
+        int index = 0;
+        byte data = 0x00;
+        //     1.2. Details Data Check
+        //          - D1 : 설치된 조명 개수
+        data = Reply[index++];
+        if ((data > MAX_LIGHT_COUNT) || (data < 0)) {
+            Log.w(TAG, "[ReplyParsing] D1 (LightCount) : Out Of Range " + ToByteString(data));
+            return null;
+        }
+        byte LightCount = data;
+
+        //          - D2 : 조명 ON/OFF 상태
+        data = Reply[index++];
+
+        //          - D3 : 조명 일괄소등 상태
+        data = Reply[index++];
+        if (!MultiSwitch.BATCHOFF_STATUS.checkRange(data)) {
+            Log.w(TAG, "[ReplyParsing] D3 (BatchOffStatus) : Out Of Range " + ToByteString(data));
+            return null;
+        }
+
+        //          - D4 : 설치된 콘센트 개수
+        data = Reply[index++];
+        if ((data > MAX_OUTLET_COUNT) || (data < 0)) {
+            Log.w(TAG, "[ReplyParsing] D4 (ConcentCount) : Out Of Range " + ToByteString(data));
+            return null;
+        }
+
+        //           - 콘센트 개수에 따른 패킷 데이터 길이 체크
+        byte ConcentCount = data;
+        int CalcLength = (int)((ConcentCount * 5) + 4);
+        if (CalcLength != Reply.length) {
+            Log.w(TAG, "[ReplyParsing] Reply.length  fail #2... (CalcLength:" + CalcLength + ", Reply.length:" + Reply.length + ")");
+            return null;
+        }
+
+        if (ConcentCount > 0) {
+            for (byte i = 0; i < ConcentCount; i++) {
+                data = Reply[index++];
+
+                if (!MultiSwitch.OUTLET_STATUS.checkRange((byte)(data & (BIT0 | BIT1 | BIT2)))) {
+                    Log.w(TAG, "[ReplyParsing] CONCENT_STATUS.CheckRange fail... " + ToByteString(data) + " , i:" + i);
+                    return null;
+                }
+
+                if (!MultiSwitch.OUTLET_MODE.checkRange((byte)((data >> 4) & (BIT0 | BIT1)))) {
+                    Log.w(TAG, "[ReplyParsing] CONCENT_MODE.CheckRange fail... " + ToByteString(data) + " , i:" + i);
+                    return null;
+                }
+                index += 4;
+            }
+        }
+
+        // 2. Data return
+        index = 0;
+        data = 0x00;
+        MultiSwitch.Device device = new MultiSwitch.Device(LightCount, ConcentCount);
+
+        //          - D1 : 설치된 조명 개수
+        index++;
+
+        //          - D2 : 조명 ON/OFF 상태
+        data = Reply[index++];
+        for (byte i = 0; i < LightCount; i++) {
+            if ((data & BIT_ARRAY[i]) != 0x00) device.setLightPower(i, true);
+        }
+
+        //          - D3 : 조명 일괄소등 상태
+        data = Reply[index++];
+        device.hBatchOffStatus = data;
+
+        //          - D4 : 설치된 콘센트 개수
+        index++;
+
+        //          - D5 ~ 콘센트 상태
+        if (ConcentCount > 0) {
+            byte Hi, Low;
+            byte Status;
+            byte Mode;
+            double NowPw;
+            double CutOffVal;
+            for (byte i = 0; i < ConcentCount; i++) {
+                data = Reply[index++];
+
+                Status = (byte)(data & (BIT0 | BIT1 | BIT2));
+                Mode   = (byte)((data >> 4) & (BIT0 | BIT1));
+
+                Hi  = Reply[index++];
+                Low = Reply[index++];
+                NowPw = Converter2ByteToDoubleP1(Hi, Low);
+
+                Hi  = Reply[index++];
+                Low = Reply[index++];
+                CutOffVal = Converter2ByteToDoubleP1(Hi, Low);
+
+                device.setOutlet(i, Status, Mode, NowPw, CutOffVal);
+            }
+        }
+
+        return device;
+    }
+
+    /**
+     * 시간 정보 알림/응답
+     *
+     * @param DeviceIdx - (byte) 시간을 동기화할 기기 인덱스 (시간 정보 사용구분자가 true 인 경우에만 전송)
+     *
+     * @return (MultiSwitch.Device) 기기상태 null - Error , Not null - OK
+     */
+    private MultiSwitch.Device Send_Time(byte DeviceIdx) {
+        DeviceLog("[Send_Time] Start");
+
+        // 1. In 파라미터 확인
+        if ((DeviceIdx < 0) || (DeviceIdx >= MAX_DEVICE_COUNT)) {
+            Log.w(TAG, "[Send_Time] param [DeviceIdx] Out of Range!!! " + DeviceIdx);
+            return null;
+        }
+
+        // 2. 패킷 데이터 만들기
+        byte [] ReqData = new byte[6];
+        Calendar cal = new GregorianCalendar();
+        ReqData[0] = (byte) (cal.get(Calendar.YEAR) - 2000);
+        ReqData[1] = (byte) (cal.get(Calendar.MONTH) + 1);
+        ReqData[2] = (byte) cal.get(Calendar.DAY_OF_MONTH);
+        ReqData[3] = (byte) cal.get(Calendar.HOUR_OF_DAY);
+        ReqData[4] = (byte) cal.get(Calendar.MINUTE);
+        ReqData[5] = (byte) cal.get(Calendar.SECOND);
+
+        // 3. 데이터 전송 및 응답
+        byte [] Reply = SendNRead_Variable( (byte)(DEVICE_ADDRESS + DeviceIdx), CMDList.Req.SetTimeInfo, ReqData);
+
+        // 4. 수신데이터 파싱
+        MultiSwitch.Device device = ReplyParsing(Reply);
+        if (device == null) {
+            DeviceLog("[Send_Time] Reply is null");
+            AddDoCount(DeviceIdx, false);
+            return null;
+        }
+        AddDoCount(DeviceIdx, true);
+
+        return device;
+    }
+
+
+
+
+
+
+    /**
+     * 기기 상태 읽기 요청/응답 V2
+     *
+     * @param DeviceIdx - (byte) 요청할 기기 인덱스
+     *
+     * @return (MultiSwitch.Info) 기기정보 null - Error , Not null - OK
+     */
+    private MultiSwitch.Info sendGetDeviceInfoV2(byte DeviceIdx, MultiSwitch.Info mInfo) {
+        try {
+            DeviceLog("[Send_GetDeviceInfoV2] Start");
+
+            // 1. In 파라미터 확인
+            if ((DeviceIdx < 0) || (DeviceIdx >= MAX_DEVICE_COUNT)) {
+                Log.w(TAG, "[Send_GetDeviceInfoV2] param [DeviceIdx] Out of Range!!! " + DeviceIdx);
+                return null;
+            }
+
+            // 2. 패킷 데이터 만들기
+            byte [] ReqData = null;
+
+            // 3. 데이터 전송 및 응답
+            byte [] Reply = SendNRead_Variable((byte) (DEVICE_ADDRESS + DeviceIdx), CMDList.Req.GetDeviceInfoV2, ReqData);
+
+            // 4. 수신데이터 파싱
+            MultiSwitch.Info info = parsingReply_GetDeviceInfoV2(Reply, mInfo);
+
+            // 5. 수신데이터 파싱결과 확인
+            if (info == null) {
+                DeviceLog("[sendGetDeviceInfoV2] Reply is null");
+                AddDoCount(false);
+                return null;
+            }
+
+            AddDoCount(true);
+
+            // 4. 수신데이터 파싱
+            //     4.1. Default Check
+            if (Reply == null) {
+                DeviceLog("[Send_GetDeviceInfoV2] Reply is null");
+                return null;
+            }
+
+            return info;
+        } catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+            return null;
+        } catch (Exception e) {
+            Log.e(TAG, "[Exception] sendGetDeviceInfoV2()");
+            //e.printStackTrace();
+            LogUtil.errorLogInfo("", TAG, e);
+            return null;
+        }
+    }
+
+    /**
+     * 메소드의 응답 공통부분 메소드이다.
+     *
+     * @param ahReply      - (byte []) 응답 Byte 배열
+     *
+     * @return (Info) null - Error , Not null - OK
+     */
+    private MultiSwitch.Info parsingReply_GetDeviceInfoV2(byte[] ahReply, MultiSwitch.Info mInfo) {
+        try {
+            // 1. 수신데이터 파싱
+            //     1.1. Default Check
+            if (ahReply == null) {
+                DeviceLog("[parsingReply_GetDeviceInfoV2] ahReply is null");
+                return null;
+            }
+
+            MultiSwitch.Info mInfoV2 = new MultiSwitch.Info();
+
+            // 최소 데이터 길이 확인
+            if (ahReply.length < 2) {
+                Log.w(TAG, "[parsingReply_GetDeviceInfoV2] Minimum Reply.length  fail!! (must be longer than 2bytes!! ahReply.length:" + ahReply.length + ")");
+                return null;
+            }
+
+            //     1.2. Details Data Check
+            //         - D1 : 기능 제공 여부 1
+            if ((ahReply[0] & (byte)(BIT2 | BIT3 | BIT4 | BIT5 | BIT6 | BIT7)) != 0x00) {
+                Log.w(TAG, "[parsingReply_GetDeviceInfoV2] D1 (DefultFuncInfo) : Unused Bit Set !!! " + String.format("0x%02X", ahReply[0]));
+                return null;
+            }
+
+            // 조명 디밍 지원
+            if ((ahReply[0] & BIT0) != 0x00) mInfoV2.Support.bDim = true;
+            else mInfoV2.Support.bDim = false;
+
+            // 에어컨 제어
+            if ((ahReply[0] & BIT1) != 0x00) mInfoV2.Support.bAirconCtrl = true;
+            else mInfoV2.Support.bAirconCtrl = false;
+
+            //         - D2 : 기능 제공 여부 2
+            if ((ahReply[1] & (byte)(BIT0 | BIT1 | BIT2 | BIT3 | BIT4 | BIT5 | BIT6 | BIT7)) != 0x00) {
+                Log.w(TAG, "[parsingReply_GetDeviceInfoV2] D2 (DefultFuncInfo) : Unused Bit Set !!! " + String.format("0x%02X", ahReply[1]));
+                return null;
+            }
+
+            /** Data length check */
+            int nExpectLength = 2;   // D1, D2
+            int nAirconCnt = 0;   // 에어컨 제어시 제어 에어컨 개수
+            if (mInfoV2.Support.bDim) nExpectLength += 2;
+            if (mInfoV2.Support.bAirconCtrl) {
+                nAirconCnt = ahReply[nExpectLength];
+                nExpectLength += 1 + nAirconCnt;
+            }
+
+            if (ahReply.length != nExpectLength) {
+                Log.w(TAG, "[parsingReply_GetDeviceInfoV2] Reply.length  fail!! (nExpectLength:" + nExpectLength + ", ahReply.length:" + ahReply.length + ")");
+                return null;
+            }
+
+            // D3
+            int nIndex = 2;
+            byte data;
+            if (mInfoV2.Support.bDim) {
+                data = ahReply[nIndex++];
+                if (data < 0 || 100 < data) {
+                    Log.w(TAG, "[parsingReply_GetDeviceInfoV2] D" + (nIndex - 1) + " (DimLevel) - Out of range!! -> " + String.format("0x%02X", data));
+                    return null;
+                }
+                mInfoV2.Support.hDimLevel = data;
+                data = ahReply[nIndex++];
+                mInfoV2.Support.hDimEnabledCircuit = data;
+            }
+
+            if (mInfoV2.Support.bAirconCtrl) {
+                data = ahReply[nIndex++];
+                if (data < 1 || 15 < data) {
+                    Log.w(TAG, "[parsingReply_GetDeviceInfoV2] D" + (nIndex - 1) + " (AirconCnt) - Out of range!! -> " + String.format("0x%02X", data));
+                    return null;
+                }
+                mInfoV2.Support.hAirconCtrlCnt = data;
+                mInfoV2.Support.hAirconCtrlID = new byte[mInfoV2.Support.hAirconCtrlCnt];
+//                Log.w(TAG, "[parsingReply_GetDeviceInfoV2] mInfoV2.Support.hAirconCtrlCnt -> " + mInfoV2.Support.hAirconCtrlCnt);
+                for (int i = 0; i < mInfoV2.Support.hAirconCtrlCnt; i++) {
+                    data = ahReply[nIndex++];
+                    mInfoV2.Support.hAirconCtrlID[i] = data;
+//                    Log.w(TAG, "[parsingReply_GetDeviceInfoV2] mInfoV2.Support.hAirconCtrlID[" + i + "] = " + mInfoV2.Support.hAirconCtrlID[i]);
+                }
+            }
+
+            mInfo.Support.bDim = mInfoV2.Support.bDim;
+            mInfo.Support.hDimLevel = mInfoV2.Support.hDimLevel;
+            mInfo.Support.hDimEnabledCircuit = mInfoV2.Support.hDimEnabledCircuit;
+            mInfo.Support.bAirconCtrl = mInfoV2.Support.bAirconCtrl;
+            mInfo.Support.hAirconCtrlCnt = mInfoV2.Support.hAirconCtrlCnt;
+            mInfo.Support.hAirconCtrlID = mInfoV2.Support.hAirconCtrlID;
+
+            return mInfo;
+        } catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+            return null;
+        } catch (Exception e) {
+            Log.e(TAG, "[Exception] parsingReply_GetDeviceInfoV2(byte[] ahReply, MultiSwitch.Info mInfo)");
+            //e.printStackTrace();
+            LogUtil.errorLogInfo("", TAG, e);
+            return null;
+        }
+    }
+
+
+
+
+    /**
+     * 조명&콘센트 상태 요청/응답
+     *
+     * @param DeviceIdx - (byte) 요청할 기기 인덱스
+     *
+     * @return (MultiSwitch.Device) 기기상태 null - Error , Not null - OK
+     */
+    private MultiSwitch.Device sendGetDeviceStatusV2(byte DeviceIdx) {
+        try {
+//            DeviceLog("[sendGetDeviceStatusV2] Start DeviceIdx = [" + ToByteString(DeviceIdx) + "]");
+
+            // 1. In 파라미터 확인
+            if ((DeviceIdx < 0) || (DeviceIdx >= MAX_DEVICE_COUNT)) {
+                Log.w(TAG, "[sendGetDeviceStatusV2] param [DeviceIdx] Out of Range!!! " + DeviceIdx);
+                return null;
+            }
+
+            // 2. 패킷 데이터 만들기
+            byte [] ReqData = null;
+            if (mDriver.Device[DeviceIdx].info.Support.bAirconCtrl) {
+                // 2. 패킷 데이터 만들기
+                byte hOption = (byte) 0x00;
+                hOption |= BIT0;
+
+                if (mDriver.Device[DeviceIdx] == null) Log.e(TAG, "[sendGetDeviceStatusV2] mDriver.Device[" + ToByteString(DeviceIdx) + "] is null!!");
+
+                if (mDriver.Device[DeviceIdx].device.airconData == null) {
+                    Log.e(TAG, "[sendGetDeviceStatusV2] mDriver.Device[" + ToByteString(DeviceIdx) + "].device.airconData is null!!");
+                    ReqData = new byte[] {(byte) 0x00};
+                }
+                else {
+//                    Log.e(TAG, "[sendGetDeviceStatusV2] ===== driver aircon start =====");
+//                    Log.i(TAG, mDriver.Device[DeviceIdx].device.airconData.ToDebugString(DeviceIdx));
+//                    Log.e(TAG, "[sendGetDeviceStatusV2] ===== driver aircon end =====");
+
+                    MultiSwitch.Device.AirconData airconData = mDriver.Device[DeviceIdx].device.airconData;
+                    if (airconData == null) Log.e(TAG, "[sendGetDeviceStatusV2] airconData is null!!");
+
+//                    Log.e(TAG, "[sendGetDeviceStatusV2] ===== msg aircon start =====");
+//                    Log.i(TAG, airconData.ToDebugString(DeviceIdx));
+//                    Log.e(TAG, "[sendGetDeviceStatusV2] ===== msg aircon end =====");
+
+                    byte hAirSwing = (byte) 0x00;
+                    if (airconData.bAirSwing) hAirSwing = (byte) 0x01;
+
+                    byte hSetData = (byte) ((int) airconData.hPower + (airconData.hAirVol << 2) + (airconData.hMode << 4) + (hAirSwing << 7));
+
+                    ReqData = new byte[] {hOption, hSetData, airconData.hSetTemper, airconData.hCurrentTemper};
+                }
+            }
+
+            // 3. 데이터 전송 및 응답
+            byte [] Reply = SendNRead_Variable((byte)(DEVICE_ADDRESS + DeviceIdx), CMDList.Req.GetDeviceStatusV2, ReqData);
+
+            // 4. 수신데이터 파싱
+            MultiSwitch.Device device = parsingReply_GetDeviceStatusV2(DeviceIdx, Reply);
+            if (device == null) {
+                DeviceLog("[sendGetDeviceStatusV2] Reply is null");
+                AddDoCount(DeviceIdx, false);
+                return null;
+            }
+            AddDoCount(DeviceIdx, true);
+
+            return device;
+        } catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+            return null;
+        } catch (Exception e) {
+            Log.e(TAG, "[Exception] sendGetDeviceStatusV2(byte DeviceIdx)");
+            //e.printStackTrace();
+            LogUtil.errorLogInfo("", TAG, e);
+            return null;
+        }
+    }
+
+    /**
+     * {@link #Send_GetLightConcentStatus(byte DeviceIdx)} <br>
+     * {@link #Send_SetLightConcentStatus(byte DeviceIdx, CtrlCmd ctrlCmd)} <br>
+     *
+     * 메소드의 응답 공통부분 메소드이다.
+     *
+     * @param Reply      - (byte []) 응답 Byte 배열
+     *
+     * @return (MultiSwitch.Device) 기기상태 null - Error , Not null - OK
+     */
+    private MultiSwitch.Device parsingReply_GetDeviceStatusV2(byte DeviceIdx, byte[] Reply) {
+        try {
+            // 1. 수신데이터 파싱
+            //     1.1. Default Check
+            if (Reply == null) {
+                DeviceLog("[parsingReply_GetDeviceStatusV2] Reply is null");
+                return null;
+            }
+
+            //     데이터는 최소 4바이트 이상임.
+            if (Reply.length < 4) {
+                Log.w(TAG, "[parsingReply_GetDeviceStatusV2] Reply.length fail #1, Must be longer than 4bytes -> Received length: " + Reply.length);
+                return null;
+            }
+
+            int index = 0;
+            byte data = 0x00;
+            //     1.2. Details Data Check
+            //          - D1 : 설치된 조명 개수
+            data = Reply[index++];
+            if ((data > MAX_LIGHT_COUNT) || (data < 0)) {
+                Log.w(TAG, "[parsingReply_GetDeviceStatusV2] D1 (LightCount) : Out Of Range " + ToByteString(data));
+                return null;
+            }
+            byte LightCount = data;
+
+            //          - D2 : 조명 ON/OFF 상태
+            data = Reply[index++];
+
+            //          - D3 : 조명 일괄소등 상태
+            data = Reply[index++];
+            if (!MultiSwitch.BATCHOFF_STATUS.checkRange(data)) {
+                Log.w(TAG, "[parsingReply_GetDeviceStatusV2] D3 (BatchOffStatus) : Out Of Range " + ToByteString(data));
+                return null;
+            }
+
+            //          - Dn : 설치된 콘센트 개수
+            data = Reply[index++];
+            if ((data > MAX_OUTLET_COUNT) || (data < 0)) {
+                Log.w(TAG, "[parsingReply_GetDeviceStatusV2] D4 (OutletCount) : Out Of Range " + ToByteString(data));
+                return null;
+            }
+
+            //           - 콘센트 개수에 따른 패킷 데이터 길이 체크
+            byte OutletCount = data;
+            if (OutletCount > 0) {
+                for (byte i = 0; i < OutletCount; i++) {
+                    data = Reply[index++];
+
+                    if (!MultiSwitch.OUTLET_STATUS.checkRange((byte)(data & (BIT0 | BIT1 | BIT2)))) {
+                        Log.w(TAG, "[parsingReply_GetDeviceStatusV2] CONCENT_STATUS.CheckRange fail... " + ToByteString(data) + " , i:" + i);
+                        return null;
+                    }
+
+                    if (!MultiSwitch.OUTLET_STATUS.checkRange((byte)((data >> 4) & (BIT0 | BIT1)))) {
+                        Log.w(TAG, "[parsingReply_GetDeviceStatusV2] CONCENT_MODE.CheckRange fail... " + ToByteString(data) + " , i:" + i);
+                        return null;
+                    }
+                    index += 4;
+                }
+            }
+
+            // 디밍/에어컨 제어에 따른 데이터 길이 확인
+            int nDimCnt = 0;   // 디밍 조명 개수
+            if (mDriver.Device[DeviceIdx].info.Support.bDim) {
+                /** 디밍 지원 */
+                //          - Dn : 조명 디밍 지원 회로 정보
+                data = Reply[index++];
+                if (data == (byte) 0x00) {
+                    Log.w(TAG, "[parsingReply_GetDeviceStatusV2] D4 (nDimCnt) : Out Of Range " + ToByteString(data));
+                    return null;
+                }
+
+                nDimCnt = Integer.bitCount(data);
+
+                // 디밍 설정 단계
+                for (int i = 0; i < nDimCnt; i++) {
+                    data = Reply[index++];
+                    if (data < 0 && mDriver.Device[DeviceIdx].info.Support.hDimLevel < data) {
+                        Log.w(TAG, "[parsingReply_GetDeviceStatusV2] D4 (hDimLevel[" + i + "]) : Out Of Range: " + ToByteString(data) + ", Enabled dim level: " + mDriver.Device[DeviceIdx].info.Support.hDimLevel);
+                        return null;
+                    }
+                }
+            }
+
+            int nAirconDataLength = 0;
+            if (mDriver.Device[DeviceIdx].info.Support.bAirconCtrl) {
+                /** 에어컨 제어 지원 */
+                //          - Dn : 제어요청 기기 종류
+                data = Reply[index++];
+                if ((data & (byte)(BIT1 | BIT2 | BIT3 | BIT4 | BIT5 | BIT6 | BIT7)) != 0x00) {
+                    Log.w(TAG, "[parsingReply_GetDeviceStatusV2] D" + (index - 1) + " (Ctrl Type) : Unused Bit Set !!! " + String.format("0x%02X", data));
+                    return null;
+                }
+
+                if ((data & (byte)BIT0) != 0x00) {
+                    // 에어컨 제어 요청 있음
+                    // 에어컨 제어 개수 확인
+                    int nAirconIDsCnt = 0;
+                    // 제어 에어컨 ID 1
+                    data = Reply[index++];
+                    nAirconIDsCnt = Integer.bitCount(data);
+                    // 제어 에어컨 ID 2
+                    data = Reply[index++];
+                    nAirconIDsCnt += Integer.bitCount(data);
+                    // 개별 실내기 제어 선택 정보
+                    data = Reply[index++];
+                    if ((data & (byte)(BIT5 | BIT6 | BIT7)) != 0x00) {
+                        Log.w(TAG, "[parsingReply_GetDeviceStatusV2] D" + (index - 1) + " (Ctrl Type) : Unused Bit Set !!! " + String.format("0x%02X", data));
+                        return null;
+                    }
+
+                    // 에어컨 상태 제어
+                    //      1.2. Mode
+                    data = Reply[index++];
+
+                    byte hPower = (byte)(data & (byte) (BIT0 | BIT1));
+                    if (!DataClasses.SystemAircon.POWER.checkPowerRange(hPower)) {
+                        // on/off 상태 확인
+                        Log.w(TAG, "[parsingReply_GetDeviceStatusV2] (hPower) : Out of Range !!! -> " + String.format("0x%02X", hPower));
+                        return null;
+                    }
+
+                    byte hAirVol = (byte)((data >> 2) & (byte) (BIT0 | BIT1));
+                    if (!DataClasses.SystemAircon.AIRVOLUME.checkAirVolRange(hAirVol)) {
+                        // 풍량 범위확인
+                        Log.w(TAG, "[parsingReply_GetDeviceStatusV2] (hAirVol) : Out of Range !!! -> " + String.format("0x%02X", hAirVol));
+                        return null;
+                    }
+
+                    byte hMode = (byte)((data >> 4) & (byte) (BIT0 | BIT1 | BIT2));
+                    if (!DataClasses.SystemAircon.MODE.checkModeRange(hMode)) {
+                        // 운전모드 범위확인
+                        Log.w(TAG, "[parsingReply_GetDeviceStatusV2] (hMode) : Out of Range !!! -> " + String.format("0x%02X", hMode));
+                        return null;
+                    }
+
+                    //     1.4.1 check supported mode
+//                    if (!checkSupportedMode(hMode, DeviceIdx)) {
+//                        Log.w(TAG, "[parsingReply_GetDeviceStatusV2] (hMode) Not support !!! -> " + DataClasses.SystemAircon.MODE.ToDebugString(hMode));
+//                        return null;
+//                    }
+
+                    boolean bAirSwing = false;
+                    if ((data & BIT7) != 0x00) {
+                        // 풍향지원 여부 확인
+                        if (!mDriver.Device[DeviceIdx].device.airconData.bSupportAirSwing) {
+                            Log.w(TAG, "[parsingReply_GetDeviceStatusV2] (bAirSwing) : Out of Range !!! -> " + bAirSwing);
+                            return null;
+                        }
+                        bAirSwing = true;
+                    }
+                    else bAirSwing = false;
+                    
+                    data = Reply[index++];
+
+                    if (data != 0x00) {
+                        if (hMode == DataClasses.SystemAircon.MODE.Cooling) {
+                            if (data < mDriver.Device[DeviceIdx].device.airconData.hMinCoolSetTemper || mDriver.Device[DeviceIdx].device.airconData.hMaxCoolSetTemper < data) {
+                                Log.w(TAG, "[parsingReply_GetDeviceStatusV2] MODE.Cold -> hMinCoolSetTemper [" + mDriver.Device[DeviceIdx].device.airconData.hMinCoolSetTemper + "], hMaxCoolSetTemper [" + mDriver.Device[DeviceIdx].device.airconData.hMaxCoolSetTemper + "], hSetTemper Out Of Range !!! - (" + String.format("0x%02X", data) + ")");
+                                return null;
+                            }
+                        }
+                        else if (hMode == DataClasses.SystemAircon.MODE.Heating) {
+                            if (data < mDriver.Device[DeviceIdx].device.airconData.hMinHeatSetTemper || mDriver.Device[DeviceIdx].device.airconData.hMaxHeatSetTemper < data) {
+                                Log.w(TAG, "[parsingReply_GetDeviceStatusV2] MODE.Cold -> hMinHeatSetTemper [" + mDriver.Device[DeviceIdx].device.airconData.hMinHeatSetTemper + "], hMaxHeatSetTemper [" + mDriver.Device[DeviceIdx].device.airconData.hMaxHeatSetTemper + "], hSetTemper Out Of Range !!! - (" + String.format("0x%02X", data) + ")");
+                                return null;
+                            }
+                        }
+                    }
+
+                    if ((data & (byte)BIT0) != 0x00) nAirconDataLength = 5;
+                }
+                else {
+                    // 에어컨 제어 요청 없음
+                    nAirconDataLength = 1;
+                }
+
+            }
+
+            int nOutletDataLength = (int) (OutletCount * 5);
+            int nDimDataLength = (nDimCnt > 0) ? nDimCnt + 1 : 0;
+            int nExpectedLength = 4 + nOutletDataLength + nDimDataLength + nAirconDataLength;
+//            if (nExpectedLength != Reply.length) {
+//                Log.w(TAG, "[parsingReply_GetDeviceStatusV2] Reply.length fail #2 (nExpectedLength:" + nExpectedLength + ", Reply.length:" + Reply.length + ")");
+//                Log.w(TAG, "[parsingReply_GetDeviceStatusV2] nOutletDataLength [" + nOutletDataLength + "], nDimDataLength [" + nDimDataLength + "], nAirconDataLength [" + nAirconDataLength + "]");
+//                return null;
+//            }
+
+            // 2. Data return
+            index = 0;
+            data = 0x00;
+//            Log.w(TAG, "[parsingReply_GetDeviceStatusV2] LightCount [" + LightCount + "], OutletCount [" + OutletCount + "]");
+            MultiSwitch.Device device = new MultiSwitch.Device(LightCount, OutletCount);
+
+//            Log.w(TAG, "[parsingReply_GetDeviceStatusV2] new hLightCnt [" + device.hLightCnt + "], hOutletCnt [" + device.hOutletCnt + "]");
+            //          - D1 : 설치된 조명 개수
+            index++;
+
+            //          - D2 : 조명 ON/OFF 상태
+            data = Reply[index++];
+            for (byte i = 0; i < LightCount; i++) {
+                if ((data & BIT_ARRAY[i]) != 0x00) device.setLightPower(i, true);
+            }
+
+            //          - D3 : 조명 일괄소등 상태
+            data = Reply[index++];
+            device.hBatchOffStatus = data;
+
+            //          - D4 : 설치된 콘센트 개수
+            index++;
+
+            //          - D5 ~ 콘센트 상태
+            if (OutletCount > 0) {
+                byte Hi, Low;
+                byte Status;
+                byte Mode;
+                double NowPw;
+                double CutOffVal;
+                for (byte i = 0; i < OutletCount; i++) {
+                    data = Reply[index++];
+
+                    Status = (byte)(data & (BIT0 | BIT1 | BIT2));
+                    Mode   = (byte)((data >> 4) & (BIT0 | BIT1));
+
+                    Hi  = Reply[index++];
+                    Low = Reply[index++];
+                    NowPw = Converter2ByteToDoubleP1(Hi, Low);
+
+                    Hi  = Reply[index++];
+                    Low = Reply[index++];
+                    CutOffVal = Converter2ByteToDoubleP1(Hi, Low);
+
+                    device.setOutlet(i, Status, Mode, NowPw, CutOffVal);
+                }
+            }
+
+            // 조명 디밍 정보
+            if (mDriver.Device[DeviceIdx].info.Support.bDim) {
+                data = Reply[index++];
+                for (byte i = 0; i < LightCount; i++) {
+                    if ((data & BIT_ARRAY[i]) != 0x00) device.setLightDimUsage(i, true);
+                }
+
+                for (int i = 0; i < device.hLightCnt; i++) {
+                    if (device.getLightDimUsage(i)) device.setLightDimLevel(i, Reply[index++]);
+                }
+            }
+
+            if (mDriver.Device[DeviceIdx].info.Support.bAirconCtrl) {
+                device.ctrlReq = new MultiSwitch.Device.CtrlReq((byte) 16);   // 에어컨 ID 필드 -> 추후 확인
+            }
+
+            // 에어컨 제어 정보
+            if (mDriver.Device[DeviceIdx].info.Support.bAirconCtrl) {
+                device.airconData = new MultiSwitch.Device.AirconData(mDriver.Device[DeviceIdx].info.Support.hAirconCtrlCnt);
+                byte hCtrlReq = Reply[index++];
+                if ((hCtrlReq & (byte)BIT0) != 0x00) {
+                    device.ctrlReq.bAircon = true;
+
+                    index++;   // 에어컨 ID 필드(2Bytes) > 추후 확인
+                    index++;   // 에어컨 ID 필드(2Bytes) > 추후 확인
+                    
+                    data = Reply[index++];
+                    device.ctrlReq.hAirconCtrlOption = data;
+
+                    data = Reply[index++];
+                    device.ctrlReq.hAirconStatus = data;
+
+                    data = Reply[index++];
+                    device.ctrlReq.hSetTemper = data;
+                }
+                else {
+                    device.ctrlReq.bAircon = false;
+                }
+            }
+
+            // 에어컨 데이터를 넣어준다.
+            if (mDriver.Device[DeviceIdx].info.Support.bAirconCtrl) device.airconData.setAirconStatus(mDriver.Device[DeviceIdx].device.airconData);
+            else device.ctrlReq = new MultiSwitch.Device.CtrlReq((byte) 0x00);
+
+            return device;
+        } catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+            return null;
+        } catch (Exception e) {
+            Log.e(TAG, "[Exception] parsingReply_GetDeviceStatusV2(byte[] Reply)");
+            //e.printStackTrace();
+            LogUtil.errorLogInfo("", TAG, e);
+            return null;
+        }
+    }
+
+    /**
+     * 제어할 운전모드 지원여부 확인
+     * @param hMode
+     * @return true: 지원함, false: 지원안함
+     */
+    private boolean checkSupportedMode(byte hMode, byte DeviceIdx) {
+        try {
+            if (hMode == DataClasses.SystemAircon.MODE.Cooling && mDriver.Device[DeviceIdx].device.airconData.bSupportModeCooling) return true;
+            else if (hMode == DataClasses.SystemAircon.MODE.Dehumidify && mDriver.Device[DeviceIdx].device.airconData.bSupportModeDehumidify) return true;
+            else if (hMode == DataClasses.SystemAircon.MODE.Fan && mDriver.Device[DeviceIdx].device.airconData.bSupportModeFan) return true;
+            else if (hMode == DataClasses.SystemAircon.MODE.Heating && mDriver.Device[DeviceIdx].device.airconData.bSupportModeHeating) return true;
+            else if (hMode == DataClasses.SystemAircon.MODE.Auto) return true;   // 자동모드는 확인하지 않는다. (자동모드 값이 0인데, 사용하지 않을때도 0으로 보내므로 확인하면 안됨 (jeff, 2020.10.20)
+            else return false;
+        } catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+            return false;
+        } catch (Exception e) {
+            Log.e(TAG, "[Exception] checkSupportedMode(byte hMode, byte DeviceIdx)");
+            //e.printStackTrace();
+            LogUtil.errorLogInfo("", TAG, e);
+            return false;
+        }
+    }
+
+    /**
+     * 조명&콘센트 상태 요청/응답
+     *
+     * @param DeviceIdx - (byte) 요청할 기기 인덱스
+     *
+     * @return (MultiSwitch.Device) 기기상태 null - Error , Not null - OK
+     */
+    private MultiSwitch.Device sendCtrlReqACKV2(byte DeviceIdx, byte hCtrlType) {
+        try {
+            DeviceLog("[sendCtrlReqACKV2] Start");
+
+            // 1. In 파라미터 확인
+            if ((DeviceIdx < 0) || (DeviceIdx >= MAX_DEVICE_COUNT)) {
+                Log.w(TAG, "[sendCtrlReqACKV2] param [DeviceIdx] Out of Range!!! " + DeviceIdx);
+                return null;
+            }
+
+            // 2. 패킷 데이터 만들기
+            byte[] ReqData = { (byte)Integer.bitCount(hCtrlType), hCtrlType };
+
+            // 3. 데이터 전송 및 응답
+            byte[] Reply = SendNRead_Variable((byte)(DEVICE_ADDRESS + DeviceIdx), CMDList.Req.ACK_StatusV2, ReqData);
+
+            // 4. 수신데이터 파싱
+            MultiSwitch.Device device = parsingReply_GetDeviceStatusV2(DeviceIdx, Reply);
+            if (device == null) {
+                DeviceLog("[sendGetDeviceStatusV2] Reply is null");
+                AddDoCount(DeviceIdx, false);
+                return null;
+            }
+            AddDoCount(DeviceIdx, true);
+
+            return device;
+        } catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+            return null;
+        } catch (Exception e) {
+            Log.e(TAG, "[Exception] sendCtrlReqACKV2(byte DeviceIdx, byte hCtrlType)");
+            //e.printStackTrace();
+            LogUtil.errorLogInfo("", TAG, e);
+            return null;
+        }
+    }
+
+    /**
+     * 조명 콘센트 제어 요청/응답
+     *
+     * @param DeviceIdx - (byte) 요청할 기기 인덱스
+     * @param ctrlCmd   - (CtrlCmd) 제어 데이터 클래스
+     *
+     * @return (MultiSwitch.Device) 기기상태 null - Error , Not null - OK
+     */
+    private MultiSwitch.Device sendSetLightConcentStatusV2(byte DeviceIdx, CtrlCmd ctrlCmd) {
+        DeviceLog("[sendSetLightConcentStatusV2] Start");
+
+        // 1. In 파라미터 확인
+        if ((DeviceIdx < 0) || (DeviceIdx >= MAX_DEVICE_COUNT)) {
+            Log.w(TAG, "[sendSetLightConcentStatusV2] param [DeviceIdx] Out of Range!!! " + DeviceIdx);
+            return null;
+        }
+
+        if (ctrlCmd == null) {
+            Log.w(TAG, "[sendSetLightConcentStatusV2] param [ctrlCmd] is null !!!");
+            return null;
+        }
+
+        // 2. 패킷 데이터 만들기
+        byte [] ReqData = ctrlCmd.getBytes();
+        if (ReqData == null) {
+            Log.w(TAG, "[sendSetLightConcentStatusV2] param [ctrlCmd.getBytes] is null !!!");
+            return null;
+        }
+
+        // 3. 데이터 전송 및 응답
+        byte[] Reply = SendNRead_Variable((byte)(DEVICE_ADDRESS + DeviceIdx), CMDList.Req.SetDeviceStatusV2, ReqData);
+
+        // 4. 수신데이터 파싱
+        MultiSwitch.Device device = parsingReply_GetDeviceStatusV2(DeviceIdx, Reply);
+        if (device == null) {
+            DeviceLog("[sendSetLightConcentStatusV2] Reply is null");
+            AddDoCount(DeviceIdx, false);
+            return null;
+        }
+        AddDoCount(DeviceIdx, true);
+
+        return device;
+    }
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    // CMDList
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+     * 명령어 리스트
+     */
+    public static class CMDList {
+        public static final class Req {
+            /////////////////////////////////////////////////////////
+            // Board
+            /////////////////////////////////////////////////////////
+            /** 기기 정보 요청 */
+            public final static byte GetDeviceInfo              = 0x01;
+
+            /////////////////////////////////////////////////////////
+            // 상태
+            /////////////////////////////////////////////////////////
+            /** 조명 콘센트 상태 요청 */
+            public final static byte GetLightConcentStatus      = 0x11;
+
+            /////////////////////////////////////////////////////////
+            // 제어
+            /////////////////////////////////////////////////////////
+            /** 조명 콘센트 제어 요청 */
+            public final static byte SetLightConcentStatus      = 0x12;
+
+            /////////////////////////////////////////////////////////
+            // 시간정보 알림
+            /////////////////////////////////////////////////////////
+            /** 시간정보 알림 */
+            public final static byte SetTimeInfo                = 0x21;
+
+            /////////////////////////////////////////////////////////
+            // V2 CMD
+            /////////////////////////////////////////////////////////
+            /** 기기 정보 요청 V2 */
+            public final static byte GetDeviceInfoV2                = 0x31;
+
+            /** 기기 상태 요청 V2 */
+            public final static byte GetDeviceStatusV2                = 0x32;
+
+            /** 기기 제어 요청 수신 알림 V2 */
+            public final static byte ACK_StatusV2                = 0x33;
+
+            /** 기기 제어 요청 V2 */
+            public final static byte SetDeviceStatusV2                = 0x34;
+
+        }
+    }
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    // UpdateVariables
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+     * 데이터를 업데이트 한다.
+     *
+     * @param DeviceIdx - (byte) 업데이트할 디바이스 인덱스
+     * @param device    - (MultiSwitch.Device) 업데이트할 디바이스 데이터
+     * @param bNotify - (boolean) 알림 업데이트 (true:무조건 변경 알림, false:변경여부에 따라 알림)
+     *
+     * @return (boolean) 데이터 변경여부 (true:변경 , false:미변경)
+     */
+    private boolean UpdateVariables(byte DeviceIdx, MultiSwitch.Device device, boolean bNotify) {
+        // 1. Param Range Check
+        if (DeviceIdx < 0) return false;
+        if (DeviceIdx >= mDriver.Polling.SearchDeviceCount) return false;
+        if (mDriver.Device[DeviceIdx].device == null) return false;
+
+        // 2. Check
+        boolean bChanged = false;
+        MultiSwitch.Device OldDevice = mDriver.Device[DeviceIdx].device;
+
+        while (true) {
+            // LightCount
+            if (OldDevice.hLightCnt != device.hLightCnt) {
+                Log.w(TAG, "[UpdateVariables] Device Change !!! LightCount Difference !!!");
+                mDriver.Device[DeviceIdx].info.Install = false;
+                bChanged = true;
+                break;
+            }
+
+            // ConcentCount
+            if (OldDevice.hOutletCnt != device.hOutletCnt) {
+                Log.w(TAG, "[UpdateVariables] Device Change !!! ConcentCount Difference !!!");
+                mDriver.Device[DeviceIdx].info.Install = false;
+                bChanged = true;
+                break;
+            }
+
+            // LightOnOff
+            for (byte i = 0; i < OldDevice.hLightCnt; i++) {
+                if (OldDevice.getLightPower(i) != device.getLightPower(i)) { bChanged = true; break; }
+                if (OldDevice.getLightDimLevel(i) != device.getLightDimLevel(i)) { bChanged = true; break; }
+                if (OldDevice.getLightDimUsage(i) != device.getLightDimUsage(i)) { bChanged = true; break; }
+            }
+
+            if (bChanged) break;
+
+            // BatchOffStatus
+            if (OldDevice.hBatchOffStatus != device.hBatchOffStatus) { bChanged = true; break; }
+
+            // Concent
+            MultiSwitch.Device.Outlet oldOutlet;
+            MultiSwitch.Device.Outlet newOutlet;
+            for (byte i = 0; i < OldDevice.hOutletCnt; i++) {
+                oldOutlet = OldDevice.getOutletStatus(i);
+                newOutlet = device.getOutletStatus(i);
+                if (oldOutlet == null || newOutlet == null) continue;
+
+                if (oldOutlet.Status != newOutlet.Status) { bChanged = true; break; }
+                if (oldOutlet.Mode != newOutlet.Mode) { bChanged = true; break; }
+                if (oldOutlet.NowPw != newOutlet.NowPw) { bChanged = true; break; }
+                if (oldOutlet.CutOffVal != newOutlet.CutOffVal) { bChanged = true; break; }
+            }
+
+            if (bChanged) break;
+
+            break;
+        }
+
+        if (bChanged || bNotify) {
+            mDriver.Device[DeviceIdx].device = device;
+            StatusChanged(DeviceIdx);
+
+            DeviceLog("UpdateVariables !!!! ***************************************");
+            DeviceLog(device.ToDebugString(DeviceIdx));
+            return true;
+        }
+
+        return false;
+    }
+}

+ 337 - 81
WallPadDevService/src/main/java/com/artncore/wallpaddevservice/driver/Sdb_Controller.java

@@ -19,6 +19,7 @@ import android.util.Log;
 
 
 import com.artncore.WallPadDataMgr.WallpadConcentAccSaveData;
 import com.artncore.WallPadDataMgr.WallpadConcentAccSaveData;
 import com.artncore.WallPadDataMgr.WallpadConcentAccSaveData.ConcentAccDataClass;
 import com.artncore.WallPadDataMgr.WallpadConcentAccSaveData.ConcentAccDataClass;
+import com.artncore.WallPadDataMgr.WallpadDeviceSet;
 import com.artncore.WallPadDataMgr.WallpadStatusData;
 import com.artncore.WallPadDataMgr.WallpadStatusData;
 import com.artncore.WallPadDataMgr.wallpaddbmgr;
 import com.artncore.WallPadDataMgr.wallpaddbmgr;
 import com.artncore.WallPadSmartLightSystem.WallPadSmartLight;
 import com.artncore.WallPadSmartLightSystem.WallPadSmartLight;
@@ -99,6 +100,14 @@ public class Sdb_Controller extends DeviceManager {
     /** 일괄소등 상태 (true:일괄소등해제, false:일괄소등) */
     /** 일괄소등 상태 (true:일괄소등해제, false:일괄소등) */
     private static boolean AllLightStatus = true;
     private static boolean AllLightStatus = true;
 
 
+    /** 각방 EM조명 순차제어 옵션 (true: 순차제어, false: 일괄제어)
+     *  현장 이슈 보완건: 각실EM에 연결된 조명이 자동점멸되는 증상 개선
+     *  순차제어는 각방EM의 조명개수가 3개 이상인 EM에 대한 전체제어시 이를 순차제어로 변경하여 제어한다.
+     *  Jeff, 2021.05.11
+     * */
+    private static boolean bEMLightCtrlbyOrder = true;
+    private boolean bEMResetRequied = false;
+
     /**
     /**
      * 일괄소등 상태를 반환한다.
      * 일괄소등 상태를 반환한다.
      *
      *
@@ -1730,6 +1739,7 @@ public class Sdb_Controller extends DeviceManager {
     {
     {
         // 드라이버 내부 제어용 API 생성
         // 드라이버 내부 제어용 API 생성
         driverInterOpAPI = new DriverInterOpAPI(MainHandler);
         driverInterOpAPI = new DriverInterOpAPI(MainHandler);
+        checkSDB_EM_LightCtrlOption();
     }
     }
 
 
     /*@Override
     /*@Override
@@ -1886,6 +1896,7 @@ public class Sdb_Controller extends DeviceManager {
                     else DeviceInfo_UpdateVariables(EM_INDEX_LIVING, false);
                     else DeviceInfo_UpdateVariables(EM_INDEX_LIVING, false);
 
 
                     // 침실에너지미터
                     // 침실에너지미터
+                    checkEMReset();
                     byte EnergyMeterCount = mDriver.Device.EnergyController.Info.EnergyMeterCount;
                     byte EnergyMeterCount = mDriver.Device.EnergyController.Info.EnergyMeterCount;
                     for (byte EmIndex=0 ; EmIndex<EnergyMeterCount ; EmIndex++) {
                     for (byte EmIndex=0 ; EmIndex<EnergyMeterCount ; EmIndex++) {
                         if (mDriver.GetReset()) return;
                         if (mDriver.GetReset()) return;
@@ -2839,6 +2850,40 @@ public class Sdb_Controller extends DeviceManager {
                 return SHMem.retVal = "SUCCESS";
                 return SHMem.retVal = "SUCCESS";
             }
             }
 
 
+            //////////////////////////////////////////////////////////
+            // SetLight : 조명을 제어한다.
+            // [0] 제어할 에너지미터 인덱스
+            // [1] 제어할 조명 인덱스
+            // [2] ON/OFF 상태 (0:OFF, 1:ON)
+            // [3] 제어할 조명 밝기 단계 (1, 2, 3 ... 10 : 10단계)
+            // [4] 제어할 조명 색상 단계 (1, 2, 3 ... 10 : 10단계)
+            //////////////////////////////////////////////////////////
+            else if(ctrDevFormat.CmdStr.equals("SetLight2"))
+            {
+                // 1. Param Get
+                byte EmIndex    = ctrDevFormat.param[0];
+                byte LightIndex = ctrDevFormat.param[1];
+                byte ByteOnOff  = ctrDevFormat.param[2];
+                byte Dimming    = ctrDevFormat.param[3];
+                byte Color      = ctrDevFormat.param[4];
+                DeviceLog("[do_ctrEmm] : SetLight2(EmIndex:" + EmIndex + ", LightIndex:" + LightIndex + ", ByteOnOff:" + ByteOnOff + ", Dimming:" + Dimming + ", Color:" + Color +")");
+
+                // 2. Make Control Data
+                LedLightControlClass LedLightControl = new LedLightControlClass();
+                LedLightControl.OnOff = ByteOnOff;
+                LedLightControl.Dimming = (byte)(Dimming * 10);
+                LedLightControl.Color   = (byte)(Color * 10);
+
+                // 3. Send
+                EnergyMeterClass.DataClass Data = Send_Set_EnergyMeterLight(EmIndex, LightIndex, LedLightControl, false);
+                if(Data == null) return SHMem.retVal = "FAIL;" + APIErrorCode.DEVICEISNORESPONSE;
+
+                // 4. Update
+                UpdateVariables(EmIndex, Data);
+
+                return SHMem.retVal = "SUCCESS";
+            }
+
             //////////////////////////////////////////////////////////
             //////////////////////////////////////////////////////////
             // SetAllLightControl : 조명 전체 제어
             // SetAllLightControl : 조명 전체 제어
             // [0] ON/OFF
             // [0] ON/OFF
@@ -5305,13 +5350,96 @@ public class Sdb_Controller extends DeviceManager {
     // SetBoard : 설정 전체
     // SetBoard : 설정 전체
     /////////////////////////////////////////////////////////
     /////////////////////////////////////////////////////////
     /**
     /**
-     * 디바이스 리셋 요청
+     * 에너지미터 리셋 요청
      *
      *
      * @return (boolean) true: 정상설정, false:에러
      * @return (boolean) true: 정상설정, false:에러
      */
      */
-    private boolean Send_SetAll_DeviceReset()
-    {
-        // Add Code
+    private boolean sendDeviceReset(byte[] reqData) {
+        String FUNC_NAME = "[sendDeviceReset]";
+        DeviceLog(FUNC_NAME + " Start");
+
+        // 1. In 파라미터 확인
+        if (reqData.length < 4 || 6 < reqData.length) {
+            DeviceLog(FUNC_NAME + " reqData length is out of range!!! -> " + reqData.length);
+            return false;
+        }
+
+        byte data;
+        int nIndex = 0;
+
+        // D1 (에너지콘트롤서/통합전력제어기/DC APU 리셋 여부)
+        data = reqData[nIndex++];
+        if ((data & (byte) (BIT3 | BIT4 | BIT5 | BIT6 | BIT7)) != 0x00) {
+            // 미사용 비트'0' 확인
+            Log.w(TAG, "[sendDeviceReset] D1 : Unused Bit Set !!! " + String.format("0x%02X", data));
+            return false;
+        }
+
+        // D2 (에너지미터 리셋 여부1)
+        data = reqData[nIndex++];
+        // 모든비트 사용
+
+        // D3 (에너지미터 리셋 여부2)
+        data = reqData[nIndex++];
+        if ((data & (byte) (BIT7)) != 0x00) {
+            // 미사용 비트'0' 확인
+            Log.w(TAG, "[sendDeviceReset] D3 : Unused Bit Set !!! " + String.format("0x%02X", data));
+            return false;
+        }
+
+        // D4 (에너지미터 하부제어기 리셋 개수)
+        data = reqData[nIndex++];
+        if (data < 0 || 13 < data) {
+            // 범위확인 (0~13)
+            Log.w(TAG, "[sendDeviceReset] D4 : Unused Bit Set !!! " + String.format("0x%02X", data));
+            return false;
+        }
+
+        // 데이터 길이 계산
+        int nExpectedLength = (data * 2) + 4;
+        if (reqData.length != nExpectedLength) {
+            Log.w(TAG, "[sendDeviceReset] data length is not match!! reqData.lenght [" + reqData.length + "], nExpectedLength [" + nExpectedLength + "]");
+            return false;
+        }
+
+        int nSubCtrlCnt = (int) data;
+        for (int  i = 0; i < nSubCtrlCnt; i++) {
+            data = reqData[nIndex++];
+            if (nIndex % 2 == 0) {
+                // 에너지미터 ID
+                if ((data < 1 || 12 < data) || (data != 15)) {
+                    Log.w(TAG, "[sendDeviceReset] data is out of range!! D" + nIndex + " -> data [" + data + "]");
+                    return false;
+                }
+            }
+            else {
+                // 대기전력 차단 콘센트 리셋 여부
+                if ((data & (byte) (BIT4 | BIT5 | BIT6 | BIT7)) != 0x00) {
+                    // 미사용 비트'0' 확인
+                    Log.w(TAG, "[sendDeviceReset] Unused Bit Set!! D" + nIndex + " -> data [" + data + "]");
+                    return false;
+                }
+            }
+        }
+
+        // 3. 데이터 전송 및 응답
+        byte[] Reply = SendNRead_Variable(DEVICE_ADDRESS, CMDList.Req.SetAll_DeviceReset, reqData);
+
+        // 4. 수신데이터 파싱
+        //     4.1. Default Check
+        if (Reply == null) {
+            DeviceLog(FUNC_NAME + " Reply is null");
+            AddDoCount(false);
+            return false;
+        }
+
+        if (Reply.length != 1) {
+            Log.w(TAG, FUNC_NAME + " Reply.length  fail!!! -> Reply.length : " + Reply.length);
+            AddDoCount(false);
+            return false;
+        }
+
+        AddDoCount(true);
         return true;
         return true;
     }
     }
 
 
@@ -5776,133 +5904,189 @@ public class Sdb_Controller extends DeviceManager {
      *
      *
      * @return (EnergyMeterClass.DataClass) 데이터 null - Error , Not null - OK
      * @return (EnergyMeterClass.DataClass) 데이터 null - Error , Not null - OK
      */
      */
-    private EnergyMeterClass.DataClass Send_Set_EnergyMeterLight(byte EmIndex, byte LightIndex, LedLightControlClass LedLightControl, boolean AccPw_Reset)
-    {
-        if(mDriver.GetReset()) return null;
+    private EnergyMeterClass.DataClass Send_Set_EnergyMeterLight(byte EmIndex, byte LightIndex, LedLightControlClass LedLightControl, boolean AccPw_Reset) {
+        if (mDriver.GetReset()) return null;
 
 
         String FUNC_NAME = "[Send_Set_EnergyMeterLight]";
         String FUNC_NAME = "[Send_Set_EnergyMeterLight]";
         DeviceLog(FUNC_NAME + " Start");
         DeviceLog(FUNC_NAME + " Start");
 
 
         // 1. In 파라미터 확인
         // 1. In 파라미터 확인
         boolean Only_AccPw_Reset = false;
         boolean Only_AccPw_Reset = false;
-        if((AccPw_Reset) && (LedLightControl == null))
-        {
+        if ((AccPw_Reset) && (LedLightControl == null)) {
             // 오직 조명 누적전력사용량만 초기화 하는 경우
             // 오직 조명 누적전력사용량만 초기화 하는 경우
             Only_AccPw_Reset = true;
             Only_AccPw_Reset = true;
         }
         }
 
 
         //     1.1. EmIndex
         //     1.1. EmIndex
-        if(!mDriver.Device.CheckEmIndex(EmIndex))
-        {
+        if (!mDriver.Device.CheckEmIndex(EmIndex)) {
             Log.w(TAG, FUNC_NAME + " Param : EmIndex - Out Of Range !!! (EmIndex:" + EmIndex + ")");
             Log.w(TAG, FUNC_NAME + " Param : EmIndex - Out Of Range !!! (EmIndex:" + EmIndex + ")");
             return null;
             return null;
         }
         }
+
         //     1.2. LightIndex
         //     1.2. LightIndex
         byte LightCount = 0;
         byte LightCount = 0;
-        if(!Only_AccPw_Reset)
-        {
+        if (!Only_AccPw_Reset) {
             LightCount = mDriver.Device.GetLightCount(EmIndex);
             LightCount = mDriver.Device.GetLightCount(EmIndex);
-            if (LightCount == 0)
-            {
+            if (LightCount == 0) {
                 Log.w(TAG, FUNC_NAME + " GetLightCount(" + EmIndex + ") result = 0 .... ");
                 Log.w(TAG, FUNC_NAME + " GetLightCount(" + EmIndex + ") result = 0 .... ");
                 return null;
                 return null;
             }
             }
-            if ( (LightIndex != define.DEVICE_ALL_OR_NOTHING) && (LightIndex != (byte)(EM_SENSOR_LIGHT_ID-1)) )
-            {
-                if (LightIndex >= LightCount)
-                {
+
+            if ((LightIndex != define.DEVICE_ALL_OR_NOTHING) && (LightIndex != (byte)(EM_SENSOR_LIGHT_ID-1))) {
+                if (LightIndex >= LightCount) {
                     Log.w(TAG, FUNC_NAME + " Param : LightIndex - Out Of Range !!! (LightIndex:" + LightIndex + ", LightCount:" + LightCount + ")");
                     Log.w(TAG, FUNC_NAME + " Param : LightIndex - Out Of Range !!! (LightIndex:" + LightIndex + ", LightCount:" + LightCount + ")");
                     return null;
                     return null;
                 }
                 }
             }
             }
         }
         }
         //     1.3. LedLightControl
         //     1.3. LedLightControl
-        if(!Only_AccPw_Reset) {
-            if (LedLightControl == null)
-            {
+        if (!Only_AccPw_Reset) {
+            if (LedLightControl == null) {
                 Log.w(TAG, FUNC_NAME + " Param : LedLightControl is null !!!");
                 Log.w(TAG, FUNC_NAME + " Param : LedLightControl is null !!!");
                 return null;
                 return null;
             }
             }
-            if (!LedLightControl.CheckRange())
-            {
+
+            if (!LedLightControl.CheckRange()) {
                 Log.w(TAG, FUNC_NAME + " Param : LedLightControl.CheckRange() Error !!!");
                 Log.w(TAG, FUNC_NAME + " Param : LedLightControl.CheckRange() Error !!!");
                 return null;
                 return null;
             }
             }
         }
         }
 
 
-        // 2. 패킷 데이터 만들기
-        byte ReqDataLength = 0;
-        byte ControlLightCount = 0;
-        if(!Only_AccPw_Reset)
-        {
-            if (LightIndex == define.DEVICE_ALL_OR_NOTHING)
-            {
-                ControlLightCount = LightCount;
-                ReqDataLength = (byte) (2 + (ControlLightCount * 6));
-            }
-            else
-            {
+        if (LightIndex == define.DEVICE_ALL_OR_NOTHING && LightCount >= 3 && bEMLightCtrlbyOrder) {
+            /** 전체제어 -> 순차제어 */
+            // 2. 패킷 데이터 만들기
+            byte ReqDataLength = 0;
+            byte ControlLightCount = 0;
+            if (!Only_AccPw_Reset) {
                 ControlLightCount = 1;
                 ControlLightCount = 1;
                 ReqDataLength = 2 + 6;
                 ReqDataLength = 2 + 6;
             }
             }
-        }
-        else
-        {
-            ReqDataLength = 2;
-        }
-        byte [] ReqData = new byte [ReqDataLength];
-        byte data = 0x00;
-        int index = 0;
+            else {
+                ReqDataLength = 2;
+            }
+            byte[] ReqData = new byte [ReqDataLength];
+            byte data = 0x00;
+            EnergyMeterClass.DataClass Data = null;
 
 
-        //     D1 : 제어할 에너지미터 ID 및 조명 개수
-        ReqData[index++] = (byte)((byte)(ControlLightCount << 4) |  (byte)(EmIndex + 1));
+            for (int i = 0; i < LightCount; i++) {
+                int index = 0;
 
 
-        //     D2 : 에너지미터 상태
-        data = 0x00;
-        if(AccPw_Reset) data |= BIT0;
-        ReqData[index++] = data;
+                //     D1 : 제어할 에너지미터 ID 및 조명 개수
+                ReqData[index++] = (byte)((byte)(ControlLightCount << 4) |  (byte)(EmIndex + 1));
 
 
-        //     D3 ~ D8
-        for(byte i=0 ; i<ControlLightCount ; i++)
-        {
-            //     D3 : 제어할 조명 n번 ID
-            if(LightIndex == define.DEVICE_ALL_OR_NOTHING) ReqData[index++] = (byte) (i + 1);
-            else                                           ReqData[index++] = (byte) (LightIndex + 1);
+                //     D2 : 에너지미터 상태
+                data = 0x00;
+                if (AccPw_Reset) data |= BIT0;
+                ReqData[index++] = data;
+
+                //     D3 ~ D8
+                //     D3 : 제어할 조명 n번 ID
+                ReqData[index++] = (byte) (i + 1);
+
+                //     D4 : n번 조명 ON/OFF 상태
+                ReqData[index++] = LedLightControl.OnOff;
+
+                //     D5 : n번 조명 디밍 상태
+                ReqData[index++] = LedLightControl.Dimming;
+
+                //     D6 : n번 조명 색온도 상태
+                ReqData[index++] = LedLightControl.Color;
+
+                //     D7 : n번 조명 센서 설정 상태
+                data = 0x00;
+                if (LedLightControl.SensorUseOnOff != define.DEVICE_ALL_OR_NOTHING) data |= LedLightControl.SensorUseOnOff;
+                if (LedLightControl.DetectionCountReset) data |= BIT7;
+                ReqData[index++] = data;
 
 
-            //     D4 : n번 조명 ON/OFF 상태
-            ReqData[index++] = LedLightControl.OnOff;
+                //     D8 : n번 센서 감도 상태
+                ReqData[index++] = LedLightControl.SensorLevel;
 
 
-            //     D5 : n번 조명 디밍 상태
-            ReqData[index++] = LedLightControl.Dimming;
+                // 3. 데이터 전송 및 응답
+                byte Command = CMDList.Req.Set_EnergyMeterLight;
+                byte[] Reply = SendNRead_Variable(DEVICE_ADDRESS, Command, ReqData);
 
 
-            //     D6 : n번 조명 색온도 상태
-            ReqData[index++] = LedLightControl.Color;
+                // 4. 수신데이터 파싱
+                Data = EnergyMeter_ReplyParsing(Command, EmIndex, Reply);
+                if (Data == null) {
+                    DeviceLog(FUNC_NAME + " Reply is null");
+                    AddDoCount(false);
+                    return null;
+                }
+                AddDoCount(true);
+            }
+            // 마지막 조명의 제어가 완료된 후 결과값을 리턴한다.
+            return Data;
+        }
+        else {
+            /** 기존 전체제어 방식 유지 */
+            // 2. 패킷 데이터 만들기
+            byte ReqDataLength = 0;
+            byte ControlLightCount = 0;
+            if (!Only_AccPw_Reset) {
+                if (LightIndex == define.DEVICE_ALL_OR_NOTHING) {
+                    ControlLightCount = LightCount;
+                    ReqDataLength = (byte) (2 + (ControlLightCount * 6));
+                }
+                else {
+                    ControlLightCount = 1;
+                    ReqDataLength = 2 + 6;
+                }
+            }
+            else {
+                ReqDataLength = 2;
+            }
+            byte[] ReqData = new byte [ReqDataLength];
+            byte data = 0x00;
+            int index = 0;
+
+            //     D1 : 제어할 에너지미터 ID 및 조명 개수
+            ReqData[index++] = (byte)((byte)(ControlLightCount << 4) |  (byte)(EmIndex + 1));
 
 
-            //     D7 : n번 조명 센서 설정 상태
+            //     D2 : 에너지미터 상태
             data = 0x00;
             data = 0x00;
-            if(LedLightControl.SensorUseOnOff != define.DEVICE_ALL_OR_NOTHING) data |= LedLightControl.SensorUseOnOff;
-            if(LedLightControl.DetectionCountReset) data |= BIT7;
+            if (AccPw_Reset) data |= BIT0;
             ReqData[index++] = data;
             ReqData[index++] = data;
 
 
-            //     D8 : n번 센서 감도 상태
-            ReqData[index++] = LedLightControl.SensorLevel;
-        }
+            //     D3 ~ D8
+            for (byte i = 0; i < ControlLightCount; i++) {
+                //     D3 : 제어할 조명 n번 ID
+                if (LightIndex == define.DEVICE_ALL_OR_NOTHING) ReqData[index++] = (byte) (i + 1);
+                else ReqData[index++] = (byte) (LightIndex + 1);
 
 
-        // 3. 데이터 전송 및 응답
-        byte Command = CMDList.Req.Set_EnergyMeterLight;
-        byte [] Reply = SendNRead_Variable(DEVICE_ADDRESS, Command, ReqData);
+                //     D4 : n번 조명 ON/OFF 상태
+                ReqData[index++] = LedLightControl.OnOff;
 
 
-        // 4. 수신데이터 파싱
-        EnergyMeterClass.DataClass Data = EnergyMeter_ReplyParsing(Command, EmIndex, Reply);
-        if(Data == null)
-        {
-            DeviceLog(FUNC_NAME + " Reply is null");
-            AddDoCount(false);
-            return null;
-        }
-        AddDoCount(true);
+                //     D5 : n번 조명 디밍 상태
+                ReqData[index++] = LedLightControl.Dimming;
 
 
-        return Data;
+                //     D6 : n번 조명 색온도 상태
+                ReqData[index++] = LedLightControl.Color;
+
+                //     D7 : n번 조명 센서 설정 상태
+                data = 0x00;
+                if (LedLightControl.SensorUseOnOff != define.DEVICE_ALL_OR_NOTHING) data |= LedLightControl.SensorUseOnOff;
+                if (LedLightControl.DetectionCountReset) data |= BIT7;
+                ReqData[index++] = data;
+
+                //     D8 : n번 센서 감도 상태
+                ReqData[index++] = LedLightControl.SensorLevel;
+            }
+
+            // 3. 데이터 전송 및 응답
+            byte Command = CMDList.Req.Set_EnergyMeterLight;
+            byte[] Reply = SendNRead_Variable(DEVICE_ADDRESS, Command, ReqData);
+
+            // 4. 수신데이터 파싱
+            EnergyMeterClass.DataClass Data = EnergyMeter_ReplyParsing(Command, EmIndex, Reply);
+            if (Data == null) {
+                DeviceLog(FUNC_NAME + " Reply is null");
+                AddDoCount(false);
+                return null;
+            }
+            AddDoCount(true);
+
+            return Data;
+        }
     }
     }
 
 
     /**
     /**
@@ -9590,4 +9774,76 @@ public class Sdb_Controller extends DeviceManager {
 
 
         return bRet;
         return bRet;
     }
     }
+
+    private void checkSDB_EM_LightCtrlOption() {
+        try {
+            WallpadDeviceSet mWallpadDeviceSet = new WallpadDeviceSet(ServiceMain.svcContext);
+            int nValue = mWallpadDeviceSet.getSDB_EM_Light_Option();
+            mWallpadDeviceSet.closeDB();
+
+            if (nValue == WallpadDeviceSet.KITCHEN_EM_BATCH_CTRL) {
+                Log.i(TAG, "[checkSDB_EM_LightCtrlOption] KITCHEN_EM_BATCH_CTRL");
+                bEMLightCtrlbyOrder = false;
+                bEMResetRequied = false;
+            }
+            else if (nValue == WallpadDeviceSet.KITCHEN_EM_ORDER_CTRL) {
+                Log.i(TAG, "[checkSDB_EM_LightCtrlOption] KITCHEN_EM_ORDER_CTRL");
+                bEMLightCtrlbyOrder = true;
+                bEMResetRequied = false;
+            }
+            else if (nValue == WallpadDeviceSet.KITCHEN_EM_ORDER_CTRL_RESET) {
+                Log.i(TAG, "[checkSDB_EM_LightCtrlOption] KITCHEN_EM_ORDER_CTRL_RESET");
+                bEMLightCtrlbyOrder = true;
+                bEMResetRequied = true;
+                Log.i(TAG, "[checkSDB_EM_LightCtrlOption] Set to KITCHEN_EM_ORDER_CTRL");
+            }
+        } catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+        } catch (Exception e) {
+            Log.e(TAG, "[checkSDB_EM_LightCtrlOption] Exception Error");
+            //e.printStackTrace();
+            LogUtil.errorLogInfo("", TAG, e);
+        }
+    }
+
+    /**
+     *  각실 EM 조명 자동 On/Off 증상 개선용 함수
+     *  조명이 3개 이상인 각실EM을 초기화 한다 (1회만)
+     */
+    private void checkEMReset() {
+        try {
+            if (!bEMResetRequied) {
+                return;
+            }
+            DeviceLog("[checkEMReset] Start");
+            byte D1 = (byte) 0x00, D2 = (byte) 0x00, D3 = (byte) 0x00, D4 = (byte) 0x00;
+
+            for (int i = 0; i < mDriver.Device.BadRoom_Em_Count; i++) {
+                if (mDriver.Device.BadRoom_EnergyMeter[i].Info.LightCount >= 3) {
+                    if (0 <= i && i <=7) D2 |= BIT_ARRAY[i];
+                    else if (8 <= i && i <= 14) D3 |= BIT_ARRAY[i - 8];
+                }
+            }
+
+            byte[] reqData = new byte[] { D1, D2, D3, D4 };
+            if (sendDeviceReset(reqData)) {
+                WallpadDeviceSet mWallpadDeviceSet = new WallpadDeviceSet(ServiceMain.svcContext);
+                boolean bRet = mWallpadDeviceSet.setSDB_EM_Light_Option(WallpadDeviceSet.KITCHEN_EM_ORDER_CTRL);
+                mWallpadDeviceSet.closeDB();
+                bEMResetRequied = !bRet;
+            }
+            else {
+                bEMResetRequied = true;
+            }
+
+        } catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+        } catch (Exception e) {
+            Log.e(TAG, "[checkEMReset] Exception Error");
+            //e.printStackTrace();
+            LogUtil.errorLogInfo("", TAG, e);
+        }
+    }
+
+
 }
 }

+ 39 - 6
WallPadDevService/src/main/java/com/artncore/wallpaddevservice/driver/Sdb_LivingRoomLight_Controller.java

@@ -108,9 +108,11 @@ public class Sdb_LivingRoomLight_Controller extends DeviceManager {
     /** 조명 ON/OFF 상태 */
     /** 조명 ON/OFF 상태 */
     public static class LIGHT_ONOFF {
     public static class LIGHT_ONOFF {
         /** ON */
         /** ON */
-        public static byte ON = 0x01;
+        public static byte ON = (byte) 0x01;
         /** OFF */
         /** OFF */
-        public static byte OFF = 0x02;
+        public static byte OFF = (byte) 0x02;
+        /** Don't Care */
+        public static byte DONT_CARE = (byte) 0xFF;
 
 
         /**
         /**
          * 범위를 체크한다.
          * 범위를 체크한다.
@@ -1428,8 +1430,39 @@ public class Sdb_LivingRoomLight_Controller extends DeviceManager {
                 LedLightControlClass LedLightControl = new LedLightControlClass();
                 LedLightControlClass LedLightControl = new LedLightControlClass();
                 if (ByteOnOff == 1) LedLightControl.OnOff = LIGHT_ONOFF.ON;
                 if (ByteOnOff == 1) LedLightControl.OnOff = LIGHT_ONOFF.ON;
                 else LedLightControl.OnOff = LIGHT_ONOFF.OFF;
                 else LedLightControl.OnOff = LIGHT_ONOFF.OFF;
-                LedLightControl.Dimming = (byte)(Dimming * 10);
-                LedLightControl.Color = (byte)(Color * 10);
+                if (Dimming != define.DEVICE_ALL_OR_NOTHING) LedLightControl.Dimming = (byte)(Dimming * 10);
+                if (Color != define.DEVICE_ALL_OR_NOTHING) LedLightControl.Color = (byte)(Color * 10);
+
+                // 3. Send
+                LivingEnergyMeterClass.DataClass Data = Send_Set_Light(LightIndex, LedLightControl, false);
+                if (Data == null) return "FAIL;" + APIErrorCode.DEVICEISNORESPONSE;
+
+                // 4. Update
+                updateVariables(Data);
+
+                return APIErrorCode.SUCCESS;
+            }
+
+            //////////////////////////////////////////////////////////
+            // SetLight2 : 조명을 제어한다. 조명전원상태 don't care 기능 추가
+            // [0] 제어할 조명 인덱스
+            // [1] ON/OFF 상태 (0x01 : ON, 0x02 : OFF, 0xFF : don't care)
+            // [2] 제어할 조명 밝기 단계 (1, 2, 3 ... 10 : 10단계)
+            // [3] 제어할 조명 색상 단계 (1, 2, 3 ... 10 : 10단계)
+            //////////////////////////////////////////////////////////
+            else if (ctrDevFormat.CmdStr.equals("SetLight2")) {
+                // 1. Param Get
+                byte LightIndex = ctrDevFormat.param[0];
+                byte ByteOnOff  = ctrDevFormat.param[1];
+                byte Dimming    = ctrDevFormat.param[2];
+                byte Color = ctrDevFormat.param[3];
+                DeviceLog("[SinkCtrl] : SetLight2(LightIndex:" + LightIndex + ", ByteOnOff:" + ByteOnOff + ", Dimming:" + Dimming + ", Color:" + Color + ")");
+
+                // 2. Make Control Data
+                LedLightControlClass LedLightControl = new LedLightControlClass();
+                LedLightControl.OnOff = ByteOnOff;
+                if (Dimming != define.DEVICE_ALL_OR_NOTHING) LedLightControl.Dimming = (byte)(Dimming * 10);
+                if (Color != define.DEVICE_ALL_OR_NOTHING) LedLightControl.Color = (byte)(Color * 10);
 
 
                 // 3. Send
                 // 3. Send
                 LivingEnergyMeterClass.DataClass Data = Send_Set_Light(LightIndex, LedLightControl, false);
                 LivingEnergyMeterClass.DataClass Data = Send_Set_Light(LightIndex, LedLightControl, false);
@@ -1479,7 +1512,7 @@ public class Sdb_LivingRoomLight_Controller extends DeviceManager {
 
 
                 // 2. Make Control Data
                 // 2. Make Control Data
                 LedLightControlClass LedLightControl = new LedLightControlClass();
                 LedLightControlClass LedLightControl = new LedLightControlClass();
-                LedLightControl.Dimming = (byte)(Dimming * 10);
+                if (Dimming != define.DEVICE_ALL_OR_NOTHING) LedLightControl.Dimming = (byte)(Dimming * 10);
 
 
                 // 3. Send
                 // 3. Send
                 LivingEnergyMeterClass.DataClass Data = Send_Set_Light(LightIndex, LedLightControl, false);
                 LivingEnergyMeterClass.DataClass Data = Send_Set_Light(LightIndex, LedLightControl, false);
@@ -1503,7 +1536,7 @@ public class Sdb_LivingRoomLight_Controller extends DeviceManager {
 
 
                 // 2. Make Control Data
                 // 2. Make Control Data
                 LedLightControlClass LedLightControl = new LedLightControlClass();
                 LedLightControlClass LedLightControl = new LedLightControlClass();
-                LedLightControl.Color = (byte)(Color * 10);
+                if (Color != define.DEVICE_ALL_OR_NOTHING) LedLightControl.Color = (byte)(Color * 10);
 
 
                 // 3. Send
                 // 3. Send
                 LivingEnergyMeterClass.DataClass Data = Send_Set_Light(LightIndex, LedLightControl, false);
                 LivingEnergyMeterClass.DataClass Data = Send_Set_Light(LightIndex, LedLightControl, false);

+ 3772 - 3720
WallPadDevService/src/main/java/com/artncore/wallpaddevservice/driver/SmartKeyRfDoor_Controller.java

@@ -1,3720 +1,3772 @@
-/*
- * Copyright (C) 2014 Android WallPad Project
- *
- * FileName  : SmartKeyRfDoor_Controller.java
- * Project   : Android WallPad Project
- * Company   : HDC I-CONTROLS ( www.icontrols.co.kr )
- * Author    : Kang Sang Ho  , lairu@icontrols.co.kr
- */
-
-package com.artncore.wallpaddevservice.driver;
-
-import java.security.SecureRandom;
-import java.util.Calendar;
-import java.util.GregorianCalendar;
-import java.util.List;
-import java.util.Random;
-
-import kr.co.icontrols.iencryptor.aes128.AES_128;
-import kr.co.icontrols.wallpadsupport.Version;
-import kr.co.icontrols.wallpadsupport.WpadSound;
-import android.annotation.SuppressLint;
-import android.app.ActivityManager;
-import android.app.ActivityManager.RunningTaskInfo;
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.CountDownTimer;
-import android.os.Handler;
-import android.os.Message;
-import android.util.Log;
-import android.view.KeyEvent;
-import android.widget.Toast;
-
-import com.artncore.WallPadDataMgr.WallpadAccessData;
-import com.artncore.WallPadDataMgr.WallpadDeviceSet;
-import com.artncore.WallPadDataMgr.WallpadSmartKeyRegData;
-import com.artncore.WallPadDataMgr.WallpadStatusData;
-import com.artncore.WallPadDataMgr.wallpaddbmgr;
-import com.artncore.WallPadDataMgr.wallpaddbmgr.AddressSet;
-import com.artncore.commons.APIErrorCode;
-import com.artncore.commons.define;
-import com.artncore.devicectr.WallPadInterface;
-import com.util.LogUtil;
-import com.artncore.wallpaddevservice.ServiceMain;
-
-
-/**
- * 스마트키 RF 현관카메라의 드라이버 모듈이다.
- */
-@SuppressLint("HandlerLeak")
-public class SmartKeyRfDoor_Controller extends DeviceManager {
-    private final static String TAG = "SmartKeyRfDoor_DRV";
-
-    private final byte DEVICE_ADDRESS  = (byte) 0xA2;
-
-    private final byte MAX_SMARTKEY_COUNT = (byte) 5;
-
-	/** RSSI 동기화 시간 (1시간) */
-    //private final long RSSI_SYNC_TICK   = (long)(60 * TIME_MINUTE);
-    private final long RSSI_SYNC_TICK   = (long)(10 * TIME_SEC);
-    /** LED 모드 동기화 시간 (5분) */
-    //private final long LED_SYNC_TICK    = (long)(5 * TIME_MINUTE);
-    private final long LED_SYNC_TICK    = (long)(10 * TIME_SEC);
-    /** 카메라 모드 동기화 시간 (5분) */
-    //private final long CAM_SYNC_TICK    = (long)(5 * TIME_MINUTE);
-    private final long CAM_SYNC_TICK    = (long)(10 * TIME_SEC);
-    /** 시간정보 동기화 시간 (1시간) */
-    private final long TIME_SYNC_TICK   = (long) TIME_MINUTE;
-
-    private boolean firstSensor = true;
-
-    /** 도어락 문열림 대기모드 설정 시간*/
-    private final byte DLOCK_STANDBYMODE_SEC     = (byte) 5;
-
-    /** 등록후 대기시간 (초) */
-    private final long REGISTERPAUSE_TIMEOUT_TICK     = (long)(5 * TIME_SEC);
-
-    /** 등록모드 시작 */
-    public final static byte STATUS_REGMODE_START                = (byte) 0x00;
-    /** 등록완료 */
-    public final static byte STATUS_REGMODE_KEY_COMPLETE         = (byte) 0x10;
-    /** 이미 등록된 키 */
-    public final static byte STATUS_REGMODE_KEY_ALREADY          = (byte) 0x20;
-    /** 무선 통신실패 */
-    public final static byte STATUS_REGMODE_ER_WIRELESSCOMMFAIL  = (byte) 0x30;
-    /** DB 저장 실패 */
-    public final static byte STATUS_REGMODE_ER_DBWRITE           = (byte) 0x40;
-    /** 등록모드 종료 */
-    public final static byte STATUS_REGMODE_END                  = (byte) 0xA0;
-    /** 등록할 공간 없음 */
-    public final static byte STATUS_REGMODE_FULL                 = (byte) 0xB0;
-
-    private static byte CheckSmartKeyNo  = 0x00;
-    public static byte GetCheckSmartKeyNo() { return CheckSmartKeyNo; }
-    private static String CheckSmartKeySn  = null;
-    public static String GetCheckSmartKeySn() { return CheckSmartKeySn; }
-
-    /** 도어락 타입 - WallpadDeviceSet.DOORLOCK_TYPE_NORMAL or WallpadDeviceSet.DOORLOCK_TYPE_RF*/
-    private int mDoorLockType = WallpadDeviceSet.DOORLOCK_TYPE_NORMAL;
-
-    private int mModelType = Version.getModelType();
-
-    /////////////////////////////////////////////////////////////
-    // 무선도어락 연동
-    /////////////////////////////////////////////////////////////
-
-    /** 문열림 대기모드 상태 true:사용, false:사용하지 않음 */
-    private boolean mDoorOpenDelay = false;
-
-    /** 자체 문열림 모드 상태 true:허용, false:비허용 */
-    private boolean mDoorStdOpenMode = false;
-
-    /** 현관카메라 전원ON을 위한 타이머*/
-    private CountDownTimer PowerOnTimer = null;
-    /** WallpadCall 패키지 명*/
-    private static final String strWallPadCallPakageName = "kr.co.icontrols.wallpadcall";
-
-
-    /** WallpadCall 호출 가능 여부 true:허용, false:비허용
-     * 초인종 눌림 -> WallpadCall 실행 가능하도록 초기 설정
-     * */
-    private boolean CallAppEnable = true;
-    /**
-     * 자체 문열림 모드 상태
-     * @return (boolean) true:허용, false:비허용
-     */
-    private boolean GetDoorStdOpenMode() { return mDoorStdOpenMode; }
-    /**
-     * 자체 문열림 모드를 설정한다.
-     *
-     * @param OnOff (boolean) true:허용, false:비허용
-     */
-    private void SetDoorStdOpenMode(boolean OnOff) {
-        mDoorStdOpenModeHandler.removeMessages(0);
-        mDoorStdOpenModeHandler.removeMessages(1);
-        if (OnOff) {
-            Log.i(TAG, "[SetDoorStdOpenMode] ON");
-            mDoorStdOpenMode = true;
-            mDoorStdOpenModeHandler.sendEmptyMessage(0);
-        }
-        else {
-            Log.i(TAG, "[SetDoorStdOpenMode] OFF");
-            mDoorStdOpenMode = false;
-        }
-    }
-
-    private Handler mDoorStdOpenModeHandler = new Handler()
-    {
-        @Override
-        public void handleMessage(Message msg)
-        {
-            if (msg.what == 0) {
-                Log.i(TAG, "[mDoorStdOpenModeHandler] Start !!!");
-                mDoorStdOpenModeHandler.sendEmptyMessageDelayed(1, (long)((long)DLOCK_STANDBYMODE_SEC * (long)1000));
-            }
-            else if (msg.what == 1) {
-                Log.i(TAG, "[mDoorStdOpenModeHandler] TimeOut...");
-                mDoorStdOpenMode = false;
-            }
-        }
-    };
-    /////////////////////////////////////////////////////////////
-
-    /** 초기 기기 검색 횟수  */
-    private final int MAX_SEARCH_COUNT   = 3;
-
-    private class InfoList {
-        /** 센서지원 유무(거동수상자 감지용)*/
-        private boolean bSensorUsage;
-        /** LED 제어 지원 유무*/
-        private boolean bLEDLightCtrlable;
-        /** RSSI 제어 지원 유무*/
-        private boolean bRSSICtrlable;
-        /** 카메라 제어 지원 유무*/
-        private boolean bCameraCtrlable;
-        /** PIR센서 지원 유무*/
-        private boolean bPIRSensorUsage;
-        /** 시간정보 지원 유무*/
-        private boolean bTimeUsage;
-
-        /** 제조사 코드 ( 0x01 : 아이콘트롤스 ) */
-        private byte hVendor;
-
-        /** 펌웨어 Build Date (년) */
-        private byte hFWVer_Year;
-        /** 펌웨어 Build Date (월) */
-        private byte hFWVer_Month;
-        /** 펌웨어 Build Date (일) */
-        private byte hFWVer_Date;
-        /** 펌웨어 Build Date (일련번호) */
-        private byte hFWVer_No;
-
-        /** 지원 프로토콜 버전 Main */
-        private byte hProtocolVer_Main;
-        /** 지원 프로토콜 버전 Sub */
-        private byte hProtocolVer_Sub;
-
-        private InfoList() {
-            bSensorUsage = false;
-            bLEDLightCtrlable = false;
-            bRSSICtrlable = false;
-            bCameraCtrlable = false;
-            bPIRSensorUsage = false;
-            bTimeUsage = false;
-
-            hVendor = 0x00;
-
-            hFWVer_Year = 0x00;
-            hFWVer_Month = 0x00;
-            hFWVer_Date = 0x00;
-            hFWVer_No = 0x00;
-
-            hProtocolVer_Main = 0x00;
-            hProtocolVer_Sub = 0x00;
-        }
-
-        public String ToDebugString() {
-            String retStr =
-                    "==========================\r\n" +
-                            "InfoList\r\n" +
-                            "==========================\r\n" +
-                            "bSensorUsage    : " + bSensorUsage + "\r\n" +
-                            "bLEDLightCtrlable   : " + bLEDLightCtrlable + "\r\n" +
-                            "bRSSICtrlable  : " + bRSSICtrlable + "\r\n" +
-                            "bCameraCtrlable: " + bCameraCtrlable + "\r\n" +
-                            "bPIRSensorUsage  : " + bPIRSensorUsage + "\r\n" +
-                            "bTimeUsage: " + bTimeUsage + "\r\n" +
-
-                            "Vender        : " + String.format("0x%02X", hVendor) + "\r\n" +
-
-                            "FW Ver.         : " + (int)(hFWVer_Year +2000) + "." + hFWVer_Month + "." + hFWVer_Date + "." + hFWVer_No + "\r\n" +
-                            "Protocol Ver.   : " +  "V" + hProtocolVer_Main + "." + hProtocolVer_Sub + "\r\n" +
-                            "==========================";
-            return retStr;
-        }
-    }
-
-    /** 기본 상태 응답값 정의 */
-    private class StatusList {
-        /** 거동수상자 센서감지 : true:감지 , false:미감지 */
-        private boolean bSensorDetect;
-        /** 카메라 센서감지 : true:동작중 , false:꺼짐 */
-        private boolean bCameraStatus;
-        /** LED 상태 : true:동작중 , false:꺼짐 */
-        private boolean bLedStatus;
-        /** 카메라 Auto 상태 : true:동작중 , false:꺼짐 */
-        private boolean bCameraAuto;
-        /** LED Auto 상태 : true:동작중 , false:꺼짐 */
-        private boolean bLedAuto;
-        /** 현관벨 상태 : true:눌림 , false:평상시 */
-        private boolean bDoorBtnStatus;
-        /** 에러상태     : true:에러 , false:정상 */
-        private boolean bError;
-        /** 인식된 RF 스마트키 개수 */
-        private byte SmartKeyCount;
-
-        private StatusList() {
-            bSensorDetect = false;
-            bCameraStatus = false;
-            bLedStatus = false;
-            bCameraAuto = false;
-            bLedAuto = false;
-
-            bDoorBtnStatus = false;
-            bError = false;
-            SmartKeyCount = 0;
-        }
-
-        public String ToDebugString() {
-            String retStr =
-                    "==========================\r\n" +
-                            "StatusList\r\n" +
-                            "==========================\r\n" +
-                            "bSensorDetect  : "  + bSensorDetect + "\r\n" +
-                            "bLedStatus     : "  + bLedStatus + "\r\n" +
-                            "bCameraStatus  : "  + bCameraStatus + "\r\n" +
-                            "bLedAuto       : "  + bLedAuto + "\r\n" +
-                            "bCameraAuto    : "  + bCameraAuto + "\r\n" +
-                            "bDoorBtnStatus : " + bDoorBtnStatus + "\r\n" +
-                            "bError         : " + bError + "\r\n" +
-                            "SmartKeyCount  : " + SmartKeyCount + "\r\n" +
-                            "==========================";
-            return retStr;
-        }
-    }
-
-    /** 거동수상자 관련 센서값 */
-    private class SensorValue {
-        /** 센서 감도 */
-        private byte Sensor_Sensitivity;
-        /** 거동수상자 판별시간 */
-        private byte Sensor_DetectTime;
-		/** LED 모드 */
-		private byte Sensor_LedMode;
-		/** 감지센서 RSSI Read */
-		private byte Sensor_RSSI_Read;
-		/** 감지센서 RSSI Write */
-		private byte Sensor_RSSI_Write;
-		/** 거동수상자 판별빈도 */
-		private byte Sensor_DetectRatio;
-		/** 카메라 모드 */
-		private byte Sensor_CameraMode;
-
-        private SensorValue() {
-            Sensor_Sensitivity 	= 0;
-            Sensor_DetectTime 	= 0;
-
-			Sensor_LedMode 		= -1;
-			Sensor_CameraMode 	= -1;
-
-            Sensor_DetectRatio 	= 100;	 // 현관카메라의 감지빈도는 기본 100%로 설정되어 있음
-			Sensor_RSSI_Read 	= -101;  // 기본값 : 범위 이탈
-			Sensor_RSSI_Write 	= -101;  // 기본값 : 범위 이탈
-        }
-
-        public String ToDebugString() {
-            String retStr =
-                    "==========================\r\n" +
-                            "SensorValue\r\n" +
-                            "==========================\r\n" +
-                            "Sensor_Sensitivity : "  + Sensor_Sensitivity + "\r\n" +
-                            "Sensor_DetectTime  : " + Sensor_DetectTime + "\r\n" +
-                            "Sensor_DetectRatio : " + Sensor_DetectRatio + "\r\n" +
-                            "Sensor_RSSI_Read   : " + Sensor_RSSI_Read + "\r\n" +
-                            "Sensor_RSSI_Write  : " + Sensor_RSSI_Write + "\r\n" +
-                            "Sensor_LedMode     : " + Sensor_LedMode + "\r\n" +
-                            "Sensor_CameraMode  : " + Sensor_CameraMode + "\r\n" +
-                            "==========================";
-            return retStr;
-        }
-    }
-
-    private class EncryptionList {
-        private byte [] Data;
-        private EncryptionList() {
-            Data = new byte [16];
-            for (int i = 0; i < Data.length; i++) Data[i] = 0x00;
-        }
-
-        public boolean Input(byte [] in, int startIdx) {
-            if (in == null) return false;
-            if ((in.length - startIdx) < 16) return false;
-
-            if (Data == null) return false;
-
-            for (int i = 0; i < Data.length; i++) Data[i] = in[startIdx + i];
-
-            return true;
-        }
-
-        public String ToDebugString(int KeyIndex) {
-            if (Data == null) return "null";
-
-            String retStr = "[" + KeyIndex + "] ";
-
-            for (int i = 0; i < Data.length; i++) {
-                retStr += String.format("%02X ", Data[i]);
-            }
-            return retStr;
-        }
-    }
-
-    private class KeyDataList {
-        private byte Count;
-
-        public EncryptionList [] Encryption;
-
-        private KeyDataList() {
-            Count = 0;
-            Encryption = null;
-        }
-
-        private KeyDataList(byte setcount) {
-            Count = 0;
-            Encryption = null;
-
-            SetCount(setcount);
-        }
-
-        private int SetCount(byte setcount) {
-            if (setcount <= 0 || setcount > MAX_SMARTKEY_COUNT) return -1;
-
-            Count = setcount;
-            Encryption = new EncryptionList[setcount];
-            for (byte i = 0; i < setcount; i++) Encryption[i] = new EncryptionList();
-
-            return 0;
-        }
-
-        private byte [] getByteArray() {
-            if (Encryption == null) return null;
-
-            byte [] retdata = new byte [(Count * 16) + 1];
-            int index = 0;
-            retdata[index++] = Count;
-
-            for (byte dataIdx = 0; dataIdx < Count; dataIdx++) {
-                for (int i = 0; i < 16; i++) {
-                    retdata[index++] = Encryption[dataIdx].Data[i];
-                }
-            }
-
-            return retdata;
-        }
-
-        public String ToDebugString() {
-            String retStr =
-                    "==========================\r\n" +
-                            "KeyDataList\r\n" +
-                            "==========================\r\n";
-
-            retStr += "Count : " + Count + "\r\n";
-
-            if (Count > 0) {
-                for(byte i = 0; i < Count; i++) retStr += Encryption[i].ToDebugString(i+1) + "\r\n";
-            }
-            retStr += "==========================\r\n";
-
-            return retStr;
-        }
-    }
-
-    private class GetRegisterDataList {
-        boolean Exit;
-        byte RegResult;
-        public EncryptionList Encryption;
-
-        private GetRegisterDataList() {
-            Exit = false;
-            RegResult = 0x00;
-            Encryption = null;
-        }
-    }
-
-    private class SetRegisterDataList {
-        byte [] LocalCode;
-        byte [] SiteCode;
-        byte [] DongCode;
-        byte [] HoCode;
-        byte CardRegNo;
-
-        private SetRegisterDataList() {
-            LocalCode = new byte [] { 0x00, 0x00 };
-            SiteCode  = new byte [] { 0x00, 0x00 };
-            DongCode  = new byte [] { 0x00, 0x00 };
-            HoCode    = new byte [] { 0x00, 0x00 };
-            CardRegNo = 0x00;
-        }
-
-        public int setSiteCode(byte [] InCode) {
-            if (InCode == null) return -1;
-            if (InCode.length < 4) return -2;
-            if (LocalCode == null) return -3;
-            if (SiteCode == null) return -4;
-
-            LocalCode[0] = InCode[0];
-            LocalCode[1] = InCode[1];
-            SiteCode[0] = InCode[2];
-            SiteCode[1] = InCode[3];
-
-            return 0;
-        }
-
-        public int setDongHoCode(byte [] InCode) {
-            if (InCode == null) return -1;
-            if (InCode.length < 4) return -2;
-            if (DongCode == null) return -3;
-            if (HoCode == null) return -4;
-
-            DongCode[0] = InCode[0];
-            DongCode[1] = InCode[1];
-            HoCode[0] = InCode[2];
-            HoCode[1] = InCode[3];
-
-            return 0;
-        }
-
-        public int setLocalCode(byte [] InCode) {
-            if (InCode == null) return -1;
-            if (InCode.length < 2) return -2;
-            if (LocalCode == null) return -3;
-
-            LocalCode[0] = InCode[0];
-            LocalCode[1] = InCode[1];
-            return 0;
-        }
-
-        public byte [] getByteArray() {
-            if (LocalCode == null) return null;
-            if (SiteCode == null) return null;
-            if (DongCode == null) return null;
-            if (HoCode == null) return null;
-
-            byte [] retArray = new byte [9];
-            int index = 0;
-
-            retArray[index++] = LocalCode[0];
-            retArray[index++] = LocalCode[1];
-            retArray[index++] = SiteCode[0];
-            retArray[index++] = SiteCode[1];
-            retArray[index++] = DongCode[0];
-            retArray[index++] = DongCode[1];
-            retArray[index++] = HoCode[0];
-            retArray[index++] = HoCode[1];
-            retArray[index++] = CardRegNo;
-
-            return retArray;
-        }
-    }
-
-    public class Driver {
-        private PollingList Polling;
-
-        private InfoList Info;
-
-        private StatusList Status;
-
-        private SensorValue Sensor_Value;
-
-        private byte [] DongHoBCD;
-
-        private byte [] SiteCodeBCD;
-
-        private boolean RegisterInitMode;
-
-        private byte CardRegNo;
-
-        public Driver() {
-            Polling = new PollingList();
-
-            Info    = new InfoList();
-
-            Status  = new StatusList();
-
-            Sensor_Value = new SensorValue();
-
-            DongHoBCD   = new byte [] { 0, 0, 0, 0 };
-            SiteCodeBCD = new byte [] { 0, 0, 0, 0 };
-
-            RegisterInitMode = false;
-
-            CardRegNo = 0x00;
-        }
-
-        /** Polling 관련 */
-        private class PollingList {
-            private final class STATUS {
-                /** 초기화 과정 */
-                public final static byte First = 0;
-                /** 초기화 타임아웃 */
-                public final static byte FirstTimeOut = 1;
-                /** 평상시 */
-                public final static byte Normal = 2;
-                /** 등록모드 시작 버튼 체크 */
-                public final static byte RegisterStartCheck = 4;
-                /** 등록모드 */
-                public final static byte Register = 5;
-                /** 등록후 일시정지 */
-                public final static byte RegisterPause = 6;
-            }
-
-            public byte Status;
-            public int SearchTryCount;
-            public boolean bRandomKeyGeneration;
-            public byte [] RandomKeyBuffer;
-
-            public long RegisterPauseTimeOutTick;
-
-			public long RssiSyncTick;
-			public long LedSyncTick;
-			public long CamSyncTick;
-            public long TimeSyncTick;
-
-            private PollingList() {
-                SetStatus(STATUS.First);
-                SearchTryCount = 0;
-
-                bRandomKeyGeneration = true;
-                RandomKeyBuffer = new byte [] { 0x00, 0x00 };
-                RegisterPauseTimeOutTick = 0;
-
-				RssiSyncTick = 0;
-                LedSyncTick = 0;
-                CamSyncTick = 0;
-                TimeSyncTick = 0;
-            }
-
-            public void SetStatus(byte ChangeStatus) {
-                switch (ChangeStatus) {
-                    case STATUS.First:
-                        Status = ChangeStatus;
-                        break;
-
-                    case STATUS.FirstTimeOut:
-                        Status = ChangeStatus;
-                        break;
-
-                    case STATUS.Normal:
-                        if ((Status == STATUS.RegisterStartCheck) || (Status == STATUS.Register) || (Status == STATUS.RegisterPause)) {
-                            StatusChanged(STATUS_REGMODE_END);
-                        }
-                        Status = ChangeStatus;
-                        break;
-
-                    case STATUS.RegisterStartCheck:
-                        Status = ChangeStatus;
-                        break;
-
-                    case STATUS.Register:
-                        Status = ChangeStatus;
-                        break;
-
-                    case STATUS.RegisterPause:
-                        RegisterPauseTimeOutTick = System.currentTimeMillis();
-                        Status = ChangeStatus;
-                        break;
-                }
-            }
-        }
-    }
-
-    private Driver mDriver = null;
-
-    private DriverInterOpAPI driverInterOpAPI;
-
-    /**
-     * 생성자
-     */
-    public SmartKeyRfDoor_Controller() {
-        /* 로그 초기상태 */
-//        log_sw = true;
-//        SerialLog = true;
-
-        /* 통신성공률 변수 초기화 */
-        super.CommDataGeneration(1);
-
-        /* 드라이버 내부 변수 초기화 */
-        mDriver = new Driver();
-
-        /* 동호 가져오기 */
-        byte [] DongHoBCD = getDongHo_BCD();
-        if (DongHoBCD != null) mDriver.DongHoBCD = DongHoBCD;
-        Log.i(TAG, "DongHoBCD   : " + ToByteString(mDriver.DongHoBCD));
-
-        /* 사이트코드 가져오기 */
-        byte [] SiteCodeBCD = getSiteCode_BCD();
-        if (SiteCodeBCD != null) mDriver.SiteCodeBCD = SiteCodeBCD;
-        Log.i(TAG, "SiteCodeBCD : " + ToByteString(mDriver.SiteCodeBCD));
-
-        /* 도어락 타입 가져오기 */
-        int getDoorLockType = getDoorLockType();
-        if (getDoorLockType >= 0) {
-            mDoorLockType = getDoorLockType;
-        }
-        else {
-            Log.i(TAG, "getDoorLockType Error (ret:" + getDoorLockType + ")");
-        }
-
-        if (mDoorLockType == WallpadDeviceSet.DOORLOCK_TYPE_RF || mDoorLockType == WallpadDeviceSet.DOORLOCK_TYPE_FINGERPRINT) {
-            int getDoorOpenDelayUse = getDoorLockOpenDelayUse();
-            if (getDoorOpenDelayUse > 0) {
-                mDoorOpenDelay = true;
-                Log.i(TAG, "mDoorOpenDelay : " + mDoorOpenDelay);
-            }
-        }
-
-        Log.i(TAG, "=========================================");
-        Log.i(TAG, "SmartKeyRfDoor_Controller - create");
-        Log.i(TAG, "=========================================");
-    }
-
-    @Override
-    public void DeviceLog(String msg) {
-        if (!log_sw) return;
-        Log.d(TAG, msg);
-    }
-
-    /**
-     * BroadcastReceiver
-     */
-    private BroadcastReceiver mWallPadNotifyBR = new BroadcastReceiver()
-    {
-        public void onReceive(Context context, Intent intent)
-        {
-            String acname = intent.getAction();
-
-            DeviceLog("Receive Notify BR [" + acname + "]");
-
-            if (mDriver.Polling.Status != Driver.PollingList.STATUS.Normal) return;
-
-            if (acname.equals(define.NOTIFY_ACNAME)) {
-                int kind = intent.getIntExtra("KIND", 0);
-                DeviceLog("Receive Notify BR " + define.NOTIFY_ACNAME + " : " + kind);
-
-            }
-
-        }
-
-    };
-
-    /**
-     * BroadcastReceiver 용 필터를 등록한다.
-     *
-     * @return (boolean) true : 성공 , false : 실패
-     */
-    private boolean Device_BrRegistration() {
-        DeviceLog("Device_BrRegistration - Start");
-
-        if (mDriver == null) return false;
-        if (mDriver.Polling.Status != Driver.PollingList.STATUS.Normal) return false;
-
-        IntentFilter filter = new IntentFilter();
-
-        // 1. NOTIFY_ACNAME
-        DeviceLog("Device_BrRegistration - filter.addAction - " + define.NOTIFY_ACNAME);
-        filter.addAction(define.NOTIFY_ACNAME);
-
-        ServiceMain.svcContext.registerReceiver(mWallPadNotifyBR, filter);
-
-        DeviceLog("Device_BrRegistration - OK");
-        return true;
-    }
-
-    /**
-     * 로딩후 처음 폴링 시퀀스
-     */
-    @Override
-    protected void do_boot()
-    {
-        driverInterOpAPI = new DriverInterOpAPI(MainHandler);
-    }
-
-    ///////////////////////////////////////////////////////////////////////////////////////////////
-    // Polling
-    ///////////////////////////////////////////////////////////////////////////////////////////////
-    /**
-     * do_ctr : 폴링스케쥴러
-     */
-    @Override
-    protected void do_ctr() {
-        DeviceLog("Polling ");
-
-        /* [[ First & FirstTimeOut ]]
-         * 초기 디바이스정보  검색 */
-        if ((mDriver.Polling.Status == Driver.PollingList.STATUS.First) || (mDriver.Polling.Status == Driver.PollingList.STATUS.FirstTimeOut)) {
-            // 1. TimeOut Check
-            if (mDriver.Polling.Status == Driver.PollingList.STATUS.First) {
-                if (mDriver.Polling.SearchTryCount++ > MAX_SEARCH_COUNT) {
-                    mDriver.Polling.SetStatus(Driver.PollingList.STATUS.FirstTimeOut);
-
-                    Log.i(TAG, "--------------------------------------------------");
-                    Log.i(TAG, "SearchDevice Fail... FirstTimeOut ");
-                    Log.i(TAG, "--------------------------------------------------");
-
-                    ServiceMain.deviceInitChecker.Remove(super.DeviceName);
-                }
-            }
-
-            // 2. 기기정보 읽기
-            InfoList Info = Send_GetDeviceInfo();
-            if (Info != null) {
-                mDriver.Info = Info;
-                Log.i(TAG, "First Smart Cam Information ~~~");
-                Log.i(TAG, mDriver.Info.ToDebugString());
-
-                mDriver.Polling.SetStatus(Driver.PollingList.STATUS.Normal);
-
-                ServiceMain.deviceInitChecker.Remove(super.DeviceName);
-
-                Device_BrRegistration();
-            }
-        }
-        /* [[ Normal ]]
-         * 평상시 */
-        else if (mDriver.Polling.Status == Driver.PollingList.STATUS.Normal) {
-			long currentTimeMillis = 0;
-
-            if (mDriver.Info.bSensorUsage) {
-                if (firstSensor) {
-                    Log.i(TAG, "First Smart Cam Send_SetSensorConfig Sending @@@@@@@");
-                    if (Send_SetSensorConfig((byte)0xFF, (byte)0xFF) >= 0) {
-                        Log.i(TAG, "First Smart Cam Get Sensor Config !!!");
-						Sleep(150);
-					}
-
-                    Log.i(TAG, "First Smart Cam Send_SetDetectRatio Sending @@@@@@@");
-					if (Send_SetDetectRatio((byte)0xFF) >= 0) {
-                        Log.i(TAG, "First Smart Cam Get Ratio !!!");
-						Sleep(150);
-					}
-
-                    Log.i(TAG, "First Smart Cam Send_SetLedMode Sending @@@@@@@");
-                    if (Send_SetLedMode( (byte)0xFF) >= 0) {
-                        Log.i(TAG, "First Smart Cam Get Led Mode !!!");
-                        Sleep(150);
-                    }
-
-                    Log.i(TAG, "First Smart Cam Send_SetRSSIMode1 Sending @@@@@@@");
-                    if (Send_SetRSSIMode((byte)0x01, (byte)0xFF) >= 0) {
-                        Log.i(TAG, "First Smart Cam Get RSSI mode !!!");
-                        Sleep(150);
-                    }
-
-                    Log.i(TAG, "First Smart Cam Send_SetCameraMode Sending @@@@@@@");
-                    if (Send_SetCameraMode( (byte)0xFF) >= 0) {
-                        Log.i(TAG, "First Smart Cam Get Camera Mode !!!");
-                        Sleep(150);
-                    }
-
-                    // 2. 기본 상태 요청
-                    StatusList Status = Send_GetStatus(mDriver.Polling.RandomKeyBuffer, true);
-                    if (Status != null) {
-                        Send_SetStatusClr(Status);
-                    }
-
-                    if (mDriver.Sensor_Value.Sensor_LedMode == (byte)0x01) {
-                        // 최초에 LED 켜져있으면 끈다.
-                        if (Send_SetLedMode( (byte)0x00) >= 0) {
-                            Log.i(TAG, "First Smart Cam - Turn Off LED $$$");
-                            Sleep(150);
-                        }
-                    }
-
-                    if (mDriver.Sensor_Value.Sensor_CameraMode == (byte)0x01) {
-                        // 최초에 카메라 열려있으면 닫는다.
-                        if (Send_SetCameraMode( (byte)0x00) >= 0) {
-                            Log.i(TAG, "First Smart Cam Turn Off Camera $$$");
-                            Sleep(150);
-                        }
-                    }
-
-                    firstSensor = false;
-                    Log.d(TAG, "@@@@@@@ First SmartCam Status @@@@@@@");
-                    if(mDriver.Sensor_Value!=null)
-                        Log.d(TAG, mDriver.Sensor_Value.ToDebugString());
-                }
-            }
-
-            // LED 모드 설정값 확인
-            if (mDriver.Info.bLEDLightCtrlable) {
-                currentTimeMillis = System.currentTimeMillis();
-                if (Math.abs(currentTimeMillis - mDriver.Polling.LedSyncTick) > LED_SYNC_TICK) {
-                    mDriver.Polling.LedSyncTick = currentTimeMillis;
-
-                    if (Send_SetSensorConfig((byte)0xFF, (byte)0xFF) >= 0) {
-                        Sleep(150);
-                    }
-
-                    if (Send_SetLedMode( (byte)0xFF) >= 0) {
-                        Sleep(150);
-                    }
-                }
-            }
-
-			// RSSI 설정값 확인
-			if (mDriver.Info.bRSSICtrlable) {
-				currentTimeMillis = System.currentTimeMillis();
-				if (Math.abs(currentTimeMillis - mDriver.Polling.RssiSyncTick) > RSSI_SYNC_TICK) {
-					mDriver.Polling.RssiSyncTick = currentTimeMillis;
-
-					if (Send_SetRSSIMode((byte)0x01, (byte)0xFF) >= 0) {
-						Sleep(150);
-					}
-				}
-			}
-
-            // 카메라 모드 설정값 확인
-            if (mDriver.Info.bCameraCtrlable) {
-                currentTimeMillis = System.currentTimeMillis();
-                if (Math.abs(currentTimeMillis - mDriver.Polling.CamSyncTick) > CAM_SYNC_TICK) {
-                    mDriver.Polling.CamSyncTick = currentTimeMillis;
-
-                    if (Send_SetCameraMode( (byte)0xFF) >= 0) {
-                        Sleep(150);
-                    }
-                }
-            }
-
-            // 1. RandomKey 생성여부
-            if (mDriver.Polling.bRandomKeyGeneration) {
-                mDriver.Polling.bRandomKeyGeneration = false;
-
-                SecureRandom rd = new SecureRandom();
-                rd.nextBytes(mDriver.Polling.RandomKeyBuffer);
-
-                Log.i(TAG, "RandomKey Generation!!!   RandomKeyValue " + "1:" + String.format("0x%02X", mDriver.Polling.RandomKeyBuffer[0]) + ", " + "2:" + String.format("0x%02X", mDriver.Polling.RandomKeyBuffer[1]));
-            }
-
-            // 2. 기본 상태 요청
-            // 시간정보 지원 확인
-            StatusList Status = null;
-            if (mDriver.Info.bTimeUsage) {
-                currentTimeMillis = System.currentTimeMillis();
-                if (Math.abs(currentTimeMillis - mDriver.Polling.TimeSyncTick) > TIME_SYNC_TICK) {
-                    mDriver.Polling.TimeSyncTick = currentTimeMillis;
-                    Status = Send_GetStatus(mDriver.Polling.RandomKeyBuffer, true);
-                    if (Status == null) return;
-                }
-                else {
-                    Status = Send_GetStatus(mDriver.Polling.RandomKeyBuffer, false);
-                    if (Status == null) return;
-                }
-            }
-            else {
-                Status = Send_GetStatus(mDriver.Polling.RandomKeyBuffer, false);
-                if (Status == null) return;
-            }
-
-
-            // 3. 기본 상태에서 버튼 눌림 처리
-            UpdateVariables(Status);
-
-            // 4. 스마트 키값 확인
-            if (Status.SmartKeyCount > 0) {
-                mDriver.Polling.bRandomKeyGeneration = true;
-
-                // 스마트 키값 요청
-                KeyDataList KeyData = Send_GetSmartKey(Status.SmartKeyCount);
-                if (KeyData == null) return;
-                Log.i(TAG, KeyData.ToDebugString());
-
-                // 스마트 키값 확인
-                boolean bRet = Send_SetSmartKeyVerify(KeyData);
-                if (!bRet) return;
-                Log.i(TAG, "SmartKeyVerify OK!!!");
-
-                // 키값 업데이트
-                UpdateVariables(KeyData);
-            }
-        }
-
-        /* [[ RegisterStartCheck ]]
-         * 등록모드 시작버튼 체크 */
-        else if (mDriver.Polling.Status == Driver.PollingList.STATUS.RegisterStartCheck) {
-            int ret = Send_SetSmartKeyRegisterStart();
-            if (ret >= 0) {
-                UpdateVariables(ret);
-            }
-        }
-
-        /* [[ Register ]]
-         * 등록모드  */
-        else if (mDriver.Polling.Status == Driver.PollingList.STATUS.Register) {
-            SetRegisterDataList setRegisterDataList = new SetRegisterDataList();
-            if (!mDriver.RegisterInitMode) {
-                setRegisterDataList.setSiteCode(mDriver.SiteCodeBCD);
-                setRegisterDataList.setDongHoCode(mDriver.DongHoBCD);
-
-                setRegisterDataList.CardRegNo = mDriver.CardRegNo;
-            }
-
-            GetRegisterDataList getRegisterDataList = Send_GetSmartKeyRegister(setRegisterDataList);
-            if (getRegisterDataList != null) {
-                UpdateVariables(getRegisterDataList);
-            }
-        }
-
-        /* [[ RegisterPause ]]
-         * 등록후 일시정지  */
-        else if (mDriver.Polling.Status == Driver.PollingList.STATUS.RegisterPause) {
-            long currentTimeMillis = System.currentTimeMillis();
-            if (Math.abs(currentTimeMillis - mDriver.Polling.RegisterPauseTimeOutTick) > REGISTERPAUSE_TIMEOUT_TICK) {
-                Send_SetSmartKeyRegisterEnd();
-                mDriver.Polling.SetStatus(Driver.PollingList.STATUS.Normal);
-            }
-        }
-
-        /*
-         * 예외처리 */
-        else {
-            mDriver = new Driver();
-        }
-    }
-
-    ///////////////////////////////////////////////////////////////////////////////////////////////
-    // Ctrl
-    ///////////////////////////////////////////////////////////////////////////////////////////////
-    /**
-     * NoSink 제어
-     *
-     * @param StrArg
-     *
-     * @return
-     */
-    public String NoSinkCtrl(String StrArg) {
-        DeviceLog("[NoSinkCtrl] Start");
-
-        // 1. 디바이스 초기화시 에러리턴
-        if ((mDriver.Polling.Status == Driver.PollingList.STATUS.First) || (mDriver.Polling.Status == Driver.PollingList.STATUS.FirstTimeOut)) {
-            Log.w(TAG, "[NoSinkCtrl] - Not Yet !!!");
-            return "FAIL;" + APIErrorCode.DEVICEISNOTREADY;
-        }
-
-        CtrDevFormat ctrDevFormat = GetCtrDevParamParsing(StrArg, 5);
-        if (ctrDevFormat.ret != APIErrorCode.C_SUCCESS) {
-            Log.w(TAG, "[NoSinkCtrl] GetCtrDevParamParsing Error (ret:" + ctrDevFormat.ret + ")");
-            return "FAIL;" + APIErrorCode.DEFAULT_PARSING_ERR;
-        }
-
-        //////////////////////////////////////////////////////////
-        // Refresh : 데이터 갱신 (No Sink)
-        //////////////////////////////////////////////////////////
-        if (ctrDevFormat.CmdStr!=null && ctrDevFormat.CmdStr.equals("Refresh")) {
-            DeviceLog("[Refresh] Enter ~~~");
-
-            return RefreshResult();
-        }
-
-        return "FAIL;" + APIErrorCode.UNKNOWNCOMMAND;
-    }
-
-    /**
-     * do_ctrEmm : 싱크 제어
-     */
-    @Override
-    @SuppressLint("DefaultLocale")
-    protected String do_ctrEmm(DeviceCtrSHMem SHMem) {
-        DeviceLog("[do_ctrEmm] Start");
-        DeviceLog("cmd    : " + SHMem.cmd);
-        DeviceLog("StrArg : " + SHMem.StrArg);
-
-        // 1. 디바이스 초기화시 에러리턴
-        if ((mDriver.Polling.Status == Driver.PollingList.STATUS.First) || (mDriver.Polling.Status == Driver.PollingList.STATUS.FirstTimeOut)) {
-            Log.w(TAG, "[do_ctrEmm] - Not Yet !!!");
-            return SHMem.retVal = "FAIL;" + APIErrorCode.DEVICEISNOTREADY;
-        }
-
-        CtrDevFormat ctrDevFormat = GetCtrDevParamParsing(SHMem.StrArg, 5);
-        if (ctrDevFormat.ret != APIErrorCode.C_SUCCESS) {
-            Log.w(TAG, "[do_ctrEmm] GetCtrDevParamParsing Error (ret:" + ctrDevFormat.ret + ")");
-            return SHMem.retVal = "FAIL;" + APIErrorCode.DEFAULT_PARSING_ERR;
-        }
-
-        if(ctrDevFormat.CmdStr!=null)
-        {
-            //////////////////////////////////////////////////////////
-            // SetRegisterModeStart : 등록모드 시작 요청 (Sink)
-            //
-            // [0] - 초기화옵션 ( 0 : 노말 , 1 : 키 초기화 (시험용) )
-            //////////////////////////////////////////////////////////
-            if (ctrDevFormat.CmdStr.equals("SetRegisterModeStart")) {
-                int ret = 0;
-
-                // 1. Mode Check
-                if ((mDriver.Polling.Status == Driver.PollingList.STATUS.Register) || (mDriver.Polling.Status == Driver.PollingList.STATUS.RegisterPause)) {
-                    // 이전 상태가 등록모드였다면 등록모드 종료
-                    Log.w(TAG, "Old Mode Register - RegisterModeEnd !!!");
-
-                    ret = Send_SetSmartKeyRegisterEnd();
-                    if (ret != 1) {
-                        return SHMem.retVal = "FAIL;" + APIErrorCode.DEVICEISNORESPONSE;
-                    }
-                }
-
-                // 2. 등록모드 시작
-                ret = Send_SetSmartKeyRegisterStart();
-                if (ret < 0) {
-                    return SHMem.retVal = "FAIL;" + APIErrorCode.DEVICEISNORESPONSE;
-                }
-
-                // 3. 사이트 코드 가져오기
-                byte [] SiteCodeBCD = getSiteCode_BCD();
-                if (SiteCodeBCD != null) mDriver.SiteCodeBCD = SiteCodeBCD;
-                Log.i(TAG, "SiteCodeBCD : " + ToByteString(mDriver.SiteCodeBCD));
-
-                mDriver.Polling.SetStatus(Driver.PollingList.STATUS.RegisterStartCheck);
-
-                // 4. Param 적용
-                if (ctrDevFormat.param[0] == 0) mDriver.RegisterInitMode = false;
-                else mDriver.RegisterInitMode = true;
-
-                UpdateVariables(ret);
-
-                return SHMem.retVal = "SUCCESS";
-            }
-
-            //////////////////////////////////////////////////////////
-            // SetRegisterModeNext : 등록모드 연장 진행 요청 (Sink)
-            //////////////////////////////////////////////////////////
-            else if (ctrDevFormat.CmdStr.equals("SetRegisterModeNext")) {
-                // 1. Mode Check
-
-                // 이전 상태가 [등록후 일시정지]가 아니라면 에러
-                if (mDriver.Polling.Status != Driver.PollingList.STATUS.RegisterPause) {
-                    // 이전 상태 [등록모드] 였을 경우
-                    if (mDriver.Polling.Status == Driver.PollingList.STATUS.Register) {
-                        //
-                        int id = DB_GetId();
-                        if (id <= 0) {
-                            Log.w(TAG, "SetRegisterModeNext - DB_GetId  Out Of Range #1 (id:" + id + ")");
-                            mDriver.Polling.SetStatus(Driver.PollingList.STATUS.Normal);
-                            return SHMem.retVal = "FAIL;" + APIErrorCode.STATUS_OUTOFRANGE;
-                        }
-                        else {
-                            mDriver.CardRegNo = (byte)id;
-                            super.StatusChanged( (byte)(STATUS_REGMODE_START | mDriver.CardRegNo));
-                            return SHMem.retVal = "SUCCESS";
-                        }
-                    }
-                    // 이전 상태가 [등록후 일시정지] or [등록모드] 둘다 아님
-                    else {
-                        Log.w(TAG, "[SetRegisterModeNext] Old Mode 'RegisterPause' is Not !!!");
-                        return SHMem.retVal = "FAIL;" + APIErrorCode.STATUS_OUTOFRANGE;
-                    }
-                }
-
-                // 2. Next id 가져오기
-                if (!mDriver.RegisterInitMode) {
-                    int id = DB_GetId();
-                    if (id <= 0) {
-                        Log.w(TAG, "SetRegisterModeNext - DB_GetId  Out Of Range #2 (id:" + id + ")");
-                        mDriver.Polling.SetStatus(Driver.PollingList.STATUS.Normal);
-                        if (id == -1) super.StatusChanged(STATUS_REGMODE_FULL);
-                        return SHMem.retVal = "FAIL;" + APIErrorCode.STATUS_OUTOFRANGE;
-                    }
-                    else {
-                        mDriver.CardRegNo = (byte)id;
-                        super.StatusChanged( (byte)(STATUS_REGMODE_START | mDriver.CardRegNo));
-                        mDriver.Polling.SetStatus(Driver.PollingList.STATUS.Register);
-                        return SHMem.retVal = "SUCCESS";
-                    }
-                }
-                else {
-                    mDriver.Polling.SetStatus(Driver.PollingList.STATUS.Normal);
-                    return SHMem.retVal = "SUCCESS";
-                }
-            }
-
-            //////////////////////////////////////////////////////////
-            // RegisterModeEnd : 등록모드 종료 요청 (Sink)
-            //////////////////////////////////////////////////////////
-            else if (ctrDevFormat.CmdStr.equals("SetRegisterModeEnd")) {
-                int ret = 0;
-
-                for (int ReTryCount = 0; ReTryCount < 3; ReTryCount++) {
-                    ret = Send_SetSmartKeyRegisterEnd();
-                    if (ret == 1) break;
-                }
-
-                mDriver.Polling.SetStatus(Driver.PollingList.STATUS.Normal);
-
-                if (ret == 1) {
-                    return SHMem.retVal = "SUCCESS";
-                }
-                else {
-                    return SHMem.retVal = "FAIL;" + APIErrorCode.DEVICEISNORESPONSE;
-                }
-            }
-
-            //////////////////////////////////////////////////////////
-            // SetDeleteKey : 카드 삭제 알림 (Sink)
-            //////////////////////////////////////////////////////////
-            else if (ctrDevFormat.CmdStr.equals("SetDeleteKey")) {
-                SetRegisterDataList setRegisterDataList = new SetRegisterDataList();
-                setRegisterDataList.setSiteCode(mDriver.SiteCodeBCD);
-                setRegisterDataList.setDongHoCode(mDriver.DongHoBCD);
-
-                byte[] TempLocalCode = new byte[2];
-                if (ctrDevFormat.param[0] == 1) {
-                    //전체
-                    TempLocalCode[0] = (byte) 0xFA;
-                    TempLocalCode[1] = (byte) 0xFA;
-                }
-                else if (ctrDevFormat.param[0] == 0) {
-                    //개별
-                    TempLocalCode[0] = (byte) 0xF0;
-                    TempLocalCode[1] = (byte) 0xF0;
-                    setRegisterDataList.CardRegNo = ctrDevFormat.param[1];
-                }
-                else {
-                    Log.w(TAG, "SetDeleteKey - ctrDevFormat.param[1]  Out Of Range #1 (ctrDevFormat.param[1]:" + ctrDevFormat.param[1] + ")");
-                    return SHMem.retVal = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
-                }
-
-                setRegisterDataList.setLocalCode(TempLocalCode);
-                boolean ret = Send_DeleteKey(setRegisterDataList);
-                if (ret) {
-                    return SHMem.retVal = "SUCCESS";
-                }
-                else {
-                    return SHMem.retVal = "FAIL;" + APIErrorCode.DEVICEISNORESPONSE;
-                }
-            }
-
-            //////////////////////////////////////////////////////////
-            // SetSensorConfig : 센서 감도/시간 설정 요청 (Sink)
-            //////////////////////////////////////////////////////////
-            else if (ctrDevFormat.CmdStr.equals("SetSensorConfig")) {
-                //if(ctrDevFormat.param.length != 2) {return SHMem.retVal = "FAIL;" + APIErrorCode.DEVICEISNORESPONSE;}
-
-                byte Sensivity = ctrDevFormat.param[0];
-                byte Time = ctrDevFormat.param[1];
-                Log.i(TAG, "Sensor Api data : " + Sensivity + " / " + Time);
-
-                try {
-                    if (mDriver.Sensor_Value!=null && Send_SetSensorConfig(Sensivity, Time) >= 0) {
-                        Log.d(TAG, mDriver.Sensor_Value.ToDebugString());
-                    }
-
-                    if (mDriver.Sensor_Value != null) {
-                        return SHMem.retVal = "SUCCESS;" + mDriver.Sensor_Value.Sensor_Sensitivity + ";" + mDriver.Sensor_Value.Sensor_DetectTime;
-                    }
-                    else {
-                        return SHMem.retVal = "FAIL;" + APIErrorCode.DEVICEISNORESPONSE;
-                    }
-                } catch (RuntimeException re) {
-                    LogUtil.errorLogInfo("", TAG, re);
-                    return SHMem.retVal = "FAIL;" + APIErrorCode.EXCEPTION;
-                } catch (Exception e) {
-                    LogUtil.errorLogInfo("", TAG, e);//
-                    return SHMem.retVal = "FAIL;" + APIErrorCode.EXCEPTION;
-                }
-            }
-
-            //////////////////////////////////////////////////////////
-            // SetLEDmode : LED 모드 설정 요청 (Sink)
-            //////////////////////////////////////////////////////////
-            else if(ctrDevFormat.CmdStr.equals("SetLEDmode")) {
-                //if(ctrDevFormat.param.length != 1) {return SHMem.retVal = "FAIL;" + APIErrorCode.DEVICEISNORESPONSE;}
-
-                byte LEDmode = ctrDevFormat.param[0];
-                Log.i(TAG, "LED Api data : " + LEDmode);
-                if (LEDmode < 0 || LEDmode > 6) {
-                    if (LEDmode == 0xFF) { }
-                    else { return "FAIL"; }
-                }
-
-                try {
-                    int ret = Send_SetLedMode(LEDmode);
-                    Log.i(TAG, "[Sink Ctr] Led Control ret 1 : " + ret);
-                    if (ret < 0) {
-                        Log.i(TAG, "[Sink Ctr] Led Control ret 2 : " + ret);
-                        return SHMem.retVal = "FAIL;" + APIErrorCode.DEVICEISNOTREADY;
-                    }
-                    else if (ret == 0) {
-                        return SHMem.retVal = "FAIL;" + APIErrorCode.DEVCTRNULL;
-                    }
-                    else if (ret == 1) {
-                        Log.d(TAG, mDriver.Sensor_Value.ToDebugString());
-
-                        return SHMem.retVal = "SUCCESS";
-                    }
-                    else if (ret == 2) {
-                        return SHMem.retVal = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
-                    }
-                    else {
-                        return SHMem.retVal = "FAIL;" + APIErrorCode.DEVICEISNOTREADY;
-                    }
-                } catch (RuntimeException re) {
-                    LogUtil.errorLogInfo("", TAG, re);
-                    return SHMem.retVal = "FAIL;" + APIErrorCode.EXCEPTION;
-                } catch (Exception e) {
-                    LogUtil.errorLogInfo("", TAG, e);//
-                    return SHMem.retVal = "FAIL;" + APIErrorCode.EXCEPTION;
-                }
-            }
-
-            //////////////////////////////////////////////////////////
-            // SetRSSImode : RSSI 모드 설정 요청 (Sink)
-            //////////////////////////////////////////////////////////
-            else if (ctrDevFormat.CmdStr.equals("SetRSSImode")) {
-                //if(ctrDevFormat.param.length != 2) {return SHMem.retVal = "FAIL;" + APIErrorCode.DEVICEISNORESPONSE;}
-
-                byte RSSImode = ctrDevFormat.param[0];
-                byte RSSIlevel = ctrDevFormat.param[1];
-                Log.i(TAG, "RSSI Api mode : " + RSSImode);
-                Log.i(TAG, "RSSI Api level : " + RSSIlevel);
-
-                if (RSSImode < 0 || RSSImode > 2) {return "FAIL";}
-                if (RSSIlevel < -100 || RSSIlevel > 100) {
-                    if (RSSIlevel == 0xFF) { }
-                    else { return "FAIL"; }
-                }
-
-                try {
-                    int ret = Send_SetRSSIMode(RSSImode, RSSIlevel);
-                    if (ret < 0) {
-                        return SHMem.retVal = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
-                    }
-                    else if (ret == 0) {
-                        return SHMem.retVal = "FAIL;" + APIErrorCode.DEVCTRNULL;
-                    }
-                    else if (ret == 1) {
-                        Log.d(TAG, mDriver.Sensor_Value.ToDebugString());
-
-                        return SHMem.retVal = "SUCCESS";
-                    }
-                    else if (ret == 2) {
-                        return SHMem.retVal = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
-                    }
-                } catch (RuntimeException re) {
-                    LogUtil.errorLogInfo("", TAG, re);
-                    return SHMem.retVal = "FAIL;" + APIErrorCode.EXCEPTION;
-                } catch (Exception e) {
-                    LogUtil.errorLogInfo("", TAG, e);//e.printStackTrace();
-                    return SHMem.retVal = "FAIL;" + APIErrorCode.EXCEPTION;
-                }
-            }
-
-            //////////////////////////////////////////////////////////
-            // SetStrangerDetectRatio : 판별 감지 빈도 설정 요청 (Sink)
-            //////////////////////////////////////////////////////////
-            else if (ctrDevFormat.CmdStr.equals("SetStrangerDetectRatio")) {
-                //if(ctrDevFormat.param.length != 1) {return SHMem.retVal = "FAIL;" + APIErrorCode.DEVICEISNORESPONSE;}
-
-                byte DetectRatio = ctrDevFormat.param[0];
-                Log.i(TAG, "Detect Ratio Api data : " + DetectRatio);
-//            if(DetectRatio < 0 || DetectRatio > 100)
-//            {
-//				if(DetectRatio == 0xFF) { }
-//				else { return "FAIL"; }
-//            }
-
-                try {
-                    int ret = Send_SetDetectRatio(DetectRatio);
-                    if (ret < 0) {
-                        return SHMem.retVal = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
-                    }
-                    else if (ret == 0) {
-                        return SHMem.retVal = "FAIL;" + APIErrorCode.DEVCTRNULL;
-                    }
-                    else if (ret == 1) {
-                        Log.d(TAG, mDriver.Sensor_Value.ToDebugString());
-
-                        return SHMem.retVal = "SUCCESS";
-                    }
-                    else if (ret == 2) {
-                        return SHMem.retVal = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
-                    }
-                } catch (RuntimeException re) {
-                    LogUtil.errorLogInfo("", TAG, re);
-                    return SHMem.retVal = "FAIL;" + APIErrorCode.EXCEPTION;
-                } catch (Exception e) {
-                    LogUtil.errorLogInfo("", TAG, e);//
-                    return SHMem.retVal = "FAIL;" + APIErrorCode.EXCEPTION;
-                }
-            }
-
-            //////////////////////////////////////////////////////////
-            // SetCAMERAmode : 카메라 모드 설정 요청 (Sink)
-            //////////////////////////////////////////////////////////
-            else if (ctrDevFormat.CmdStr.equals("SetCAMERAmode")) {
-                //if(ctrDevFormat.param.length != 1) {return SHMem.retVal = "FAIL;" + APIErrorCode.DEVICEISNORESPONSE;}
-
-                byte CameraMode = ctrDevFormat.param[0];
-                Log.i(TAG, "Camera Mode Api data : " + CameraMode);
-                if (CameraMode < 0 || CameraMode > 3) {
-                    if (CameraMode == 0xFF) { }
-                    else { return "FAIL"; }
-                }
-
-                try {
-                    int ret = Send_SetCameraMode(CameraMode);
-                    if (ret < 0) {
-                        return SHMem.retVal = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
-                    }
-                    else if (ret == 0) {
-                        return SHMem.retVal = "FAIL;" + APIErrorCode.DEVCTRNULL;
-                    }
-                    else if (ret == 1) {
-                        Log.d(TAG, mDriver.Sensor_Value.ToDebugString());
-
-                        return SHMem.retVal = "SUCCESS";
-                    }
-                    else if (ret == 2) {
-                        return SHMem.retVal = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
-                    }
-                } catch (RuntimeException re) {
-                    LogUtil.errorLogInfo("", TAG, re);
-                    return SHMem.retVal = "FAIL;" + APIErrorCode.EXCEPTION;
-                } catch (Exception e) {
-                    LogUtil.errorLogInfo("", TAG, e);//
-                    return SHMem.retVal = "FAIL;" + APIErrorCode.EXCEPTION;
-                }
-            }
-        }
-
-
-
-        return SHMem.retVal = "UNKNOWNCMD";
-    }
-
-    ///////////////////////////////////////////////////////////////////////////////////////////////
-    // Refresh Result
-    ///////////////////////////////////////////////////////////////////////////////////////////////
-    private String RefreshResult() {
-        String result;
-
-        DeviceLog("RefreshResult call : ");
-
-        // 1. Check Polling Status
-        if ((mDriver.Polling.Status == Driver.PollingList.STATUS.First) || (mDriver.Polling.Status == Driver.PollingList.STATUS.FirstTimeOut)) {
-            result = "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
-            return result;
-        }
-
-        // 2. Make Return String Format
-        try {
-            if (mDriver == null) return "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
-            if (mDriver.Status == null) return "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
-            if (mDriver.Info == null) return "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
-
-            /*
-             * [Format]
-             *
-             * SUCCESS          - (String) 성공
-             *
-             * [Status]
-             * bDoorBtnStatus   - (boolean) 버튼 눌림 상태
-             * bSensorDetect    - (boolean) 거동수상자 감지여부
-             * bLedStatus       - (boolean) LED 상태
-             * bCameraStatus    - (boolean) 카메라 상태
-             * bLedAuto         - (boolean) LED Auto 상태
-             * bCameraAuto      - (boolean) 카메라 Auto 상태
-             * bError           - (boolean) 에러 상태
-             * SmartKeyCount    - (byte)    인식된 스마트키 수
-             *
-             * [Sensor_Value]
-             * Sensor_Sensitivity   - (byte) 센서 감도
-             * Sensor_DetectTime    - (byte) 센서 감지시간
-             * Sensor_LedMode       - (byte) LED 모드
-             * Sensor_RSSI_Read     - (byte) 읽기 RSSI 세기
-             * Sensor_RSSI_Write    - (byte) 쓰기 RSSI 세기
-             * Sensor_DetectRatio   - (byte) 판별빈도
-             * Sensor_CameraMode    - (byte) 카메라 모드
-             */
-
-            result = APIErrorCode.SUCCESS + ";";
-
-            result += mDriver.Status.bDoorBtnStatus + ";";
-            result += mDriver.Status.bSensorDetect + ";";
-            result += mDriver.Status.bLedStatus   + ";";
-            result += mDriver.Status.bCameraStatus   + ";";
-            result += mDriver.Status.bLedAuto  + ";";
-            result += mDriver.Status.bCameraAuto  + ";";
-            result += mDriver.Status.bError + ";";
-            result += mDriver.Status.SmartKeyCount + ";";
-
-            result += mDriver.Sensor_Value.Sensor_Sensitivity + ";";
-            result += mDriver.Sensor_Value.Sensor_DetectTime + ";";
-            result += mDriver.Sensor_Value.Sensor_LedMode + ";";
-            result += mDriver.Sensor_Value.Sensor_RSSI_Read + ";";
-            result += mDriver.Sensor_Value.Sensor_RSSI_Write + ";";
-            result += mDriver.Sensor_Value.Sensor_DetectRatio + ";";
-            result += mDriver.Sensor_Value.Sensor_CameraMode;
-        } catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-            result = "FAIL;"+APIErrorCode.EXCEPTION;
-        } catch (Exception e) {
-            Log.e(TAG, "[Exception Error] RefreshResult");
-            LogUtil.errorLogInfo("", TAG, e);//e.printStackTrace();
-            result = "FAIL;"+APIErrorCode.EXCEPTION;
-        }
-        DeviceLog(" RefreshResult_Sample return : "+result);
-
-        return result;
-    }
-
-
-    ///////////////////////////////////////////////////////////////////////////////////////////////
-    // Protocol Command Send Func
-    ///////////////////////////////////////////////////////////////////////////////////////////////
-
-    /**
-     * 기기 정보 요청 응답.
-     *
-     * @return (InfoList) null - Error , Not null - OK
-     */
-    private InfoList Send_GetDeviceInfo() {
-        DeviceLog("[Send_GetDeviceInfo] Start");
-
-        // 1. In 파라미터 확인
-
-        // 2. 패킷 데이터 만들기
-        byte [] ReqData = null;
-
-        // 3. 데이터 전송 및 응답
-        byte [] Reply = SendNRead_Variable((byte)(DEVICE_ADDRESS), CMDList.Req.GetDeviceInfo, ReqData);
-
-        // 4. 수신데이터 파싱
-        byte data = 0x00;
-        int index = 0;
-        boolean bError = false;
-        while (true) {
-            if (Reply == null) {
-                DeviceLog("[GetDeviceInfo_RepParsing] Reply is null");
-                bError = true; break;
-            }
-
-            if (Reply.length != 9) {
-                Log.w(TAG, "[GetDeviceInfo_RepParsing] Reply.length  fail ... " + Reply.length);
-                bError = true; break;
-            }
-
-            //     1.2. Details Data Check
-            data = 0x00;
-            index = 0;
-
-            //         - D1 : 기능 지원 정보#1
-            data = Reply[index++];
-            if ((data & (byte) (BIT6 | BIT7)) != 0x00) {
-                Log.w(TAG, "[Send_GetDeviceInfo] D1:Unused Bit Set !!! " + String.format("0x%02X", Reply[2]));
-            }
-
-            //         - D2 : 기능 지원 정보#2
-            data = Reply[index++];
-
-            //         - D3 : 제조사구분정보
-            data = Reply[index++];
-
-            //         - D4 : 펌웨어 Build Date (Year)
-            data = Reply[index++];
-
-            //         - D5 : 펌웨어 Build Date (Month)
-            data = Reply[index++];
-            if ((data > 12) || (data <= 0)) {
-                Log.w(TAG, "[GetDeviceInfo_RepParsing] D5 (Build Date - Month) : Out of Range !!! (data:" + data + ")");
-                bError = true; break;
-            }
-
-            //         - D6 : 펌웨어 Build Date (Day)
-            data = Reply[index++];
-            if ((data > 31) || (data <= 0)) {
-                Log.w(TAG, "[GetDeviceInfo_RepParsing] D6 (Build Date - Day) : Out of Range !!! (data:" + data + ")");
-                bError = true; break;
-            }
-
-            //         - D7 : 펌웨어 Build Date (Number)
-            data = Reply[index++];
-
-            //         - D8 : Protocol 버전정보 (Main)
-            data = Reply[index++];
-
-            //         - D9 : Protocol 버전정보 (Sub)
-            data = Reply[index++];
-
-            break;
-        }
-
-        if (bError) {
-            AddDoCount(false);
-            DeviceLog("[Send_GetDeviceInfo] FAIL");
-            return null;
-        }
-
-        AddDoCount(true);
-
-        // 5. Data return
-        InfoList Info = new InfoList();
-        index = 0;
-        data = 0;
-
-        //         - D1 : 기능 지원 정보#1
-        if ((Reply[index] & BIT0) != 0x00) Info.bSensorUsage = true;
-        else Info.bSensorUsage = false;
-
-        if ((Reply[index] & BIT1) != 0x00) Info.bLEDLightCtrlable = true;
-        else Info.bLEDLightCtrlable = false;
-
-        if ((Reply[index] & BIT2) != 0x00) Info.bRSSICtrlable = true;
-        else Info.bRSSICtrlable = false;
-
-        if ((Reply[index] & BIT3) != 0x00) Info.bCameraCtrlable = true;
-        else Info.bCameraCtrlable = false;
-
-        if ((Reply[index] & BIT4) != 0x00) Info.bPIRSensorUsage = true;
-        else Info.bPIRSensorUsage = false;
-
-        if ((Reply[index] & BIT5) != 0x00) Info.bTimeUsage = true;
-        else Info.bTimeUsage = false;
-
-        index++;
-        //         - D2 : 기능 지원 정보#2
-        index++;
-
-        //         - D3 : 제조사 구분정보
-        Info.hVendor = Reply[index++];
-        //         - D4 : 펌웨어 Build Date (Year)
-        Info.hFWVer_Year = Reply[index++];
-        //         - D5 : 펌웨어 Build Date (Month)
-        Info.hFWVer_Month = Reply[index++];
-        //         - D6 : 펌웨어 Build Date (Day)
-        Info.hFWVer_Date = Reply[index++];
-        //         - D7 : 펌웨어 Build Date (Number)
-        Info.hFWVer_No = Reply[index++];
-        //         - D8 : Protocol 버전정보 (Main)
-        Info.hProtocolVer_Main = Reply[index++];
-        //         - D9 : Protocol 버전정보 (Sub)
-        Info.hProtocolVer_Sub = Reply[index++];
-
-        DeviceLog("[Send_GetDeviceInfo] END");
-        return Info;
-    }
-
-    /**
-     * 기본상태 요청 응답.
-     *
-     * @return (StatusList) null - Error , Not null - OK
-     */
-    private StatusList Send_GetStatus(byte[] RandomKey, boolean bSendTime) {
-        DeviceLog("[Send_GetStatus] Start");
-
-        // 1. In 파라미터 확인
-        if (RandomKey == null) {
-            Log.w(TAG, "[Send_GetStatus] Param - RandomKey is null !!!");
-            return null;
-        }
-
-        if (RandomKey.length != 2) {
-            Log.w(TAG, "[Send_GetStatus] Param - RandomKey length Not Match !!! (length:" + RandomKey.length + ")");
-            return null;
-        }
-
-        // 2. 패킷 데이터 만들기
-        byte[] ReqData = new byte [] { RandomKey[0], RandomKey[1] };
-        if (bSendTime) {
-            byte[] TempReqData = new byte[8];
-            Calendar cal = new GregorianCalendar();
-            int index = 0;
-            TempReqData[index++] = RandomKey[0];
-            TempReqData[index++] = RandomKey[1];
-            TempReqData[index++] = (byte) (cal.get(Calendar.YEAR) - 2000);
-            TempReqData[index++] = (byte) (cal.get(Calendar.MONTH) + 1);
-            TempReqData[index++] = (byte) cal.get(Calendar.DAY_OF_MONTH);
-            TempReqData[index++] = (byte) cal.get(Calendar.HOUR_OF_DAY);
-            TempReqData[index++] = (byte) cal.get(Calendar.MINUTE);
-            TempReqData[index++] = (byte) cal.get(Calendar.SECOND);
-            ReqData = TempReqData;
-        }
-        else {
-            byte[] TempReqData = new byte [] { RandomKey[0], RandomKey[1] };
-            ReqData = TempReqData;
-        }
-
-        // 3. 데이터 전송 및 응답
-        byte [] Reply = SendNRead_Variable((byte) (DEVICE_ADDRESS), CMDList.Req.GetStatus, ReqData);
-
-        // 4. 수신데이터 파싱
-        byte data = 0x00;
-        int index = 0;
-
-        boolean bError = false;
-        while (true) {
-            if (Reply == null) {
-                DeviceLog("[GetStatus_RepParsing] Reply is null");
-                bError = true; break;
-            }
-
-            if (Reply.length != 2) {
-                Log.w(TAG, "[GetStatus_RepParsing] Reply.length  fail ... " + Reply.length);
-                bError = true; break;
-            }
-
-            //     1.2. Details Data Check
-            //         - D1 : 현관카메라 상태
-            data = Reply[index++];
-            if ((data & (BIT6)) != 0x00) {
-                Log.w(TAG, "[GetStatus_RepParsing] D1 (Mode) : Unused Bit Set !!! " + String.format("0x%02X", data));
-                //bError = true; break;
-            }
-
-            //         - D2 : 인식된 RF 스마트키 개수
-            data = Reply[index++];
-            if (!((data >= 0) && (data <= 5))) {
-                Log.w(TAG, "[GetStatus_RepParsing] D2 (KeyCount) : Out Of Range !!! " + String.format("0x%02X", data));
-                //bError = true; break;
-            }
-
-            break;
-        }
-
-        if (bError) {
-            AddDoCount(false);
-            DeviceLog("[Send_GetStatus] FAIL");
-            return null;
-        }
-
-        AddDoCount(true);
-
-        // 5. Data return
-        StatusList Status = new StatusList();
-        index = 0;
-        data = 0;
-
-        //         - D1 : 현관카메라 상태
-        data = Reply[index++];
-        if ((byte)(data & BIT0) != 0x00) Status.bDoorBtnStatus = true;
-        else Status.bDoorBtnStatus = false;
-
-        if ((byte)(data & BIT1) != 0x00) Status.bSensorDetect = true;
-        else Status.bSensorDetect = false;
-
-        if ((byte)(data & BIT2) != 0x00) Status.bLedStatus = true;
-        else Status.bLedStatus = false;
-
-        if ((byte)(data & BIT3) != 0x00) Status.bCameraStatus = true;
-        else Status.bCameraStatus = false;
-
-        if ((byte)(data & BIT4) != 0x00) Status.bLedAuto = true;
-        else Status.bLedAuto = false;
-
-        if ((byte)(data & BIT5) != 0x00) Status.bCameraAuto = true;
-        else Status.bCameraAuto = false;
-
-        if ((byte)(data & BIT7) != 0x00) Status.bError = true;
-        else Status.bError = false;
-
-        //         - D2 : 인식된 RF 스마트키 개수
-        data = Reply[index++];
-        if (!((data >= 0) && (data <= 5))) {
-            // 현관카메라 버그로 인한 예외처리 요구사항
-            Log.w(TAG, "[GetStatus_RepParsing] Status.SmartKeyCount will be 5 ");
-            data = 5;
-        }
-        Status.SmartKeyCount = data;
-
-        DeviceLog("[Send_GetStatus] END");
-        return Status;
-    }
-
-    /**
-     * 기본상태값 해제 요청
-     *
-     * @return (boolean) true : 정상 , false : 실패
-     */
-    private boolean Send_SetStatusClr(StatusList ClearStatus) {
-        DeviceLog("[Send_SetStatusClr] Start");
-
-        // 1. In 파라미터 확인
-        if (ClearStatus == null) {
-            Log.w(TAG, "[Send_SetStatusClr] Param - ClearStatus is null !!!");
-            return false;
-        }
-
-        // 2. 패킷 데이터 만들기
-        byte [] ReqData = new byte [] { 0x00 };
-
-        if (ClearStatus.bDoorBtnStatus || firstSensor) ReqData[0] |= BIT0;
-        if (ClearStatus.bSensorDetect || firstSensor) ReqData[0] |= BIT1;
-        if (ClearStatus.bError || firstSensor) ReqData[0] |= BIT7;
-
-
-        // 3. 데이터 전송 및 응답
-        byte [] Reply = SendNRead_Variable( (byte)(DEVICE_ADDRESS), CMDList.Req.SetStatusClr, ReqData);
-
-        // 4. 수신데이터 파싱
-        boolean bError = false;
-        while (true) {
-            if (Reply == null) {
-                DeviceLog("[Send_SetStatusClr] Reply is null");
-                bError = true; break;
-            }
-
-            if (Reply.length != 1) {
-                Log.w(TAG, "[Send_SetStatusClr] Reply.length  fail ... " + Reply.length);
-                bError = true; break;
-            }
-
-            //     1.2. Details Data Check
-            byte data = 0x00;
-            int index = 0;
-            //         - D1 : 현관카메라 상태
-            data = Reply[index++];
-            if ((data & (byte)( BIT2 | BIT3 | BIT4 | BIT5 | BIT6)) != 0x00) {
-                Log.w(TAG, "[Send_SetStatusClr] D1 (Mode) : Unused Bit Set !!! " + String.format("0x%02X", data));
-                bError = true; break;
-            }
-            break;
-        }
-
-        if (bError) {
-            AddDoCount(false);
-            DeviceLog("[Send_SetStatusClr] FAIL");
-            return false;
-        }
-        AddDoCount(true);
-
-        DeviceLog("[Send_SetStatusClr] END");
-        return true;
-    }
-
-    /**
-     * 스마트 키값 요청/반환
-     *
-     * @param ReqSmartKeyCount - (byte) 요청할 스마트RF키 개수
-     *
-     * @return (KeyDataList) 응답받은 KayData : null - Error , Not null - OK
-     */
-    private KeyDataList Send_GetSmartKey(byte ReqSmartKeyCount) {
-        DeviceLog("[Send_GetSmartKey] Start");
-
-        // 1. In 파라미터 확인
-        if ((ReqSmartKeyCount <= 0) || (ReqSmartKeyCount > MAX_SMARTKEY_COUNT)) {
-            Log.w(TAG, "[Send_GetSmartKey] Param - ClearStatus is null !!!");
-            return null;
-        }
-
-        // 2. 패킷 데이터 만들기
-        byte [] ReqData = new byte [] { ReqSmartKeyCount };
-
-        // 3. 데이터 전송 및 응답
-        byte [] Reply = SendNRead_Variable( (byte)(DEVICE_ADDRESS), CMDList.Req.GetSmartKey, ReqData);
-
-        // 4. 수신데이터 파싱
-        boolean bError = false;
-        while (true) {
-            //     null Check
-            if (Reply == null) {
-                DeviceLog("[Send_GetSmartKey] Reply is null");
-                bError = true; break;
-            }
-            //     Length Check
-
-            //Reply[0] bit7 Clear 필요 (현관카메라 버그로 인한 예외처리 요구사항)
-            Reply[0] = (byte) (Reply[0] & 0x7F); //7번 비트 Clear
-
-            int CalcLen = (int) ((byte)(Reply[0] * 16) + 1);
-            if (Reply.length != CalcLen) {
-                Log.w(TAG, "[Send_GetSmartKey] Reply.length  fail ... (length:" + Reply.length + ", CalcLen:" + CalcLen + ")");
-                bError = true; break;
-            }
-
-            byte data = 0x00;
-            int index = 0;
-
-            //     D1 : 응답할 스마트RF키 개수
-            data = Reply[index++];
-            if (data != ReqSmartKeyCount) {
-                Log.w(TAG, "[Send_GetSmartKey] D1 : Req/Rep SmartKeyCount Not Match!!!  ReqSmartKeyCount:" + ReqSmartKeyCount + "   RepSmartKeyCount:" + data);
-                bError = true; break;
-            }
-
-            break;
-        }
-
-        if (bError) {
-            AddDoCount(false);
-            DeviceLog("[Send_GetSmartKey] FAIL");
-            return null;
-        }
-        AddDoCount(true);
-
-        // 5. Data return
-        KeyDataList keyDataList = new KeyDataList(ReqSmartKeyCount);
-        try {
-            for (byte i = 0; i < ReqSmartKeyCount; i++) {
-                keyDataList.Encryption[i].Input(Reply, (int)(1+(i*16)));
-            }
-        } catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-            return null;
-        } catch (Exception e) {
-            Log.e(TAG, "[Send_GetSmartKey] - [Exception Error] ");
-            LogUtil.errorLogInfo("", TAG, e);//e.printStackTrace();
-            return null;
-        }
-
-        DeviceLog("[Send_GetSmartKey] END");
-        return keyDataList;
-    }
-
-    /**
-     * 스마트 키값 요청/반환
-     *
-     * @param ReqKeyData - (KeyDataList) 확인 요청할 스마트키 Class
-     *
-     * @return (KeyDataList) 응답받은 KayData : null - Error , Not null - OK
-     */
-    private boolean Send_SetSmartKeyVerify(KeyDataList ReqKeyData) {
-        DeviceLog("[Send_SetSmartKeyVerify] Start");
-
-        // 1. In 파라미터 확인
-        if (ReqKeyData == null) {
-            Log.w(TAG, "[Send_SetSmartKeyVerify] Param - ReqKeyData is null !!!");
-            return false;
-        }
-
-        // 2. 패킷 데이터 만들기
-        byte [] ReqData = ReqKeyData.getByteArray();
-
-        // 3. 데이터 전송 및 응답
-        byte [] Reply = SendNRead_Variable( (byte)(DEVICE_ADDRESS), CMDList.Req.SetSmartKeyVerify, ReqData);
-
-        // 4. 수신데이터 파싱
-        boolean bError = false;
-
-        while (true) {
-            //     null Check
-            if (Reply == null) {
-                DeviceLog("[Send_SetSmartKeyVerify] Reply is null");
-                bError = true; break;
-            }
-
-            //     Length Check
-            if (Reply.length != 3) {
-                Log.w(TAG, "[Send_SetSmartKeyVerify] Reply.length  fail ... (length:" + Reply.length + ")");
-                bError = true; break;
-            }
-
-            byte data = 0x00;
-            int index = 0;
-
-            //     D1 : 응답할 스마트RF키 개수
-            data = Reply[index++];
-            if (data != ReqKeyData.Count) {
-                Log.w(TAG, "[Send_SetSmartKeyVerify] D1 : Req/Rep SmartKeyCount Not Match!!!  ReqSmartKeyCount:" + ReqKeyData.Count + "   RepSmartKeyCount:" + data);
-                bError = true; break;
-            }
-
-            break;
-        }
-
-        if (bError) {
-            AddDoCount(false);
-            DeviceLog("[Send_SetSmartKeyVerify] FAIL");
-            return false;
-        }
-        AddDoCount(true);
-
-        // 5. 데이터 확인
-        byte[] Result = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00 };
-        for (int i = 0; i < 5; i++) {
-            if (i < 4) Result[i] = (byte)((byte)(Reply[1] >> (i * 2)) & (byte)(BIT0 | BIT1));   // 0 ~ 4
-            else Result[i] = (byte)((byte)(Reply[2] >> 0) & (byte)(BIT0 | BIT1));               // 5
-        }
-
-        for (byte i = 0; i < Reply[0]; i++) {
-            switch (Result[i]) {
-                case 0x00:
-                    Log.w(TAG, "Send_SetSmartKeyVerify - CheckVerify Error0( Index:" + i + ", data:" + String.format("0x%02X", Result[i]) + ")");
-                    return false;
-
-                case 0x01:
-                    // 정상
-                    break;
-
-                case 0x02:
-                    // 오류
-                    Log.w(TAG, "Send_SetSmartKeyVerify - CheckVerify Error2( Index:" + i + ", data:" + String.format("0x%02X", Result[i]) + ")");
-                    return false;
-            }
-        }
-
-        DeviceLog("[Send_SetSmartKeyVerify] END");
-        return true;
-    }
-
-    /**
-     * 등록모드 시작 요청
-     *
-     * @return (int) 진입결과 - >=0 : 성공(0:미진입 , 1:진입) , <0 : 실패
-     */
-    private int Send_SetSmartKeyRegisterStart() {
-        DeviceLog("[Send_SetSmartKeyRegisterStart] Start");
-
-        // 1. In 파라미터 확인
-
-        // 2. 패킷 데이터 만들기
-        byte [] ReqData = null;
-
-        // 3. 데이터 전송 및 응답
-        byte [] Reply = SendNRead_Variable( (byte)(DEVICE_ADDRESS), CMDList.Req.SetSmartKeyRegisterStart, ReqData);
-
-        // 4. 수신데이터 파싱
-        byte data = 0x00;
-        int index = 0;
-        boolean bError = false;
-        while (true) {
-            //     null Check
-            if (Reply == null) {
-                DeviceLog("[Send_SetSmartKeyRegisterStart] Reply is null");
-                bError = true; break;
-            }
-
-            //     Length Check
-            if (Reply.length != 1) {
-                Log.w(TAG, "[Send_SetSmartKeyRegisterStart] Reply.length  fail ... (length:" + Reply.length + ")");
-                bError = true; break;
-            }
-
-            data = 0x00;
-            index = 0;
-
-            //     D1 : 등록모드 시작 상태값
-            data = Reply[index++];
-            if ((data & (byte)(BIT1 | BIT2 | BIT3 | BIT4 | BIT5 | BIT6)) != 0x00) {
-                Log.w(TAG, "[Send_SetSmartKeyRegisterStart] D1 : Unused BIT SET  (data:" + String.format("0x%02X", data) + ")");
-                bError = true; break;
-            }
-
-            break;
-        }
-
-        if (bError) {
-            AddDoCount(false);
-            DeviceLog("[Send_SetSmartKeyRegisterStart] FAIL");
-            return -1;
-        }
-        AddDoCount(true);
-
-
-        // 5. 데이터 확인
-        data = 0x00;
-        index = 0;
-        //      D1 : 등록모드 시작 상태값
-        data = Reply[index++];
-        if ((byte)(data & BIT7) != 0x00) {
-            Log.w(TAG, "[Send_SetSmartKeyRegisterStart] D1 : Error Bit Set !!!");
-            return -10;
-        }
-
-        if ((byte)(data & BIT0) != 0x00) {
-            // 진입 성공
-            DeviceLog("[Send_SetSmartKeyRegisterStart] END");
-            return 1;
-        }
-
-        // 진입 실패
-        DeviceLog("[Send_SetSmartKeyRegisterStart] END");
-        return 0;
-    }
-
-    /**
-     * 등록 스마트 키값 요청/응답
-     *
-     * @return (GetRegisterDataList) null - Error , Not null - OK
-     */
-    private GetRegisterDataList Send_GetSmartKeyRegister(SetRegisterDataList setRegisterData) {
-        DeviceLog("[Send_GetSmartKeyRegister] Start");
-
-        // 1. In 파라미터 확인
-        if (setRegisterData == null) {
-            Log.w(TAG, "[Send_GetSmartKeyRegister] Param - RegisterData is null !!!");
-            return null;
-        }
-
-        // 2. 패킷 데이터 만들기
-        byte [] ReqData = setRegisterData.getByteArray();
-
-        // 3. 데이터 전송 및 응답
-        byte [] Reply = SendNRead_Variable( (byte)(DEVICE_ADDRESS), CMDList.Req.GetSmartKeyRegister, ReqData);
-
-        // 4. 수신데이터 파싱
-        boolean bError = false;
-        byte data = 0x00;
-        int index = 0;
-
-        byte RegResult = 0;
-        while (true) {
-            //     null Check
-            if (Reply == null) {
-                DeviceLog("[Send_GetSmartKeyRegister] Reply is null");
-                bError = true; break;
-            }
-
-            //     Length Check
-            if (Reply.length < 1) {
-                Log.w(TAG, "[Send_GetSmartKeyRegister] Reply.length  fail #1... (length:" + Reply.length + ")");
-                bError = true; break;
-            }
-
-            index = 0;
-
-            //     D1 : 등록모드 상태값
-            data = Reply[index++];
-            if ((data & (byte)(BIT4 | BIT5 | BIT6 | BIT7)) != 0x00) {
-                Log.w(TAG, "[Send_GetSmartKeyRegister] D1 : Unused BIT SET  (data:" + String.format("0x%02X", data) + ")");
-                bError = true; break;
-            }
-
-            if ((data & BIT0) != 0x00) {
-                if (Reply.length != (int)(1+16)) {
-                    Log.w(TAG, "[Send_GetSmartKeyRegister] Reply.length  fail #2... (length:" + Reply.length + ")");
-                    bError = true; break;
-                }
-            }
-
-            RegResult = (byte)((data >> 2) & (byte)(BIT0|BIT1));
-            switch (RegResult) {
-                case 0x00: case 0x01: case 0x02: break;
-                default:
-                    Log.w(TAG, "[Send_GetSmartKeyRegister] RegResult  Out Of Range !!!(RegResult:" + String.format("0x%02X", RegResult) + ")");
-                    bError = true; break;
-            }
-            break;
-        }
-
-        if (bError) {
-            AddDoCount(false);
-            DeviceLog("[Send_GetSmartKeyRegister] FAIL");
-            return null;
-        }
-        AddDoCount(true);
-
-
-        // 5. 데이터 확인
-        index = 0;
-        GetRegisterDataList getRegisterDataList = new GetRegisterDataList();
-
-        data = Reply[index++];
-
-        //     D1 : BIT0 - 등록데이터 준재여부
-        if ((byte)(data & BIT0) != 0x00) {
-            getRegisterDataList.Encryption = new EncryptionList();
-            getRegisterDataList.Encryption.Input(Reply, 1);
-        }
-
-        //          BIT1 - 종료 여부
-        if ((byte)(data & BIT1) != 0x00) {
-            getRegisterDataList.Exit = true;
-        }
-
-        //          BIT2 ~ BIT3 - 등록 결과
-        getRegisterDataList.RegResult  = RegResult;
-
-        DeviceLog("[Send_GetSmartKeyRegister] END");
-        return getRegisterDataList;
-    }
-
-    /**
-     * 등록모드 종료 요청
-     *
-     * @return (int) 진입결과 - >=0 : 성공(0:미진입 , 1:진입) , <0 : 실패
-     */
-    private int Send_SetSmartKeyRegisterEnd() {
-        DeviceLog("[Send_SetSmartKeyRegisterEnd] Start");
-
-        // 1. In 파라미터 확인
-
-        // 2. 패킷 데이터 만들기
-        byte [] ReqData = null;
-
-        // 3. 데이터 전송 및 응답
-        byte [] Reply = SendNRead_Variable( (byte)(DEVICE_ADDRESS), CMDList.Req.SetSmartKeyRegisterEnd, ReqData);
-
-        // 4. 수신데이터 파싱
-        boolean bError = false;
-
-        while (true) {
-            //     null Check
-            if (Reply == null) {
-                DeviceLog("[Send_SetSmartKeyRegisterEnd] Reply is null");
-                bError = true; break;
-            }
-
-            //     Length Check
-            if (Reply.length != 1) {
-                Log.w(TAG, "[Send_SetSmartKeyRegisterEnd] Reply.length  fail ... (length:" + Reply.length + ")");
-                bError = true; break;
-            }
-
-            byte data = 0x00;
-            int index = 0;
-
-            //     D1 : 등록모드 시작 상태값
-            data = Reply[index++];
-            if ((data & (byte)(BIT1 | BIT2 | BIT3 | BIT4 | BIT5 | BIT6)) != 0x00) {
-                Log.w(TAG, "[Send_SetSmartKeyRegisterEnd] D1 : Unused BIT SET  (data:" + String.format("0x%02X", data) + ")");
-                bError = true; break;
-            }
-
-            break;
-        }
-
-        if (bError) {
-            AddDoCount(false);
-            DeviceLog("[Send_SetSmartKeyRegisterEnd] FAIL");
-            return -1;
-        }
-        AddDoCount(true);
-
-
-        // 5. 데이터 확인
-        if ((byte)(Reply[0] & BIT7) != 0x00) {
-            Log.w(TAG, "[Send_SetSmartKeyRegisterEnd] D1 : Error Bit Set !!!");
-            return -10;
-        }
-
-        if ((byte)(Reply[0] & BIT0) != 0x00) {
-            // 종료 성공
-            DeviceLog("[Send_SetSmartKeyRegisterEnd] END");
-            return 1;
-        }
-
-        // 종료 실패
-        DeviceLog("[Send_SetSmartKeyRegisterEnd] END");
-        return 0;
-    }
-
-    /**
-     * 센서 감도/시간 설정 보내기
-     *
-     * @return (int)  >0 : 성공, <0 : 실패
-     */
-    private int Send_SetSensorConfig(byte Sensivity, byte Time) {
-        DeviceLog("[Send_SetSensorConfig] Start");
-
-        // 1. In 파라미터 확인
-        if ((Sensivity < 1 || Sensivity > 5)) {
-            if ((Sensivity == (byte)0xFF)) {
-
-            }
-            else {
-                Log.e(TAG, "[SetSensorConfig] - Sensing Range ERROR : " + Sensivity);
-                return -1;
-            }
-        }
-
-        if ((getInt(Time) < 1 || getInt(Time) > 250)) {
-            if ((Time == (byte)0xFF)) {
-
-            }
-            else {
-                Log.e(TAG, "[SetSensorConfig] - Time Range ERROR :" + Time);
-                return -2;
-            }
-        }
-
-        // 2. 패킷 데이터 만들기
-        byte [] ReqData = {Sensivity, Time};
-
-        // 3. 데이터 전송 및 응답
-        byte [] Reply = SendNRead_Variable( (byte)(DEVICE_ADDRESS), CMDList.Req.SetSensorStatus, ReqData);
-
-        // 4. 수신데이터 파싱
-        boolean bError = false;
-
-        //     null Check
-        if (Reply == null) {
-            DeviceLog("[Send_SetSensorConfig] Reply is null");
-            bError = true;
-        }
-
-        //     Length Check
-        if (Reply != null && Reply.length != 2) {
-            DeviceLog("[Send_SetSensorConfig] Reply.length  fail ... (length:" + Reply.length + ")");
-            bError = true;
-        }
-
-		if (bError) {
-			AddDoCount(false);
-            DeviceLog("[Send_SetSensorConfig] FAIL");
-			return -3;
-		}
-		AddDoCount(true);
-
-        byte data = 0x00;
-
-        /*for(int i = 0; i < 2; i++)
-        {
-            Log.i(TAG, "SmartDcam Reply[" + i + "] = " + Reply[i]);
-        }*/
-
-        //     D1 : 센서 감도
-        data = Reply[0];
-        if (data < 1 || data > 5) {
-            if ((data == (byte)0xFF)) {
-
-            }
-            else {
-                Log.w(TAG, "[Send_SetSensorConfig] D1 : Range Error  (data:" + String.format("0x%02X", data) + ")");
-            }
-        }
-        else {
-            // D1 정상 수신
-            //Log.d(TAG, "[Send_SetSensorConfig] D1 Accepted ~");
-            mDriver.Sensor_Value.Sensor_Sensitivity = data;
-        }
-
-        data = Reply[1];
-        if (data < 1 || data > 250) {
-            if ((data == (byte)0xFF)) {
-
-            }
-            else {
-                Log.w(TAG, "[Send_SetSensorConfig] D2 : Range Error  (data:" + String.format("0x%02X", data) + ")");
-            }
-        }
-        else {
-            // D2 정상 수신
-            //Log.d(TAG, "[Send_SetSensorConfig] D2 Accepted ~");
-			mDriver.Sensor_Value.Sensor_DetectTime = data;
-        }
-
-        CompareStatus_Sensivity_DetectTime();
-
-        DeviceLog("[Send_SetSensorConfig] END");
-        return 0;
-    }
-
-    private void CompareStatus_Sensivity_DetectTime() {
-        if (mDriver.Sensor_Value == null) { return;}
-
-        int sensitivity = -1;
-        int dura = -1;
-
-        if (mDriver.Sensor_Value.Sensor_Sensitivity > 0) {
-            // DB 저장
-            try {
-                WallpadStatusData wsd = new WallpadStatusData(ServiceMain.svcContext);
-                sensitivity = wsd.GetSmartDoorCamSensorSensitivity();
-
-                if (sensitivity != mDriver.Sensor_Value.Sensor_Sensitivity) {
-                    wsd.SetSmartDoorSensorSensitivity(mDriver.Sensor_Value.Sensor_Sensitivity);
-                }
-                wsd.closeDB();
-            } catch (RuntimeException re) {
-                LogUtil.errorLogInfo("", TAG, re);
-            } catch (Exception e) {
-                LogUtil.errorLogInfo("", TAG, e);//
-            }
-        }
-
-        if (mDriver.Sensor_Value.Sensor_DetectTime > 0) {
-            // DB 저장
-            try {
-                WallpadStatusData wsd = new WallpadStatusData(ServiceMain.svcContext);
-                dura = wsd.GetSmartDoorCamSensorDuration();
-
-                if (dura != mDriver.Sensor_Value.Sensor_DetectTime) {
-                    wsd.SetSmartDoorSensorDuration(mDriver.Sensor_Value.Sensor_DetectTime);
-                }
-                wsd.closeDB();
-            } catch (RuntimeException re) {
-                LogUtil.errorLogInfo("", TAG, re);
-            } catch (Exception e) {
-                LogUtil.errorLogInfo("", TAG, e);//e.printStackTrace();
-            }
-        }
-    }
-
-
-    /**
-     * LED 제어 기능이 있는 현관카메라의 LED 모드를 제어한다.
-     * @param mode 범위(0~6, FF)
-     * @return (- : 에러), (0 : 실패) , (1 : 성공), (2 : 모드값 설정안됨)
-     */
-    private int Send_SetLedMode(byte mode) {
-        DeviceLog("[Send_SetLedMode] Start");
-
-        if (mode < 0 || mode > 6) {
-            if (mode == (byte)0xFF) {
-                //Log.i(TAG, "[Send_SetLedMode] 0xFF : Get Value");
-            }
-            else {
-                Log.w(TAG, "[Send_SetLedMode] mode range error");
-                return -1;
-            }
-        }
-
-        // 2. 패킷 데이터 만들기
-        byte [] ReqData = {mode};
-
-        // 3. 데이터 전송 및 응답
-        byte [] Reply = SendNRead_Variable( (DEVICE_ADDRESS), CMDList.Req.SetLedMode, ReqData);
-
-        // 4. 수신데이터 파싱
-        boolean bError = false;
-
-        //     null Check
-        if (Reply == null) {
-            DeviceLog("[Send_SetLedMode] Reply is null");
-            bError = true;
-        }
-
-        //     Length Check
-        if (Reply != null && Reply.length != 2) {
-            DeviceLog("[Send_SetLedMode] Reply.length  fail ... (length:" + Reply.length + ")");
-            bError = true;
-        }
-
-        if (bError) {
-            //Log.w(TAG,"[Send_SetLedMode] bError fail");
-            DeviceLog("[Send_SetLedMode] FAIL");
-            AddDoCount(false);
-            return -100;
-        }
-        AddDoCount(true);
-
-        // 동작 성공 여부 확인
-        // 스마트현관카메라 버그 : LED 제어명령에 대해 D1을 00(실패)로 무조건 응답함 -> 주석처리 : 2019.06.17
-        /*if(Reply[0] == 0)
-        {
-            Log.w(TAG, "[Send_SetLedMode] Device Act Fail !!!");
-            return 0;
-        }
-        else if(Reply[0] == 1)*/
-        {
-            //Log.d(TAG, "[Send_SetLedMode] Device Act Run ~~~");
-
-			if (Reply[1] == mode || mode == (byte)0xFF) {
-				//Log.d(TAG, "[Send_SetLedMode] Device Act Success ~~~");
-				//Log.d(TAG, "[Send_SetLedMode] Device LED mode Same : " + Reply[1]);
-				mDriver.Sensor_Value.Sensor_LedMode = Reply[1];
-				StatusChanged();
-
-                DeviceLog("[Send_SetLedMode] END");
-				return 1;
-			}
-			else {
-				//Log.d(TAG, "[Send_SetLedMode] Device LED mode Diff : " + Reply[1]);
-                DeviceLog("[Send_SetLedMode] END");
-				return 2;
-			}
-        }
-
-        //return 0;
-    }
-
-    /**
-     * RSSI 제어 기능이 있는 현관카메라의 RSSI 모드, 단계를 제어한다.
-     * @param mode 범위(0~2 , FF)
-     * @return (- : 에러), (0 : 실패) , (1 : 성공), (2 : 모드값 설정안됨)
-     */
-    private int Send_SetRSSIMode(byte mode, byte level) {
-        DeviceLog("[Send_SetRSSIMode] Start");
-
-        if (mode < (byte)0 || mode > (byte)2) {
-            Log.w(TAG, "[Send_SetRSSIMode] mode range error");
-        	return -1;
-        }
-
-        if (level < (byte)-100 || level > (byte)100) {
-			if (mode == (byte)0xFF) {
-                DeviceLog("[Send_SetRSSIMode] 0xFF : Get Value");
-            }
-			else {
-                DeviceLog("[Send_SetRSSIMode] level range error");
-				return -2;
-			}
-        }
-
-        // 2. 패킷 데이터 만들기
-        byte [] ReqData = {mode, level};
-
-        // 3. 데이터 전송 및 응답
-        byte [] Reply = SendNRead_Variable(DEVICE_ADDRESS, CMDList.Req.SetRssiMode, ReqData);
-
-        // 4. 수신데이터 파싱
-        boolean bError = false;
-
-        //     null Check
-        if (Reply == null) {
-            DeviceLog("[Send_SetRSSIMode] Reply is null");
-            bError = true;
-        }
-
-        //     Length Check
-        if (Reply != null && Reply.length != 2) {
-            DeviceLog("[Send_SetRSSIMode] Reply.length  fail ... (length:" + Reply.length + ")");
-            bError = true;
-        }
-
-        if (bError) {
-            //Log.w(TAG, "[Send_SetRSSIMode] bError fail");
-            AddDoCount(false);
-            DeviceLog("[Send_SetRSSIMode] FAIL");
-            return -100;
-        }
-        AddDoCount(true);
-
-        // 동작 성공 여부 확인
-        if (Reply[0] == 0) {
-            Log.w(TAG, "[Send_SetRSSIMode] Device Act Fail !!!");
-            return 0;
-        }
-        else if (Reply[0] == 1) {
-            //Log.d(TAG, "[Send_SetRSSIMode] Device Act Run ~~~");
-
-            if (Reply[1] == level || level == (byte)0xFF) {
-                // 변경한 단계와 동일하거나, 현재상태값을 요청이 성공한 경우
-                //Log.d(TAG, "[Send_SetRSSIMode] Device Act Success ~~~");
-                //Log.d(TAG, "[Send_SetRSSIMode] Device RSSI level Same : " + Reply[1]);
-
-                if (mode == 1) {
-                    // 읽기 모드
-					mDriver.Sensor_Value.Sensor_RSSI_Read = Reply[1];
-				}
-                else if (mode == 2) {
-                    // 쓰기 모드
-					mDriver.Sensor_Value.Sensor_RSSI_Write = Reply[1];
-				}
-                StatusChanged();
-
-                DeviceLog("[Send_SetRSSIMode] END");
-                return 1;
-            }
-            else {
-                //Log.d(TAG, "[Send_SetRSSIMode] Device RSSI level Diff : " + Reply[1]);
-                DeviceLog("[Send_SetRSSIMode] END");
-                return 2;
-            }
-        }
-
-        return 0;
-    }
-
-    /**
-     *  판별 감지빈도 제어 기능이 있는 현관카메라의 빈도(%)를 제어한다.
-     * @param level 범위(0~4, FF)
-     * @return (- : 에러), (0 : 실패) , (1 : 성공), (2 : 모드값 설정안됨)
-     */
-    private int Send_SetDetectRatio(byte level) {
-        DeviceLog("[Send_SetDetectRatio] Start");
-        //Log.i(TAG, "[Send_SetDetectRatio] Start");
-
-        if (level < (byte)0 || level > (byte)100) {
-            if (level == (byte)0xFF) {
-                //Log.i(TAG, "[Send_SetDetectRatio] 0xFF : Get Value");
-            }
-            else {
-                Log.w(TAG, "[Send_SetDetectRatio] level range error");
-                return -1;
-            }
-        }
-        // 2. 패킷 데이터 만들기
-        byte [] ReqData = {level };
-
-        // 3. 데이터 전송 및 응답
-        byte [] Reply = SendNRead_Variable( (DEVICE_ADDRESS), CMDList.Req.SetDetectRatio, ReqData);
-
-        // 4. 수신데이터 파싱
-        boolean bError = false;
-
-        //     null Check
-        if (Reply == null) {
-            DeviceLog("[Send_SetDetectRatio] Reply is null");
-            bError = true;
-        }
-
-        //     Length Check
-        if (Reply != null && Reply.length != 2) {
-            DeviceLog("[Send_SetDetectRatio] Reply.length  fail ... (length:" + Reply.length + ")");
-            bError = true;
-        }
-
-        if (bError) {
-            AddDoCount(false);
-            DeviceLog("[Send_SetDetectRatio] FAIL");
-            return -100;
-        }
-        AddDoCount(true);
-
-        // 동작 성공 여부 확인
-        if (Reply[0] == 0) {
-            Log.w(TAG, "[Send_SetDetectRatio] Device Act Fail !!!");
-            return 0;
-        }
-        else if (Reply[0] == 1) {
-            //Log.d(TAG, "[Send_SetDetectRatio] Device Act Run ~~~");
-			if (Reply[1] == level || level == (byte)0xFF) {
-				//Log.d(TAG, "[Send_SetDetectRatio] Device Act Success ~~~");
-				//Log.d(TAG, "[Send_SetDetectRatio] Device DetectRatio level Same : " + Reply[1]);
-				mDriver.Sensor_Value.Sensor_DetectRatio = Reply[1];
-				StatusChanged();
-
-                DeviceLog("[Send_SetDetectRatio] END");
-				return 1;
-			}
-			else {
-				//Log.d(TAG, "[Send_SetDetectRatio] Device DetectRatio level Diff : " + Reply[1]);.
-                DeviceLog("[Send_SetDetectRatio] END");
-				return 2;
-			}
-        }
-
-        return 0;
-    }
-
-    /**
-     *  카메라 상태 제어 기능이 있는 현관카메라의 카메라모드를 제어한다.
-     * @param mode 범위(0~3, FF)
-     * @return (- : 에러), (0 : 실패) , (1 : 성공), (2 : 모드값 설정안됨)
-     */
-    private int Send_SetCameraMode(byte mode) {
-        DeviceLog("[Send_SetCameraMode] Start");
-
-        if (mode < (byte)0 || mode > (byte)3) {
-            if (mode == (byte)0xFF) {
-                //Log.i(TAG, "[Send_SetCameraMode] 0xFF : Get Value");
-            }
-            else {
-                Log.w(TAG, "[Send_SetCameraMode] mode range error");
-                return -1;
-            }
-        }
-
-        // 2. 패킷 데이터 만들기
-        byte [] ReqData = {mode };
-
-        // 3. 데이터 전송 및 응답
-        byte [] Reply = SendNRead_Variable( (DEVICE_ADDRESS), CMDList.Req.SetCameraMode, ReqData);
-
-        // 4. 수신데이터 파싱
-        boolean bError = false;
-
-        //     null Check
-        if (Reply == null) {
-            DeviceLog("[Send_SetCameraMode] Reply is null");
-            bError = true;
-        }
-
-        //     Length Check
-        if (Reply != null && Reply.length != 2) {
-            DeviceLog("[Send_SetCameraMode] Reply.length  fail ... (length:" + Reply.length + ")");
-            bError = true;
-        }
-
-        if (bError) {
-            //Log.w(TAG, "[Send_SetCameraMode] bError fail");
-            AddDoCount(false);
-            DeviceLog("[Send_SetCameraMode] FAIL");
-            return -100;
-        }
-        AddDoCount(true);
-
-        // 동작 성공 여부 확인
-        if (Reply[0] == (byte)0) {
-            Log.w(TAG, "[Send_SetCameraMode] Device Act Fail !!!");
-            return 0;
-        }
-        else if (Reply[0] == (byte)1) {
-            //Log.d(TAG, "[Send_SetCameraMode] Device Act Run ~~~");
-
-            if (Reply[1] == mode || mode == (byte)0xFF) {
-                //Log.d(TAG, "[Send_SetCameraMode] Device Act Success ~~~");
-                //Log.d(TAG, "[Send_SetCameraMode] Device DetectRatio level Same : " + Reply[1]);
-                mDriver.Sensor_Value.Sensor_CameraMode = Reply[1];
-                StatusChanged();
-
-                DeviceLog("[Send_SetCameraMode] END");
-                return 1;
-            }
-            else {
-                //Log.d(TAG, "[Send_SetCameraMode] Device DetectRatio level Diff : " + Reply[1]);
-                DeviceLog("[Send_SetCameraMode] END");
-                return 2;
-            }
-        }
-
-        return 0;
-    }
-
-
-    /**
-     * 스마트키 삭제
-     *
-     * @return (boolean) false - Error , true - OK
-     */
-    private boolean Send_DeleteKey(SetRegisterDataList setRegisterData) {
-        DeviceLog("[Send_DeleteKey] Start");
-
-        // 1. In 파라미터 확인
-        if (setRegisterData == null) {
-            Log.w(TAG, "[Send_DeleteKey] Param - RegisterData is null !!!");
-            return false;
-        }
-
-        // 2. 패킷 데이터 만들기
-        byte [] ReqData = setRegisterData.getByteArray();
-
-        // 3. 데이터 전송 및 응답
-        byte [] Reply = SendNRead_Variable( (byte)(DEVICE_ADDRESS), CMDList.Req.GetSmartKeyRegister, ReqData);
-
-        // 4. 수신데이터 파싱
-        boolean bError = false;
-        byte data = 0x00;
-        int index = 0;
-
-        byte RegResult = 0;
-        while (true) {
-            //     null Check
-            if (Reply == null) {
-                DeviceLog("[Send_DeleteKey] Reply is null");
-                bError = true; break;
-            }
-
-            //     Length Check
-            if (Reply.length < 1) {
-                Log.w(TAG, "[Send_DeleteKey] Reply.length  fail #1... (length:" + Reply.length + ")");
-                bError = true; break;
-            }
-
-            index = 0;
-
-            //     D1 : 등록모드 상태값
-            data = Reply[index++];
-            if ((data & (byte)(BIT4 | BIT5 | BIT6 | BIT7)) != 0x00) {
-                Log.w(TAG, "[Send_DeleteKey] D1 : Unused BIT SET  (data:" + String.format("0x%02X", data) + ")");
-                bError = true; break;
-            }
-
-            if ((data & BIT0) != 0x00) {
-                if (Reply.length != (int)(1 + 16)) {
-                    Log.w(TAG, "[Send_DeleteKey] Reply.length  fail #2... (length:" + Reply.length + ")");
-                    bError = true; break;
-                }
-            }
-
-            RegResult = (byte)((data >> 2) & (byte)(BIT0|BIT1));
-            switch (RegResult) {
-                case 0x00: case 0x01: case 0x02: break;
-                default:
-                    Log.w(TAG, "[Send_DeleteKey] RegResult  Out Of Range !!!(RegResult:" + String.format("0x%02X", RegResult) + ")");
-                    bError = true; break;
-            }
-            break;
-        }
-
-        if (bError) {
-            AddDoCount(false);
-            DeviceLog("[Send_DeleteKey] FAIL");
-            return false;
-        }
-        AddDoCount(true);
-
-
-        // 5. 데이터 확인
-        if (RegResult == 0) {
-            Log.i(TAG, "[Send_DeleteKey] Delete success");
-            DeviceLog("[Send_DeleteKey] END");
-            return true;
-        }
-        else {
-            Log.i(TAG, "[Send_DeleteKey] Delete Fail -> RegResult:" + String.format("0x%02X", RegResult) + ")");
-            DeviceLog("[Send_DeleteKey] END");
-            return false;
-        }
-    }
-
-
-
-
-    ///////////////////////////////////////////////////////////////////////////////////////////////
-    // CMDList
-    ///////////////////////////////////////////////////////////////////////////////////////////////
-    /**
-     * 명령어 리스트
-     */
-    public static class CMDList {
-        public static final class Req {
-            /////////////////////////////////////////////////////////
-            // Board
-            /////////////////////////////////////////////////////////
-            /** 기기 정보 요청 */
-            public final static byte GetDeviceInfo              = 0x01;
-
-            /////////////////////////////////////////////////////////
-            // 기본 상태 커맨드
-            /////////////////////////////////////////////////////////
-            /** 기본상태 요청 */
-            public final static byte GetStatus                  = 0x11;
-            /** 기본상태값 해제 요청 */
-            public final static byte SetStatusClr               = 0x12;
-
-            /////////////////////////////////////////////////////////
-            // 스마트 키값 읽기 커맨드
-            /////////////////////////////////////////////////////////
-            /** 스마트 키값 요청 */
-            public final static byte GetSmartKey                = 0x21;
-            /** 스마트 키값 확인 요청 */
-            public final static byte SetSmartKeyVerify          = 0x22;
-
-            /////////////////////////////////////////////////////////
-            // 스마트키 등록 커맨드
-            /////////////////////////////////////////////////////////
-            /** 등록모드 시작 요청 */
-            public final static byte SetSmartKeyRegisterStart   = 0x31;
-            /** 등록 스마트 키값 요청 */
-            public final static byte GetSmartKeyRegister        = 0x32;
-            /** 등록모드 종료 요청 */
-            public final static byte SetSmartKeyRegisterEnd     = 0x33;
-
-            /////////////////////////////////////////////////////////
-            // 센서 관련 커맨드
-            /////////////////////////////////////////////////////////
-            /** 센서상태 요청 및 제어 */
-            public final static byte SetSensorStatus            = 0x41;
-            /** LED 모드 제어 */
-            public final static byte SetLedMode                 = 0x42;
-            /** RSSI 모드 제어 */
-            public final static byte SetRssiMode                = 0x43;
-            /** 판별감도 제어 */
-            public final static byte SetDetectRatio             = 0x44;
-            /** 카메라 상태 제어 */
-            public final static byte SetCameraMode              = 0x45;
-        }
-    }
-
-    ///////////////////////////////////////////////////////////////////////////////////////////////
-    // UpdateVariables
-    ///////////////////////////////////////////////////////////////////////////////////////////////
-    /**
-     * [현관콜 , 에러]를 업데이트 한다.
-     *
-     * @param Status - (StatusList) 업데이트할 기본상태 응답 클래스
-     *
-     * @return (boolean) 데이터 변경여부 (true:변경 , false:미변경)
-     */
-    private boolean UpdateVariables(StatusList Status) {
-        DeviceLog("[UpdateVariables] (Status) Start");
-        if (Status == null) {
-            return false;
-        }
-
-        boolean bChanged = false;
-
-        // 1. 현관콜
-        if (mDriver.Status.bDoorBtnStatus != Status.bDoorBtnStatus) {
-            if ((!mDriver.Status.bDoorBtnStatus) && (Status.bDoorBtnStatus)) {
-                if (GetDoorStdOpenMode()) {
-                    SetDoorStdOpenMode(false);
-
-                    Log.i(TAG, "*****************************");
-                    Log.i(TAG, "*   DLOCK_STANDBYOPEN(RF)   *");
-                    Log.i(TAG, "*****************************");
-
-                    int ret = -1;
-
-                    // 도어락 열기
-                    if (Version.getGatewayUsage()) {
-                        if (ServiceMain.dataBaseLoader.data.wallpadDeviceSet.Get_DoorLock_Info[1] == WallpadDeviceSet.DOORLOCK_TYPE_FINGERPRINT) {
-                            ret = driverInterOpAPI.FPdLock_SetDoorOpen();
-                            Log.i(TAG, "[UpdateVariables] FPdLock_SetDoorOpen - ret : " + ret);
-                        }
-                        else {
-                            ret = driverInterOpAPI.IGW_SetWddrCont(true);
-                            Log.i(TAG, "[UpdateVariables] IGW_SetWddrCont - ret : " + ret);
-                        }
-                        // 현산향 모델에도 무선도어락이 적용되기에
-                        // 도어락을 터치해서 문을 열 수 없다.
-                        WallPadInterface devioctr = new WallPadInterface();
-                        TurnOnDcamPower(devioctr); //현재 통화 상태에서는 동작 X
-                    }
-                    else {
-                        WallPadInterface devioctr = new WallPadInterface();
-                        devioctr.DoorLockControl(true);
-                        TurnOnDcamPower(devioctr); //현재 통화 상태에서는 동작 X
-                        ret = 1;
-                    }
-
-                    if (ret >= 0) {
-                        // 출입 데이터 기록 (스마트키에 의한 문열림)
-                        WallpadAccessData WpadAccessData = new WallpadAccessData(ServiceMain.svcContext);
-                        String sn = SmartKeyRfDoor_Controller.GetCheckSmartKeySn();
-                        ret = WpadAccessData.Insert(WallpadAccessData.KIND.SMART_KEY, sn);
-                        WpadAccessData.closeDB();
-                        Log.d(TAG, "WpadAccessData.Insert(SMART_KEY) - ret:" + ret);
-
-
-                        // 최근사용일자 갱신
-                        WallpadSmartKeyRegData WpadSmartKeyRegData = new WallpadSmartKeyRegData(ServiceMain.svcContext);
-                        byte no = SmartKeyRfDoor_Controller.GetCheckSmartKeyNo();
-                        ret = WpadSmartKeyRegData.UpdateLastUseDate(no);
-                        Log.d(TAG, "WpadAccessData.UpdateLastUseDate(" + no + ") - ret:" + ret);
-                        WpadSmartKeyRegData.closeDB();
-                    }
-                }
-                else {
-                    if (CallAppEnable) {
-                        // 현관콜 시작
-                        Log.i(TAG, "============================================");
-                        Log.i(TAG, "                 DOOR CALL");
-                        Log.i(TAG, "============================================");
-
-                        setSendEventBR(WallPadInterface.BTN_DOOR);
-                    }
-                    else {
-                        Log.w(TAG, "CallAppEnable FALSE -> DoorLock Opening, Wait until Turn off the Dcam Light");
-                    }
-                }
-            }
-            mDriver.Status.bDoorBtnStatus = Status.bDoorBtnStatus;
-        }
-
-        // 2. 거동수상자 감지
-        boolean sensorClear = false;
-        if (mDriver.Status.bSensorDetect != Status.bSensorDetect) {
-            Log.i(TAG, "[UpdateVariables] - Wpad sensor data : " + mDriver.Status.bSensorDetect);
-            Log.i(TAG, "[UpdateVariables] - new receive sensor data : " + Status.bSensorDetect);
-            // (월패드 : 감지안됨) && (스마트현관 : 감지됨) 인 경우에만 동작 : 거동수상자 발생
-            if ((!mDriver.Status.bSensorDetect) && (Status.bSensorDetect)) {
-                Log.i(TAG, "[UpdateVariables] - Sensor Detect Occur !!!");
-
-                Intent mIntent = new Intent();
-                mIntent.setAction(define.NOTIFY_ACNAME);
-                mIntent.putExtra(define.NOTIBR_KIND, define.NOTIFY_SMART_DCAM_DETECT);
-                ServiceMain.svcContext.sendBroadcast(mIntent);
-
-                sensorClear = true;
-
-                Log.i(TAG, "============================================");
-                Log.i(TAG, "               STRANGE DETECT !");
-                Log.i(TAG, "============================================");
-            }
-            // (월패드 : 감지됨) && (스마트현관 : 감지안됨) 인 경우에만 동작 : 거동수상자 해소
-            else if ((mDriver.Status.bSensorDetect) && (!Status.bSensorDetect)) {
-                Log.i(TAG, "[UpdateVariables] - Sensor Detect Release !!!");
-
-                Intent mIntent = new Intent();
-                mIntent.setAction(define.NOTIFY_ACNAME);
-                mIntent.putExtra(define.NOTIBR_KIND, define.NOTIFY_SMART_DCAM_RELEASE);
-                ServiceMain.svcContext.sendBroadcast(mIntent);
-
-                Log.i(TAG, "============================================");
-                Log.i(TAG, "               STRANGE RELEASE~~");
-                Log.i(TAG, "============================================");
-            }
-
-            mDriver.Status.bSensorDetect = Status.bSensorDetect;
-        }
-
-        // 3. LED 상태
-        if (mDriver.Status.bLedStatus != Status.bLedStatus) {
-            Log.i(TAG, "[UpdateVariables] - past Wpad LedStatus data : " + mDriver.Status.bLedStatus);
-            Log.i(TAG, "[UpdateVariables] - new receive LedStatus data : " + Status.bLedStatus);
-            mDriver.Status.bLedStatus = Status.bLedStatus;
-        }
-
-        // 4. 카메라 상태
-        if (mDriver.Status.bCameraStatus != Status.bCameraStatus) {
-            Log.i(TAG, "[UpdateVariables] - past Wpad CameraStatus data : " + mDriver.Status.bCameraStatus);
-            Log.i(TAG, "[UpdateVariables] - new receive CameraStatus data : " + Status.bCameraStatus);
-            mDriver.Status.bCameraStatus = Status.bCameraStatus;
-        }
-
-        // 5. LED Auto 상태
-        if (mDriver.Status.bLedAuto != Status.bLedAuto) {
-            Log.i(TAG, "[UpdateVariables] - past Wpad LedAuto data : " + mDriver.Status.bLedAuto);
-            Log.i(TAG, "[UpdateVariables] - new receive LedAuto data : " + Status.bLedAuto);
-            mDriver.Status.bLedAuto = Status.bLedAuto;
-        }
-
-        // 6. 카메라 Auto 상태
-        if (mDriver.Status.bCameraAuto != Status.bCameraAuto) {
-            Log.i(TAG, "[UpdateVariables] - past Wpad CameraAuto data : " + mDriver.Status.bCameraAuto);
-            Log.i(TAG, "[UpdateVariables] - new receive CameraAuto data : " + Status.bCameraAuto);
-            mDriver.Status.bCameraAuto = Status.bCameraAuto;
-        }
-
-        // 7. 에러
-        if (mDriver.Status.bError != Status.bError) {
-            if ((!mDriver.Status.bError) && (Status.bError)) {
-                Log.i(TAG, "UpdateVariables - ERROR Detection !!!");
-            }
-            else if ((mDriver.Status.bError) && (!Status.bError)) {
-                Log.i(TAG, "UpdateVariables - ERROR Clear !!!");
-            }
-            mDriver.Status.bError = Status.bError;
-        }
-
-        // 3. 상태 클리어
-        if (Status.bDoorBtnStatus || Status.bError || sensorClear) {
-            Send_SetStatusClr(Status);
-            bChanged = true;
-        }
-
-        DeviceLog("[UpdateVariables] (Status) End");
-        return bChanged;
-    }
-
-    /**
-     * 스마트키값이 등록된 키값인지 비교한다.
-     *
-     * @param KeyData - (KeyDataList) 인식된 스마트키값 클래스
-     *
-     * @return (boolean) 데이터 변경여부 (true:변경 , false:미변경)
-     */
-    private boolean UpdateVariables(KeyDataList KeyData) {
-        if (KeyData == null) return false;
-        if (KeyData.Count <= 0) return false;
-        if (KeyData.Encryption == null) return false;
-
-        boolean FindKey = false;
-        for (byte i=0; i < KeyData.Count; i++) {
-            if (KeyData.Encryption[i] != null) {
-                FindKey = CheckSmartKey(KeyData.Encryption[i].Data);
-                if (FindKey) {
-                    break;
-                }
-            }
-        }
-
-        if (FindKey) {
-            // 등록된키값 인식
-            // 도어락 문열림대기모드 시작
-            Log.i(TAG, "[UpdateVariables] FindKey !!!");
-
-            int ret = -1;
-            if (mDoorLockType == WallpadDeviceSet.DOORLOCK_TYPE_NORMAL) {
-                Log.i(TAG, "[UpdateVariables] mDoorLockType 1 : " + mDoorLockType);
-                ret = driverInterOpAPI.DLock_SetDoorOpenStandbyMode(true, DLOCK_STANDBYMODE_SEC);
-                Log.i(TAG, "[UpdateVariables] DLock_SetDoorOpenStandbyMode - ret : " + ret);
-            }
-            else if (mDoorLockType == WallpadDeviceSet.DOORLOCK_TYPE_RF) {
-                Log.i(TAG, "[UpdateVariables] mDoorLockType 2 : " + mDoorLockType);
-                if (mDoorOpenDelay) {
-                    // 문열림 대기모드 동작 신 시나리오 (무선 도어락 터치 시 문열림)
-                    ret = driverInterOpAPI.IGW_SetWddrOpenDelayCont(DLOCK_STANDBYMODE_SEC);
-                    Log.i(TAG, "[UpdateVariables] IGW200D_SetWddrOpenDelayCont - ret : " + ret);
-                }
-                else {
-                    // 문열림 대기모드 동작 구 시나리오 (현관카메라 버튼 누를 시 문열림)
-                    SetDoorStdOpenMode(true);
-                }
-                Log.i(TAG, "[UpdateVariables] SetDoorStdOpenMode(ON) 1");
-            }
-            else if (mDoorLockType == WallpadDeviceSet.DOORLOCK_TYPE_FINGERPRINT) {
-                Log.i(TAG, "[UpdateVariables] mDoorLockType 3 : " + mDoorLockType);
-                SetDoorStdOpenMode(true);
-                Log.i(TAG, "[UpdateVariables] SetDoorStdOpenMode(ON) 2");
-            }
-
-            WallpadStatusData wallpadStatusData = new WallpadStatusData(ServiceMain.svcContext);
-            boolean SmartKeyDetectionAlarm = wallpadStatusData.GetSmartKeyDetectionAlarm();
-            wallpadStatusData.closeDB();
-            if (SmartKeyDetectionAlarm) {
-                // DB 저장 (스마트키감지)
-                WallpadAccessData WpadAccessData = new WallpadAccessData(ServiceMain.svcContext);
-                WpadAccessData.setMaxCount(1000);
-                ret = WpadAccessData.Insert(WallpadAccessData.KIND.SMART_KEY_DETECTION, CheckSmartKeySn);
-                WpadAccessData.closeDB();
-                Log.d(TAG, "WpadAccessData.Insert(SMART_KEY_DETECTION) - ret:" + ret);
-
-                // 사운드 알람
-                WpadSound Sound = new WpadSound(ServiceMain.svcContext);
-                Sound.PlayMent(WpadSound.SND.effect.EFFECT1);
-
-                // LCD 를 Normal 상태로 변경하는 기능 추가
-                //PowerManager pm = (PowerManager) (ServiceMain.svcContext).getSystemService(Context.POWER_SERVICE);
-                //pm.userActivity(1, true);
-
-                // 인텐트를 전송하여 제어 UI 혹은 스마트키등록 화면에서 flag를 세우도록 설정하기
-                //getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
-
-                // Toast 메시지 표시
-                Toast.makeText(ServiceMain.svcContext,
-                        "SmartKey Detection : [" + CheckSmartKeySn + "]",
-                        Toast.LENGTH_SHORT).show();
-            }
-
-            return true;
-        }
-
-        return false;
-    }
-
-    /**
-     * 등록모드 시작버튼 체크
-     *
-     * @param RegisterModeStart - (int) 체크할 시작버튼 상태 (1:감지)
-     */
-    private void UpdateVariables(int RegisterModeStart) {
-        if (RegisterModeStart == 1) {
-            Log.i(TAG, "UpdateVariables - Start Button DETECTION !!!");
-
-            if (!mDriver.RegisterInitMode) {
-                int id = DB_GetId();
-                if (id <= 0) {
-                    mDriver.Polling.SetStatus(Driver.PollingList.STATUS.Normal);
-                    Log.w(TAG, "UpdateVariables - DB_GetId  Out Of Range (id:" + id + ")");
-                }
-                else {
-                    mDriver.CardRegNo = (byte)id;
-                    super.StatusChanged( (byte)(STATUS_REGMODE_START | mDriver.CardRegNo));
-                    mDriver.Polling.SetStatus(Driver.PollingList.STATUS.Register);
-                }
-            }
-            else {
-                super.StatusChanged(STATUS_REGMODE_START);
-                mDriver.Polling.SetStatus(Driver.PollingList.STATUS.Register);
-            }
-        }
-    }
-
-    /**
-     *
-     *
-     * @param GetRegisterData
-     */
-    private void UpdateVariables(GetRegisterDataList GetRegisterData) {
-        if (GetRegisterData == null) return;
-
-        // 1. 스마트RF현관카메라 에서 종료
-        if (GetRegisterData.Exit) {
-            mDriver.Polling.SetStatus(Driver.PollingList.STATUS.Normal);
-            Log.i(TAG, "UpdateVariables - END Button DETECTION !!!");
-        }
-
-        // 2. 에러체크
-        if (GetRegisterData.RegResult != 0x00) {
-            switch (GetRegisterData.RegResult) {
-                case 0x01:
-                    // 이미 등록된 키
-                    super.StatusChanged(STATUS_REGMODE_KEY_ALREADY);
-                    Log.i(TAG, "UpdateVariables - STATUS_REGMODE_KEY_ALREADY");
-                    break;
-
-                case 0x02:
-                    // 무선 통신 실패
-                    super.StatusChanged(STATUS_REGMODE_ER_WIRELESSCOMMFAIL);
-                    Log.i(TAG, "UpdateVariables - STATUS_REGMODE_ER_WIRELESSCOMMFAIL");
-                    break;
-            }
-        }
-
-        // 3. 등록 데이터 체크
-        if (!(GetRegisterData.Exit) && (GetRegisterData.RegResult == 0x00)) {
-            if (GetRegisterData.Encryption != null) {
-                if (!mDriver.RegisterInitMode) {
-                    byte Status = 0;
-                    int ret = SaveSmartKey(GetRegisterData.Encryption.Data);
-                    if (ret > 0) {
-                        Status = STATUS_REGMODE_KEY_COMPLETE;
-                        Status |= (byte)ret;
-                    }
-                    else {
-                        Status = STATUS_REGMODE_ER_DBWRITE;
-                    }
-                    super.StatusChanged(Status);
-
-                    mDriver.Polling.SetStatus(Driver.PollingList.STATUS.RegisterPause);
-                    Log.i(TAG, "UpdateVariables - STATUS_REGMODE_KEY_COMPLETE (Status:" + String.format("0x%02X", Status) + ")");
-                }
-                else {
-                    super.StatusChanged(STATUS_REGMODE_KEY_COMPLETE);
-                    mDriver.Polling.SetStatus(Driver.PollingList.STATUS.RegisterPause);
-                }
-            }
-        }
-    }
-
-    ///////////////////////////////////////////////////////////////////////////////////////////////
-    // DB
-    ///////////////////////////////////////////////////////////////////////////////////////////////
-    private int DB_GetId() {
-        try {
-            WallpadSmartKeyRegData WpadSmartKeyRegData = new WallpadSmartKeyRegData(ServiceMain.svcContext);
-            int id = WpadSmartKeyRegData.GetEmptyId();
-            WpadSmartKeyRegData.closeDB();
-            return id;
-        } catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-            return -1000;
-        } catch (Exception e) {
-            Log.e(TAG, "[DB_GetId] - [Exception Error] ");
-            LogUtil.errorLogInfo("", TAG, e);//
-            return -1000;
-        }
-    }
-
-    private int DB_Register(byte id, byte[] Uid, byte[] SiteCode, byte[] DongHo) {
-        try {
-            WallpadSmartKeyRegData WpadSmartKeyRegData = new WallpadSmartKeyRegData(ServiceMain.svcContext);
-            int ret = WpadSmartKeyRegData.Register((byte) id, Uid, SiteCode, DongHo);
-            WpadSmartKeyRegData.closeDB();
-            return ret;
-        } catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-            return -1000;
-        } catch (Exception e) {
-            Log.e(TAG, "[DB_Register] - [Exception Error] ");
-            LogUtil.errorLogInfo("", TAG, e);//e.printStackTrace();
-            return -1000;
-        }
-    }
-
-    private String DB_isExist(byte id, byte[] Uid, byte[] SiteCode, byte[] DongHo) {
-        try {
-            WallpadSmartKeyRegData WpadSmartKeyRegData = new WallpadSmartKeyRegData(ServiceMain.svcContext);
-            String sn = WpadSmartKeyRegData.isExist(id, Uid, SiteCode, DongHo);
-            WpadSmartKeyRegData.closeDB();
-            return sn;
-        } catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-            return null;
-        } catch (Exception e) {
-            Log.e(TAG, "[DB_Register] - [Exception Error] ");
-            LogUtil.errorLogInfo("", TAG, e);//e.printStackTrace();
-            return null;
-        }
-    }
-
-    ///////////////////////////////////////////////////////////////////////////////////////////////
-    // Util
-    ///////////////////////////////////////////////////////////////////////////////////////////////
-
-    /**
-     * 스마트키 데이터를 등록데이터와 비교 체크한다.
-     *
-     * @param Input - (byte []) 읽은 스마트키 데이터 배열
-     *
-     * @return (boolean) 결과 - true:있음 , false:아님
-     */
-    private boolean CheckSmartKey(byte [] Input) {
-        boolean DEBUG = false;
-
-        if (DEBUG) Log.d(TAG, "[CheckSmartKey] Start");
-        try {
-            // 1. 복호화 체크
-            byte [] Output = null;
-
-            if (ServiceMain.dataBaseLoader.data.wallpadDeviceSet.Get_BLE_SmartKey == false) {
-                // 기존 스마트키 사용일 경우
-                Output = AES_128.Encrypt(AES_128.ENCRYPTTYPE.SMARTKEY_CAM, Input);
-            }
-            else {
-                // BLE스마트키 사용일 경우
-                Output = AES_128.Decrypt_ECB(AES_128.ENCRYPTTYPE.SMARTKEY_CAM, Input);
-            }
-
-            if (DEBUG) Log.d(TAG, "[CheckSmartKey] Input - " + super.ToByteString(Input));
-            if (DEBUG) Log.d(TAG, "[CheckSmartKey] Output - " + super.ToByteString(Output));
-            if (Output == null) {
-                Log.w(TAG, "[CheckSmartKey] AES_128.Encrypt - Output is null !!!");
-                return false;
-            }
-
-            // 2. 복호화 데이터 길이 체크
-            if (Output.length != 16) {
-                Log.w(TAG, "[CheckSmartKey] Output.length Not Match !!! (length:" + Output.length + ")");
-                return false;
-            }
-
-            // 3. RandomKey 체크
-            if ((Output[0] != mDriver.Polling.RandomKeyBuffer[0]) || (Output[15] != mDriver.Polling.RandomKeyBuffer[1])) {
-                Log.w(TAG, "[CheckSmartKey] RandomKey Data Not Match !!!");
-
-                Log.i(TAG, "RandomKeyValue " + "1:" + String.format("0x%02X", mDriver.Polling.RandomKeyBuffer[0]) + ", " + "2:" + String.format("0x%02X", mDriver.Polling.RandomKeyBuffer[1]));
-                Log.i(TAG, "ReadRandomKeyValue " + "1:" + String.format("0x%02X", Output[0]) + ", " + "2:" + String.format("0x%02X", Output[15]));
-                return false;
-            }
-
-            // 4. Uid 암호화 및 그외 데이터 분리
-            byte [] Uid = new byte [] { Output[1], Output[2], Output[3], Output[4] };
-            byte [] EncryptUid = AES_128.Encrypt(AES_128.ENCRYPTTYPE.NORMAL, Uid);
-            if (DEBUG) Log.d(TAG, "[CheckSmartKey] EncryptUid - " + super.ToByteString(EncryptUid));
-            byte [] SiteCode = new byte [] { Output[5], Output[6], Output[7], Output[8] };
-            byte [] DongHo   = new byte [] { Output[9], Output[10], Output[11], Output[12] };
-            byte CardRegNo = Output[13];
-
-            // 5. 존재유무 DB 확인
-            String sn = DB_isExist(CardRegNo, EncryptUid, SiteCode, DongHo);
-            if (sn != null) {
-                CheckSmartKeyNo = CardRegNo;
-                CheckSmartKeySn = sn;
-                if (DEBUG) Log.d(TAG, "[CheckSmartKey] DB_isExist - true");
-
-                return true;
-            }
-            else return false;
-        } catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-            return false;
-        } catch (Exception e) {
-            Log.e(TAG, "[CheckSmartKey] - [Exception Error] ");
-            LogUtil.errorLogInfo("", TAG, e);//e.printStackTrace();
-            return false;
-        }
-    }
-
-    private int SaveSmartKey(byte [] Input) {
-        boolean DEBUG = true;
-
-        if (DEBUG) Log.d(TAG, "[SaveSmartKey] Start");
-        try {
-            if (Input == null) return -1;
-            if (Input.length != 16) return -2;
-
-            // 1. D1 : 0xCA 체크
-            //            if(DEBUG) Log.d(TAG, "[SaveSmartKey] Step1 : D1 Check");
-            //            if(Input[0] != (byte)0xCA)
-            //            {
-            //                Log.w(TAG, "[SaveSmartKey] D1 : Data Not Match !!!");
-            //                return -11;
-            //            }
-
-            boolean bRet = false;
-
-            // 2. SiteCode 체크
-            if (DEBUG) Log.d(TAG, "[SaveSmartKey] Step2 : SiteCode Check");
-            byte [] SiteCode = new byte [] { Input[5], Input[6], Input[7], Input[8] };
-            bRet = CompareByteArray(SiteCode, mDriver.SiteCodeBCD);
-            if (!bRet) {
-                Log.w(TAG, "[SaveSmartKey] SiteCode : Data Not Match !!!");
-                return -12;
-            }
-
-            // 3. DongHo 체크
-            if (DEBUG) Log.d(TAG, "[SaveSmartKey] Step3 : DongHo Check");
-            byte [] DongHo   = new byte [] { Input[9], Input[10], Input[11], Input[12] };
-            bRet = CompareByteArray(DongHo, mDriver.DongHoBCD);
-            if (!bRet) {
-                Log.w(TAG, "[SaveSmartKey] DongHo : Data Not Match !!!");
-                return -13;
-            }
-
-            // 4. Card Reg No. 체크
-            if (DEBUG) Log.d(TAG, "[SaveSmartKey] Step4 : Card Reg No Check");
-            byte CardRegNo = Input[13];
-            if (CardRegNo != mDriver.CardRegNo) {
-                Log.w(TAG, "[SaveSmartKey] CardRegNo : Data Not Match !!!");
-                return -14;
-            }
-
-            // 5. Uid 복호화
-            byte [] Uid = new byte [] { Input[1], Input[2], Input[3], Input[4] };
-            byte [] NormalUid = AES_128.Encrypt(AES_128.ENCRYPTTYPE.NORMAL, Uid);
-            if (DEBUG) {
-                Log.d(TAG, "[SaveSmartKey] Step5 : Uid");
-                Log.d(TAG, "                       Uid       - " + super.ToByteString(Uid));
-                Log.d(TAG, "                       NormalUid - " + super.ToByteString(NormalUid));
-            }
-
-            // 5. DB 저장
-            int ret = DB_Register(CardRegNo, NormalUid, SiteCode, DongHo);
-            if (DEBUG) Log.d(TAG, "[SaveSmartKey] Step6 : DB_Register = " + ret);
-            if (ret >= 0) {
-                return (int) CardRegNo;
-            }
-
-            return ret;
-        } catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-            return -1000;
-        } catch (Exception e) {
-            Log.e(TAG, "[SaveSmartKey] - [Exception Error] ");
-            LogUtil.errorLogInfo("", TAG, e);//e.printStackTrace();
-            return -1000;
-        }
-    }
-
-
-    /**
-     * 현관호출 or 전화호출시 사용되는 keycode - Broadcast 을 송신한다.
-     *
-     * @param code - (int) 송신할 keycode
-     * @return (int) - >=0 : 성공, <0 : 실패
-     */
-    private int setSendEventBR(int code) {
-        try {
-            KeyEvent event = new KeyEvent(KeyEvent.ACTION_UP, code);
-            Intent intent = new Intent("EVENT_DEVICE_CONTROL", null);
-            intent.putExtra(Intent.EXTRA_KEY_EVENT, event);
-            intent.putExtra("keycode",code);
-            ServiceMain.svcContext.sendBroadcast(intent);
-        } catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-            return -100;
-        } catch (Exception e) {
-            Log.e(TAG, "[setSendEventBR] - [Exception Error] code:" + code);
-            Log.e(TAG, "[setSendEventBR] - " + e.toString());
-            LogUtil.errorLogInfo("", TAG, e);//
-            return -100;
-        }
-        return 0;
-    }
-
-    /**
-     * 동호 데이터를 BCD Code 로 가져온다.
-     *
-     * @return (byte []) null - Error , Not null - OK
-     */
-    private byte [] getDongHo_BCD() {
-        try {
-            wallpaddbmgr dbmgr = new wallpaddbmgr(ServiceMain.svcContext);
-            AddressSet addc =  dbmgr.getAddressMGR();
-            dbmgr.closeDB();
-
-            byte [] RetBytes = new byte [] { 0, 0, 0, 0 };
-            byte [] Temp = new byte [] { '0', '0', '0', '0' };
-            int offset = 0;
-            int index = 0;
-
-            // DONG
-            byte [] DongBytes = addc.Dong.getBytes();
-            if(DongBytes == null) return null;
-
-            offset = 0;
-            switch (DongBytes.length) {
-                case 1: offset = 3; break;
-                case 2: offset = 2; break;
-                case 3: offset = 1; break;
-                case 4: offset = 0; break;
-                default:
-                    return null;
-            }
-
-            index = 0;
-            for (int i = offset; i < 4; i++) Temp[i] = DongBytes[index++];
-
-            RetBytes[0]  = (byte)((((Temp[0] - '0') & 0x0F) << 4) & (byte)0xF0);
-            RetBytes[0] |= (byte)((((Temp[1] - '0') & 0x0F) << 0) );
-
-            RetBytes[1]  = (byte)((((Temp[2] - '0') & 0x0F) << 4) & (byte)0xF0);
-            RetBytes[1] |= (byte)((((Temp[3] - '0') & 0x0F) << 0) );
-
-            // HO
-            byte [] HoBytes = null;
-            if (addc.UseOrNotRentHouse == true) {
-                String temp = addc.Ho.substring(0, (addc.Ho.length() - 2));
-                HoBytes = temp.getBytes();
-            }
-            else {
-                HoBytes = addc.Ho.getBytes();
-            }
-
-            if (HoBytes   == null) return null;
-
-            Temp = new byte [] { '0', '0', '0', '0' };
-            offset = 0;
-            switch (HoBytes.length) {
-                case 1: offset = 3; break;
-                case 2: offset = 2; break;
-                case 3: offset = 1; break;
-                case 4: offset = 0; break;
-                default:
-                    return null;
-            }
-
-            index = 0;
-            for (int i = offset; i < 4; i++) Temp[i] = HoBytes[index++];
-
-            RetBytes[2]  = (byte)((((Temp[0] - '0') & 0x0F) << 4) & (byte)0xF0);
-            RetBytes[2] |= (byte)((((Temp[1] - '0') & 0x0F) << 0) );
-
-            RetBytes[3]  = (byte)((((Temp[2] - '0') & 0x0F) << 4) & (byte)0xF0);
-            RetBytes[3] |= (byte)((((Temp[3] - '0') & 0x0F) << 0) );
-
-            return RetBytes;
-        } catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-            return null;
-        } catch (Exception e) {
-            Log.e(TAG, "[getDongHo_BCD] - [Exception Error] ");
-            LogUtil.errorLogInfo("", TAG, e);//
-            return null;
-        }
-    }
-
-    /**
-     * SiteCode 를 String 으로 가져온다.
-     *
-     * @return (String) SiteCode
-     */
-    private String getSiteCode_String() {
-        String[] getData = null;
-        String strSiteCode = null;
-
-        WallpadDeviceSet devset = new WallpadDeviceSet(ServiceMain.svcContext);
-        getData = devset.GetSettingData("site_code");
-        devset.closeDB();
-
-        if ((getData != null) && getData.length > 1) {
-            strSiteCode = getData[1];
-        }
-        return strSiteCode;
-    }
-
-    /**
-     * SiteCode 를 BCD 데이터로 가져온다.
-     *
-     * @return (byte []) null - Error , Not null - OK
-     */
-    private byte [] getSiteCode_BCD() {
-        try {
-            String SiteCodeStr = getSiteCode_String();
-            if (SiteCodeStr == null) return null;
-
-            byte [] RetBytes = new byte [] { 0, 0, 0, 0 };
-            byte [] SiteCodeBytes = SiteCodeStr.getBytes();
-
-            if (SiteCodeBytes == null) return null;
-            if (SiteCodeBytes.length != 8) return null;
-
-            RetBytes[0]  = (byte)((((SiteCodeBytes[0] - '0') & 0x0F) << 4) & (byte)0xF0);
-            RetBytes[0] |= (byte)((((SiteCodeBytes[1] - '0') & 0x0F) << 0) );
-
-            RetBytes[1]  = (byte)((((SiteCodeBytes[2] - '0') & 0x0F) << 4) & (byte)0xF0);
-            RetBytes[1] |= (byte)((((SiteCodeBytes[3] - '0') & 0x0F) << 0) );
-
-            RetBytes[2]  = (byte)((((SiteCodeBytes[4] - '0') & 0x0F) << 4) & (byte)0xF0);
-            RetBytes[2] |= (byte)((((SiteCodeBytes[5] - '0') & 0x0F) << 0) );
-
-            RetBytes[3]  = (byte)((((SiteCodeBytes[6] - '0') & 0x0F) << 4) & (byte)0xF0);
-            RetBytes[3] |= (byte)((((SiteCodeBytes[7] - '0') & 0x0F) << 0) );
-
-            return RetBytes;
-        } catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-            return null;
-        } catch (Exception e) {
-            Log.e(TAG, "[getSiteCode_BCD] - [Exception Error] ");
-            LogUtil.errorLogInfo("", TAG, e);//e.printStackTrace();
-            return null;
-        }
-    }
-
-    /**
-     * 도어락 타입을 반환한다.
-     *
-     * @return (int) - >=0 : 도어락 타입, <0 : 실패
-     */
-    private int getDoorLockType() {
-        // 1. get DB
-        WallpadDeviceSet devset = new WallpadDeviceSet(ServiceMain.svcContext);
-        int[] Doorinfo = devset.Get_DoorLock_Info();
-        devset.closeDB();
-
-        // 2. Check
-        if (Doorinfo == null) {
-            return -1;
-        }
-
-        if (Doorinfo.length < 2) {
-            return -2;
-        }
-
-        if (Doorinfo[0] == 0) {
-            return -3;
-        }
-
-        // 3. return
-        switch (Doorinfo[1]) {
-            case WallpadDeviceSet.DOORLOCK_TYPE_RF:
-            case WallpadDeviceSet.DOORLOCK_TYPE_NORMAL:
-            case WallpadDeviceSet.DOORLOCK_TYPE_FINGERPRINT:
-                return Doorinfo[1];
-            default:
-                return -4;
-        }
-    }
-
-    /**
-     * 무선 도어락 문열림 대기모드 사용여부
-     *
-     * @return (int) - >0 : 무선 도어락 문열림 대기모드 사용, <0 : 실패 또는 미사용
-     */
-    private int getDoorLockOpenDelayUse() {
-        // 1. get DB
-        WallpadDeviceSet devset = new WallpadDeviceSet(ServiceMain.svcContext);
-        int Doorinfo = devset.GetDeviceSetted("무선도어락문열림대기모드");
-        devset.closeDB();
-
-        // 2. Check        
-        if (Doorinfo == WallpadDeviceSet.DEV_DATA_ENABLE) {
-            return 1;
-        }
-        else if (Doorinfo == WallpadDeviceSet.DEV_DATA_DISABLE) {
-            return -1;
-        }
-        else if (Doorinfo == WallpadDeviceSet.DEV_DATA_NONE) {
-            return -2;
-        }
-        else {
-            return -3;
-        }
-    }
-
-    private boolean CompareByteArray(byte [] a, byte [] b) {
-        if ((a == null) && (b == null)) return true;
-        if ((a == null) || (b == null)) return false;
-        if (a.length != b.length) return false;
-        for(int i = 0; i < a.length; i++) { if(a[i] != b[i]) return false; }
-        return true;
-    }
-
-    /**
-     * 스마트키 인식하여 문이 열릴 경우,<br>
-     * 현관카메라에서 3초간 전원이 유지되도록 한다.
-     * @param devioctr (WallPadInterface)
-     */
-    private void TurnOnDcamPower(final WallPadInterface devioctr) {
-        Log.d(TAG, "[TurnOnDcamPower] Start");
-
-        String topActivityName = getTopActivity();
-        if(topActivityName!=null)
-        {
-            Log.d(TAG, "[TurnOnDcamPower] getTopActivity : " + topActivityName);
-
-            if (topActivityName.equals(strWallPadCallPakageName) || getCallAppRunningStatus()) {
-                Log.d(TAG, "[TurnOnDcamPower] Now WallPadCall ON");
-                return;
-            }
-        }
-
-
-        if (PowerOnTimer != null) PowerOnTimer.cancel();
-
-        CallAppEnable = false; // 문열림 동작 중에는 WallpadCall이 실행되지 않도록 false
-
-        // 현관카메라 조명 3초동안 점등 유지한 후, 다시 소등
-        Log.d(TAG, "[TurnOnDcamPower] Camera Power ON !!!");
-        int[] camType = {};
-        try {
-            WallpadDeviceSet wds = new WallpadDeviceSet(ServiceMain.svcContext);
-            camType =  wds.Get_RFDoorCAM_Info();
-            wds.closeDB();
-        } catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-        } catch (Exception e) {
-            LogUtil.errorLogInfo("", TAG, e);//e.printStackTrace();
-        }
-
-        if (camType[1] == WallpadDeviceSet.DOORTYPE_IOT_SMART) {
-            // 여기서 제어하면 안되고
-            // 플래그만 세워야 됨
-            // 실제 패킷 전송은 폴링구조 안에서 해야함
-            /*Send_SetLedMode( (byte)0x01 ); // LED ON*/
-            driverInterOpAPI.SmartIotDCam_CtrLed(true);
-        }
-        else {
-            if (Version.getModelType() == Version.MODEL_TYPE.IHN_D101 || Version.getModelType() == Version.MODEL_TYPE.IHN_D101_I
-                    || Version.getModelType() == Version.MODEL_TYPE.IHN_D101K || Version.getModelType() == Version.MODEL_TYPE.IHN_D101K_I)
-            {
-                driverInterOpAPI.IGW_SetLedOnOff(true);
-            }
-            else {
-                devioctr.cameraPowerControll(true);
-            }
-        }
-
-        PowerOnTimer = new CountDownTimer(2 * 1000, 1000) {
-            @Override
-            public void onFinish() {
-                Log.d(TAG, "[TurnOnDcamPower] PowerOnTimer Start");
-                if (getTopActivity().equals(strWallPadCallPakageName) || getCallAppRunningStatus()) {
-                    Log.d(TAG, "[TurnOnDcamPower] Now WallPadCall ON");
-                    Log.d(TAG, "[TurnOnDcamPower] Do Not TURN LED OFF !!!");
-                }
-                else {
-                    WallpadDeviceSet wds = new WallpadDeviceSet(ServiceMain.svcContext);
-                    int[] camTypes =  wds.Get_RFDoorCAM_Info();
-                    wds.closeDB();
-
-                    Log.d(TAG, "[TurnOnDcamPower] Camera Power OFF !!!");
-                    if (camTypes[1] == WallpadDeviceSet.DOORTYPE_IOT_SMART) {
-                        int ret = driverInterOpAPI.SmartIotDCam_CtrLed(false);
-                        if (ret < 0) {
-                            Log.w(TAG, "[TurnOnDcamPower] Camera Off Timer ERROR !!!");
-                        }
-                    }
-                    else {
-						if (Version.getModelType() == Version.MODEL_TYPE.IHN_D101 || Version.getModelType() == Version.MODEL_TYPE.IHN_D101_I
-                                || Version.getModelType() == Version.MODEL_TYPE.IHN_D101K || Version.getModelType() == Version.MODEL_TYPE.IHN_D101K_I) {
-							driverInterOpAPI.IGW_SetLedOnOff(false);
-						}
-						else {
-							devioctr.cameraPowerControll(false);
-						}
-                    }
-                }
-
-                CallAppEnable = true; // 현관카메라 파워 off시, WallpadCall 호출 가능
-                Log.d(TAG, "[TurnOnDcamPower] PowerOnTimer END");
-            }
-
-            @Override
-            public void onTick(long arg0) {
-            }
-        };
-        PowerOnTimer.cancel();
-        PowerOnTimer.start();
-
-        Log.d(TAG, "[TurnOnDcamPower] END");
-    }
-
-    /**
-     * 최 상위 activity 가져오기
-     */
-    private String getTopActivity() {
-        try {
-            ActivityManager mActivityManager = (ActivityManager)ServiceMain.svcContext.getSystemService(Context.ACTIVITY_SERVICE);
-            List<RunningTaskInfo> mTaskInfo = null;
-            if (mActivityManager != null) {
-                mTaskInfo = mActivityManager.getRunningTasks(5);
-            }
-            if(mTaskInfo!=null)
-            {
-                ComponentName mComponentName = mTaskInfo.get(0).topActivity;
-                return mComponentName.getPackageName();
-            }
-            else
-            {
-                return null;
-            }
-
-        } catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-            return null;
-        } catch (Exception e) {
-            Log.e(TAG, "[Exception] getTopActivity()");
-            LogUtil.errorLogInfo("", TAG, e);//e.printStackTrace();
-            return null;
-        }
-    }
-
-    private boolean getCallAppRunningStatus() {
-        boolean bRunning = false;
-
-        try {
-            WallpadStatusData DBMGR = new WallpadStatusData(ServiceMain.svcContext);
-            bRunning = DBMGR.GetCallAPKStatusRunning();
-            DBMGR.closeDB();
-
-            Log.d(TAG, "[getCallAppRunningStatus] - CALL Running : " + bRunning);
-            return bRunning;
-        } catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-            return false;
-        } catch (Exception e) {
-            Log.d(TAG, "[Exception] getCallAppRunningStatus()");
-            LogUtil.errorLogInfo("", TAG, e);//e.printStackTrace();
-            return false;
-        }
-    }
-
-}
+/*
+ * Copyright (C) 2014 Android WallPad Project
+ *
+ * FileName  : SmartKeyRfDoor_Controller.java
+ * Project   : Android WallPad Project
+ * Company   : HDC I-CONTROLS ( www.icontrols.co.kr )
+ * Author    : Kang Sang Ho  , lairu@icontrols.co.kr
+ */
+
+package com.artncore.wallpaddevservice.driver;
+
+import java.security.SecureRandom;
+import java.util.Calendar;
+import java.util.GregorianCalendar;
+import java.util.List;
+import java.util.Random;
+
+import kr.co.icontrols.iencryptor.aes128.AES_128;
+import kr.co.icontrols.wallpadsupport.Version;
+import kr.co.icontrols.wallpadsupport.WpadSound;
+import android.annotation.SuppressLint;
+import android.app.ActivityManager;
+import android.app.ActivityManager.RunningTaskInfo;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.CountDownTimer;
+import android.os.Handler;
+import android.os.Message;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.widget.Toast;
+
+import com.artncore.WallPadDataMgr.WallpadAccessData;
+import com.artncore.WallPadDataMgr.WallpadDeviceSet;
+import com.artncore.WallPadDataMgr.WallpadSmartKeyRegData;
+import com.artncore.WallPadDataMgr.WallpadStatusData;
+import com.artncore.WallPadDataMgr.wallpaddbmgr;
+import com.artncore.WallPadDataMgr.wallpaddbmgr.AddressSet;
+import com.artncore.commons.APIErrorCode;
+import com.artncore.commons.define;
+import com.artncore.devicectr.WallPadInterface;
+import com.util.LogUtil;
+import com.artncore.wallpaddevservice.ServiceMain;
+
+
+/**
+ * 스마트키 RF 현관카메라의 드라이버 모듈이다.
+ */
+@SuppressLint("HandlerLeak")
+public class SmartKeyRfDoor_Controller extends DeviceManager {
+    private final static String TAG = "SmartKeyRfDoor_DRV";
+
+    private final byte DEVICE_ADDRESS  = (byte) 0xA2;
+
+    private final byte MAX_SMARTKEY_COUNT = (byte) 5;
+
+	/** RSSI 동기화 시간 (1시간) */
+    //private final long RSSI_SYNC_TICK   = (long)(60 * TIME_MINUTE);
+    private final long RSSI_SYNC_TICK   = (long)(10 * TIME_SEC);
+    /** LED 모드 동기화 시간 (5분) */
+    //private final long LED_SYNC_TICK    = (long)(5 * TIME_MINUTE);
+    private final long LED_SYNC_TICK    = (long)(10 * TIME_SEC);
+    /** 카메라 모드 동기화 시간 (5분) */
+    //private final long CAM_SYNC_TICK    = (long)(5 * TIME_MINUTE);
+    private final long CAM_SYNC_TICK    = (long)(10 * TIME_SEC);
+    /** 시간정보 동기화 시간 (1시간) */
+    private final long TIME_SYNC_TICK   = (long) TIME_MINUTE;
+
+    private boolean firstSensor = true;
+
+    /** 도어락 문열림 대기모드 설정 시간*/
+    private final byte DLOCK_STANDBYMODE_SEC     = (byte) 5;
+
+    /** 등록후 대기시간 (초) */
+    private final long REGISTERPAUSE_TIMEOUT_TICK     = (long)(5 * TIME_SEC);
+
+    /** 등록모드 시작 */
+    public final static byte STATUS_REGMODE_START                = (byte) 0x00;
+    /** 등록완료 */
+    public final static byte STATUS_REGMODE_KEY_COMPLETE         = (byte) 0x10;
+    /** 이미 등록된 키 */
+    public final static byte STATUS_REGMODE_KEY_ALREADY          = (byte) 0x20;
+    /** 무선 통신실패 */
+    public final static byte STATUS_REGMODE_ER_WIRELESSCOMMFAIL  = (byte) 0x30;
+    /** DB 저장 실패 */
+    public final static byte STATUS_REGMODE_ER_DBWRITE           = (byte) 0x40;
+    /** 등록모드 종료 */
+    public final static byte STATUS_REGMODE_END                  = (byte) 0xA0;
+    /** 등록할 공간 없음 */
+    public final static byte STATUS_REGMODE_FULL                 = (byte) 0xB0;
+
+    private static byte CheckSmartKeyNo  = 0x00;
+    public static byte GetCheckSmartKeyNo() { return CheckSmartKeyNo; }
+    private static String CheckSmartKeySn  = null;
+    public static String GetCheckSmartKeySn() { return CheckSmartKeySn; }
+
+    /** 도어락 타입 - WallpadDeviceSet.DOORLOCK_TYPE_NORMAL or WallpadDeviceSet.DOORLOCK_TYPE_RF*/
+    private int mDoorLockType = WallpadDeviceSet.DOORLOCK_TYPE_NORMAL;
+
+    private int mModelType = Version.getModelType();
+
+    /////////////////////////////////////////////////////////////
+    // 무선도어락 연동
+    /////////////////////////////////////////////////////////////
+
+    /** 문열림 대기모드 상태 true:사용, false:사용하지 않음 */
+    private boolean mDoorOpenDelay = false;
+
+    /** 자체 문열림 모드 상태 true:허용, false:비허용 */
+    private boolean mDoorStdOpenMode = false;
+
+    /** 현관카메라 전원ON을 위한 타이머*/
+    private CountDownTimer PowerOnTimer = null;
+    /** WallpadCall 패키지 명*/
+    private static final String strWallPadCallPakageName = "kr.co.icontrols.wallpadcall";
+
+
+    /** WallpadCall 호출 가능 여부 true:허용, false:비허용
+     * 초인종 눌림 -> WallpadCall 실행 가능하도록 초기 설정
+     * */
+    private boolean CallAppEnable = true;
+    /**
+     * 자체 문열림 모드 상태
+     * @return (boolean) true:허용, false:비허용
+     */
+    private boolean GetDoorStdOpenMode() { return mDoorStdOpenMode; }
+    /**
+     * 자체 문열림 모드를 설정한다.
+     *
+     * @param OnOff (boolean) true:허용, false:비허용
+     */
+    private void SetDoorStdOpenMode(boolean OnOff) {
+        mDoorStdOpenModeHandler.removeMessages(0);
+        mDoorStdOpenModeHandler.removeMessages(1);
+        if (OnOff) {
+            Log.i(TAG, "[SetDoorStdOpenMode] ON");
+            mDoorStdOpenMode = true;
+            mDoorStdOpenModeHandler.sendEmptyMessage(0);
+        }
+        else {
+            Log.i(TAG, "[SetDoorStdOpenMode] OFF");
+            mDoorStdOpenMode = false;
+        }
+    }
+
+    private Handler mDoorStdOpenModeHandler = new Handler()
+    {
+        @Override
+        public void handleMessage(Message msg)
+        {
+            if (msg.what == 0) {
+                Log.i(TAG, "[mDoorStdOpenModeHandler] Start !!!");
+                mDoorStdOpenModeHandler.sendEmptyMessageDelayed(1, (long)((long)DLOCK_STANDBYMODE_SEC * (long)1000));
+            }
+            else if (msg.what == 1) {
+                Log.i(TAG, "[mDoorStdOpenModeHandler] TimeOut...");
+                mDoorStdOpenMode = false;
+            }
+        }
+    };
+    /////////////////////////////////////////////////////////////
+
+    /** 초기 기기 검색 횟수  */
+    private final int MAX_SEARCH_COUNT   = 3;
+
+    private class InfoList {
+        /** 센서지원 유무(거동수상자 감지용)*/
+        private boolean bSensorUsage;
+        /** LED 제어 지원 유무*/
+        private boolean bLEDLightCtrlable;
+        /** RSSI 제어 지원 유무*/
+        private boolean bRSSICtrlable;
+        /** 카메라 제어 지원 유무*/
+        private boolean bCameraCtrlable;
+        /** PIR센서 지원 유무*/
+        private boolean bPIRSensorUsage;
+        /** 시간정보 지원 유무*/
+        private boolean bTimeUsage;
+
+        /** 제조사 코드 ( 0x01 : 아이콘트롤스 ) */
+        private byte hVendor;
+
+        /** 펌웨어 Build Date (년) */
+        private byte hFWVer_Year;
+        /** 펌웨어 Build Date (월) */
+        private byte hFWVer_Month;
+        /** 펌웨어 Build Date (일) */
+        private byte hFWVer_Date;
+        /** 펌웨어 Build Date (일련번호) */
+        private byte hFWVer_No;
+
+        /** 지원 프로토콜 버전 Main */
+        private byte hProtocolVer_Main;
+        /** 지원 프로토콜 버전 Sub */
+        private byte hProtocolVer_Sub;
+
+        private InfoList() {
+            bSensorUsage = false;
+            bLEDLightCtrlable = false;
+            bRSSICtrlable = false;
+            bCameraCtrlable = false;
+            bPIRSensorUsage = false;
+            bTimeUsage = false;
+
+            hVendor = 0x00;
+
+            hFWVer_Year = 0x00;
+            hFWVer_Month = 0x00;
+            hFWVer_Date = 0x00;
+            hFWVer_No = 0x00;
+
+            hProtocolVer_Main = 0x00;
+            hProtocolVer_Sub = 0x00;
+        }
+
+        public String ToDebugString() {
+            String retStr =
+                    "==========================\r\n" +
+                            "InfoList\r\n" +
+                            "==========================\r\n" +
+                            "bSensorUsage    : " + bSensorUsage + "\r\n" +
+                            "bLEDLightCtrlable   : " + bLEDLightCtrlable + "\r\n" +
+                            "bRSSICtrlable  : " + bRSSICtrlable + "\r\n" +
+                            "bCameraCtrlable: " + bCameraCtrlable + "\r\n" +
+                            "bPIRSensorUsage  : " + bPIRSensorUsage + "\r\n" +
+                            "bTimeUsage: " + bTimeUsage + "\r\n" +
+
+                            "Vender        : " + String.format("0x%02X", hVendor) + "\r\n" +
+
+                            "FW Ver.         : " + (int)(hFWVer_Year +2000) + "." + hFWVer_Month + "." + hFWVer_Date + "." + hFWVer_No + "\r\n" +
+                            "Protocol Ver.   : " +  "V" + hProtocolVer_Main + "." + hProtocolVer_Sub + "\r\n" +
+                            "==========================";
+            return retStr;
+        }
+    }
+
+    /** 기본 상태 응답값 정의 */
+    private class StatusList {
+        /** 거동수상자 센서감지 : true:감지 , false:미감지 */
+        private boolean bSensorDetect;
+        /** 카메라 센서감지 : true:동작중 , false:꺼짐 */
+        private boolean bCameraStatus;
+        /** LED 상태 : true:동작중 , false:꺼짐 */
+        private boolean bLedStatus;
+        /** 카메라 Auto 상태 : true:동작중 , false:꺼짐 */
+        private boolean bCameraAuto;
+        /** LED Auto 상태 : true:동작중 , false:꺼짐 */
+        private boolean bLedAuto;
+        /** 현관벨 상태 : true:눌림 , false:평상시 */
+        private boolean bDoorBtnStatus;
+        /** 에러상태     : true:에러 , false:정상 */
+        private boolean bError;
+        /** 인식된 RF 스마트키 개수 */
+        private byte SmartKeyCount;
+
+        private StatusList() {
+            bSensorDetect = false;
+            bCameraStatus = false;
+            bLedStatus = false;
+            bCameraAuto = false;
+            bLedAuto = false;
+
+            bDoorBtnStatus = false;
+            bError = false;
+            SmartKeyCount = 0;
+        }
+
+        public String ToDebugString() {
+            String retStr =
+                    "==========================\r\n" +
+                            "StatusList\r\n" +
+                            "==========================\r\n" +
+                            "bSensorDetect  : "  + bSensorDetect + "\r\n" +
+                            "bLedStatus     : "  + bLedStatus + "\r\n" +
+                            "bCameraStatus  : "  + bCameraStatus + "\r\n" +
+                            "bLedAuto       : "  + bLedAuto + "\r\n" +
+                            "bCameraAuto    : "  + bCameraAuto + "\r\n" +
+                            "bDoorBtnStatus : " + bDoorBtnStatus + "\r\n" +
+                            "bError         : " + bError + "\r\n" +
+                            "SmartKeyCount  : " + SmartKeyCount + "\r\n" +
+                            "==========================";
+            return retStr;
+        }
+    }
+
+    /** 거동수상자 관련 센서값 */
+    private class SensorValue {
+        /** 센서 감도 */
+        private byte Sensor_Sensitivity;
+        /** 거동수상자 판별시간 */
+        private byte Sensor_DetectTime;
+		/** LED 모드 */
+		private byte Sensor_LedMode;
+		/** 감지센서 RSSI Read */
+		private byte Sensor_RSSI_Read;
+		/** 감지센서 RSSI Write */
+		private byte Sensor_RSSI_Write;
+		/** 거동수상자 판별빈도 */
+		private byte Sensor_DetectRatio;
+		/** 카메라 모드 */
+		private byte Sensor_CameraMode;
+
+        private SensorValue() {
+            Sensor_Sensitivity 	= 0;
+            Sensor_DetectTime 	= 0;
+
+			Sensor_LedMode 		= -1;
+			Sensor_CameraMode 	= -1;
+
+            Sensor_DetectRatio 	= 100;	 // 현관카메라의 감지빈도는 기본 100%로 설정되어 있음
+			Sensor_RSSI_Read 	= -101;  // 기본값 : 범위 이탈
+			Sensor_RSSI_Write 	= -101;  // 기본값 : 범위 이탈
+        }
+
+        public String ToDebugString() {
+            String retStr =
+                    "==========================\r\n" +
+                            "SensorValue\r\n" +
+                            "==========================\r\n" +
+                            "Sensor_Sensitivity : "  + Sensor_Sensitivity + "\r\n" +
+                            "Sensor_DetectTime  : " + Sensor_DetectTime + "\r\n" +
+                            "Sensor_DetectRatio : " + Sensor_DetectRatio + "\r\n" +
+                            "Sensor_RSSI_Read   : " + Sensor_RSSI_Read + "\r\n" +
+                            "Sensor_RSSI_Write  : " + Sensor_RSSI_Write + "\r\n" +
+                            "Sensor_LedMode     : " + Sensor_LedMode + "\r\n" +
+                            "Sensor_CameraMode  : " + Sensor_CameraMode + "\r\n" +
+                            "==========================";
+            return retStr;
+        }
+    }
+
+    private class EncryptionList {
+        private byte [] Data;
+        private EncryptionList() {
+            Data = new byte [16];
+            for (int i = 0; i < Data.length; i++) Data[i] = 0x00;
+        }
+
+        public boolean Input(byte [] in, int startIdx) {
+            if (in == null) return false;
+            if ((in.length - startIdx) < 16) return false;
+
+            if (Data == null) return false;
+
+            for (int i = 0; i < Data.length; i++) Data[i] = in[startIdx + i];
+
+            return true;
+        }
+
+        public String ToDebugString(int KeyIndex) {
+            if (Data == null) return "null";
+
+            String retStr = "[" + KeyIndex + "] ";
+
+            for (int i = 0; i < Data.length; i++) {
+                retStr += String.format("%02X ", Data[i]);
+            }
+            return retStr;
+        }
+    }
+
+    private class KeyDataList {
+        private byte Count;
+
+        public EncryptionList [] Encryption;
+
+        private KeyDataList() {
+            Count = 0;
+            Encryption = null;
+        }
+
+        private KeyDataList(byte setcount) {
+            Count = 0;
+            Encryption = null;
+
+            SetCount(setcount);
+        }
+
+        private int SetCount(byte setcount) {
+            if (setcount <= 0 || setcount > MAX_SMARTKEY_COUNT) return -1;
+
+            Count = setcount;
+            Encryption = new EncryptionList[setcount];
+            for (byte i = 0; i < setcount; i++) Encryption[i] = new EncryptionList();
+
+            return 0;
+        }
+
+        private byte [] getByteArray() {
+            if (Encryption == null) return null;
+
+            byte [] retdata = new byte [(Count * 16) + 1];
+            int index = 0;
+            retdata[index++] = Count;
+
+            for (byte dataIdx = 0; dataIdx < Count; dataIdx++) {
+                for (int i = 0; i < 16; i++) {
+                    retdata[index++] = Encryption[dataIdx].Data[i];
+                }
+            }
+
+            return retdata;
+        }
+
+        public String ToDebugString() {
+            String retStr =
+                    "==========================\r\n" +
+                            "KeyDataList\r\n" +
+                            "==========================\r\n";
+
+            retStr += "Count : " + Count + "\r\n";
+
+            if (Count > 0) {
+                for(byte i = 0; i < Count; i++) retStr += Encryption[i].ToDebugString(i+1) + "\r\n";
+            }
+            retStr += "==========================\r\n";
+
+            return retStr;
+        }
+    }
+
+    private class GetRegisterDataList {
+        boolean Exit;
+        byte RegResult;
+        public EncryptionList Encryption;
+
+        private GetRegisterDataList() {
+            Exit = false;
+            RegResult = 0x00;
+            Encryption = null;
+        }
+    }
+
+    private class SetRegisterDataList {
+        byte [] LocalCode;
+        byte [] SiteCode;
+        byte [] DongCode;
+        byte [] HoCode;
+        byte CardRegNo;
+
+        private SetRegisterDataList() {
+            LocalCode = new byte [] { 0x00, 0x00 };
+            SiteCode  = new byte [] { 0x00, 0x00 };
+            DongCode  = new byte [] { 0x00, 0x00 };
+            HoCode    = new byte [] { 0x00, 0x00 };
+            CardRegNo = 0x00;
+        }
+
+        public int setSiteCode(byte [] InCode) {
+            if (InCode == null) return -1;
+            if (InCode.length < 4) return -2;
+            if (LocalCode == null) return -3;
+            if (SiteCode == null) return -4;
+
+            LocalCode[0] = InCode[0];
+            LocalCode[1] = InCode[1];
+            SiteCode[0] = InCode[2];
+            SiteCode[1] = InCode[3];
+
+            return 0;
+        }
+
+        public int setDongHoCode(byte [] InCode) {
+            if (InCode == null) return -1;
+            if (InCode.length < 4) return -2;
+            if (DongCode == null) return -3;
+            if (HoCode == null) return -4;
+
+            DongCode[0] = InCode[0];
+            DongCode[1] = InCode[1];
+            HoCode[0] = InCode[2];
+            HoCode[1] = InCode[3];
+
+            return 0;
+        }
+
+        public int setLocalCode(byte [] InCode) {
+            if (InCode == null) return -1;
+            if (InCode.length < 2) return -2;
+            if (LocalCode == null) return -3;
+
+            LocalCode[0] = InCode[0];
+            LocalCode[1] = InCode[1];
+            return 0;
+        }
+
+        public byte [] getByteArray() {
+            if (LocalCode == null) return null;
+            if (SiteCode == null) return null;
+            if (DongCode == null) return null;
+            if (HoCode == null) return null;
+
+            byte [] retArray = new byte [9];
+            int index = 0;
+
+            retArray[index++] = LocalCode[0];
+            retArray[index++] = LocalCode[1];
+            retArray[index++] = SiteCode[0];
+            retArray[index++] = SiteCode[1];
+            retArray[index++] = DongCode[0];
+            retArray[index++] = DongCode[1];
+            retArray[index++] = HoCode[0];
+            retArray[index++] = HoCode[1];
+            retArray[index++] = CardRegNo;
+
+            return retArray;
+        }
+    }
+
+    public class Driver {
+        private PollingList Polling;
+
+        private InfoList Info;
+
+        private StatusList Status;
+
+        private SensorValue Sensor_Value;
+
+        private byte [] DongHoBCD;
+
+        private byte [] SiteCodeBCD;
+
+        private boolean RegisterInitMode;
+
+        private byte CardRegNo;
+
+        public Driver() {
+            Polling = new PollingList();
+
+            Info    = new InfoList();
+
+            Status  = new StatusList();
+
+            Sensor_Value = new SensorValue();
+
+            DongHoBCD   = new byte [] { 0, 0, 0, 0 };
+            SiteCodeBCD = new byte [] { 0, 0, 0, 0 };
+
+            RegisterInitMode = false;
+
+            CardRegNo = 0x00;
+        }
+
+        /** Polling 관련 */
+        private class PollingList {
+            private final class STATUS {
+                /** 초기화 과정 */
+                public final static byte First = 0;
+                /** 초기화 타임아웃 */
+                public final static byte FirstTimeOut = 1;
+                /** 평상시 */
+                public final static byte Normal = 2;
+                /** 등록모드 시작 버튼 체크 */
+                public final static byte RegisterStartCheck = 4;
+                /** 등록모드 */
+                public final static byte Register = 5;
+                /** 등록후 일시정지 */
+                public final static byte RegisterPause = 6;
+            }
+
+            public byte Status;
+            public int SearchTryCount;
+            public boolean bRandomKeyGeneration;
+            public byte [] RandomKeyBuffer;
+
+            public long RegisterPauseTimeOutTick;
+
+			public long RssiSyncTick;
+			public long LedSyncTick;
+			public long CamSyncTick;
+            public long TimeSyncTick;
+
+            private PollingList() {
+                SetStatus(STATUS.First);
+                SearchTryCount = 0;
+
+                bRandomKeyGeneration = true;
+                RandomKeyBuffer = new byte [] { 0x00, 0x00 };
+                RegisterPauseTimeOutTick = 0;
+
+				RssiSyncTick = 0;
+                LedSyncTick = 0;
+                CamSyncTick = 0;
+                TimeSyncTick = 0;
+            }
+
+            public void SetStatus(byte ChangeStatus) {
+                switch (ChangeStatus) {
+                    case STATUS.First:
+                        Status = ChangeStatus;
+                        break;
+
+                    case STATUS.FirstTimeOut:
+                        Status = ChangeStatus;
+                        break;
+
+                    case STATUS.Normal:
+                        if ((Status == STATUS.RegisterStartCheck) || (Status == STATUS.Register) || (Status == STATUS.RegisterPause)) {
+                            StatusChanged(STATUS_REGMODE_END);
+                        }
+                        Status = ChangeStatus;
+                        break;
+
+                    case STATUS.RegisterStartCheck:
+                        Status = ChangeStatus;
+                        break;
+
+                    case STATUS.Register:
+                        Status = ChangeStatus;
+                        break;
+
+                    case STATUS.RegisterPause:
+                        RegisterPauseTimeOutTick = System.currentTimeMillis();
+                        Status = ChangeStatus;
+                        break;
+                }
+            }
+        }
+    }
+
+    private Driver mDriver = null;
+
+    private DriverInterOpAPI driverInterOpAPI;
+
+    /**
+     * 생성자
+     */
+    public SmartKeyRfDoor_Controller() {
+        /* 로그 초기상태 */
+//        log_sw = true;
+//        SerialLog = true;
+
+        /* 통신성공률 변수 초기화 */
+        super.CommDataGeneration(1);
+
+        /* 드라이버 내부 변수 초기화 */
+        mDriver = new Driver();
+
+        ismDoorOpenDelay = false;
+
+        /* 동호 가져오기 */
+        byte [] DongHoBCD = getDongHo_BCD();
+        if (DongHoBCD != null) mDriver.DongHoBCD = DongHoBCD;
+        Log.i(TAG, "DongHoBCD   : " + ToByteString(mDriver.DongHoBCD));
+
+        /* 사이트코드 가져오기 */
+        byte [] SiteCodeBCD = getSiteCode_BCD();
+        if (SiteCodeBCD != null) mDriver.SiteCodeBCD = SiteCodeBCD;
+        Log.i(TAG, "SiteCodeBCD : " + ToByteString(mDriver.SiteCodeBCD));
+
+        /* 도어락 타입 가져오기 */
+        int getDoorLockType = getDoorLockType();
+        if (getDoorLockType >= 0) {
+            mDoorLockType = getDoorLockType;
+        }
+        else {
+            Log.i(TAG, "getDoorLockType Error (ret:" + getDoorLockType + ")");
+        }
+
+        if (mDoorLockType == WallpadDeviceSet.DOORLOCK_TYPE_RF || mDoorLockType == WallpadDeviceSet.DOORLOCK_TYPE_FINGERPRINT) {
+            int getDoorOpenDelayUse = getDoorLockOpenDelayUse();
+            if (getDoorOpenDelayUse > 0) {
+                mDoorOpenDelay = true;
+                Log.i(TAG, "mDoorOpenDelay : " + mDoorOpenDelay);
+            } else {
+                WallPadInterface mWallPadInterface = new WallPadInterface();
+                mWallPadInterface.ctrlDoorlockOpenStandbyMode(2); // 문열림 대기 미설정
+            }
+        }
+
+        Log.i(TAG, "=========================================");
+        Log.i(TAG, "SmartKeyRfDoor_Controller - create");
+        Log.i(TAG, "=========================================");
+    }
+
+    @Override
+    public void DeviceLog(String msg) {
+        if (!log_sw) return;
+        Log.d(TAG, msg);
+    }
+
+    /**
+     * BroadcastReceiver
+     */
+    private BroadcastReceiver mWallPadNotifyBR = new BroadcastReceiver()
+    {
+        public void onReceive(Context context, Intent intent)
+        {
+            String acname = intent.getAction();
+
+            DeviceLog("Receive Notify BR [" + acname + "]");
+
+            if (mDriver.Polling.Status != Driver.PollingList.STATUS.Normal) return;
+
+            if (acname.equals(define.NOTIFY_ACNAME)) {
+                int kind = intent.getIntExtra("KIND", 0);
+                DeviceLog("Receive Notify BR " + define.NOTIFY_ACNAME + " : " + kind);
+
+            }
+
+        }
+
+    };
+
+    /**
+     * BroadcastReceiver 용 필터를 등록한다.
+     *
+     * @return (boolean) true : 성공 , false : 실패
+     */
+    private boolean Device_BrRegistration() {
+        DeviceLog("Device_BrRegistration - Start");
+
+        if (mDriver == null) return false;
+        if (mDriver.Polling.Status != Driver.PollingList.STATUS.Normal) return false;
+
+        IntentFilter filter = new IntentFilter();
+
+        // 1. NOTIFY_ACNAME
+        DeviceLog("Device_BrRegistration - filter.addAction - " + define.NOTIFY_ACNAME);
+        filter.addAction(define.NOTIFY_ACNAME);
+
+        ServiceMain.svcContext.registerReceiver(mWallPadNotifyBR, filter);
+
+        DeviceLog("Device_BrRegistration - OK");
+        return true;
+    }
+
+    /**
+     * 로딩후 처음 폴링 시퀀스
+     */
+    @Override
+    protected void do_boot()
+    {
+        driverInterOpAPI = new DriverInterOpAPI(MainHandler);
+    }
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    // Polling
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+     * do_ctr : 폴링스케쥴러
+     */
+    @Override
+    protected void do_ctr() {
+        DeviceLog("Polling ");
+
+        /* [[ First & FirstTimeOut ]]
+         * 초기 디바이스정보  검색 */
+        if ((mDriver.Polling.Status == Driver.PollingList.STATUS.First) || (mDriver.Polling.Status == Driver.PollingList.STATUS.FirstTimeOut)) {
+            // 1. TimeOut Check
+            if (mDriver.Polling.Status == Driver.PollingList.STATUS.First) {
+                if (mDriver.Polling.SearchTryCount++ > MAX_SEARCH_COUNT) {
+                    mDriver.Polling.SetStatus(Driver.PollingList.STATUS.FirstTimeOut);
+
+                    Log.i(TAG, "--------------------------------------------------");
+                    Log.i(TAG, "SearchDevice Fail... FirstTimeOut ");
+                    Log.i(TAG, "--------------------------------------------------");
+
+                    ServiceMain.deviceInitChecker.Remove(super.DeviceName);
+                }
+            }
+
+            // 2. 기기정보 읽기
+            InfoList Info = Send_GetDeviceInfo();
+            if (Info != null) {
+                mDriver.Info = Info;
+                Log.i(TAG, "First Smart Cam Information ~~~");
+                Log.i(TAG, mDriver.Info.ToDebugString());
+
+                mDriver.Polling.SetStatus(Driver.PollingList.STATUS.Normal);
+
+                ServiceMain.deviceInitChecker.Remove(super.DeviceName);
+
+                Device_BrRegistration();
+            }
+        }
+        /* [[ Normal ]]
+         * 평상시 */
+        else if (mDriver.Polling.Status == Driver.PollingList.STATUS.Normal) {
+			long currentTimeMillis = 0;
+
+            if (mDriver.Info.bSensorUsage) {
+                if (firstSensor) {
+                    Log.i(TAG, "First Smart Cam Send_SetSensorConfig Sending @@@@@@@");
+                    if (Send_SetSensorConfig((byte)0xFF, (byte)0xFF) >= 0) {
+                        Log.i(TAG, "First Smart Cam Get Sensor Config !!!");
+						Sleep(150);
+					}
+
+                    Log.i(TAG, "First Smart Cam Send_SetDetectRatio Sending @@@@@@@");
+					if (Send_SetDetectRatio((byte)0xFF) >= 0) {
+                        Log.i(TAG, "First Smart Cam Get Ratio !!!");
+						Sleep(150);
+					}
+
+                    Log.i(TAG, "First Smart Cam Send_SetLedMode Sending @@@@@@@");
+                    if (Send_SetLedMode( (byte)0xFF) >= 0) {
+                        Log.i(TAG, "First Smart Cam Get Led Mode !!!");
+                        Sleep(150);
+                    }
+
+                    Log.i(TAG, "First Smart Cam Send_SetRSSIMode1 Sending @@@@@@@");
+                    if (Send_SetRSSIMode((byte)0x01, (byte)0xFF) >= 0) {
+                        Log.i(TAG, "First Smart Cam Get RSSI mode !!!");
+                        Sleep(150);
+                    }
+
+                    Log.i(TAG, "First Smart Cam Send_SetCameraMode Sending @@@@@@@");
+                    if (Send_SetCameraMode( (byte)0xFF) >= 0) {
+                        Log.i(TAG, "First Smart Cam Get Camera Mode !!!");
+                        Sleep(150);
+                    }
+
+                    // 2. 기본 상태 요청
+                    StatusList Status = Send_GetStatus(mDriver.Polling.RandomKeyBuffer, true);
+                    if (Status != null) {
+                        Send_SetStatusClr(Status);
+                    }
+
+                    if (mDriver.Sensor_Value.Sensor_LedMode == (byte)0x01) {
+                        // 최초에 LED 켜져있으면 끈다.
+                        if (Send_SetLedMode( (byte)0x00) >= 0) {
+                            Log.i(TAG, "First Smart Cam - Turn Off LED $$$");
+                            Sleep(150);
+                        }
+                    }
+
+                    if (mDriver.Sensor_Value.Sensor_CameraMode == (byte)0x01) {
+                        // 최초에 카메라 열려있으면 닫는다.
+                        if (Send_SetCameraMode( (byte)0x00) >= 0) {
+                            Log.i(TAG, "First Smart Cam Turn Off Camera $$$");
+                            Sleep(150);
+                        }
+                    }
+
+                    firstSensor = false;
+                    Log.d(TAG, "@@@@@@@ First SmartCam Status @@@@@@@");
+                    if(mDriver.Sensor_Value!=null)
+                        Log.d(TAG, mDriver.Sensor_Value.ToDebugString());
+                }
+            }
+
+            // LED 모드 설정값 확인
+            if (mDriver.Info.bLEDLightCtrlable) {
+                currentTimeMillis = System.currentTimeMillis();
+                if (Math.abs(currentTimeMillis - mDriver.Polling.LedSyncTick) > LED_SYNC_TICK) {
+                    mDriver.Polling.LedSyncTick = currentTimeMillis;
+
+                    if (Send_SetSensorConfig((byte)0xFF, (byte)0xFF) >= 0) {
+                        Sleep(150);
+                    }
+
+                    if (Send_SetLedMode( (byte)0xFF) >= 0) {
+                        Sleep(150);
+                    }
+                }
+            }
+
+			// RSSI 설정값 확인
+			if (mDriver.Info.bRSSICtrlable) {
+				currentTimeMillis = System.currentTimeMillis();
+				if (Math.abs(currentTimeMillis - mDriver.Polling.RssiSyncTick) > RSSI_SYNC_TICK) {
+					mDriver.Polling.RssiSyncTick = currentTimeMillis;
+
+					if (Send_SetRSSIMode((byte)0x01, (byte)0xFF) >= 0) {
+						Sleep(150);
+					}
+				}
+			}
+
+            // 카메라 모드 설정값 확인
+            if (mDriver.Info.bCameraCtrlable) {
+                currentTimeMillis = System.currentTimeMillis();
+                if (Math.abs(currentTimeMillis - mDriver.Polling.CamSyncTick) > CAM_SYNC_TICK) {
+                    mDriver.Polling.CamSyncTick = currentTimeMillis;
+
+                    if (Send_SetCameraMode( (byte)0xFF) >= 0) {
+                        Sleep(150);
+                    }
+                }
+            }
+
+            // 1. RandomKey 생성여부
+            if (mDriver.Polling.bRandomKeyGeneration) {
+                mDriver.Polling.bRandomKeyGeneration = false;
+
+                SecureRandom rd = new SecureRandom();
+                rd.nextBytes(mDriver.Polling.RandomKeyBuffer);
+
+                Log.i(TAG, "RandomKey Generation!!!   RandomKeyValue " + "1:" + String.format("0x%02X", mDriver.Polling.RandomKeyBuffer[0]) + ", " + "2:" + String.format("0x%02X", mDriver.Polling.RandomKeyBuffer[1]));
+            }
+
+            // 2. 기본 상태 요청
+            // 시간정보 지원 확인
+            StatusList Status = null;
+            if (mDriver.Info.bTimeUsage) {
+                currentTimeMillis = System.currentTimeMillis();
+                if (Math.abs(currentTimeMillis - mDriver.Polling.TimeSyncTick) > TIME_SYNC_TICK) {
+                    mDriver.Polling.TimeSyncTick = currentTimeMillis;
+                    Status = Send_GetStatus(mDriver.Polling.RandomKeyBuffer, true);
+                    if (Status == null) return;
+                }
+                else {
+                    Status = Send_GetStatus(mDriver.Polling.RandomKeyBuffer, false);
+                    if (Status == null) return;
+                }
+            }
+            else {
+                Status = Send_GetStatus(mDriver.Polling.RandomKeyBuffer, false);
+                if (Status == null) return;
+            }
+
+
+            // 3. 기본 상태에서 버튼 눌림 처리
+            UpdateVariables(Status);
+
+            // 4. 스마트 키값 확인
+            if (Status.SmartKeyCount > 0) {
+                mDriver.Polling.bRandomKeyGeneration = true;
+
+                // 스마트 키값 요청
+                KeyDataList KeyData = Send_GetSmartKey(Status.SmartKeyCount);
+                if (KeyData == null) return;
+                Log.i(TAG, KeyData.ToDebugString());
+
+                // 스마트 키값 확인
+                boolean bRet = Send_SetSmartKeyVerify(KeyData);
+                if (!bRet) return;
+                Log.i(TAG, "SmartKeyVerify OK!!!");
+
+                // 키값 업데이트
+                UpdateVariables(KeyData);
+            }
+        }
+
+        /* [[ RegisterStartCheck ]]
+         * 등록모드 시작버튼 체크 */
+        else if (mDriver.Polling.Status == Driver.PollingList.STATUS.RegisterStartCheck) {
+            int ret = Send_SetSmartKeyRegisterStart();
+            if (ret >= 0) {
+                UpdateVariables(ret);
+            }
+        }
+
+        /* [[ Register ]]
+         * 등록모드  */
+        else if (mDriver.Polling.Status == Driver.PollingList.STATUS.Register) {
+            SetRegisterDataList setRegisterDataList = new SetRegisterDataList();
+            if (!mDriver.RegisterInitMode) {
+                setRegisterDataList.setSiteCode(mDriver.SiteCodeBCD);
+                setRegisterDataList.setDongHoCode(mDriver.DongHoBCD);
+
+                setRegisterDataList.CardRegNo = mDriver.CardRegNo;
+            }
+
+            GetRegisterDataList getRegisterDataList = Send_GetSmartKeyRegister(setRegisterDataList);
+            if (getRegisterDataList != null) {
+                UpdateVariables(getRegisterDataList);
+            }
+        }
+
+        /* [[ RegisterPause ]]
+         * 등록후 일시정지  */
+        else if (mDriver.Polling.Status == Driver.PollingList.STATUS.RegisterPause) {
+            long currentTimeMillis = System.currentTimeMillis();
+            if (Math.abs(currentTimeMillis - mDriver.Polling.RegisterPauseTimeOutTick) > REGISTERPAUSE_TIMEOUT_TICK) {
+                Send_SetSmartKeyRegisterEnd();
+                mDriver.Polling.SetStatus(Driver.PollingList.STATUS.Normal);
+            }
+        }
+
+        /*
+         * 예외처리 */
+        else {
+            mDriver = new Driver();
+        }
+    }
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    // Ctrl
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+     * NoSink 제어
+     *
+     * @param StrArg
+     *
+     * @return
+     */
+    public String NoSinkCtrl(String StrArg) {
+        DeviceLog("[NoSinkCtrl] Start");
+
+        // 1. 디바이스 초기화시 에러리턴
+        if ((mDriver.Polling.Status == Driver.PollingList.STATUS.First) || (mDriver.Polling.Status == Driver.PollingList.STATUS.FirstTimeOut)) {
+            Log.w(TAG, "[NoSinkCtrl] - Not Yet !!!");
+            return "FAIL;" + APIErrorCode.DEVICEISNOTREADY;
+        }
+
+        CtrDevFormat ctrDevFormat = GetCtrDevParamParsing(StrArg, 5);
+        if (ctrDevFormat.ret != APIErrorCode.C_SUCCESS) {
+            Log.w(TAG, "[NoSinkCtrl] GetCtrDevParamParsing Error (ret:" + ctrDevFormat.ret + ")");
+            return "FAIL;" + APIErrorCode.DEFAULT_PARSING_ERR;
+        }
+
+        //////////////////////////////////////////////////////////
+        // Refresh : 데이터 갱신 (No Sink)
+        //////////////////////////////////////////////////////////
+        if (ctrDevFormat.CmdStr!=null && ctrDevFormat.CmdStr.equals("Refresh")) {
+            DeviceLog("[Refresh] Enter ~~~");
+
+            return RefreshResult();
+        }
+
+        return "FAIL;" + APIErrorCode.UNKNOWNCOMMAND;
+    }
+
+    /**
+     * do_ctrEmm : 싱크 제어
+     */
+    @Override
+    @SuppressLint("DefaultLocale")
+    protected String do_ctrEmm(DeviceCtrSHMem SHMem) {
+        DeviceLog("[do_ctrEmm] Start");
+        DeviceLog("cmd    : " + SHMem.cmd);
+        DeviceLog("StrArg : " + SHMem.StrArg);
+
+        // 1. 디바이스 초기화시 에러리턴
+        if ((mDriver.Polling.Status == Driver.PollingList.STATUS.First) || (mDriver.Polling.Status == Driver.PollingList.STATUS.FirstTimeOut)) {
+            Log.w(TAG, "[do_ctrEmm] - Not Yet !!!");
+            return SHMem.retVal = "FAIL;" + APIErrorCode.DEVICEISNOTREADY;
+        }
+
+        CtrDevFormat ctrDevFormat = GetCtrDevParamParsing(SHMem.StrArg, 5);
+        if (ctrDevFormat.ret != APIErrorCode.C_SUCCESS) {
+            Log.w(TAG, "[do_ctrEmm] GetCtrDevParamParsing Error (ret:" + ctrDevFormat.ret + ")");
+            return SHMem.retVal = "FAIL;" + APIErrorCode.DEFAULT_PARSING_ERR;
+        }
+
+        if(ctrDevFormat.CmdStr!=null)
+        {
+            //////////////////////////////////////////////////////////
+            // SetRegisterModeStart : 등록모드 시작 요청 (Sink)
+            //
+            // [0] - 초기화옵션 ( 0 : 노말 , 1 : 키 초기화 (시험용) )
+            //////////////////////////////////////////////////////////
+            if (ctrDevFormat.CmdStr.equals("SetRegisterModeStart")) {
+                int ret = 0;
+
+                // 1. Mode Check
+                if ((mDriver.Polling.Status == Driver.PollingList.STATUS.Register) || (mDriver.Polling.Status == Driver.PollingList.STATUS.RegisterPause)) {
+                    // 이전 상태가 등록모드였다면 등록모드 종료
+                    Log.w(TAG, "Old Mode Register - RegisterModeEnd !!!");
+
+                    ret = Send_SetSmartKeyRegisterEnd();
+                    if (ret != 1) {
+                        return SHMem.retVal = "FAIL;" + APIErrorCode.DEVICEISNORESPONSE;
+                    }
+                }
+
+                // 2. 등록모드 시작
+                ret = Send_SetSmartKeyRegisterStart();
+                if (ret < 0) {
+                    return SHMem.retVal = "FAIL;" + APIErrorCode.DEVICEISNORESPONSE;
+                }
+
+                // 3. 사이트 코드 가져오기
+                byte [] SiteCodeBCD = getSiteCode_BCD();
+                if (SiteCodeBCD != null) mDriver.SiteCodeBCD = SiteCodeBCD;
+                Log.i(TAG, "SiteCodeBCD : " + ToByteString(mDriver.SiteCodeBCD));
+
+                mDriver.Polling.SetStatus(Driver.PollingList.STATUS.RegisterStartCheck);
+
+                // 4. Param 적용
+                if (ctrDevFormat.param[0] == 0) mDriver.RegisterInitMode = false;
+                else mDriver.RegisterInitMode = true;
+
+                UpdateVariables(ret);
+
+                return SHMem.retVal = "SUCCESS";
+            }
+
+            //////////////////////////////////////////////////////////
+            // SetRegisterModeNext : 등록모드 연장 진행 요청 (Sink)
+            //////////////////////////////////////////////////////////
+            else if (ctrDevFormat.CmdStr.equals("SetRegisterModeNext")) {
+                // 1. Mode Check
+
+                // 이전 상태가 [등록후 일시정지]가 아니라면 에러
+                if (mDriver.Polling.Status != Driver.PollingList.STATUS.RegisterPause) {
+                    // 이전 상태 [등록모드] 였을 경우
+                    if (mDriver.Polling.Status == Driver.PollingList.STATUS.Register) {
+                        //
+                        int id = DB_GetId();
+                        if (id <= 0) {
+                            Log.w(TAG, "SetRegisterModeNext - DB_GetId  Out Of Range #1 (id:" + id + ")");
+                            mDriver.Polling.SetStatus(Driver.PollingList.STATUS.Normal);
+                            return SHMem.retVal = "FAIL;" + APIErrorCode.STATUS_OUTOFRANGE;
+                        }
+                        else {
+                            mDriver.CardRegNo = (byte)id;
+                            super.StatusChanged( (byte)(STATUS_REGMODE_START | mDriver.CardRegNo));
+                            return SHMem.retVal = "SUCCESS";
+                        }
+                    }
+                    // 이전 상태가 [등록후 일시정지] or [등록모드] 둘다 아님
+                    else {
+                        Log.w(TAG, "[SetRegisterModeNext] Old Mode 'RegisterPause' is Not !!!");
+                        return SHMem.retVal = "FAIL;" + APIErrorCode.STATUS_OUTOFRANGE;
+                    }
+                }
+
+                // 2. Next id 가져오기
+                if (!mDriver.RegisterInitMode) {
+                    int id = DB_GetId();
+                    if (id <= 0) {
+                        Log.w(TAG, "SetRegisterModeNext - DB_GetId  Out Of Range #2 (id:" + id + ")");
+                        mDriver.Polling.SetStatus(Driver.PollingList.STATUS.Normal);
+                        if (id == -1) super.StatusChanged(STATUS_REGMODE_FULL);
+                        return SHMem.retVal = "FAIL;" + APIErrorCode.STATUS_OUTOFRANGE;
+                    }
+                    else {
+                        mDriver.CardRegNo = (byte)id;
+                        super.StatusChanged( (byte)(STATUS_REGMODE_START | mDriver.CardRegNo));
+                        mDriver.Polling.SetStatus(Driver.PollingList.STATUS.Register);
+                        return SHMem.retVal = "SUCCESS";
+                    }
+                }
+                else {
+                    mDriver.Polling.SetStatus(Driver.PollingList.STATUS.Normal);
+                    return SHMem.retVal = "SUCCESS";
+                }
+            }
+
+            //////////////////////////////////////////////////////////
+            // RegisterModeEnd : 등록모드 종료 요청 (Sink)
+            //////////////////////////////////////////////////////////
+            else if (ctrDevFormat.CmdStr.equals("SetRegisterModeEnd")) {
+                int ret = 0;
+
+                for (int ReTryCount = 0; ReTryCount < 3; ReTryCount++) {
+                    ret = Send_SetSmartKeyRegisterEnd();
+                    if (ret == 1) break;
+                }
+
+                mDriver.Polling.SetStatus(Driver.PollingList.STATUS.Normal);
+
+                if (ret == 1) {
+                    return SHMem.retVal = "SUCCESS";
+                }
+                else {
+                    return SHMem.retVal = "FAIL;" + APIErrorCode.DEVICEISNORESPONSE;
+                }
+            }
+
+            //////////////////////////////////////////////////////////
+            // SetDeleteKey : 카드 삭제 알림 (Sink)
+            //////////////////////////////////////////////////////////
+            else if (ctrDevFormat.CmdStr.equals("SetDeleteKey")) {
+                SetRegisterDataList setRegisterDataList = new SetRegisterDataList();
+                setRegisterDataList.setSiteCode(mDriver.SiteCodeBCD);
+                setRegisterDataList.setDongHoCode(mDriver.DongHoBCD);
+
+                byte[] TempLocalCode = new byte[2];
+                if (ctrDevFormat.param[0] == 1) {
+                    //전체
+                    TempLocalCode[0] = (byte) 0xFA;
+                    TempLocalCode[1] = (byte) 0xFA;
+                }
+                else if (ctrDevFormat.param[0] == 0) {
+                    //개별
+                    TempLocalCode[0] = (byte) 0xF0;
+                    TempLocalCode[1] = (byte) 0xF0;
+                    setRegisterDataList.CardRegNo = ctrDevFormat.param[1];
+                }
+                else {
+                    Log.w(TAG, "SetDeleteKey - ctrDevFormat.param[1]  Out Of Range #1 (ctrDevFormat.param[1]:" + ctrDevFormat.param[1] + ")");
+                    return SHMem.retVal = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
+                }
+
+                setRegisterDataList.setLocalCode(TempLocalCode);
+                boolean ret = Send_DeleteKey(setRegisterDataList);
+                if (ret) {
+                    return SHMem.retVal = "SUCCESS";
+                }
+                else {
+                    return SHMem.retVal = "FAIL;" + APIErrorCode.DEVICEISNORESPONSE;
+                }
+            }
+
+            //////////////////////////////////////////////////////////
+            // SetSensorConfig : 센서 감도/시간 설정 요청 (Sink)
+            //////////////////////////////////////////////////////////
+            else if (ctrDevFormat.CmdStr.equals("SetSensorConfig")) {
+                //if(ctrDevFormat.param.length != 2) {return SHMem.retVal = "FAIL;" + APIErrorCode.DEVICEISNORESPONSE;}
+
+                byte Sensivity = ctrDevFormat.param[0];
+                byte Time = ctrDevFormat.param[1];
+                Log.i(TAG, "Sensor Api data : " + Sensivity + " / " + Time);
+
+                try {
+                    if (mDriver.Sensor_Value!=null && Send_SetSensorConfig(Sensivity, Time) >= 0) {
+                        Log.d(TAG, mDriver.Sensor_Value.ToDebugString());
+                    }
+
+                    if (mDriver.Sensor_Value != null) {
+                        return SHMem.retVal = "SUCCESS;" + mDriver.Sensor_Value.Sensor_Sensitivity + ";" + mDriver.Sensor_Value.Sensor_DetectTime;
+                    }
+                    else {
+                        return SHMem.retVal = "FAIL;" + APIErrorCode.DEVICEISNORESPONSE;
+                    }
+                } catch (RuntimeException re) {
+                    LogUtil.errorLogInfo("", TAG, re);
+                    return SHMem.retVal = "FAIL;" + APIErrorCode.EXCEPTION;
+                } catch (Exception e) {
+                    LogUtil.errorLogInfo("", TAG, e);//
+                    return SHMem.retVal = "FAIL;" + APIErrorCode.EXCEPTION;
+                }
+            }
+
+            //////////////////////////////////////////////////////////
+            // SetLEDmode : LED 모드 설정 요청 (Sink)
+            //////////////////////////////////////////////////////////
+            else if(ctrDevFormat.CmdStr.equals("SetLEDmode")) {
+                //if(ctrDevFormat.param.length != 1) {return SHMem.retVal = "FAIL;" + APIErrorCode.DEVICEISNORESPONSE;}
+
+                byte LEDmode = ctrDevFormat.param[0];
+                Log.i(TAG, "LED Api data : " + LEDmode);
+                if (LEDmode < 0 || LEDmode > 6) {
+                    if (LEDmode == 0xFF) { }
+                    else { return "FAIL"; }
+                }
+
+                try {
+                    int ret = Send_SetLedMode(LEDmode);
+                    Log.i(TAG, "[Sink Ctr] Led Control ret 1 : " + ret);
+                    if (ret < 0) {
+                        Log.i(TAG, "[Sink Ctr] Led Control ret 2 : " + ret);
+                        return SHMem.retVal = "FAIL;" + APIErrorCode.DEVICEISNOTREADY;
+                    }
+                    else if (ret == 0) {
+                        return SHMem.retVal = "FAIL;" + APIErrorCode.DEVCTRNULL;
+                    }
+                    else if (ret == 1) {
+                        Log.d(TAG, mDriver.Sensor_Value.ToDebugString());
+
+                        return SHMem.retVal = "SUCCESS";
+                    }
+                    else if (ret == 2) {
+                        return SHMem.retVal = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
+                    }
+                    else {
+                        return SHMem.retVal = "FAIL;" + APIErrorCode.DEVICEISNOTREADY;
+                    }
+                } catch (RuntimeException re) {
+                    LogUtil.errorLogInfo("", TAG, re);
+                    return SHMem.retVal = "FAIL;" + APIErrorCode.EXCEPTION;
+                } catch (Exception e) {
+                    LogUtil.errorLogInfo("", TAG, e);//
+                    return SHMem.retVal = "FAIL;" + APIErrorCode.EXCEPTION;
+                }
+            }
+
+            //////////////////////////////////////////////////////////
+            // SetRSSImode : RSSI 모드 설정 요청 (Sink)
+            //////////////////////////////////////////////////////////
+            else if (ctrDevFormat.CmdStr.equals("SetRSSImode")) {
+                //if(ctrDevFormat.param.length != 2) {return SHMem.retVal = "FAIL;" + APIErrorCode.DEVICEISNORESPONSE;}
+
+                byte RSSImode = ctrDevFormat.param[0];
+                byte RSSIlevel = ctrDevFormat.param[1];
+                Log.i(TAG, "RSSI Api mode : " + RSSImode);
+                Log.i(TAG, "RSSI Api level : " + RSSIlevel);
+
+                if (RSSImode < 0 || RSSImode > 2) {return "FAIL";}
+                if (RSSIlevel < -100 || RSSIlevel > 100) {
+                    if (RSSIlevel == 0xFF) { }
+                    else { return "FAIL"; }
+                }
+
+                try {
+                    int ret = Send_SetRSSIMode(RSSImode, RSSIlevel);
+                    if (ret < 0) {
+                        return SHMem.retVal = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
+                    }
+                    else if (ret == 0) {
+                        return SHMem.retVal = "FAIL;" + APIErrorCode.DEVCTRNULL;
+                    }
+                    else if (ret == 1) {
+                        Log.d(TAG, mDriver.Sensor_Value.ToDebugString());
+
+                        return SHMem.retVal = "SUCCESS";
+                    }
+                    else if (ret == 2) {
+                        return SHMem.retVal = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
+                    }
+                } catch (RuntimeException re) {
+                    LogUtil.errorLogInfo("", TAG, re);
+                    return SHMem.retVal = "FAIL;" + APIErrorCode.EXCEPTION;
+                } catch (Exception e) {
+                    LogUtil.errorLogInfo("", TAG, e);//e.printStackTrace();
+                    return SHMem.retVal = "FAIL;" + APIErrorCode.EXCEPTION;
+                }
+            }
+
+            //////////////////////////////////////////////////////////
+            // SetStrangerDetectRatio : 판별 감지 빈도 설정 요청 (Sink)
+            //////////////////////////////////////////////////////////
+            else if (ctrDevFormat.CmdStr.equals("SetStrangerDetectRatio")) {
+                //if(ctrDevFormat.param.length != 1) {return SHMem.retVal = "FAIL;" + APIErrorCode.DEVICEISNORESPONSE;}
+
+                byte DetectRatio = ctrDevFormat.param[0];
+                Log.i(TAG, "Detect Ratio Api data : " + DetectRatio);
+//            if(DetectRatio < 0 || DetectRatio > 100)
+//            {
+//				if(DetectRatio == 0xFF) { }
+//				else { return "FAIL"; }
+//            }
+
+                try {
+                    int ret = Send_SetDetectRatio(DetectRatio);
+                    if (ret < 0) {
+                        return SHMem.retVal = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
+                    }
+                    else if (ret == 0) {
+                        return SHMem.retVal = "FAIL;" + APIErrorCode.DEVCTRNULL;
+                    }
+                    else if (ret == 1) {
+                        Log.d(TAG, mDriver.Sensor_Value.ToDebugString());
+
+                        return SHMem.retVal = "SUCCESS";
+                    }
+                    else if (ret == 2) {
+                        return SHMem.retVal = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
+                    }
+                } catch (RuntimeException re) {
+                    LogUtil.errorLogInfo("", TAG, re);
+                    return SHMem.retVal = "FAIL;" + APIErrorCode.EXCEPTION;
+                } catch (Exception e) {
+                    LogUtil.errorLogInfo("", TAG, e);//
+                    return SHMem.retVal = "FAIL;" + APIErrorCode.EXCEPTION;
+                }
+            }
+
+            //////////////////////////////////////////////////////////
+            // SetCAMERAmode : 카메라 모드 설정 요청 (Sink)
+            //////////////////////////////////////////////////////////
+            else if (ctrDevFormat.CmdStr.equals("SetCAMERAmode")) {
+                //if(ctrDevFormat.param.length != 1) {return SHMem.retVal = "FAIL;" + APIErrorCode.DEVICEISNORESPONSE;}
+
+                byte CameraMode = ctrDevFormat.param[0];
+                Log.i(TAG, "Camera Mode Api data : " + CameraMode);
+                if (CameraMode < 0 || CameraMode > 3) {
+                    if (CameraMode == 0xFF) { }
+                    else { return "FAIL"; }
+                }
+
+                try {
+                    int ret = Send_SetCameraMode(CameraMode);
+                    if (ret < 0) {
+                        return SHMem.retVal = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
+                    }
+                    else if (ret == 0) {
+                        return SHMem.retVal = "FAIL;" + APIErrorCode.DEVCTRNULL;
+                    }
+                    else if (ret == 1) {
+                        Log.d(TAG, mDriver.Sensor_Value.ToDebugString());
+
+                        return SHMem.retVal = "SUCCESS";
+                    }
+                    else if (ret == 2) {
+                        return SHMem.retVal = "FAIL;" + APIErrorCode.INVALIDPARAMETER;
+                    }
+                } catch (RuntimeException re) {
+                    LogUtil.errorLogInfo("", TAG, re);
+                    return SHMem.retVal = "FAIL;" + APIErrorCode.EXCEPTION;
+                } catch (Exception e) {
+                    LogUtil.errorLogInfo("", TAG, e);//
+                    return SHMem.retVal = "FAIL;" + APIErrorCode.EXCEPTION;
+                }
+            }
+        }
+
+
+
+        return SHMem.retVal = "UNKNOWNCMD";
+    }
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    // Refresh Result
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    private String RefreshResult() {
+        String result;
+
+        DeviceLog("RefreshResult call : ");
+
+        // 1. Check Polling Status
+        if ((mDriver.Polling.Status == Driver.PollingList.STATUS.First) || (mDriver.Polling.Status == Driver.PollingList.STATUS.FirstTimeOut)) {
+            result = "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
+            return result;
+        }
+
+        // 2. Make Return String Format
+        try {
+            if (mDriver == null) return "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
+            if (mDriver.Status == null) return "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
+            if (mDriver.Info == null) return "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
+
+            /*
+             * [Format]
+             *
+             * SUCCESS          - (String) 성공
+             *
+             * [Status]
+             * bDoorBtnStatus   - (boolean) 버튼 눌림 상태
+             * bSensorDetect    - (boolean) 거동수상자 감지여부
+             * bLedStatus       - (boolean) LED 상태
+             * bCameraStatus    - (boolean) 카메라 상태
+             * bLedAuto         - (boolean) LED Auto 상태
+             * bCameraAuto      - (boolean) 카메라 Auto 상태
+             * bError           - (boolean) 에러 상태
+             * SmartKeyCount    - (byte)    인식된 스마트키 수
+             *
+             * [Sensor_Value]
+             * Sensor_Sensitivity   - (byte) 센서 감도
+             * Sensor_DetectTime    - (byte) 센서 감지시간
+             * Sensor_LedMode       - (byte) LED 모드
+             * Sensor_RSSI_Read     - (byte) 읽기 RSSI 세기
+             * Sensor_RSSI_Write    - (byte) 쓰기 RSSI 세기
+             * Sensor_DetectRatio   - (byte) 판별빈도
+             * Sensor_CameraMode    - (byte) 카메라 모드
+             */
+
+            result = APIErrorCode.SUCCESS + ";";
+
+            result += mDriver.Status.bDoorBtnStatus + ";";
+            result += mDriver.Status.bSensorDetect + ";";
+            result += mDriver.Status.bLedStatus   + ";";
+            result += mDriver.Status.bCameraStatus   + ";";
+            result += mDriver.Status.bLedAuto  + ";";
+            result += mDriver.Status.bCameraAuto  + ";";
+            result += mDriver.Status.bError + ";";
+            result += mDriver.Status.SmartKeyCount + ";";
+
+            result += mDriver.Sensor_Value.Sensor_Sensitivity + ";";
+            result += mDriver.Sensor_Value.Sensor_DetectTime + ";";
+            result += mDriver.Sensor_Value.Sensor_LedMode + ";";
+            result += mDriver.Sensor_Value.Sensor_RSSI_Read + ";";
+            result += mDriver.Sensor_Value.Sensor_RSSI_Write + ";";
+            result += mDriver.Sensor_Value.Sensor_DetectRatio + ";";
+            result += mDriver.Sensor_Value.Sensor_CameraMode;
+        } catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+            result = "FAIL;"+APIErrorCode.EXCEPTION;
+        } catch (Exception e) {
+            Log.e(TAG, "[Exception Error] RefreshResult");
+            LogUtil.errorLogInfo("", TAG, e);//e.printStackTrace();
+            result = "FAIL;"+APIErrorCode.EXCEPTION;
+        }
+        DeviceLog(" RefreshResult_Sample return : "+result);
+
+        return result;
+    }
+
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    // Protocol Command Send Func
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+
+    /**
+     * 기기 정보 요청 응답.
+     *
+     * @return (InfoList) null - Error , Not null - OK
+     */
+    private InfoList Send_GetDeviceInfo() {
+        DeviceLog("[Send_GetDeviceInfo] Start");
+
+        // 1. In 파라미터 확인
+
+        // 2. 패킷 데이터 만들기
+        byte [] ReqData = null;
+
+        // 3. 데이터 전송 및 응답
+        byte [] Reply = SendNRead_Variable((byte)(DEVICE_ADDRESS), CMDList.Req.GetDeviceInfo, ReqData);
+
+        // 4. 수신데이터 파싱
+        byte data = 0x00;
+        int index = 0;
+        boolean bError = false;
+        while (true) {
+            if (Reply == null) {
+                DeviceLog("[GetDeviceInfo_RepParsing] Reply is null");
+                bError = true; break;
+            }
+
+            if (Reply.length != 9) {
+                Log.w(TAG, "[GetDeviceInfo_RepParsing] Reply.length  fail ... " + Reply.length);
+                bError = true; break;
+            }
+
+            //     1.2. Details Data Check
+            data = 0x00;
+            index = 0;
+
+            //         - D1 : 기능 지원 정보#1
+            data = Reply[index++];
+            if ((data & (byte) (BIT6 | BIT7)) != 0x00) {
+                Log.w(TAG, "[Send_GetDeviceInfo] D1:Unused Bit Set !!! " + String.format("0x%02X", Reply[2]));
+            }
+
+            //         - D2 : 기능 지원 정보#2
+            data = Reply[index++];
+
+            //         - D3 : 제조사구분정보
+            data = Reply[index++];
+
+            //         - D4 : 펌웨어 Build Date (Year)
+            data = Reply[index++];
+
+            //         - D5 : 펌웨어 Build Date (Month)
+            data = Reply[index++];
+            if ((data > 12) || (data <= 0)) {
+                Log.w(TAG, "[GetDeviceInfo_RepParsing] D5 (Build Date - Month) : Out of Range !!! (data:" + data + ")");
+                bError = true; break;
+            }
+
+            //         - D6 : 펌웨어 Build Date (Day)
+            data = Reply[index++];
+            if ((data > 31) || (data <= 0)) {
+                Log.w(TAG, "[GetDeviceInfo_RepParsing] D6 (Build Date - Day) : Out of Range !!! (data:" + data + ")");
+                bError = true; break;
+            }
+
+            //         - D7 : 펌웨어 Build Date (Number)
+            data = Reply[index++];
+
+            //         - D8 : Protocol 버전정보 (Main)
+            data = Reply[index++];
+
+            //         - D9 : Protocol 버전정보 (Sub)
+            data = Reply[index++];
+
+            break;
+        }
+
+        if (bError) {
+            AddDoCount(false);
+            DeviceLog("[Send_GetDeviceInfo] FAIL");
+            return null;
+        }
+
+        AddDoCount(true);
+
+        // 5. Data return
+        InfoList Info = new InfoList();
+        index = 0;
+        data = 0;
+
+        //         - D1 : 기능 지원 정보#1
+        if ((Reply[index] & BIT0) != 0x00) Info.bSensorUsage = true;
+        else Info.bSensorUsage = false;
+
+        if ((Reply[index] & BIT1) != 0x00) Info.bLEDLightCtrlable = true;
+        else Info.bLEDLightCtrlable = false;
+
+        if ((Reply[index] & BIT2) != 0x00) Info.bRSSICtrlable = true;
+        else Info.bRSSICtrlable = false;
+
+        if ((Reply[index] & BIT3) != 0x00) Info.bCameraCtrlable = true;
+        else Info.bCameraCtrlable = false;
+
+        if ((Reply[index] & BIT4) != 0x00) Info.bPIRSensorUsage = true;
+        else Info.bPIRSensorUsage = false;
+
+        if ((Reply[index] & BIT5) != 0x00) Info.bTimeUsage = true;
+        else Info.bTimeUsage = false;
+
+        index++;
+        //         - D2 : 기능 지원 정보#2
+        index++;
+
+        //         - D3 : 제조사 구분정보
+        Info.hVendor = Reply[index++];
+        //         - D4 : 펌웨어 Build Date (Year)
+        Info.hFWVer_Year = Reply[index++];
+        //         - D5 : 펌웨어 Build Date (Month)
+        Info.hFWVer_Month = Reply[index++];
+        //         - D6 : 펌웨어 Build Date (Day)
+        Info.hFWVer_Date = Reply[index++];
+        //         - D7 : 펌웨어 Build Date (Number)
+        Info.hFWVer_No = Reply[index++];
+        //         - D8 : Protocol 버전정보 (Main)
+        Info.hProtocolVer_Main = Reply[index++];
+        //         - D9 : Protocol 버전정보 (Sub)
+        Info.hProtocolVer_Sub = Reply[index++];
+
+        DeviceLog("[Send_GetDeviceInfo] END");
+        return Info;
+    }
+
+    /**
+     * 기본상태 요청 응답.
+     *
+     * @return (StatusList) null - Error , Not null - OK
+     */
+    private StatusList Send_GetStatus(byte[] RandomKey, boolean bSendTime) {
+        DeviceLog("[Send_GetStatus] Start");
+
+        // 1. In 파라미터 확인
+        if (RandomKey == null) {
+            Log.w(TAG, "[Send_GetStatus] Param - RandomKey is null !!!");
+            return null;
+        }
+
+        if (RandomKey.length != 2) {
+            Log.w(TAG, "[Send_GetStatus] Param - RandomKey length Not Match !!! (length:" + RandomKey.length + ")");
+            return null;
+        }
+
+        // 2. 패킷 데이터 만들기
+        byte[] ReqData = new byte [] { RandomKey[0], RandomKey[1] };
+        if (bSendTime) {
+            byte[] TempReqData = new byte[8];
+            Calendar cal = new GregorianCalendar();
+            int index = 0;
+            TempReqData[index++] = RandomKey[0];
+            TempReqData[index++] = RandomKey[1];
+            TempReqData[index++] = (byte) (cal.get(Calendar.YEAR) - 2000);
+            TempReqData[index++] = (byte) (cal.get(Calendar.MONTH) + 1);
+            TempReqData[index++] = (byte) cal.get(Calendar.DAY_OF_MONTH);
+            TempReqData[index++] = (byte) cal.get(Calendar.HOUR_OF_DAY);
+            TempReqData[index++] = (byte) cal.get(Calendar.MINUTE);
+            TempReqData[index++] = (byte) cal.get(Calendar.SECOND);
+            ReqData = TempReqData;
+        }
+        else {
+            byte[] TempReqData = new byte [] { RandomKey[0], RandomKey[1] };
+            ReqData = TempReqData;
+        }
+
+        // 3. 데이터 전송 및 응답
+        byte [] Reply = SendNRead_Variable((byte) (DEVICE_ADDRESS), CMDList.Req.GetStatus, ReqData);
+
+        // 4. 수신데이터 파싱
+        byte data = 0x00;
+        int index = 0;
+
+        boolean bError = false;
+        while (true) {
+            if (Reply == null) {
+                DeviceLog("[GetStatus_RepParsing] Reply is null");
+                bError = true; break;
+            }
+
+            if (Reply.length != 2) {
+                Log.w(TAG, "[GetStatus_RepParsing] Reply.length  fail ... " + Reply.length);
+                bError = true; break;
+            }
+
+            //     1.2. Details Data Check
+            //         - D1 : 현관카메라 상태
+            data = Reply[index++];
+            if ((data & (BIT6)) != 0x00) {
+                Log.w(TAG, "[GetStatus_RepParsing] D1 (Mode) : Unused Bit Set !!! " + String.format("0x%02X", data));
+                //bError = true; break;
+            }
+
+            //         - D2 : 인식된 RF 스마트키 개수
+            data = Reply[index++];
+            if (!((data >= 0) && (data <= 5))) {
+                Log.w(TAG, "[GetStatus_RepParsing] D2 (KeyCount) : Out Of Range !!! " + String.format("0x%02X", data));
+                //bError = true; break;
+            }
+
+            break;
+        }
+
+        if (bError) {
+            AddDoCount(false);
+            DeviceLog("[Send_GetStatus] FAIL");
+            return null;
+        }
+
+        AddDoCount(true);
+
+        // 5. Data return
+        StatusList Status = new StatusList();
+        index = 0;
+        data = 0;
+
+        //         - D1 : 현관카메라 상태
+        data = Reply[index++];
+        if ((byte)(data & BIT0) != 0x00) Status.bDoorBtnStatus = true;
+        else Status.bDoorBtnStatus = false;
+
+        if ((byte)(data & BIT1) != 0x00) Status.bSensorDetect = true;
+        else Status.bSensorDetect = false;
+
+        if ((byte)(data & BIT2) != 0x00) Status.bLedStatus = true;
+        else Status.bLedStatus = false;
+
+        if ((byte)(data & BIT3) != 0x00) Status.bCameraStatus = true;
+        else Status.bCameraStatus = false;
+
+        if ((byte)(data & BIT4) != 0x00) Status.bLedAuto = true;
+        else Status.bLedAuto = false;
+
+        if ((byte)(data & BIT5) != 0x00) Status.bCameraAuto = true;
+        else Status.bCameraAuto = false;
+
+        if ((byte)(data & BIT7) != 0x00) Status.bError = true;
+        else Status.bError = false;
+
+        //         - D2 : 인식된 RF 스마트키 개수
+        data = Reply[index++];
+        if (!((data >= 0) && (data <= 5))) {
+            // 현관카메라 버그로 인한 예외처리 요구사항
+            Log.w(TAG, "[GetStatus_RepParsing] Status.SmartKeyCount will be 5 ");
+            data = 5;
+        }
+        Status.SmartKeyCount = data;
+
+        DeviceLog("[Send_GetStatus] END");
+        return Status;
+    }
+
+    /**
+     * 기본상태값 해제 요청
+     *
+     * @return (boolean) true : 정상 , false : 실패
+     */
+    private boolean Send_SetStatusClr(StatusList ClearStatus) {
+        DeviceLog("[Send_SetStatusClr] Start");
+
+        // 1. In 파라미터 확인
+        if (ClearStatus == null) {
+            Log.w(TAG, "[Send_SetStatusClr] Param - ClearStatus is null !!!");
+            return false;
+        }
+
+        // 2. 패킷 데이터 만들기
+        byte [] ReqData = new byte [] { 0x00 };
+
+        if (ClearStatus.bDoorBtnStatus || firstSensor) ReqData[0] |= BIT0;
+        if (ClearStatus.bSensorDetect || firstSensor) ReqData[0] |= BIT1;
+        if (ClearStatus.bError || firstSensor) ReqData[0] |= BIT7;
+
+
+        // 3. 데이터 전송 및 응답
+        byte [] Reply = SendNRead_Variable( (byte)(DEVICE_ADDRESS), CMDList.Req.SetStatusClr, ReqData);
+
+        // 4. 수신데이터 파싱
+        boolean bError = false;
+        while (true) {
+            if (Reply == null) {
+                DeviceLog("[Send_SetStatusClr] Reply is null");
+                bError = true; break;
+            }
+
+            if (Reply.length != 1) {
+                Log.w(TAG, "[Send_SetStatusClr] Reply.length  fail ... " + Reply.length);
+                bError = true; break;
+            }
+
+            //     1.2. Details Data Check
+            byte data = 0x00;
+            int index = 0;
+            //         - D1 : 현관카메라 상태
+            data = Reply[index++];
+            if ((data & (byte)( BIT2 | BIT3 | BIT4 | BIT5 | BIT6)) != 0x00) {
+                Log.w(TAG, "[Send_SetStatusClr] D1 (Mode) : Unused Bit Set !!! " + String.format("0x%02X", data));
+                bError = true; break;
+            }
+            break;
+        }
+
+        if (bError) {
+            AddDoCount(false);
+            DeviceLog("[Send_SetStatusClr] FAIL");
+            return false;
+        }
+        AddDoCount(true);
+
+        DeviceLog("[Send_SetStatusClr] END");
+        return true;
+    }
+
+    /**
+     * 스마트 키값 요청/반환
+     *
+     * @param ReqSmartKeyCount - (byte) 요청할 스마트RF키 개수
+     *
+     * @return (KeyDataList) 응답받은 KayData : null - Error , Not null - OK
+     */
+    private KeyDataList Send_GetSmartKey(byte ReqSmartKeyCount) {
+        DeviceLog("[Send_GetSmartKey] Start");
+
+        // 1. In 파라미터 확인
+        if ((ReqSmartKeyCount <= 0) || (ReqSmartKeyCount > MAX_SMARTKEY_COUNT)) {
+            Log.w(TAG, "[Send_GetSmartKey] Param - ClearStatus is null !!!");
+            return null;
+        }
+
+        // 2. 패킷 데이터 만들기
+        byte [] ReqData = new byte [] { ReqSmartKeyCount };
+
+        // 3. 데이터 전송 및 응답
+        byte [] Reply = SendNRead_Variable( (byte)(DEVICE_ADDRESS), CMDList.Req.GetSmartKey, ReqData);
+
+        // 4. 수신데이터 파싱
+        boolean bError = false;
+        while (true) {
+            //     null Check
+            if (Reply == null) {
+                DeviceLog("[Send_GetSmartKey] Reply is null");
+                bError = true; break;
+            }
+            //     Length Check
+
+            //Reply[0] bit7 Clear 필요 (현관카메라 버그로 인한 예외처리 요구사항)
+            Reply[0] = (byte) (Reply[0] & 0x7F); //7번 비트 Clear
+
+            int CalcLen = (int) ((byte)(Reply[0] * 16) + 1);
+            if (Reply.length != CalcLen) {
+                Log.w(TAG, "[Send_GetSmartKey] Reply.length  fail ... (length:" + Reply.length + ", CalcLen:" + CalcLen + ")");
+                bError = true; break;
+            }
+
+            byte data = 0x00;
+            int index = 0;
+
+            //     D1 : 응답할 스마트RF키 개수
+            data = Reply[index++];
+            if (data != ReqSmartKeyCount) {
+                Log.w(TAG, "[Send_GetSmartKey] D1 : Req/Rep SmartKeyCount Not Match!!!  ReqSmartKeyCount:" + ReqSmartKeyCount + "   RepSmartKeyCount:" + data);
+                bError = true; break;
+            }
+
+            break;
+        }
+
+        if (bError) {
+            AddDoCount(false);
+            DeviceLog("[Send_GetSmartKey] FAIL");
+            return null;
+        }
+        AddDoCount(true);
+
+        // 5. Data return
+        KeyDataList keyDataList = new KeyDataList(ReqSmartKeyCount);
+        try {
+            for (byte i = 0; i < ReqSmartKeyCount; i++) {
+                keyDataList.Encryption[i].Input(Reply, (int)(1+(i*16)));
+            }
+        } catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+            return null;
+        } catch (Exception e) {
+            Log.e(TAG, "[Send_GetSmartKey] - [Exception Error] ");
+            LogUtil.errorLogInfo("", TAG, e);//e.printStackTrace();
+            return null;
+        }
+
+        DeviceLog("[Send_GetSmartKey] END");
+        return keyDataList;
+    }
+
+    /**
+     * 스마트 키값 요청/반환
+     *
+     * @param ReqKeyData - (KeyDataList) 확인 요청할 스마트키 Class
+     *
+     * @return (KeyDataList) 응답받은 KayData : null - Error , Not null - OK
+     */
+    private boolean Send_SetSmartKeyVerify(KeyDataList ReqKeyData) {
+        DeviceLog("[Send_SetSmartKeyVerify] Start");
+
+        // 1. In 파라미터 확인
+        if (ReqKeyData == null) {
+            Log.w(TAG, "[Send_SetSmartKeyVerify] Param - ReqKeyData is null !!!");
+            return false;
+        }
+
+        // 2. 패킷 데이터 만들기
+        byte [] ReqData = ReqKeyData.getByteArray();
+
+        // 3. 데이터 전송 및 응답
+        byte [] Reply = SendNRead_Variable( (byte)(DEVICE_ADDRESS), CMDList.Req.SetSmartKeyVerify, ReqData);
+
+        // 4. 수신데이터 파싱
+        boolean bError = false;
+
+        while (true) {
+            //     null Check
+            if (Reply == null) {
+                DeviceLog("[Send_SetSmartKeyVerify] Reply is null");
+                bError = true; break;
+            }
+
+            //     Length Check
+            if (Reply.length != 3) {
+                Log.w(TAG, "[Send_SetSmartKeyVerify] Reply.length  fail ... (length:" + Reply.length + ")");
+                bError = true; break;
+            }
+
+            byte data = 0x00;
+            int index = 0;
+
+            //     D1 : 응답할 스마트RF키 개수
+            data = Reply[index++];
+            if (data != ReqKeyData.Count) {
+                Log.w(TAG, "[Send_SetSmartKeyVerify] D1 : Req/Rep SmartKeyCount Not Match!!!  ReqSmartKeyCount:" + ReqKeyData.Count + "   RepSmartKeyCount:" + data);
+                bError = true; break;
+            }
+
+            break;
+        }
+
+        if (bError) {
+            AddDoCount(false);
+            DeviceLog("[Send_SetSmartKeyVerify] FAIL");
+            return false;
+        }
+        AddDoCount(true);
+
+        // 5. 데이터 확인
+        byte[] Result = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00 };
+        for (int i = 0; i < 5; i++) {
+            if (i < 4) Result[i] = (byte)((byte)(Reply[1] >> (i * 2)) & (byte)(BIT0 | BIT1));   // 0 ~ 4
+            else Result[i] = (byte)((byte)(Reply[2] >> 0) & (byte)(BIT0 | BIT1));               // 5
+        }
+
+        for (byte i = 0; i < Reply[0]; i++) {
+            switch (Result[i]) {
+                case 0x00:
+                    Log.w(TAG, "Send_SetSmartKeyVerify - CheckVerify Error0( Index:" + i + ", data:" + String.format("0x%02X", Result[i]) + ")");
+                    return false;
+
+                case 0x01:
+                    // 정상
+                    break;
+
+                case 0x02:
+                    // 오류
+                    Log.w(TAG, "Send_SetSmartKeyVerify - CheckVerify Error2( Index:" + i + ", data:" + String.format("0x%02X", Result[i]) + ")");
+                    return false;
+            }
+        }
+
+        DeviceLog("[Send_SetSmartKeyVerify] END");
+        return true;
+    }
+
+    /**
+     * 등록모드 시작 요청
+     *
+     * @return (int) 진입결과 - >=0 : 성공(0:미진입 , 1:진입) , <0 : 실패
+     */
+    private int Send_SetSmartKeyRegisterStart() {
+        DeviceLog("[Send_SetSmartKeyRegisterStart] Start");
+
+        // 1. In 파라미터 확인
+
+        // 2. 패킷 데이터 만들기
+        byte [] ReqData = null;
+
+        // 3. 데이터 전송 및 응답
+        byte [] Reply = SendNRead_Variable( (byte)(DEVICE_ADDRESS), CMDList.Req.SetSmartKeyRegisterStart, ReqData);
+
+        // 4. 수신데이터 파싱
+        byte data = 0x00;
+        int index = 0;
+        boolean bError = false;
+        while (true) {
+            //     null Check
+            if (Reply == null) {
+                DeviceLog("[Send_SetSmartKeyRegisterStart] Reply is null");
+                bError = true; break;
+            }
+
+            //     Length Check
+            if (Reply.length != 1) {
+                Log.w(TAG, "[Send_SetSmartKeyRegisterStart] Reply.length  fail ... (length:" + Reply.length + ")");
+                bError = true; break;
+            }
+
+            data = 0x00;
+            index = 0;
+
+            //     D1 : 등록모드 시작 상태값
+            data = Reply[index++];
+            if ((data & (byte)(BIT1 | BIT2 | BIT3 | BIT4 | BIT5 | BIT6)) != 0x00) {
+                Log.w(TAG, "[Send_SetSmartKeyRegisterStart] D1 : Unused BIT SET  (data:" + String.format("0x%02X", data) + ")");
+                bError = true; break;
+            }
+
+            break;
+        }
+
+        if (bError) {
+            AddDoCount(false);
+            DeviceLog("[Send_SetSmartKeyRegisterStart] FAIL");
+            return -1;
+        }
+        AddDoCount(true);
+
+
+        // 5. 데이터 확인
+        data = 0x00;
+        index = 0;
+        //      D1 : 등록모드 시작 상태값
+        data = Reply[index++];
+        if ((byte)(data & BIT7) != 0x00) {
+            Log.w(TAG, "[Send_SetSmartKeyRegisterStart] D1 : Error Bit Set !!!");
+            return -10;
+        }
+
+        if ((byte)(data & BIT0) != 0x00) {
+            // 진입 성공
+            DeviceLog("[Send_SetSmartKeyRegisterStart] END");
+            return 1;
+        }
+
+        // 진입 실패
+        DeviceLog("[Send_SetSmartKeyRegisterStart] END");
+        return 0;
+    }
+
+    /**
+     * 등록 스마트 키값 요청/응답
+     *
+     * @return (GetRegisterDataList) null - Error , Not null - OK
+     */
+    private GetRegisterDataList Send_GetSmartKeyRegister(SetRegisterDataList setRegisterData) {
+        DeviceLog("[Send_GetSmartKeyRegister] Start");
+
+        // 1. In 파라미터 확인
+        if (setRegisterData == null) {
+            Log.w(TAG, "[Send_GetSmartKeyRegister] Param - RegisterData is null !!!");
+            return null;
+        }
+
+        // 2. 패킷 데이터 만들기
+        byte [] ReqData = setRegisterData.getByteArray();
+
+        // 3. 데이터 전송 및 응답
+        byte [] Reply = SendNRead_Variable( (byte)(DEVICE_ADDRESS), CMDList.Req.GetSmartKeyRegister, ReqData);
+
+        // 4. 수신데이터 파싱
+        boolean bError = false;
+        byte data = 0x00;
+        int index = 0;
+
+        byte RegResult = 0;
+        while (true) {
+            //     null Check
+            if (Reply == null) {
+                DeviceLog("[Send_GetSmartKeyRegister] Reply is null");
+                bError = true; break;
+            }
+
+            //     Length Check
+            if (Reply.length < 1) {
+                Log.w(TAG, "[Send_GetSmartKeyRegister] Reply.length  fail #1... (length:" + Reply.length + ")");
+                bError = true; break;
+            }
+
+            index = 0;
+
+            //     D1 : 등록모드 상태값
+            data = Reply[index++];
+            if ((data & (byte)(BIT4 | BIT5 | BIT6 | BIT7)) != 0x00) {
+                Log.w(TAG, "[Send_GetSmartKeyRegister] D1 : Unused BIT SET  (data:" + String.format("0x%02X", data) + ")");
+                bError = true; break;
+            }
+
+            if ((data & BIT0) != 0x00) {
+                if (Reply.length != (int)(1+16)) {
+                    Log.w(TAG, "[Send_GetSmartKeyRegister] Reply.length  fail #2... (length:" + Reply.length + ")");
+                    bError = true; break;
+                }
+            }
+
+            RegResult = (byte)((data >> 2) & (byte)(BIT0|BIT1));
+            switch (RegResult) {
+                case 0x00: case 0x01: case 0x02: break;
+                default:
+                    Log.w(TAG, "[Send_GetSmartKeyRegister] RegResult  Out Of Range !!!(RegResult:" + String.format("0x%02X", RegResult) + ")");
+                    bError = true; break;
+            }
+            break;
+        }
+
+        if (bError) {
+            AddDoCount(false);
+            DeviceLog("[Send_GetSmartKeyRegister] FAIL");
+            return null;
+        }
+        AddDoCount(true);
+
+
+        // 5. 데이터 확인
+        index = 0;
+        GetRegisterDataList getRegisterDataList = new GetRegisterDataList();
+
+        data = Reply[index++];
+
+        //     D1 : BIT0 - 등록데이터 준재여부
+        if ((byte)(data & BIT0) != 0x00) {
+            getRegisterDataList.Encryption = new EncryptionList();
+            getRegisterDataList.Encryption.Input(Reply, 1);
+        }
+
+        //          BIT1 - 종료 여부
+        if ((byte)(data & BIT1) != 0x00) {
+            getRegisterDataList.Exit = true;
+        }
+
+        //          BIT2 ~ BIT3 - 등록 결과
+        getRegisterDataList.RegResult  = RegResult;
+
+        DeviceLog("[Send_GetSmartKeyRegister] END");
+        return getRegisterDataList;
+    }
+
+    /**
+     * 등록모드 종료 요청
+     *
+     * @return (int) 진입결과 - >=0 : 성공(0:미진입 , 1:진입) , <0 : 실패
+     */
+    private int Send_SetSmartKeyRegisterEnd() {
+        DeviceLog("[Send_SetSmartKeyRegisterEnd] Start");
+
+        // 1. In 파라미터 확인
+
+        // 2. 패킷 데이터 만들기
+        byte [] ReqData = null;
+
+        // 3. 데이터 전송 및 응답
+        byte [] Reply = SendNRead_Variable( (byte)(DEVICE_ADDRESS), CMDList.Req.SetSmartKeyRegisterEnd, ReqData);
+
+        // 4. 수신데이터 파싱
+        boolean bError = false;
+
+        while (true) {
+            //     null Check
+            if (Reply == null) {
+                DeviceLog("[Send_SetSmartKeyRegisterEnd] Reply is null");
+                bError = true; break;
+            }
+
+            //     Length Check
+            if (Reply.length != 1) {
+                Log.w(TAG, "[Send_SetSmartKeyRegisterEnd] Reply.length  fail ... (length:" + Reply.length + ")");
+                bError = true; break;
+            }
+
+            byte data = 0x00;
+            int index = 0;
+
+            //     D1 : 등록모드 시작 상태값
+            data = Reply[index++];
+            if ((data & (byte)(BIT1 | BIT2 | BIT3 | BIT4 | BIT5 | BIT6)) != 0x00) {
+                Log.w(TAG, "[Send_SetSmartKeyRegisterEnd] D1 : Unused BIT SET  (data:" + String.format("0x%02X", data) + ")");
+                bError = true; break;
+            }
+
+            break;
+        }
+
+        if (bError) {
+            AddDoCount(false);
+            DeviceLog("[Send_SetSmartKeyRegisterEnd] FAIL");
+            return -1;
+        }
+        AddDoCount(true);
+
+
+        // 5. 데이터 확인
+        if ((byte)(Reply[0] & BIT7) != 0x00) {
+            Log.w(TAG, "[Send_SetSmartKeyRegisterEnd] D1 : Error Bit Set !!!");
+            return -10;
+        }
+
+        if ((byte)(Reply[0] & BIT0) != 0x00) {
+            // 종료 성공
+            DeviceLog("[Send_SetSmartKeyRegisterEnd] END");
+            return 1;
+        }
+
+        // 종료 실패
+        DeviceLog("[Send_SetSmartKeyRegisterEnd] END");
+        return 0;
+    }
+
+    /**
+     * 센서 감도/시간 설정 보내기
+     *
+     * @return (int)  >0 : 성공, <0 : 실패
+     */
+    private int Send_SetSensorConfig(byte Sensivity, byte Time) {
+        DeviceLog("[Send_SetSensorConfig] Start");
+
+        // 1. In 파라미터 확인
+        if ((Sensivity < 1 || Sensivity > 5)) {
+            if ((Sensivity == (byte)0xFF)) {
+
+            }
+            else {
+                Log.e(TAG, "[SetSensorConfig] - Sensing Range ERROR : " + Sensivity);
+                return -1;
+            }
+        }
+
+        if ((getInt(Time) < 1 || getInt(Time) > 250)) {
+            if ((Time == (byte)0xFF)) {
+
+            }
+            else {
+                Log.e(TAG, "[SetSensorConfig] - Time Range ERROR :" + Time);
+                return -2;
+            }
+        }
+
+        // 2. 패킷 데이터 만들기
+        byte [] ReqData = {Sensivity, Time};
+
+        // 3. 데이터 전송 및 응답
+        byte [] Reply = SendNRead_Variable( (byte)(DEVICE_ADDRESS), CMDList.Req.SetSensorStatus, ReqData);
+
+        // 4. 수신데이터 파싱
+        boolean bError = false;
+
+        //     null Check
+        if (Reply == null) {
+            DeviceLog("[Send_SetSensorConfig] Reply is null");
+            bError = true;
+        }
+
+        //     Length Check
+        if (Reply != null && Reply.length != 2) {
+            DeviceLog("[Send_SetSensorConfig] Reply.length  fail ... (length:" + Reply.length + ")");
+            bError = true;
+        }
+
+		if (bError) {
+			AddDoCount(false);
+            DeviceLog("[Send_SetSensorConfig] FAIL");
+			return -3;
+		}
+		AddDoCount(true);
+
+        byte data = 0x00;
+
+        /*for(int i = 0; i < 2; i++)
+        {
+            Log.i(TAG, "SmartDcam Reply[" + i + "] = " + Reply[i]);
+        }*/
+
+        //     D1 : 센서 감도
+        data = Reply[0];
+        if (data < 1 || data > 5) {
+            if ((data == (byte)0xFF)) {
+
+            }
+            else {
+                Log.w(TAG, "[Send_SetSensorConfig] D1 : Range Error  (data:" + String.format("0x%02X", data) + ")");
+            }
+        }
+        else {
+            // D1 정상 수신
+            //Log.d(TAG, "[Send_SetSensorConfig] D1 Accepted ~");
+            mDriver.Sensor_Value.Sensor_Sensitivity = data;
+        }
+
+        data = Reply[1];
+        if (data < 1 || data > 250) {
+            if ((data == (byte)0xFF)) {
+
+            }
+            else {
+                Log.w(TAG, "[Send_SetSensorConfig] D2 : Range Error  (data:" + String.format("0x%02X", data) + ")");
+            }
+        }
+        else {
+            // D2 정상 수신
+            //Log.d(TAG, "[Send_SetSensorConfig] D2 Accepted ~");
+			mDriver.Sensor_Value.Sensor_DetectTime = data;
+        }
+
+        CompareStatus_Sensivity_DetectTime();
+
+        DeviceLog("[Send_SetSensorConfig] END");
+        return 0;
+    }
+
+    private void CompareStatus_Sensivity_DetectTime() {
+        if (mDriver.Sensor_Value == null) { return;}
+
+        int sensitivity = -1;
+        int dura = -1;
+
+        if (mDriver.Sensor_Value.Sensor_Sensitivity > 0) {
+            // DB 저장
+            try {
+                WallpadStatusData wsd = new WallpadStatusData(ServiceMain.svcContext);
+                sensitivity = wsd.GetSmartDoorCamSensorSensitivity();
+
+                if (sensitivity != mDriver.Sensor_Value.Sensor_Sensitivity) {
+                    wsd.SetSmartDoorSensorSensitivity(mDriver.Sensor_Value.Sensor_Sensitivity);
+                }
+                wsd.closeDB();
+            } catch (RuntimeException re) {
+                LogUtil.errorLogInfo("", TAG, re);
+            } catch (Exception e) {
+                LogUtil.errorLogInfo("", TAG, e);//
+            }
+        }
+
+        if (mDriver.Sensor_Value.Sensor_DetectTime > 0) {
+            // DB 저장
+            try {
+                WallpadStatusData wsd = new WallpadStatusData(ServiceMain.svcContext);
+                dura = wsd.GetSmartDoorCamSensorDuration();
+
+                if (dura != mDriver.Sensor_Value.Sensor_DetectTime) {
+                    wsd.SetSmartDoorSensorDuration(mDriver.Sensor_Value.Sensor_DetectTime);
+                }
+                wsd.closeDB();
+            } catch (RuntimeException re) {
+                LogUtil.errorLogInfo("", TAG, re);
+            } catch (Exception e) {
+                LogUtil.errorLogInfo("", TAG, e);//e.printStackTrace();
+            }
+        }
+    }
+
+
+    /**
+     * LED 제어 기능이 있는 현관카메라의 LED 모드를 제어한다.
+     * @param mode 범위(0~6, FF)
+     * @return (- : 에러), (0 : 실패) , (1 : 성공), (2 : 모드값 설정안됨)
+     */
+    private int Send_SetLedMode(byte mode) {
+        DeviceLog("[Send_SetLedMode] Start");
+
+        if (mode < 0 || mode > 6) {
+            if (mode == (byte)0xFF) {
+                //Log.i(TAG, "[Send_SetLedMode] 0xFF : Get Value");
+            }
+            else {
+                Log.w(TAG, "[Send_SetLedMode] mode range error");
+                return -1;
+            }
+        }
+
+        // 2. 패킷 데이터 만들기
+        byte [] ReqData = {mode};
+
+        // 3. 데이터 전송 및 응답
+        byte [] Reply = SendNRead_Variable( (DEVICE_ADDRESS), CMDList.Req.SetLedMode, ReqData);
+
+        // 4. 수신데이터 파싱
+        boolean bError = false;
+
+        //     null Check
+        if (Reply == null) {
+            DeviceLog("[Send_SetLedMode] Reply is null");
+            bError = true;
+        }
+
+        //     Length Check
+        if (Reply != null && Reply.length != 2) {
+            DeviceLog("[Send_SetLedMode] Reply.length  fail ... (length:" + Reply.length + ")");
+            bError = true;
+        }
+
+        if (bError) {
+            //Log.w(TAG,"[Send_SetLedMode] bError fail");
+            DeviceLog("[Send_SetLedMode] FAIL");
+            AddDoCount(false);
+            return -100;
+        }
+        AddDoCount(true);
+
+        // 동작 성공 여부 확인
+        // 스마트현관카메라 버그 : LED 제어명령에 대해 D1을 00(실패)로 무조건 응답함 -> 주석처리 : 2019.06.17
+        /*if(Reply[0] == 0)
+        {
+            Log.w(TAG, "[Send_SetLedMode] Device Act Fail !!!");
+            return 0;
+        }
+        else if(Reply[0] == 1)*/
+        {
+            //Log.d(TAG, "[Send_SetLedMode] Device Act Run ~~~");
+
+			if (Reply[1] == mode || mode == (byte)0xFF) {
+				//Log.d(TAG, "[Send_SetLedMode] Device Act Success ~~~");
+				//Log.d(TAG, "[Send_SetLedMode] Device LED mode Same : " + Reply[1]);
+				mDriver.Sensor_Value.Sensor_LedMode = Reply[1];
+				StatusChanged();
+
+                DeviceLog("[Send_SetLedMode] END");
+				return 1;
+			}
+			else {
+				//Log.d(TAG, "[Send_SetLedMode] Device LED mode Diff : " + Reply[1]);
+                DeviceLog("[Send_SetLedMode] END");
+				return 2;
+			}
+        }
+
+        //return 0;
+    }
+
+    /**
+     * RSSI 제어 기능이 있는 현관카메라의 RSSI 모드, 단계를 제어한다.
+     * @param mode 범위(0~2 , FF)
+     * @return (- : 에러), (0 : 실패) , (1 : 성공), (2 : 모드값 설정안됨)
+     */
+    private int Send_SetRSSIMode(byte mode, byte level) {
+        DeviceLog("[Send_SetRSSIMode] Start");
+
+        if (mode < (byte)0 || mode > (byte)2) {
+            Log.w(TAG, "[Send_SetRSSIMode] mode range error");
+        	return -1;
+        }
+
+        if (level < (byte)-100 || level > (byte)100) {
+			if (mode == (byte)0xFF) {
+                DeviceLog("[Send_SetRSSIMode] 0xFF : Get Value");
+            }
+			else {
+                DeviceLog("[Send_SetRSSIMode] level range error");
+				return -2;
+			}
+        }
+
+        // 2. 패킷 데이터 만들기
+        byte [] ReqData = {mode, level};
+
+        // 3. 데이터 전송 및 응답
+        byte [] Reply = SendNRead_Variable(DEVICE_ADDRESS, CMDList.Req.SetRssiMode, ReqData);
+
+        // 4. 수신데이터 파싱
+        boolean bError = false;
+
+        //     null Check
+        if (Reply == null) {
+            DeviceLog("[Send_SetRSSIMode] Reply is null");
+            bError = true;
+        }
+
+        //     Length Check
+        if (Reply != null && Reply.length != 2) {
+            DeviceLog("[Send_SetRSSIMode] Reply.length  fail ... (length:" + Reply.length + ")");
+            bError = true;
+        }
+
+        if (bError) {
+            //Log.w(TAG, "[Send_SetRSSIMode] bError fail");
+            AddDoCount(false);
+            DeviceLog("[Send_SetRSSIMode] FAIL");
+            return -100;
+        }
+        AddDoCount(true);
+
+        // 동작 성공 여부 확인
+        if (Reply[0] == 0) {
+            Log.w(TAG, "[Send_SetRSSIMode] Device Act Fail !!!");
+            return 0;
+        }
+        else if (Reply[0] == 1) {
+            //Log.d(TAG, "[Send_SetRSSIMode] Device Act Run ~~~");
+
+            if (Reply[1] == level || level == (byte)0xFF) {
+                // 변경한 단계와 동일하거나, 현재상태값을 요청이 성공한 경우
+                //Log.d(TAG, "[Send_SetRSSIMode] Device Act Success ~~~");
+                //Log.d(TAG, "[Send_SetRSSIMode] Device RSSI level Same : " + Reply[1]);
+
+                if (mode == 1) {
+                    // 읽기 모드
+					mDriver.Sensor_Value.Sensor_RSSI_Read = Reply[1];
+				}
+                else if (mode == 2) {
+                    // 쓰기 모드
+					mDriver.Sensor_Value.Sensor_RSSI_Write = Reply[1];
+				}
+                StatusChanged();
+
+                DeviceLog("[Send_SetRSSIMode] END");
+                return 1;
+            }
+            else {
+                //Log.d(TAG, "[Send_SetRSSIMode] Device RSSI level Diff : " + Reply[1]);
+                DeviceLog("[Send_SetRSSIMode] END");
+                return 2;
+            }
+        }
+
+        return 0;
+    }
+
+    /**
+     *  판별 감지빈도 제어 기능이 있는 현관카메라의 빈도(%)를 제어한다.
+     * @param level 범위(0~4, FF)
+     * @return (- : 에러), (0 : 실패) , (1 : 성공), (2 : 모드값 설정안됨)
+     */
+    private int Send_SetDetectRatio(byte level) {
+        DeviceLog("[Send_SetDetectRatio] Start");
+        //Log.i(TAG, "[Send_SetDetectRatio] Start");
+
+        if (level < (byte)0 || level > (byte)100) {
+            if (level == (byte)0xFF) {
+                //Log.i(TAG, "[Send_SetDetectRatio] 0xFF : Get Value");
+            }
+            else {
+                Log.w(TAG, "[Send_SetDetectRatio] level range error");
+                return -1;
+            }
+        }
+        // 2. 패킷 데이터 만들기
+        byte [] ReqData = {level };
+
+        // 3. 데이터 전송 및 응답
+        byte [] Reply = SendNRead_Variable( (DEVICE_ADDRESS), CMDList.Req.SetDetectRatio, ReqData);
+
+        // 4. 수신데이터 파싱
+        boolean bError = false;
+
+        //     null Check
+        if (Reply == null) {
+            DeviceLog("[Send_SetDetectRatio] Reply is null");
+            bError = true;
+        }
+
+        //     Length Check
+        if (Reply != null && Reply.length != 2) {
+            DeviceLog("[Send_SetDetectRatio] Reply.length  fail ... (length:" + Reply.length + ")");
+            bError = true;
+        }
+
+        if (bError) {
+            AddDoCount(false);
+            DeviceLog("[Send_SetDetectRatio] FAIL");
+            return -100;
+        }
+        AddDoCount(true);
+
+        // 동작 성공 여부 확인
+        if (Reply[0] == 0) {
+            Log.w(TAG, "[Send_SetDetectRatio] Device Act Fail !!!");
+            return 0;
+        }
+        else if (Reply[0] == 1) {
+            //Log.d(TAG, "[Send_SetDetectRatio] Device Act Run ~~~");
+			if (Reply[1] == level || level == (byte)0xFF) {
+				//Log.d(TAG, "[Send_SetDetectRatio] Device Act Success ~~~");
+				//Log.d(TAG, "[Send_SetDetectRatio] Device DetectRatio level Same : " + Reply[1]);
+				mDriver.Sensor_Value.Sensor_DetectRatio = Reply[1];
+				StatusChanged();
+
+                DeviceLog("[Send_SetDetectRatio] END");
+				return 1;
+			}
+			else {
+				//Log.d(TAG, "[Send_SetDetectRatio] Device DetectRatio level Diff : " + Reply[1]);.
+                DeviceLog("[Send_SetDetectRatio] END");
+				return 2;
+			}
+        }
+
+        return 0;
+    }
+
+    /**
+     *  카메라 상태 제어 기능이 있는 현관카메라의 카메라모드를 제어한다.
+     * @param mode 범위(0~3, FF)
+     * @return (- : 에러), (0 : 실패) , (1 : 성공), (2 : 모드값 설정안됨)
+     */
+    private int Send_SetCameraMode(byte mode) {
+        DeviceLog("[Send_SetCameraMode] Start");
+
+        if (mode < (byte)0 || mode > (byte)3) {
+            if (mode == (byte)0xFF) {
+                //Log.i(TAG, "[Send_SetCameraMode] 0xFF : Get Value");
+            }
+            else {
+                Log.w(TAG, "[Send_SetCameraMode] mode range error");
+                return -1;
+            }
+        }
+
+        // 2. 패킷 데이터 만들기
+        byte [] ReqData = {mode };
+
+        // 3. 데이터 전송 및 응답
+        byte [] Reply = SendNRead_Variable( (DEVICE_ADDRESS), CMDList.Req.SetCameraMode, ReqData);
+
+        // 4. 수신데이터 파싱
+        boolean bError = false;
+
+        //     null Check
+        if (Reply == null) {
+            DeviceLog("[Send_SetCameraMode] Reply is null");
+            bError = true;
+        }
+
+        //     Length Check
+        if (Reply != null && Reply.length != 2) {
+            DeviceLog("[Send_SetCameraMode] Reply.length  fail ... (length:" + Reply.length + ")");
+            bError = true;
+        }
+
+        if (bError) {
+            //Log.w(TAG, "[Send_SetCameraMode] bError fail");
+            AddDoCount(false);
+            DeviceLog("[Send_SetCameraMode] FAIL");
+            return -100;
+        }
+        AddDoCount(true);
+
+        // 동작 성공 여부 확인
+        if (Reply[0] == (byte)0) {
+            Log.w(TAG, "[Send_SetCameraMode] Device Act Fail !!!");
+            return 0;
+        }
+        else if (Reply[0] == (byte)1) {
+            //Log.d(TAG, "[Send_SetCameraMode] Device Act Run ~~~");
+
+            if (Reply[1] == mode || mode == (byte)0xFF) {
+                //Log.d(TAG, "[Send_SetCameraMode] Device Act Success ~~~");
+                //Log.d(TAG, "[Send_SetCameraMode] Device DetectRatio level Same : " + Reply[1]);
+                mDriver.Sensor_Value.Sensor_CameraMode = Reply[1];
+                StatusChanged();
+
+                DeviceLog("[Send_SetCameraMode] END");
+                return 1;
+            }
+            else {
+                //Log.d(TAG, "[Send_SetCameraMode] Device DetectRatio level Diff : " + Reply[1]);
+                DeviceLog("[Send_SetCameraMode] END");
+                return 2;
+            }
+        }
+
+        return 0;
+    }
+
+
+    /**
+     * 스마트키 삭제
+     *
+     * @return (boolean) false - Error , true - OK
+     */
+    private boolean Send_DeleteKey(SetRegisterDataList setRegisterData) {
+        DeviceLog("[Send_DeleteKey] Start");
+
+        // 1. In 파라미터 확인
+        if (setRegisterData == null) {
+            Log.w(TAG, "[Send_DeleteKey] Param - RegisterData is null !!!");
+            return false;
+        }
+
+        // 2. 패킷 데이터 만들기
+        byte [] ReqData = setRegisterData.getByteArray();
+
+        // 3. 데이터 전송 및 응답
+        byte [] Reply = SendNRead_Variable( (byte)(DEVICE_ADDRESS), CMDList.Req.GetSmartKeyRegister, ReqData);
+
+        // 4. 수신데이터 파싱
+        boolean bError = false;
+        byte data = 0x00;
+        int index = 0;
+
+        byte RegResult = 0;
+        while (true) {
+            //     null Check
+            if (Reply == null) {
+                DeviceLog("[Send_DeleteKey] Reply is null");
+                bError = true; break;
+            }
+
+            //     Length Check
+            if (Reply.length < 1) {
+                Log.w(TAG, "[Send_DeleteKey] Reply.length  fail #1... (length:" + Reply.length + ")");
+                bError = true; break;
+            }
+
+            index = 0;
+
+            //     D1 : 등록모드 상태값
+            data = Reply[index++];
+            if ((data & (byte)(BIT4 | BIT5 | BIT6 | BIT7)) != 0x00) {
+                Log.w(TAG, "[Send_DeleteKey] D1 : Unused BIT SET  (data:" + String.format("0x%02X", data) + ")");
+                bError = true; break;
+            }
+
+            if ((data & BIT0) != 0x00) {
+                if (Reply.length != (int)(1 + 16)) {
+                    Log.w(TAG, "[Send_DeleteKey] Reply.length  fail #2... (length:" + Reply.length + ")");
+                    bError = true; break;
+                }
+            }
+
+            RegResult = (byte)((data >> 2) & (byte)(BIT0|BIT1));
+            switch (RegResult) {
+                case 0x00: case 0x01: case 0x02: break;
+                default:
+                    Log.w(TAG, "[Send_DeleteKey] RegResult  Out Of Range !!!(RegResult:" + String.format("0x%02X", RegResult) + ")");
+                    bError = true; break;
+            }
+            break;
+        }
+
+        if (bError) {
+            AddDoCount(false);
+            DeviceLog("[Send_DeleteKey] FAIL");
+            return false;
+        }
+        AddDoCount(true);
+
+
+        // 5. 데이터 확인
+        if (RegResult == 0) {
+            Log.i(TAG, "[Send_DeleteKey] Delete success");
+            DeviceLog("[Send_DeleteKey] END");
+            return true;
+        }
+        else {
+            Log.i(TAG, "[Send_DeleteKey] Delete Fail -> RegResult:" + String.format("0x%02X", RegResult) + ")");
+            DeviceLog("[Send_DeleteKey] END");
+            return false;
+        }
+    }
+
+
+
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    // CMDList
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+     * 명령어 리스트
+     */
+    public static class CMDList {
+        public static final class Req {
+            /////////////////////////////////////////////////////////
+            // Board
+            /////////////////////////////////////////////////////////
+            /** 기기 정보 요청 */
+            public final static byte GetDeviceInfo              = 0x01;
+
+            /////////////////////////////////////////////////////////
+            // 기본 상태 커맨드
+            /////////////////////////////////////////////////////////
+            /** 기본상태 요청 */
+            public final static byte GetStatus                  = 0x11;
+            /** 기본상태값 해제 요청 */
+            public final static byte SetStatusClr               = 0x12;
+
+            /////////////////////////////////////////////////////////
+            // 스마트 키값 읽기 커맨드
+            /////////////////////////////////////////////////////////
+            /** 스마트 키값 요청 */
+            public final static byte GetSmartKey                = 0x21;
+            /** 스마트 키값 확인 요청 */
+            public final static byte SetSmartKeyVerify          = 0x22;
+
+            /////////////////////////////////////////////////////////
+            // 스마트키 등록 커맨드
+            /////////////////////////////////////////////////////////
+            /** 등록모드 시작 요청 */
+            public final static byte SetSmartKeyRegisterStart   = 0x31;
+            /** 등록 스마트 키값 요청 */
+            public final static byte GetSmartKeyRegister        = 0x32;
+            /** 등록모드 종료 요청 */
+            public final static byte SetSmartKeyRegisterEnd     = 0x33;
+
+            /////////////////////////////////////////////////////////
+            // 센서 관련 커맨드
+            /////////////////////////////////////////////////////////
+            /** 센서상태 요청 및 제어 */
+            public final static byte SetSensorStatus            = 0x41;
+            /** LED 모드 제어 */
+            public final static byte SetLedMode                 = 0x42;
+            /** RSSI 모드 제어 */
+            public final static byte SetRssiMode                = 0x43;
+            /** 판별감도 제어 */
+            public final static byte SetDetectRatio             = 0x44;
+            /** 카메라 상태 제어 */
+            public final static byte SetCameraMode              = 0x45;
+        }
+    }
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    // UpdateVariables
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+     * [현관콜 , 에러]를 업데이트 한다.
+     *
+     * @param Status - (StatusList) 업데이트할 기본상태 응답 클래스
+     *
+     * @return (boolean) 데이터 변경여부 (true:변경 , false:미변경)
+     */
+    private boolean UpdateVariables(StatusList Status) {
+        DeviceLog("[UpdateVariables] (Status) Start");
+        if (Status == null) {
+            return false;
+        }
+
+        boolean bChanged = false;
+
+        // 1. 현관콜
+        if (mDriver.Status.bDoorBtnStatus != Status.bDoorBtnStatus) {
+            if ((!mDriver.Status.bDoorBtnStatus) && (Status.bDoorBtnStatus)) {
+                if (GetDoorStdOpenMode()) {
+                    SetDoorStdOpenMode(false);
+
+                    Log.i(TAG, "*****************************");
+                    Log.i(TAG, "*   DLOCK_STANDBYOPEN(RF)   *");
+                    Log.i(TAG, "*****************************");
+
+                    int ret = -1;
+
+                    // 도어락 열기
+                    if (Version.getGatewayUsage()) {
+                        if (ServiceMain.dataBaseLoader.data.wallpadDeviceSet.Get_DoorLock_Info[1] == WallpadDeviceSet.DOORLOCK_TYPE_FINGERPRINT) {
+                            ret = driverInterOpAPI.FPdLock_SetDoorOpen();
+                            Log.i(TAG, "[UpdateVariables] FPdLock_SetDoorOpen - ret : " + ret);
+                        }
+                        else {
+                            ret = driverInterOpAPI.IGW_SetWddrCont(true);
+                            Log.i(TAG, "[UpdateVariables] IGW_SetWddrCont - ret : " + ret);
+                        }
+                        // 현산향 모델에도 무선도어락이 적용되기에
+                        // 도어락을 터치해서 문을 열 수 없다.
+                        WallPadInterface devioctr = new WallPadInterface();
+                        TurnOnDcamPower(devioctr); //현재 통화 상태에서는 동작 X
+                    }
+                    else {
+                        WallPadInterface devioctr = new WallPadInterface();
+                        devioctr.DoorLockControl(true);
+                        TurnOnDcamPower(devioctr); // 현재 통화 상태에서는 동작 X
+                        ret = 1;
+                    }
+
+                    if (ret >= 0) {
+                        // 출입 데이터 기록 (스마트키에 의한 문열림)
+                        WallpadAccessData WpadAccessData = new WallpadAccessData(ServiceMain.svcContext);
+                        String sn = SmartKeyRfDoor_Controller.GetCheckSmartKeySn();
+                        ret = WpadAccessData.Insert(WallpadAccessData.KIND.SMART_KEY, sn);
+                        WpadAccessData.closeDB();
+                        Log.d(TAG, "WpadAccessData.Insert(SMART_KEY) - ret:" + ret);
+
+
+                        // 최근사용일자 갱신
+                        WallpadSmartKeyRegData WpadSmartKeyRegData = new WallpadSmartKeyRegData(ServiceMain.svcContext);
+                        byte no = SmartKeyRfDoor_Controller.GetCheckSmartKeyNo();
+                        ret = WpadSmartKeyRegData.UpdateLastUseDate(no);
+                        Log.d(TAG, "WpadAccessData.UpdateLastUseDate(" + no + ") - ret:" + ret);
+                        WpadSmartKeyRegData.closeDB();
+                    }
+                }
+                else {
+                    if (CallAppEnable) {
+                        // 현관콜 시작
+                        Log.i(TAG, "============================================");
+                        Log.i(TAG, "                 DOOR CALL");
+                        Log.i(TAG, "============================================");
+
+                        setSendEventBR(WallPadInterface.BTN_DOOR);
+                    }
+                    else {
+                        Log.w(TAG, "CallAppEnable FALSE -> DoorLock Opening, Wait until Turn off the Dcam Light");
+                    }
+                }
+            }
+            mDriver.Status.bDoorBtnStatus = Status.bDoorBtnStatus;
+        }
+
+        // 2. 거동수상자 감지
+        boolean sensorClear = false;
+        if (mDriver.Status.bSensorDetect != Status.bSensorDetect) {
+            Log.i(TAG, "[UpdateVariables] - Wpad sensor data : " + mDriver.Status.bSensorDetect);
+            Log.i(TAG, "[UpdateVariables] - new receive sensor data : " + Status.bSensorDetect);
+            // (월패드 : 감지안됨) && (스마트현관 : 감지됨) 인 경우에만 동작 : 거동수상자 발생
+            if ((!mDriver.Status.bSensorDetect) && (Status.bSensorDetect)) {
+                Log.i(TAG, "[UpdateVariables] - Sensor Detect Occur !!!");
+
+                Intent mIntent = new Intent();
+                mIntent.setAction(define.NOTIFY_ACNAME);
+                mIntent.putExtra(define.NOTIBR_KIND, define.NOTIFY_SMART_DCAM_DETECT);
+                ServiceMain.svcContext.sendBroadcast(mIntent);
+
+                sensorClear = true;
+
+                Log.i(TAG, "============================================");
+                Log.i(TAG, "               STRANGE DETECT !");
+                Log.i(TAG, "============================================");
+            }
+            // (월패드 : 감지됨) && (스마트현관 : 감지안됨) 인 경우에만 동작 : 거동수상자 해소
+            else if ((mDriver.Status.bSensorDetect) && (!Status.bSensorDetect)) {
+                Log.i(TAG, "[UpdateVariables] - Sensor Detect Release !!!");
+
+                Intent mIntent = new Intent();
+                mIntent.setAction(define.NOTIFY_ACNAME);
+                mIntent.putExtra(define.NOTIBR_KIND, define.NOTIFY_SMART_DCAM_RELEASE);
+                ServiceMain.svcContext.sendBroadcast(mIntent);
+
+                Log.i(TAG, "============================================");
+                Log.i(TAG, "               STRANGE RELEASE~~");
+                Log.i(TAG, "============================================");
+            }
+
+            mDriver.Status.bSensorDetect = Status.bSensorDetect;
+        }
+
+        // 3. LED 상태
+        if (mDriver.Status.bLedStatus != Status.bLedStatus) {
+            Log.i(TAG, "[UpdateVariables] - past Wpad LedStatus data : " + mDriver.Status.bLedStatus);
+            Log.i(TAG, "[UpdateVariables] - new receive LedStatus data : " + Status.bLedStatus);
+            mDriver.Status.bLedStatus = Status.bLedStatus;
+        }
+
+        // 4. 카메라 상태
+        if (mDriver.Status.bCameraStatus != Status.bCameraStatus) {
+            Log.i(TAG, "[UpdateVariables] - past Wpad CameraStatus data : " + mDriver.Status.bCameraStatus);
+            Log.i(TAG, "[UpdateVariables] - new receive CameraStatus data : " + Status.bCameraStatus);
+            mDriver.Status.bCameraStatus = Status.bCameraStatus;
+        }
+
+        // 5. LED Auto 상태
+        if (mDriver.Status.bLedAuto != Status.bLedAuto) {
+            Log.i(TAG, "[UpdateVariables] - past Wpad LedAuto data : " + mDriver.Status.bLedAuto);
+            Log.i(TAG, "[UpdateVariables] - new receive LedAuto data : " + Status.bLedAuto);
+            mDriver.Status.bLedAuto = Status.bLedAuto;
+        }
+
+        // 6. 카메라 Auto 상태
+        if (mDriver.Status.bCameraAuto != Status.bCameraAuto) {
+            Log.i(TAG, "[UpdateVariables] - past Wpad CameraAuto data : " + mDriver.Status.bCameraAuto);
+            Log.i(TAG, "[UpdateVariables] - new receive CameraAuto data : " + Status.bCameraAuto);
+            mDriver.Status.bCameraAuto = Status.bCameraAuto;
+        }
+
+        // 7. 에러
+        if (mDriver.Status.bError != Status.bError) {
+            if ((!mDriver.Status.bError) && (Status.bError)) {
+                Log.i(TAG, "UpdateVariables - ERROR Detection !!!");
+            }
+            else if ((mDriver.Status.bError) && (!Status.bError)) {
+                Log.i(TAG, "UpdateVariables - ERROR Clear !!!");
+            }
+            mDriver.Status.bError = Status.bError;
+        }
+
+        // 3. 상태 클리어
+        if (Status.bDoorBtnStatus || Status.bError || sensorClear) {
+            Send_SetStatusClr(Status);
+            bChanged = true;
+        }
+
+        DeviceLog("[UpdateVariables] (Status) End");
+        return bChanged;
+    }
+
+    private int[] DoorLock_OpenDelayTime = { 3, 4, 5 };
+    private boolean ismDoorOpenDelay = false;
+
+    /**
+     * 자동문 대기 모드 신호가 자주오는것을 방지 하기 위해 막음
+     */
+    Handler openDelayHandler = new Handler() {
+        @Override
+        public void handleMessage(Message msg) {
+            ismDoorOpenDelay = false;
+        }
+    };
+
+
+    /**
+     * 스마트키값이 등록된 키값인지 비교한다.
+     *
+     * @param KeyData - (KeyDataList) 인식된 스마트키값 클래스
+     *
+     * @return (boolean) 데이터 변경여부 (true:변경 , false:미변경)
+     */
+    private boolean UpdateVariables(KeyDataList KeyData) {
+        if (KeyData == null) return false;
+        if (KeyData.Count <= 0) return false;
+        if (KeyData.Encryption == null) return false;
+
+        boolean FindKey = false;
+        for (byte i=0; i < KeyData.Count; i++) {
+            if (KeyData.Encryption[i] != null) {
+                FindKey = CheckSmartKey(KeyData.Encryption[i].Data);
+                if (FindKey) {
+                    break;
+                }
+            }
+        }
+
+        if (FindKey) {
+            // 등록된키값 인식
+            // 도어락 문열림대기모드 시작
+            Log.i(TAG, "[UpdateVariables] FindKey !!!");
+
+            int ret = -1;
+            if (mDoorLockType == WallpadDeviceSet.DOORLOCK_TYPE_NORMAL) {
+                Log.i(TAG, "[UpdateVariables] mDoorLockType 1 : " + mDoorLockType);
+                ret = driverInterOpAPI.DLock_SetDoorOpenStandbyMode(true, DLOCK_STANDBYMODE_SEC);
+                Log.i(TAG, "[UpdateVariables] DLock_SetDoorOpenStandbyMode - ret : " + ret);
+            }
+            else if (mDoorLockType == WallpadDeviceSet.DOORLOCK_TYPE_RF) {
+                Log.i(TAG, "[UpdateVariables] mDoorLockType 2 : " + mDoorLockType);
+                if (mDoorOpenDelay) {
+                    WallpadStatusData statusData = new WallpadStatusData(ServiceMain.svcContext);
+                    int openDelayTime = statusData.Get_DoorOpen_WaitTime();
+                    statusData.closeDB();
+                    Log.i(TAG, "[UpdateVariables] openDelayTime [" + openDelayTime + "]");
+                    // 문열림 대기모드 동작 신 시나리오 (무선 도어락 터치 시 문열림)
+                    ret = driverInterOpAPI.IGW_SetWddrOpenDelayCont(openDelayTime);
+                    Log.i(TAG, "[UpdateVariables] IGW200D_SetWddrOpenDelayCont - ret : " + ret);
+
+                    if (openDelayTime == 5) openDelayTime = DoorLock_OpenDelayTime[1];
+                    else if (openDelayTime == 10) openDelayTime = DoorLock_OpenDelayTime[2];
+                    Log.i(TAG, "[UpdateVariables] openDelayTime [" + openDelayTime + "]");
+
+                    // DB에서 문열림 대기모드 설정값을 가져와서 JNI를 통해 신호를 전달한다.
+                    // param nValue 0: 등록, 1: 문열림, 2: 문열림 대기 미설정, 3: 문열림 대기 3초, 4: 문열림 대기 5초, 5: 문열림 대기 10초
+                    // 문열림 대기모드이므로, 3(3초)/4(5초)/5(10초) 중 하나를 전달한다.
+                    if (openDelayTime >= 3 && openDelayTime <= 5) {
+                        WallPadInterface mWallPadInterface = new WallPadInterface();
+                        if(!ismDoorOpenDelay) {
+                            mWallPadInterface.ctrlDoorlockOpenStandbyMode(openDelayTime);
+                            ismDoorOpenDelay = true;
+                            Message msg = openDelayHandler.obtainMessage();
+                            int delay_time = openDelayTime;
+                            if(openDelayTime == 4)
+                            {
+                                delay_time = 5;
+                            }
+                            else if(openDelayTime == 5)
+                            {
+                                delay_time = 10;
+                            }
+                            int time = delay_time*1000 * 2;
+                            openDelayHandler.sendMessageDelayed(msg, time);
+                        }
+                    }
+                }
+                else {
+                    // 문열림 대기모드 동작 구 시나리오 (현관카메라 버튼 누를 시 문열림)
+                    SetDoorStdOpenMode(true);
+                }
+                Log.i(TAG, "[UpdateVariables] SetDoorStdOpenMode(ON) 1");
+            }
+            else if (mDoorLockType == WallpadDeviceSet.DOORLOCK_TYPE_FINGERPRINT) {
+                Log.i(TAG, "[UpdateVariables] mDoorLockType 3 : " + mDoorLockType);
+                SetDoorStdOpenMode(true);
+                Log.i(TAG, "[UpdateVariables] SetDoorStdOpenMode(ON) 2");
+            }
+
+            WallpadStatusData wallpadStatusData = new WallpadStatusData(ServiceMain.svcContext);
+            boolean SmartKeyDetectionAlarm = wallpadStatusData.GetSmartKeyDetectionAlarm();
+            wallpadStatusData.closeDB();
+            if (SmartKeyDetectionAlarm) {
+                // DB 저장 (스마트키감지)
+                WallpadAccessData WpadAccessData = new WallpadAccessData(ServiceMain.svcContext);
+                WpadAccessData.setMaxCount(1000);
+                ret = WpadAccessData.Insert(WallpadAccessData.KIND.SMART_KEY_DETECTION, CheckSmartKeySn);
+                WpadAccessData.closeDB();
+                Log.d(TAG, "[UpdateVariables] WpadAccessData.Insert(SMART_KEY_DETECTION) - ret:" + ret);
+
+                // 사운드 알람
+                WpadSound Sound = new WpadSound(ServiceMain.svcContext);
+                Sound.PlayMent(WpadSound.SND.effect.EFFECT1);
+
+                // LCD 를 Normal 상태로 변경하는 기능 추가
+                //PowerManager pm = (PowerManager) (ServiceMain.svcContext).getSystemService(Context.POWER_SERVICE);
+                //pm.userActivity(1, true);
+
+                // 인텐트를 전송하여 제어 UI 혹은 스마트키등록 화면에서 flag를 세우도록 설정하기
+                //getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+
+                // Toast 메시지 표시
+                Toast.makeText(ServiceMain.svcContext,
+                        "SmartKey Detection : [" + CheckSmartKeySn + "]",
+                        Toast.LENGTH_SHORT).show();
+            }
+
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * 등록모드 시작버튼 체크
+     *
+     * @param RegisterModeStart - (int) 체크할 시작버튼 상태 (1:감지)
+     */
+    private void UpdateVariables(int RegisterModeStart) {
+        if (RegisterModeStart == 1) {
+            Log.i(TAG, "UpdateVariables - Start Button DETECTION !!!");
+
+            if (!mDriver.RegisterInitMode) {
+                int id = DB_GetId();
+                if (id <= 0) {
+                    mDriver.Polling.SetStatus(Driver.PollingList.STATUS.Normal);
+                    Log.w(TAG, "UpdateVariables - DB_GetId  Out Of Range (id:" + id + ")");
+                }
+                else {
+                    mDriver.CardRegNo = (byte)id;
+                    super.StatusChanged( (byte)(STATUS_REGMODE_START | mDriver.CardRegNo));
+                    mDriver.Polling.SetStatus(Driver.PollingList.STATUS.Register);
+                }
+            }
+            else {
+                super.StatusChanged(STATUS_REGMODE_START);
+                mDriver.Polling.SetStatus(Driver.PollingList.STATUS.Register);
+            }
+        }
+    }
+
+    /**
+     *
+     *
+     * @param GetRegisterData
+     */
+    private void UpdateVariables(GetRegisterDataList GetRegisterData) {
+        if (GetRegisterData == null) return;
+
+        // 1. 스마트RF현관카메라 에서 종료
+        if (GetRegisterData.Exit) {
+            mDriver.Polling.SetStatus(Driver.PollingList.STATUS.Normal);
+            Log.i(TAG, "UpdateVariables - END Button DETECTION !!!");
+        }
+
+        // 2. 에러체크
+        if (GetRegisterData.RegResult != 0x00) {
+            switch (GetRegisterData.RegResult) {
+                case 0x01:
+                    // 이미 등록된 키
+                    super.StatusChanged(STATUS_REGMODE_KEY_ALREADY);
+                    Log.i(TAG, "UpdateVariables - STATUS_REGMODE_KEY_ALREADY");
+                    break;
+
+                case 0x02:
+                    // 무선 통신 실패
+                    super.StatusChanged(STATUS_REGMODE_ER_WIRELESSCOMMFAIL);
+                    Log.i(TAG, "UpdateVariables - STATUS_REGMODE_ER_WIRELESSCOMMFAIL");
+                    break;
+            }
+        }
+
+        // 3. 등록 데이터 체크
+        if (!(GetRegisterData.Exit) && (GetRegisterData.RegResult == 0x00)) {
+            if (GetRegisterData.Encryption != null) {
+                if (!mDriver.RegisterInitMode) {
+                    byte Status = 0;
+                    int ret = SaveSmartKey(GetRegisterData.Encryption.Data);
+                    if (ret > 0) {
+                        Status = STATUS_REGMODE_KEY_COMPLETE;
+                        Status |= (byte)ret;
+                    }
+                    else {
+                        Status = STATUS_REGMODE_ER_DBWRITE;
+                    }
+                    super.StatusChanged(Status);
+
+                    mDriver.Polling.SetStatus(Driver.PollingList.STATUS.RegisterPause);
+                    Log.i(TAG, "UpdateVariables - STATUS_REGMODE_KEY_COMPLETE (Status:" + String.format("0x%02X", Status) + ")");
+                }
+                else {
+                    super.StatusChanged(STATUS_REGMODE_KEY_COMPLETE);
+                    mDriver.Polling.SetStatus(Driver.PollingList.STATUS.RegisterPause);
+                }
+            }
+        }
+    }
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    // DB
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    private int DB_GetId() {
+        try {
+            WallpadSmartKeyRegData WpadSmartKeyRegData = new WallpadSmartKeyRegData(ServiceMain.svcContext);
+            int id = WpadSmartKeyRegData.GetEmptyId();
+            WpadSmartKeyRegData.closeDB();
+            return id;
+        } catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+            return -1000;
+        } catch (Exception e) {
+            Log.e(TAG, "[DB_GetId] - [Exception Error] ");
+            LogUtil.errorLogInfo("", TAG, e);//
+            return -1000;
+        }
+    }
+
+    private int DB_Register(byte id, byte[] Uid, byte[] SiteCode, byte[] DongHo) {
+        try {
+            WallpadSmartKeyRegData WpadSmartKeyRegData = new WallpadSmartKeyRegData(ServiceMain.svcContext);
+            int ret = WpadSmartKeyRegData.Register((byte) id, Uid, SiteCode, DongHo);
+            WpadSmartKeyRegData.closeDB();
+            return ret;
+        } catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+            return -1000;
+        } catch (Exception e) {
+            Log.e(TAG, "[DB_Register] - [Exception Error] ");
+            LogUtil.errorLogInfo("", TAG, e);//e.printStackTrace();
+            return -1000;
+        }
+    }
+
+    private String DB_isExist(byte id, byte[] Uid, byte[] SiteCode, byte[] DongHo) {
+        try {
+            WallpadSmartKeyRegData WpadSmartKeyRegData = new WallpadSmartKeyRegData(ServiceMain.svcContext);
+            String sn = WpadSmartKeyRegData.isExist(id, Uid, SiteCode, DongHo);
+            WpadSmartKeyRegData.closeDB();
+            return sn;
+        } catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+            return null;
+        } catch (Exception e) {
+            Log.e(TAG, "[DB_Register] - [Exception Error] ");
+            LogUtil.errorLogInfo("", TAG, e);//e.printStackTrace();
+            return null;
+        }
+    }
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    // Util
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+
+    /**
+     * 스마트키 데이터를 등록데이터와 비교 체크한다.
+     *
+     * @param Input - (byte []) 읽은 스마트키 데이터 배열
+     *
+     * @return (boolean) 결과 - true:있음 , false:아님
+     */
+    private boolean CheckSmartKey(byte [] Input) {
+        boolean DEBUG = false;
+
+        if (DEBUG) Log.d(TAG, "[CheckSmartKey] Start");
+        try {
+            // 1. 복호화 체크
+            byte [] Output = null;
+
+            if (ServiceMain.dataBaseLoader.data.wallpadDeviceSet.Get_BLE_SmartKey == false) {
+                // 기존 스마트키 사용일 경우
+                Output = AES_128.Encrypt(AES_128.ENCRYPTTYPE.SMARTKEY_CAM, Input);
+            }
+            else {
+                // BLE스마트키 사용일 경우
+                Output = AES_128.Decrypt_ECB(AES_128.ENCRYPTTYPE.SMARTKEY_CAM, Input);
+            }
+
+            if (DEBUG) Log.d(TAG, "[CheckSmartKey] Input - " + super.ToByteString(Input));
+            if (DEBUG) Log.d(TAG, "[CheckSmartKey] Output - " + super.ToByteString(Output));
+            if (Output == null) {
+                Log.w(TAG, "[CheckSmartKey] AES_128.Encrypt - Output is null !!!");
+                return false;
+            }
+
+            // 2. 복호화 데이터 길이 체크
+            if (Output.length != 16) {
+                Log.w(TAG, "[CheckSmartKey] Output.length Not Match !!! (length:" + Output.length + ")");
+                return false;
+            }
+
+            // 3. RandomKey 체크
+            if ((Output[0] != mDriver.Polling.RandomKeyBuffer[0]) || (Output[15] != mDriver.Polling.RandomKeyBuffer[1])) {
+                Log.w(TAG, "[CheckSmartKey] RandomKey Data Not Match !!!");
+
+                Log.i(TAG, "[CheckSmartKey] RandomKeyValue " + "1:" + String.format("0x%02X", mDriver.Polling.RandomKeyBuffer[0]) + ", " + "2:" + String.format("0x%02X", mDriver.Polling.RandomKeyBuffer[1]));
+                Log.i(TAG, "[CheckSmartKey] ReadRandomKeyValue " + "1:" + String.format("0x%02X", Output[0]) + ", " + "2:" + String.format("0x%02X", Output[15]));
+                return false;
+            }
+
+            // 4. Uid 암호화 및 그외 데이터 분리
+            byte [] Uid = new byte [] { Output[1], Output[2], Output[3], Output[4] };
+            byte [] EncryptUid = AES_128.Encrypt(AES_128.ENCRYPTTYPE.NORMAL, Uid);
+            if (DEBUG) Log.d(TAG, "[CheckSmartKey] EncryptUid - " + super.ToByteString(EncryptUid));
+            byte [] SiteCode = new byte [] { Output[5], Output[6], Output[7], Output[8] };
+            byte [] DongHo   = new byte [] { Output[9], Output[10], Output[11], Output[12] };
+            byte CardRegNo = Output[13];
+
+            // 5. 존재유무 DB 확인
+            String sn = DB_isExist(CardRegNo, EncryptUid, SiteCode, DongHo);
+            if (sn != null) {
+                CheckSmartKeyNo = CardRegNo;
+                CheckSmartKeySn = sn;
+                if (DEBUG) Log.d(TAG, "[CheckSmartKey] DB_isExist - true");
+
+                return true;
+            }
+            else return false;
+        } catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+            return false;
+        } catch (Exception e) {
+            Log.e(TAG, "[CheckSmartKey] - [Exception Error] ");
+            LogUtil.errorLogInfo("", TAG, e);//e.printStackTrace();
+            return false;
+        }
+    }
+
+    private int SaveSmartKey(byte [] Input) {
+        boolean DEBUG = true;
+
+        if (DEBUG) Log.d(TAG, "[SaveSmartKey] Start");
+        try {
+            if (Input == null) return -1;
+            if (Input.length != 16) return -2;
+
+            // 1. D1 : 0xCA 체크
+            //            if(DEBUG) Log.d(TAG, "[SaveSmartKey] Step1 : D1 Check");
+            //            if(Input[0] != (byte)0xCA)
+            //            {
+            //                Log.w(TAG, "[SaveSmartKey] D1 : Data Not Match !!!");
+            //                return -11;
+            //            }
+
+            boolean bRet = false;
+
+            // 2. SiteCode 체크
+            if (DEBUG) Log.d(TAG, "[SaveSmartKey] Step2 : SiteCode Check");
+            byte [] SiteCode = new byte [] { Input[5], Input[6], Input[7], Input[8] };
+            bRet = CompareByteArray(SiteCode, mDriver.SiteCodeBCD);
+            if (!bRet) {
+                Log.w(TAG, "[SaveSmartKey] SiteCode : Data Not Match !!!");
+                return -12;
+            }
+
+            // 3. DongHo 체크
+            if (DEBUG) Log.d(TAG, "[SaveSmartKey] Step3 : DongHo Check");
+            byte [] DongHo   = new byte [] { Input[9], Input[10], Input[11], Input[12] };
+            bRet = CompareByteArray(DongHo, mDriver.DongHoBCD);
+            if (!bRet) {
+                Log.w(TAG, "[SaveSmartKey] DongHo : Data Not Match !!!");
+                return -13;
+            }
+
+            // 4. Card Reg No. 체크
+            if (DEBUG) Log.d(TAG, "[SaveSmartKey] Step4 : Card Reg No Check");
+            byte CardRegNo = Input[13];
+            if (CardRegNo != mDriver.CardRegNo) {
+                Log.w(TAG, "[SaveSmartKey] CardRegNo : Data Not Match !!!");
+                return -14;
+            }
+
+            // 5. Uid 복호화
+            byte [] Uid = new byte [] { Input[1], Input[2], Input[3], Input[4] };
+            byte [] NormalUid = AES_128.Encrypt(AES_128.ENCRYPTTYPE.NORMAL, Uid);
+            if (DEBUG) {
+                Log.d(TAG, "[SaveSmartKey] Step5 : Uid");
+                Log.d(TAG, "                       Uid       - " + super.ToByteString(Uid));
+                Log.d(TAG, "                       NormalUid - " + super.ToByteString(NormalUid));
+            }
+
+            // 5. DB 저장
+            int ret = DB_Register(CardRegNo, NormalUid, SiteCode, DongHo);
+            if (DEBUG) Log.d(TAG, "[SaveSmartKey] Step6 : DB_Register = " + ret);
+            if (ret >= 0) {
+                return (int) CardRegNo;
+            }
+
+            return ret;
+        } catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+            return -1000;
+        } catch (Exception e) {
+            Log.e(TAG, "[SaveSmartKey] - [Exception Error] ");
+            LogUtil.errorLogInfo("", TAG, e);//e.printStackTrace();
+            return -1000;
+        }
+    }
+
+
+    /**
+     * 현관호출 or 전화호출시 사용되는 keycode - Broadcast 을 송신한다.
+     *
+     * @param code - (int) 송신할 keycode
+     * @return (int) - >=0 : 성공, <0 : 실패
+     */
+    private int setSendEventBR(int code) {
+        try {
+            KeyEvent event = new KeyEvent(KeyEvent.ACTION_UP, code);
+            Intent intent = new Intent("EVENT_DEVICE_CONTROL", null);
+            intent.putExtra(Intent.EXTRA_KEY_EVENT, event);
+            intent.putExtra("keycode",code);
+            ServiceMain.svcContext.sendBroadcast(intent);
+        } catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+            return -100;
+        } catch (Exception e) {
+            Log.e(TAG, "[setSendEventBR] - [Exception Error] code:" + code);
+            Log.e(TAG, "[setSendEventBR] - " + e.toString());
+            LogUtil.errorLogInfo("", TAG, e);//
+            return -100;
+        }
+        return 0;
+    }
+
+    /**
+     * 동호 데이터를 BCD Code 로 가져온다.
+     *
+     * @return (byte []) null - Error , Not null - OK
+     */
+    private byte [] getDongHo_BCD() {
+        try {
+            wallpaddbmgr dbmgr = new wallpaddbmgr(ServiceMain.svcContext);
+            AddressSet addc =  dbmgr.getAddressMGR();
+            dbmgr.closeDB();
+
+            byte [] RetBytes = new byte [] { 0, 0, 0, 0 };
+            byte [] Temp = new byte [] { '0', '0', '0', '0' };
+            int offset = 0;
+            int index = 0;
+
+            // DONG
+            byte [] DongBytes = addc.Dong.getBytes();
+            if(DongBytes == null) return null;
+
+            offset = 0;
+            switch (DongBytes.length) {
+                case 1: offset = 3; break;
+                case 2: offset = 2; break;
+                case 3: offset = 1; break;
+                case 4: offset = 0; break;
+                default:
+                    return null;
+            }
+
+            index = 0;
+            for (int i = offset; i < 4; i++) Temp[i] = DongBytes[index++];
+
+            RetBytes[0]  = (byte)((((Temp[0] - '0') & 0x0F) << 4) & (byte)0xF0);
+            RetBytes[0] |= (byte)((((Temp[1] - '0') & 0x0F) << 0) );
+
+            RetBytes[1]  = (byte)((((Temp[2] - '0') & 0x0F) << 4) & (byte)0xF0);
+            RetBytes[1] |= (byte)((((Temp[3] - '0') & 0x0F) << 0) );
+
+            // HO
+            byte [] HoBytes = null;
+            if (addc.UseOrNotRentHouse == true) {
+                String temp = addc.Ho.substring(0, (addc.Ho.length() - 2));
+                HoBytes = temp.getBytes();
+            }
+            else {
+                HoBytes = addc.Ho.getBytes();
+            }
+
+            if (HoBytes   == null) return null;
+
+            Temp = new byte [] { '0', '0', '0', '0' };
+            offset = 0;
+            switch (HoBytes.length) {
+                case 1: offset = 3; break;
+                case 2: offset = 2; break;
+                case 3: offset = 1; break;
+                case 4: offset = 0; break;
+                default:
+                    return null;
+            }
+
+            index = 0;
+            for (int i = offset; i < 4; i++) Temp[i] = HoBytes[index++];
+
+            RetBytes[2]  = (byte)((((Temp[0] - '0') & 0x0F) << 4) & (byte)0xF0);
+            RetBytes[2] |= (byte)((((Temp[1] - '0') & 0x0F) << 0) );
+
+            RetBytes[3]  = (byte)((((Temp[2] - '0') & 0x0F) << 4) & (byte)0xF0);
+            RetBytes[3] |= (byte)((((Temp[3] - '0') & 0x0F) << 0) );
+
+            return RetBytes;
+        } catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+            return null;
+        } catch (Exception e) {
+            Log.e(TAG, "[getDongHo_BCD] - [Exception Error] ");
+            LogUtil.errorLogInfo("", TAG, e);//
+            return null;
+        }
+    }
+
+    /**
+     * SiteCode 를 String 으로 가져온다.
+     *
+     * @return (String) SiteCode
+     */
+    private String getSiteCode_String() {
+        String[] getData = null;
+        String strSiteCode = null;
+
+        WallpadDeviceSet devset = new WallpadDeviceSet(ServiceMain.svcContext);
+        getData = devset.GetSettingData("site_code");
+        devset.closeDB();
+
+        if ((getData != null) && getData.length > 1) {
+            strSiteCode = getData[1];
+        }
+        return strSiteCode;
+    }
+
+    /**
+     * SiteCode 를 BCD 데이터로 가져온다.
+     *
+     * @return (byte []) null - Error , Not null - OK
+     */
+    private byte [] getSiteCode_BCD() {
+        try {
+            String SiteCodeStr = getSiteCode_String();
+            if (SiteCodeStr == null) return null;
+
+            byte [] RetBytes = new byte [] { 0, 0, 0, 0 };
+            byte [] SiteCodeBytes = SiteCodeStr.getBytes();
+
+            if (SiteCodeBytes == null) return null;
+            if (SiteCodeBytes.length != 8) return null;
+
+            RetBytes[0]  = (byte)((((SiteCodeBytes[0] - '0') & 0x0F) << 4) & (byte)0xF0);
+            RetBytes[0] |= (byte)((((SiteCodeBytes[1] - '0') & 0x0F) << 0) );
+
+            RetBytes[1]  = (byte)((((SiteCodeBytes[2] - '0') & 0x0F) << 4) & (byte)0xF0);
+            RetBytes[1] |= (byte)((((SiteCodeBytes[3] - '0') & 0x0F) << 0) );
+
+            RetBytes[2]  = (byte)((((SiteCodeBytes[4] - '0') & 0x0F) << 4) & (byte)0xF0);
+            RetBytes[2] |= (byte)((((SiteCodeBytes[5] - '0') & 0x0F) << 0) );
+
+            RetBytes[3]  = (byte)((((SiteCodeBytes[6] - '0') & 0x0F) << 4) & (byte)0xF0);
+            RetBytes[3] |= (byte)((((SiteCodeBytes[7] - '0') & 0x0F) << 0) );
+
+            return RetBytes;
+        } catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+            return null;
+        } catch (Exception e) {
+            Log.e(TAG, "[getSiteCode_BCD] - [Exception Error] ");
+            LogUtil.errorLogInfo("", TAG, e);//e.printStackTrace();
+            return null;
+        }
+    }
+
+    /**
+     * 도어락 타입을 반환한다.
+     *
+     * @return (int) - >=0 : 도어락 타입, <0 : 실패
+     */
+    private int getDoorLockType() {
+        // 1. get DB
+        WallpadDeviceSet devset = new WallpadDeviceSet(ServiceMain.svcContext);
+        int[] Doorinfo = devset.Get_DoorLock_Info();
+        devset.closeDB();
+
+        // 2. Check
+        if (Doorinfo == null) {
+            return -1;
+        }
+
+        if (Doorinfo.length < 2) {
+            return -2;
+        }
+
+        if (Doorinfo[0] == 0) {
+            return -3;
+        }
+
+        // 3. return
+        switch (Doorinfo[1]) {
+            case WallpadDeviceSet.DOORLOCK_TYPE_RF:
+            case WallpadDeviceSet.DOORLOCK_TYPE_NORMAL:
+            case WallpadDeviceSet.DOORLOCK_TYPE_FINGERPRINT:
+                return Doorinfo[1];
+            default:
+                return -4;
+        }
+    }
+
+    /**
+     * 무선 도어락 문열림 대기모드 사용여부
+     *
+     * @return (int) - >0 : 무선 도어락 문열림 대기모드 사용, <0 : 실패 또는 미사용
+     */
+    private int getDoorLockOpenDelayUse() {
+        // 1. get DB
+        WallpadDeviceSet devset = new WallpadDeviceSet(ServiceMain.svcContext);
+        int Doorinfo = devset.GetDeviceSetted("무선도어락문열림대기모드");
+        devset.closeDB();
+
+        // 2. Check        
+        if (Doorinfo == WallpadDeviceSet.DEV_DATA_ENABLE) {
+            return 1;
+        }
+        else if (Doorinfo == WallpadDeviceSet.DEV_DATA_DISABLE) {
+            return -1;
+        }
+        else if (Doorinfo == WallpadDeviceSet.DEV_DATA_NONE) {
+            return -2;
+        }
+        else {
+            return -3;
+        }
+    }
+
+    private boolean CompareByteArray(byte [] a, byte [] b) {
+        if ((a == null) && (b == null)) return true;
+        if ((a == null) || (b == null)) return false;
+        if (a.length != b.length) return false;
+        for(int i = 0; i < a.length; i++) { if(a[i] != b[i]) return false; }
+        return true;
+    }
+
+    /**
+     * 스마트키 인식하여 문이 열릴 경우,<br>
+     * 현관카메라에서 3초간 전원이 유지되도록 한다.
+     * @param devioctr (WallPadInterface)
+     */
+    private void TurnOnDcamPower(final WallPadInterface devioctr) {
+        Log.d(TAG, "[TurnOnDcamPower] Start");
+
+        String topActivityName = getTopActivity();
+        if(topActivityName!=null)
+        {
+            Log.d(TAG, "[TurnOnDcamPower] getTopActivity : " + topActivityName);
+
+            if (topActivityName.equals(strWallPadCallPakageName) || getCallAppRunningStatus()) {
+                Log.d(TAG, "[TurnOnDcamPower] Now WallPadCall ON");
+                return;
+            }
+        }
+
+
+        if (PowerOnTimer != null) PowerOnTimer.cancel();
+
+        CallAppEnable = false; // 문열림 동작 중에는 WallpadCall이 실행되지 않도록 false
+
+        // 현관카메라 조명 3초동안 점등 유지한 후, 다시 소등
+        Log.d(TAG, "[TurnOnDcamPower] Camera Power ON !!!");
+        int[] camType = {};
+        try {
+            WallpadDeviceSet wds = new WallpadDeviceSet(ServiceMain.svcContext);
+            camType =  wds.Get_RFDoorCAM_Info();
+            wds.closeDB();
+        } catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+        } catch (Exception e) {
+            LogUtil.errorLogInfo("", TAG, e);//e.printStackTrace();
+        }
+
+        if (camType[1] == WallpadDeviceSet.DOORTYPE_IOT_SMART) {
+            // 여기서 제어하면 안되고
+            // 플래그만 세워야 됨
+            // 실제 패킷 전송은 폴링구조 안에서 해야함
+            /*Send_SetLedMode( (byte)0x01 ); // LED ON*/
+            driverInterOpAPI.SmartIotDCam_CtrLed(true);
+        }
+        else {
+            if (Version.getModelType() == Version.MODEL_TYPE.IHN_D101 || Version.getModelType() == Version.MODEL_TYPE.IHN_D101_I
+                    || Version.getModelType() == Version.MODEL_TYPE.IHN_D101K || Version.getModelType() == Version.MODEL_TYPE.IHN_D101K_I
+                    || Version.getModelType() == Version.MODEL_TYPE.IHN_D101_I_OCF)
+            {
+                driverInterOpAPI.IGW_SetLedOnOff(true);
+            }
+            else {
+                devioctr.cameraPowerControll(true);
+            }
+        }
+
+        PowerOnTimer = new CountDownTimer(2 * 1000, 1000) {
+            @Override
+            public void onFinish() {
+                Log.d(TAG, "[TurnOnDcamPower] PowerOnTimer Start");
+                if (getTopActivity().equals(strWallPadCallPakageName) || getCallAppRunningStatus()) {
+                    Log.d(TAG, "[TurnOnDcamPower] Now WallPadCall ON");
+                    Log.d(TAG, "[TurnOnDcamPower] Do Not TURN LED OFF !!!");
+                }
+                else {
+                    WallpadDeviceSet wds = new WallpadDeviceSet(ServiceMain.svcContext);
+                    int[] camTypes =  wds.Get_RFDoorCAM_Info();
+                    wds.closeDB();
+
+                    Log.d(TAG, "[TurnOnDcamPower] Camera Power OFF !!!");
+                    if (camTypes[1] == WallpadDeviceSet.DOORTYPE_IOT_SMART) {
+                        int ret = driverInterOpAPI.SmartIotDCam_CtrLed(false);
+                        if (ret < 0) {
+                            Log.w(TAG, "[TurnOnDcamPower] Camera Off Timer ERROR !!!");
+                        }
+                    }
+                    else {
+						if (Version.getModelType() == Version.MODEL_TYPE.IHN_D101 || Version.getModelType() == Version.MODEL_TYPE.IHN_D101_I
+                                || Version.getModelType() == Version.MODEL_TYPE.IHN_D101K || Version.getModelType() == Version.MODEL_TYPE.IHN_D101K_I
+                                || Version.getModelType() == Version.MODEL_TYPE.IHN_D101_I_OCF) {
+							driverInterOpAPI.IGW_SetLedOnOff(false);
+						}
+						else {
+							devioctr.cameraPowerControll(false);
+						}
+                    }
+                }
+
+                CallAppEnable = true; // 현관카메라 파워 off시, WallpadCall 호출 가능
+                Log.d(TAG, "[TurnOnDcamPower] PowerOnTimer END");
+            }
+
+            @Override
+            public void onTick(long arg0) {
+            }
+        };
+        PowerOnTimer.cancel();
+        PowerOnTimer.start();
+
+        Log.d(TAG, "[TurnOnDcamPower] END");
+    }
+
+    /**
+     * 최 상위 activity 가져오기
+     */
+    private String getTopActivity() {
+        try {
+            ActivityManager mActivityManager = (ActivityManager)ServiceMain.svcContext.getSystemService(Context.ACTIVITY_SERVICE);
+            List<RunningTaskInfo> mTaskInfo = null;
+            if (mActivityManager != null) {
+                mTaskInfo = mActivityManager.getRunningTasks(5);
+            }
+            if(mTaskInfo!=null)
+            {
+                ComponentName mComponentName = mTaskInfo.get(0).topActivity;
+                return mComponentName.getPackageName();
+            }
+            else
+            {
+                return null;
+            }
+
+        } catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+            return null;
+        } catch (Exception e) {
+            Log.e(TAG, "[Exception] getTopActivity()");
+            LogUtil.errorLogInfo("", TAG, e);//e.printStackTrace();
+            return null;
+        }
+    }
+
+    private boolean getCallAppRunningStatus() {
+        boolean bRunning = false;
+
+        try {
+            WallpadStatusData DBMGR = new WallpadStatusData(ServiceMain.svcContext);
+            bRunning = DBMGR.GetCallAPKStatusRunning();
+            DBMGR.closeDB();
+
+            Log.d(TAG, "[getCallAppRunningStatus] - CALL Running : " + bRunning);
+            return bRunning;
+        } catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+            return false;
+        } catch (Exception e) {
+            Log.d(TAG, "[Exception] getCallAppRunningStatus()");
+            LogUtil.errorLogInfo("", TAG, e);//e.printStackTrace();
+            return false;
+        }
+    }
+
+}

+ 3704 - 3528
WallPadDevService/src/main/java/com/artncore/wallpaddevservice/driver/SmartSwitchPol_Controller.java

@@ -1,3528 +1,3704 @@
-/*
- * Copyright (C) 2014 Android WallPad Project
- *
- * FileName  : SmartSwitchPol_Controller.java
- * Project   : Android WallPad Project
- * Company   : HDC I-CONTROLS ( www.icontrols.co.kr )
- * Author    : Kang Sang Ho  , lairu@icontrols.co.kr
- */
-
-package com.artncore.wallpaddevservice.driver;
-
-import java.util.Calendar;
-import java.util.GregorianCalendar;
-
-import kr.co.icontrols.wallpadsupport.Version;
-import android.annotation.SuppressLint;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.util.Log;
-
-import com.artncore.WallPadDataMgr.WallpadDeviceSet;
-import com.artncore.WallPadDataMgr.WallpadParkInfo;
-import com.artncore.WallPadDataMgr.WallpadStatusData;
-import com.artncore.WallPadDataMgr.WallpadStatusData.WeatherTable;
-import com.artncore.WallPadDataMgr.wallpaddbmgr.AddressSet;
-import com.artncore.commons.APIErrorCode;
-import com.artncore.commons.DataClasses.CarParkingData;
-import com.artncore.commons.define;
-import com.util.LogUtil;
-import com.artncore.wallpaddevservice.ServiceMain;
-
-
-/**
- * 스마트스위치 (폴링) 드라이버 모듈이다.<br>
- * 모델명 : ISS-430(LCD type), ISS-201
- */
-@SuppressLint("HandlerLeak")
-public class SmartSwitchPol_Controller extends DeviceManager
-{
-    private final static String TAG = "SmartSwitchPol";
-
-    private final byte ELE_CALL_DOWN = BIT0;
-    private final byte ELE_CALL_UP   = BIT1;
-    private final byte ELE_ARR_DOWN  = BIT2;
-    private final byte ELE_ARR_UP    = BIT3;
-
-    /** 디바이스 주소 */
-    private final byte DEVICE_ADDRESS  = (byte) 0xC1;
-
-    /** 초기 기기 검색 횟수  */
-    private final int MAX_SEARCH_COUNT   = 6;
-
-    /** 시간 및 상태 동기화 시간 (초)  (시간, 엘리베이터 정보, 가스상태, 외출, 일괄소등, 조명상태) */
-    private final long STATUS_SYNC_TICK   = (long)(20 * TIME_SEC);
-
-    /** 에너지 정보 동기화 시간 (초) */
-    private final long ENERGY_SYNC_TICK    = (long)(30 * TIME_SEC);
-
-    /** 스마트스위치로 부터 일괄소등 변경 정보를 받은후 일정시간 동기화 하지 않는시간 (초) */
-    private final long ALLLIGHT_SYNC_TICK    = (long)(2 * TIME_SEC);
-
-    /** 주차위치 정보 문자열 최대 길이 */
-    private final byte MAX_PARKING_INFO_STR_COUNT   = 10;
-
-    private byte   ELEStatus = 0;
-    private String ELELoc    = "NONE";
-    private int    ELEMove   = define.NOTIFY_DEVICE_ELE_MOVE_DIR_ERROR;
-
-    private DriverInterOpAPI driverInterOpAPI;
-
-    private int mModelType = Version.MODEL_TYPE.OTHER;
-
-    /** 부팅 시에 이미 가지고 있던 공지사항 수 */
-    private int DefaultNotiCNT = 0;    // 공지사항 수는 IC_WallPadMain의 DrawEventAlarm에서 인텐트 수신하여 저장
-
-    /** 부팅 시에 이미 가지고 있던 방문자 수 */
-    private int DefaultVisitorCNT = 0; // 방문자 수는 IC_WallPadMain의 DrawEventAlarm에서 인텐트 수신하여 저장
-
-    /** 부팅 시에 이미 가지고 있던 택배 수 */
-    private int DefaultParcelCNT = 0;  // 택배 수는 IC_WallPadMain의 DrawEventAlarm에서 인텐트 수신하여 저장
-
-    /** 부팅 시에 이미 가지고 있던 메모 수 */
-    private int DefaultMemoCNT = 0;    // 메모 수는 WallPadAddService의 memo관련 class에서 인텐트 수신하여 저장
-
-    /** BroadcastReceiver에서 수신한 알림정보들을 관리하는 array */
-    private int NotiArr[] = {0, 0, 0, 0}; // (0: notice / 1: parcel / 2: visitor / 3: memo)
-
-    /** 난방정보를 얻기 위한 컨트롤러 */
-    HeatingV2_Controller H2Cont;
-
-
-    /** 기기정보 */
-    public class Info
-    {
-        /** 조명개수( 범위 : 0~4) */
-        public byte LightCnt;
-
-        /** 기능 지원 여부 */
-        public class SupportClass
-        {
-            /** 시간정보 */
-            public boolean Time = false;
-            /** 주차정보 */
-            public boolean Parking = false;
-            /** 에너지 사용량 */
-            public boolean Energy = false;
-            /** 날씨정보 */
-            public boolean Weather = false;
-            /** 일괄소등 */
-            public boolean BatchOff = false;
-            /** 외출설정 */
-            public boolean Outing = false;
-            /** 가스 */
-            public boolean Gas = false;
-            /** 엘리베이터 */
-            public boolean Elevator = false;
-            /** 일괄소등 직접제어 */
-            public boolean BatchOffDirCtrl = false;
-            /** 현재 날씨 */
-            public boolean NowWeather = false;
-            /** 엘리베이터 운행방향 */
-            public boolean ElevatorDir = false;
-            /** 알림 정보 */
-            public boolean NotiInfo = false;
-            /** 난방 정보 */
-            public boolean HeatingInfo = false;
-        }
-        /** 기능 지원 여부 */
-        SupportClass Support;
-
-        /** 펌웨어 Build Date (년) */
-        public byte FwVer_Year;
-        /** 펌웨어 Build Date (월) */
-        public byte FwVer_Month;
-        /** 펌웨어 Build Date (일) */
-        public byte FwVer_Day;
-        /** 펌웨어 Build Date (일련번호) */
-        public byte FwVer_Number;
-
-        /** 지원 프로토콜 버전 Main */
-        public byte ProtocolVer_Main;
-        /** 지원 프로토콜 버전 Sub */
-        public byte ProtocolVer_Sub;
-
-        /** 생성자 */
-        public Info()
-        {
-            LightCnt = 0;
-            Support = new SupportClass();
-        }
-
-        /** 본 클래스 디버깅 메시지 */
-        public String ToDebugString()
-        {
-            String retStr =
-                    "==========================\r\n" +
-                            " Info\r\n" +
-                            "==========================\r\n" +
-                            "LightCnt     : " + LightCnt + "\r\n" +
-                            "FwVer        : " + (int)(FwVer_Year+2000) + "." + FwVer_Month + "." + FwVer_Day + "." + FwVer_Number + "\r\n" +
-                            "ProtocolVer  : " +  "V" + ProtocolVer_Main + "." + ProtocolVer_Sub + "\r\n" +
-
-                            "[Support]" + "\r\n" +
-                            "Time            : " + Support.Time + "\r\n" +
-                            "Parking         : " + Support.Parking + "\r\n" +
-                            "Energy          : " + Support.Energy + "\r\n" +
-                            "Weather         : " + Support.Weather + "\r\n" +
-                            "BatchOff        : " + Support.BatchOff + "\r\n" +
-                            "Outing          : " + Support.Outing + "\r\n" +
-                            "Gas             : " + Support.Gas + "\r\n" +
-                            "Elevator        : " + Support.Elevator + "\r\n" +
-                            "BatchOffDirCtrl : " + Support.BatchOffDirCtrl + "\r\n" +
-                            "NowWeather      : " + Support.NowWeather + "\r\n" +
-                            "ElevatorDir     : " + Support.ElevatorDir + "\r\n" +
-                            "NotiInfo        : " + Support.NotiInfo + "\r\n" +
-                            "HeatingInfo     : " + Support.HeatingInfo + "\r\n" +
-                            "==========================";
-            return retStr;
-        }
-    }
-
-    /** 기기 상태 */
-    private class Status
-    {
-        /** 엘리베이터 */
-        public EachStatus Elevator;
-        /** 가스 */
-        public EachStatus Gas;
-        /** 일괄소등 */
-        public EachStatus BatchOff;
-        /** 외출설정 */
-        public EachStatus Outing;
-        /** 난방 정보 */
-        public EachStatus HeatingInfo;
-        /** 조명개수( 범위 : 0~4) */
-        public byte LightCnt;
-
-        /** 조명 1 정보 */
-        public EachStatus L1;
-        /** 조명 2 정보 */
-        public EachStatus L2;
-        /** 조명 3 정보 */
-        public EachStatus L3;
-        /** 조명 4 정보 */
-        public EachStatus L4;
-
-        public Status()
-        {
-            Elevator = new EachStatus();
-            Gas      = new EachStatus();
-            BatchOff = new EachStatus();
-            Outing   = new EachStatus();
-            HeatingInfo = new EachStatus();
-
-            LightCnt = 0;
-
-            L1 = new EachStatus();
-            L2 = new EachStatus();
-            L3 = new EachStatus();
-            L4 = new EachStatus();
-        }
-
-        /** 본 클래스 디버깅 메시지 */
-        public String ToDebugString(String name)
-        {
-            String retStr =
-                    "==========================\r\n" +
-                            name + " - Status\r\n" +
-                            "==========================\r\n" +
-                            "Elevator - Now(" + ToByteString(Elevator.Now) + ")  Ctrl(" + ToByteString(Elevator.Ctrl) + ")" + "\r\n" +
-                            "Gas      - Now(" + ToByteString(Gas.Now)      + ")  Ctrl(" + ToByteString(Gas.Ctrl)      + ")" + "\r\n" +
-                            "BatchOff - Now(" + ToByteString(BatchOff.Now) + ")  Ctrl(" + ToByteString(BatchOff.Ctrl) + ")" + "\r\n" +
-                            "Outing   - Now(" + ToByteString(Outing.Now)   + ")  Ctrl(" + ToByteString(Outing.Ctrl)   + ")" + "\r\n" +
-                            "HeatInfo - Now(" + ToByteString(HeatingInfo.Now)   + ")  Ctrl(" + ToByteString(HeatingInfo.Ctrl)   + ")" + "\r\n" +
-                            "\r\n" +
-                            "LightCnt - " + LightCnt + "\r\n" +
-                            "L1       - Now(" + ToByteString(L1.Now) + ")  Ctrl(" + ToByteString(L1.Ctrl) + ")" + "\r\n" +
-                            "L2       - Now(" + ToByteString(L2.Now) + ")  Ctrl(" + ToByteString(L2.Ctrl) + ")" + "\r\n" +
-                            "L3       - Now(" + ToByteString(L3.Now) + ")  Ctrl(" + ToByteString(L3.Ctrl) + ")" + "\r\n" +
-                            "L4       - Now(" + ToByteString(L4.Now) + ")  Ctrl(" + ToByteString(L4.Ctrl) + ")" + "\r\n";
-            return retStr;
-        }
-
-        private String ToByteString(byte data) { return String.format("0x%02X", data); }
-
-    }
-
-    /** 각 상태 구분 클래스 */
-    private class EachStatus
-    {
-        public byte Now;
-        public byte Ctrl;
-        public EachStatus()
-        {
-            Now = 0x00;
-            Ctrl = 0x00;
-        }
-    }
-
-    /** 기기 제어 */
-    private class CtrlStatus
-    {
-        public byte ElevatorCall;
-        public byte ElevatorDir;
-        public byte ElevatorLayer;
-
-        public byte Gas;
-
-        public byte Outing;
-
-        public byte BatchOff;
-
-        public byte LightCnt;
-
-        public byte [] LightStatus;
-
-        public CtrlStatus()
-        {
-            ElevatorCall  = 0x00;
-            ElevatorDir   = 0x00;
-            ElevatorLayer = 0x00;
-            Gas = 0x00;
-            Outing = 0x00;
-            BatchOff = 0x00;
-
-            LightCnt = mDriver.info.LightCnt;
-            LightStatus = new byte[LightCnt];
-            for(int i=0 ; i<LightStatus.length ; i++) LightStatus[i] = 0x00;
-        }
-
-        /**
-         * 기기 상태 변경 알림 명령어 0x13 - 에서 사용할 데이터 byte array 를 반환한다.
-         * 시간데이터는 자동으로 현재시간으로 체워진다. <br>
-         * 그외 엘리베이터 정보등은 지원을 할경우에 자동으로 현재 상태로 체워진다.<br>
-         * 단, 각 데이터를 0x00 초기값에서 설정하지 않을 경우에 한하여 현재상태로 체워진다.
-         *
-         * @return byte [] 명령어 0x13 용 데이터
-         */
-        public byte [] getByteArray()
-        {
-            if(mDriver == null) return null;
-            if(mDriver.info == null) return null;
-
-            byte [] retData = new byte [12 + LightCnt];
-            int index = 0;
-
-            // D1 ~ D6 : 현재날짜
-            // 년,월,일,시,분,초
-            if(mDriver.info.Support.Time)
-            {
-                Calendar cal = new GregorianCalendar();
-                retData[index++] = (byte) (cal.get(Calendar.YEAR) - 2000);
-                retData[index++] = (byte) (cal.get(Calendar.MONTH) + 1);
-                retData[index++] = (byte) cal.get(Calendar.DAY_OF_MONTH);
-                retData[index++] = (byte) cal.get(Calendar.HOUR_OF_DAY);
-                retData[index++] = (byte) cal.get(Calendar.MINUTE);
-                retData[index++] = (byte) cal.get(Calendar.SECOND);
-            }
-            else
-            {
-                retData[index++] = 0x00;
-                retData[index++] = 0x00;
-                retData[index++] = 0x00;
-                retData[index++] = 0x00;
-                retData[index++] = 0x00;
-                retData[index++] = 0x00;
-            }
-
-            // D7 : 엘리베이터 정보
-            byte Elevator = 0x00;
-            if(mDriver.info.Support.Elevator)
-            {
-                if(this.ElevatorCall == 0x00)
-                {
-                    this.ElevatorCall = ELEStatus;
-                    if (((ELEStatus&(byte)ELE_CALL_DOWN) == 0) && ((ELEStatus&(byte)ELE_ARR_DOWN)>0))
-                        ELEStatus^=(byte)ELE_ARR_DOWN;
-                    if (((ELEStatus&(byte)ELE_CALL_UP) == 0) && ((ELEStatus&(byte)ELE_ARR_UP)>0))
-                        ELEStatus^=(byte)ELE_ARR_UP;
-                    if (ELEStatus==0) ELELoc = "NONE";
-
-                    if(mDriver.info.Support.ElevatorDir)
-                    {
-                        if (ELEStatus == 0)
-                        {
-                            ELEMove = define.NOTIFY_DEVICE_ELE_MOVE_DIR_ERROR;
-                        }
-                    }
-                }
-                Elevator = this.ElevatorCall;
-            }
-            if(mDriver.info.Support.ElevatorDir)
-            {
-                if(this.ElevatorDir == 0x00)
-                {
-                    switch(ELEMove)
-                    {
-                        case define.NOTIFY_DEVICE_ELE_MOVE_DIR_UP:      this.ElevatorDir = define.BIT4; break;
-                        case define.NOTIFY_DEVICE_ELE_MOVE_DIR_DOWN:    this.ElevatorDir = define.BIT5; break;
-                        case define.NOTIFY_DEVICE_ELE_MOVE_DIR_STOP:    this.ElevatorDir = define.BIT4 | define.BIT5; break;
-                        case define.NOTIFY_DEVICE_ELE_MOVE_DIR_ERROR:   break;
-                    }
-                }
-                Elevator |= this.ElevatorDir;
-            }
-            retData[index++] = Elevator;
-
-            // D8 : 엘리베이터층 정보
-            if(mDriver.info.Support.Elevator)
-            {
-                if(ElevatorLayer == 0x00)
-                {
-                    byte floorinfo = 0;
-
-                    if( ((Elevator & ELE_ARR_DOWN) != 0x00) || ((Elevator & ELE_ARR_UP) != 0x00) )
-                    {
-                        // 엘리베이터 도착일 경우
-                        floorinfo = mDriver.HomeFloorNumber;
-                    }
-                    else
-                    {
-                        try {
-                            if (ELELoc.equals("NONE"))
-                            {
-                                floorinfo = (byte)0xFF;
-                            }
-                            else if (ELELoc.startsWith("B"))
-                            {
-                                floorinfo = Byte.parseByte(ELELoc.replace("B", ""));
-                                floorinfo|=(byte)0x80;
-                            }
-                            else
-                                floorinfo = Byte.parseByte(ELELoc);
-                        }
-                        catch (RuntimeException re) {
-                            LogUtil.errorLogInfo("", TAG, re);
-                            floorinfo = (byte)0xFF;
-                        }
-                        catch (Exception E) {
-                            LogUtil.errorLogInfo("", TAG, E);//
-                            floorinfo = (byte)0xFF;
-                        }
-                    }
-                    ElevatorLayer = floorinfo;
-                }
-            }
-            retData[index++] = ElevatorLayer;
-
-            // D9 : 가스 현재상태
-            if(mDriver.info.Support.Gas)
-            {
-                if(Gas == 0x00)
-                {
-                    byte GasValveStatus = GasValve_Controller.GetGasStatus();
-                    if (ServiceMain.gasValve_Controller != null && GasValveStatus != -1)
-                        Gas = (byte) (GasValveStatus == 0 ? 1 :(GasValveStatus == 2 ? 3 : 2));
-                }
-            }
-            retData[index++] = Gas;
-
-            // D10 : 외출설정 현재상태
-            if(mDriver.info.Support.Outing)
-            {
-                if(Outing == 0x00)
-                {
-                    int AlarmStatus = DB_GetAlarmStatus();
-                    switch(AlarmStatus)
-                    {
-                        case WallpadStatusData.ALARM_NONE:
-                            Outing = 0x02; // 외출설정 해제상태
-                            break;
-                        case WallpadStatusData.GUARD_OUT_WAIT:
-                            Outing = 0x03; // 외출설정 대기상태
-                            break;
-                        case WallpadStatusData.GUARD_OUT:
-                        case WallpadStatusData.OUT_MODE:
-                            Outing = 0x01; // 외출설정 상태
-                            break;
-                    }
-                }
-            }
-            retData[index++] = Outing;
-
-            // D11 : 일괄소등 현재상태
-            if(mDriver.info.Support.BatchOff)
-            {
-                if(!mDriver.info.Support.BatchOffDirCtrl)
-                {
-                    if(BatchOff == 0x00)
-                    {
-                        if(driverInterOpAPI.getAllLight())
-                        {
-                            BatchOff = 0x02;
-                        }
-                        else
-                        {
-                            BatchOff = 0x01;
-                        }
-                    }
-                }
-            }
-            retData[index++] = BatchOff;
-
-            // D12 : 조명 버튼 개수
-            retData[index++] = LightCnt;
-
-            // D13 ~ D16
-            if(LightCnt > 0)
-            {
-                byte Status = 0x00;
-                if(LightStatus[0] == 0x00)
-                {
-                    if(driverInterOpAPI.getLight(mDriver.L1Map)) Status = 0x01;
-                    else Status = 0x02;
-                    LightStatus[0] = Status;
-                }
-
-                if(LightCnt > 1)
-                {
-                    if(driverInterOpAPI.getLight(mDriver.L2Map)) Status = 0x01;
-                    else Status = 0x02;
-                    LightStatus[1] = Status;
-                }
-
-                for(byte i=0 ; i<LightCnt ; i++)
-                {
-                    retData[index++] = LightStatus[i];
-                }
-            }
-
-            return retData;
-        }
-    }
-
-    /** 드라이버 내부 변수     */
-    public class Driver
-    {
-        private Info info;           // 기기 정보
-
-        private Status status;       // 기기 상태
-
-        private PollingList Polling; // 폴링 상태
-
-        /** 서브일괄소등인 경우 (※일괄소등을 직접제어 하지만 메인 일괄소등제어기가 존재함) */
-        private boolean bSubBatchOffDirCtrl;
-
-        private byte L1Map;
-        private byte L2Map;
-
-        private int TargetModel;
-
-        /** 최초 일괄소등 상태 BR 송신 상태 */
-        private boolean bFirstBatchOffBRSend;
-
-        private byte HomeFloorNumber;
-
-        public Driver()
-        {
-            info = new Info();
-            status = new Status();
-            Polling = new PollingList();
-
-            bSubBatchOffDirCtrl = false;
-
-            L1Map = 0;
-            L2Map = 1;
-
-            TargetModel = WallpadDeviceSet.BATCH_TYPE_HDC_LCD_SMART;
-
-            bFirstBatchOffBRSend = false;
-
-            //세대 층정보 최초 입력 시작
-            int numberHo = 0;
-            String myHo = null;
-            try
-            {
-                WallpadStatusData DBMGR = new WallpadStatusData(ServiceMain.svcContext);
-                AddressSet addc =  DBMGR.getAddressMGR();
-                myHo = addc.Ho;
-                if(addc.UseOrNotRentHouse == true)
-                {
-                    numberHo = addc.Ho_Integer;
-                }
-                else
-                {
-                    numberHo = Integer.parseInt(myHo)/100;
-                }
-                DBMGR.closeDB();
-            }
-            catch (RuntimeException re) {
-                LogUtil.errorLogInfo("", TAG, re);
-            }
-            catch (Exception e) {
-                Log.e(TAG, "[Exception Error] Get addc.Ho");
-            }
-            HomeFloorNumber = (byte)(numberHo);
-            Log.i(TAG, "My Ho :" + myHo + ", HomeFloorNumber :+"+HomeFloorNumber);
-        }
-
-        /** Polling 관련 */
-        private class PollingList
-        {
-            private final class STATUS
-            {
-                public final static int First = 0;
-                public final static int FirstTimeOut = 1;
-                public final static int Normal = 2;
-            }
-
-            public int Status;
-            public int SearchTryCount;
-            public long StatusSinkTick;
-            public long EnergySinkTick;
-            public boolean ReBootDetect;
-
-            private boolean WeatherUpdate;
-            public void setWeatherUpdate(boolean set)    { WeatherUpdate = set; }
-            public boolean getWeatherUpdate() { return WeatherUpdate; }
-
-            private boolean ParkingUpdate;
-            public void setParkingUpdate(boolean set)    { ParkingUpdate = set; }
-            public boolean getParkingUpdate() { return ParkingUpdate; }
-
-            private boolean NotiInfoUpdate; // 알림 정보 사용 여부
-            public void setNotiInfoUpdate(boolean set)      { NotiInfoUpdate = set; }
-            public boolean getNotiInfoUpdate()   { return NotiInfoUpdate; }
-
-            private boolean HeatingInfoUpdate; // 난방 정보 사용 여부
-            public void setHeatingInfoUpdate(boolean set)    { HeatingInfoUpdate = set; }
-            public boolean getHeatingInfoUpdate()    { return HeatingInfoUpdate; }
-
-
-
-            private boolean AllLightSinkStart;
-            private boolean AllLightSinkDelay;
-            private long AllLightSinkTick;
-
-            private PollingList()
-            {
-                Status = STATUS.First;
-                SearchTryCount = 0;
-                StatusSinkTick = 0;
-                EnergySinkTick = 0;
-                ReBootDetect = false;
-
-                WeatherUpdate = false;
-                ParkingUpdate = false;
-
-                AllLightSinkStart = false;
-                AllLightSinkDelay = false;
-                AllLightSinkTick = 0;
-            }
-
-            public void StatusSinkTickReset()
-            {
-                StatusSinkTick = 0;
-            }
-
-            /**
-             * 일괄소등 동기화 딜레이를 설정한다.
-             */
-            public void SetAllLightSinkDelay()
-            {
-                AllLightSinkTick = System.currentTimeMillis();
-                AllLightSinkDelay = true;
-            }
-
-            /**
-             * 일괄소등 동기화를 해도되는지 체크한다.
-             *
-             * @return (boolean) 일괄소등 동기화 여부  true : 동기화가능,  false:동기화 불능
-             */
-            public boolean CheckAllLightSink()
-            {
-                // 1. 일괄소등 제어기가 연결이 완료되었는지 체크
-                if(!AllLightSinkStart)
-                {
-                    return false;
-                }
-
-                // 2. 동기화 시간 딜레이 체크
-                if(AllLightSinkDelay)
-                {
-                    long currentTimeMillis = System.currentTimeMillis();
-                    if(Math.abs(currentTimeMillis - mDriver.Polling.AllLightSinkTick) > ALLLIGHT_SYNC_TICK)
-                    {
-                        AllLightSinkDelay = false;
-                        return true;
-                    }
-                    else
-                    {
-                        return false;
-                    }
-                }
-                return true;
-            }
-        }
-    }
-    private Driver mDriver = null;
-
-    /**
-     * 생성자
-     */
-    public SmartSwitchPol_Controller() {
-        /** 로그 초기상태 */
-//        log_sw = true;
-//        SerialLog = true;
-
-        /** 모델정보 가져오기 */
-        mModelType = Version.getModelType();
-
-        /** 통신성공률 변수 초기화 */
-        CommDataGeneration(1);
-
-        /** 드라이버 내부 변수 초기화 */
-        mDriver = new Driver();
-
-        /** 스마트스위치 L1 & L2 맵핑 데이터 가져오기 */
-        GetBatchSwInfo();
-
-        /** 월패드 설정 - 스마트스위치 모델명 가져오기 */
-        int [] Get_BatchSW_Info = ServiceMain.dataBaseLoader.data.wallpadDeviceSet.Get_BatchSW_Info;
-        if (Get_BatchSW_Info != null) {
-            if (Get_BatchSW_Info.length >= 2) {
-                mDriver.TargetModel = Get_BatchSW_Info[1];
-                Log.i(TAG, "[SmartSwitchPol_Controller] WallpadDeviceSet - OK!!!");
-            }
-        }
-
-        Log.i(TAG, "[SmartSwitchPol_Controller] mDriver.TargetModel: " + mDriver.TargetModel);
-
-        // 부팅 시, 월패드가 이미 가지고 있던 각 알림정보 요소들의 개수를 가져온다.
-        // 초기 값을 설정하여 인텐트로 수신받은 각 알림정보 요소들이 증가,감소 하는지 확인하기 위해 사용한다.
-        WallpadStatusData OriginWsd = new WallpadStatusData(ServiceMain.svcContext);
-        DefaultNotiCNT = OriginWsd.GetNoticeCNT();
-        DefaultParcelCNT = OriginWsd.GetParcelCNT();
-        DefaultMemoCNT = OriginWsd.GetMemoCNT();
-
-        Log.i(TAG, "default Noti = " + DefaultNotiCNT);
-        Log.i(TAG, "default Parcel = " + DefaultParcelCNT);
-        Log.i(TAG, "default Memo = " + DefaultMemoCNT);
-        OriginWsd.closeDB();
-
-        Log.i(TAG, "=========================================");
-        Log.i(TAG, "SmartSwitchPol_Controller - create");
-        Log.i(TAG, "=========================================");
-    }
-
-    /**
-     * 스마트스위치 L1 & L2 맵핑 데이터 가져온다.
-     *
-     * @return (int) - >=0 : 성공, <0 : 실패
-     */
-    private int GetBatchSwInfo() {
-        try {
-            int [] Get_BatchSW_Info = ServiceMain.dataBaseLoader.data.wallpadDeviceSet.Get_BatchSW_Info;
-            DeviceLog("GetBatchSwInfo "+Get_BatchSW_Info[0]+" : "+Get_BatchSW_Info[1]+" : "+Get_BatchSW_Info[2]+" : "+Get_BatchSW_Info[3]);
-
-            if ((Get_BatchSW_Info[2] > 0) && (Get_BatchSW_Info[2] <= 6)) {
-                mDriver.L1Map = (byte)(Get_BatchSW_Info[2]-1);
-            }
-
-            if ((Get_BatchSW_Info[3] > 0) && (Get_BatchSW_Info[3] <= 6)) {
-                mDriver.L2Map = (byte)(Get_BatchSW_Info[3]-1);
-            }
-
-            DeviceLog("GetBatchSwInfo  L1Map : " + mDriver.L1Map + " / L2Map : " + mDriver.L2Map);
-        } catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-            return -1;
-        } catch (Exception e) {
-            Log.e(TAG, "[Exception Error] GetBatchSwInfo()");
-            //e.printStackTrace();
-            LogUtil.errorLogInfo("", TAG, e);
-            return -1;
-        }
-        return 0;
-    }
-
-    /**
-     * BroadcastReceiver 용 필터를 등록한다.
-     *
-     * @return (boolean) true : 성공 , false : 실패
-     */
-    private boolean Device_BrRegistration() {
-        DeviceLog("Device_BrRegistration - Start");
-
-        if (mDriver == null) return false;
-        if (mDriver.Polling.Status != Driver.PollingList.STATUS.Normal) return false;
-
-        IntentFilter filter = new IntentFilter();
-
-        // 1. NOTIFY_ACNAME
-        if (mDriver.info.Support.Weather || mDriver.info.Support.Parking || mDriver.info.Support.Elevator || mDriver.info.Support.Energy || mDriver.info.Support.Time || mDriver.info.Support.Outing || mDriver.info.Support.BatchOff) {
-            DeviceLog("Device_BrRegistration - filter.addAction - " + define.NOTIFY_ACNAME);
-            filter.addAction(define.NOTIFY_ACNAME);
-        }
-
-        // 2. DRIVER_LIGHT_BR
-        if (mDriver.info.LightCnt > 0) {
-            DeviceLog("Device_BrRegistration - filter.addAction - " + define.DRIVER_LIGHT_BR);
-            driverInterOpAPI.setLightRegBR(define.DRIVER_LIGHT_BR);
-            filter.addAction(define.DRIVER_LIGHT_BR);
-        }
-
-        // 3. DRIVER_GAS_BR
-        if (mDriver.info.Support.Gas) {
-            DeviceLog("Device_BrRegistration - filter.addAction - " + define.DRIVER_GAS_BR);
-            driverInterOpAPI.GasRegBR(define.DRIVER_GAS_BR);
-            filter.addAction(define.DRIVER_GAS_BR);
-        }
-
-        // 4. ISD의 알림정보 제공을 위한 Action 추가
-        if (mDriver.info.Support.NotiInfo) {
-            DeviceLog("Device_BrRegistration - filter.addAction - " + "ISD_NotiInfo");
-            filter.addAction(define.DRIVER_ISD_NOTIINFO);
-        }
-
-        ServiceMain.svcContext.registerReceiver(mWallPadNotifyBR, filter);
-        DeviceLog("Device_BrRegistration - OK");
-
-        return true;
-    }
-
-    @Override
-    public void DeviceLog(String msg) {
-        if (!log_sw) return;
-        Log.d(TAG, msg);
-    }
-
-    /**
-     * BroadcastReceiver
-     */
-    private BroadcastReceiver mWallPadNotifyBR = new BroadcastReceiver() {
-        public void onReceive(Context context, Intent intent) {
-            String strActionName = intent.getAction();
-            DeviceLog("[mWallPadNotifyBR] strActionName ["+ strActionName + "]");
-
-            if (mDriver.Polling.Status != Driver.PollingList.STATUS.Normal) return;
-
-            if (strActionName.equals(define.NOTIFY_ACNAME)) {
-                int kind = intent.getIntExtra("KIND", 0);
-                DeviceLog("[mWallPadNotifyBR] "+ define.NOTIFY_ACNAME + " : " + kind);
-
-                switch (kind) {
-                    case define.NOTIFY_UPDATEWEATHER:
-                        if (mDriver.info.Support.Weather) {
-                            mDriver.Polling.setWeatherUpdate(true);
-                        }
-                        break;
-
-                    case define.NOTIFY_UPDATEPARKING:
-                        if (mDriver.info.Support.Parking) {
-                            mDriver.Polling.setParkingUpdate(true);
-                        }
-                        break;
-
-                    //////////////////////////////////////////////////////////////
-                    // 엘리베이터 관련
-                    //////////////////////////////////////////////////////////////
-                    case define.NOTIFY_ELE_MOVE:
-                        // 엘리베이터 이동 알림
-                        if (mDriver.info.Support.Elevator) {
-                            ELELoc = intent.getStringExtra(define.NOTIBR_FLOOR);
-                            DeviceLog("[mWallPadNotifyBR] define.NOTIFY_ELE_MOVE -> ELELoc:" + ELELoc);
-                            mDriver.Polling.StatusSinkTickReset();
-                        }
-
-                        if (mDriver.info.Support.ElevatorDir) {
-                            ELEMove = intent.getIntExtra(define.NOTIBR_MOVEDIR, define.NOTIFY_DEVICE_ELE_MOVE_DIR_ERROR);
-                            DeviceLog("[mWallPadNotifyBR] define.NOTIFY_ELE_MOVE -> ELEMove:" + ELEMove);
-                            mDriver.Polling.StatusSinkTickReset();
-                        }
-                        break;
-
-                    case define.NOTIFY_ELE_CALL_UP:
-                        // 상향 - 엘리베이터 호출 성공
-                        if (mDriver.info.Support.Elevator) {
-                            DeviceLog("[mWallPadNotifyBR] define.NOTIFY_ELE_CALL_UP");
-                            ELEStatus|=(byte)ELE_CALL_UP;
-                            mDriver.Polling.StatusSinkTickReset();
-                        }
-                        break;
-
-                    case define.NOTIFY_ELE_CALL_DOWN:
-                        // 하향 - 엘리베이터 호출 성공
-                        if (mDriver.info.Support.Elevator) {
-                            DeviceLog("[mWallPadNotifyBR] define.NOTIFY_ELE_CALL_DOWN");
-                            ELEStatus|=(byte)ELE_CALL_DOWN;
-                            mDriver.Polling.StatusSinkTickReset();
-                        }
-                        break;
-
-                    case define.NOTIFY_ELE_ARRIVAL_UP:
-                        // 상향 - 엘리베이터 도착
-                        if (mDriver.info.Support.Elevator) {
-                            DeviceLog("[mWallPadNotifyBR] define.NOTIFY_ELE_ARRIVAL_UP");
-
-                            if ((ELEStatus&ELE_CALL_UP)>0) ELEStatus^=(byte)ELE_CALL_UP;
-                            ELEStatus |= ELE_ARR_UP;
-                            mDriver.Polling.StatusSinkTickReset();
-                        }
-                        break;
-
-                    case define.NOTIFY_ELE_ARRIVAL_DOWN:
-                        // 하향 - 엘리베이터 도착
-                        if (mDriver.info.Support.Elevator) {
-                            DeviceLog("[mWallPadNotifyBR] define.NOTIFY_ELE_ARRIVAL_DOWN");
-                            if ((ELEStatus&ELE_CALL_DOWN)>0) ELEStatus^=(byte)ELE_CALL_DOWN;
-                            ELEStatus |= ELE_ARR_DOWN;
-                            mDriver.Polling.StatusSinkTickReset();
-                        }
-                        break;
-
-                    case define.NOTIFY_ELE_CALL_UP_ERROR:
-                        // 상향 - 엘리베이터 호출 에러
-                        if (mDriver.info.Support.Elevator) {
-                            DeviceLog("[mWallPadNotifyBR] define.NOTIFY_ELE_CALL_UP_ERROR");
-
-                            if ((ELEStatus&ELE_CALL_UP)>0) {
-                                ELEStatus^=(byte)ELE_CALL_UP;
-                                mDriver.Polling.StatusSinkTickReset();
-                            }
-                        }
-                        break;
-
-                    case define.NOTIFY_ELE_CALL_DOWN_ERROR:
-                        // 하향 - 엘리베이터 호출 에러
-                        if (mDriver.info.Support.Elevator) {
-                            DeviceLog("[mWallPadNotifyBR] define.NOTIFY_ELE_CALL_DOWN_ERROR");
-
-                            if ((ELEStatus&ELE_CALL_DOWN)>0) {
-                                ELEStatus^=(byte)ELE_CALL_DOWN;
-                                mDriver.Polling.StatusSinkTickReset();
-                            }
-                        }
-                        break;
-
-                    case define.NOTIFY_ELE_CALL_UP_TIMEOUT:
-                        // 상향 - 엘리베이터 호출 타임아웃
-                        if (mDriver.info.Support.Elevator) {
-                            DeviceLog("[mWallPadNotifyBR] define.NOTIFY_ELE_CALL_UP_TIMEOUT");
-
-                            if ((ELEStatus&ELE_CALL_UP)>0) {
-                                ELEStatus^=(byte)ELE_CALL_UP;
-                                mDriver.Polling.StatusSinkTickReset();
-                            }
-                        }
-                        break;
-
-                    case define.NOTIFY_ELE_CALL_DOWN_TIMEOUT:
-                        // 하향 - 엘리베이터 호출 타임아웃
-                        if (mDriver.info.Support.Elevator) {
-                            if ((ELEStatus&ELE_CALL_DOWN)>0) {
-                                ELEStatus^=(byte)ELE_CALL_DOWN;
-                                mDriver.Polling.StatusSinkTickReset();
-                            }
-                        }
-                        break;
-
-                    case define.NOTIFY_ENERGYUPDATE:
-                        // 에너지 사용량 업데이트
-                        if (mDriver.info.Support.Energy) {
-                        }
-                        break;
-
-                    case define.NOTIFY_SYSTEMTIMESETTED:
-                        // 시스템시간 업데이트
-                        if (mDriver.info.Support.Time) {
-                            DeviceLog("[mWallPadNotifyBR] define.NOTIFY_SYSTEMTIMESETTED");
-                            mDriver.Polling.StatusSinkTickReset();
-                        }
-                        break;
-
-                    case define.NOTIFY_ALL_LIGHT_ON:
-                        // 일괄소등 해제
-                        mDriver.Polling.AllLightSinkStart = true;
-                        if (mDriver.info.Support.BatchOff && !mDriver.info.Support.BatchOffDirCtrl) {
-                            if (mDriver.status.BatchOff.Now != 0x02) mDriver.Polling.StatusSinkTickReset();
-                        }
-                        break;
-
-                    case define.NOTIFY_ALL_LIGHT_OFF:
-                        // 일괄소등 설정
-                        mDriver.Polling.AllLightSinkStart = true;
-                        if (mDriver.info.Support.BatchOff && !mDriver.info.Support.BatchOffDirCtrl) {
-                            if (mDriver.status.BatchOff.Now != 0x01) mDriver.Polling.StatusSinkTickReset();
-                        }
-                        break;
-
-                    case define.NOTIFY_ALARM_CHANGE:
-                        // 알람상태가 DB에서 갱신되었을 경우
-                        if (mDriver.info.Support.Outing) {
-                            mDriver.Polling.StatusSinkTickReset();
-                        }
-                        break;
-
-                    case define.NOTIFY_TELEMETERING_DAILY_USAGE:
-                        // 원격검침값이 갱신된 경우
-                        DeviceLog("[mWallPadNotifyBR] define.NOTIFY_TELEMETERING_DAILY_USAGE");
-                        if (ServiceMain.realTimeMeter_Controller != null) {
-                            DeviceLog("[mWallPadNotifyBR] define.NOTIFY_TELEMETERING_DAILY_USAGE -> ServiceMain.realTimeMeter_Controller is not null!!!");
-                        }
-                        else  {
-                            DeviceLog("[mWallPadNotifyBR] define.NOTIFY_TELEMETERING_DAILY_USAGE -> ServiceMain.realTimeMeter_Controller is null!!!");
-                            procTelemeteringData(intent);
-                        }
-                        break;
-                }
-            }
-            else if (strActionName.equals(define.DRIVER_GAS_BR)) {
-                if (mDriver.info.Support.Gas) {
-                    mDriver.Polling.StatusSinkTickReset();
-                }
-            }
-            else if (strActionName.equals(define.DRIVER_LIGHT_BR)) {
-                if (mDriver.info.LightCnt > 0) {
-                    byte RoomIdx = intent.getByteExtra("STATUS", (byte)0xF0);
-                    if ((RoomIdx == (byte)0) || (RoomIdx == (byte)0xF0)) {
-                        // 현산일체형조명제어기 or 대외향 거실조명 의 경우 STATUS 값이 없으므로 0xF0
-                        // 멀티스위치일 경우에는 0번 (거실) 만 처리 하도록
-                        boolean bLight = false;
-                        boolean bChanged = false;
-
-                        // L1
-                        bLight = driverInterOpAPI.getLight(mDriver.L1Map);
-                        DeviceLog("[mWallPadNotifyBR] define.DRIVER_LIGHT_BR -> getLight - L1Map (" + mDriver.L1Map + ") " + bLight + "  /  mDriver.status.L1.Now : " + mDriver.status.L1.Now);
-                        if (bLight) { if (mDriver.status.L1.Now != 0x01) bChanged = true; }
-                        else { if (mDriver.status.L1.Now != 0x02) bChanged = true; }
-                        if (bChanged) mDriver.Polling.StatusSinkTickReset();
-
-                        if (mDriver.info.LightCnt > 1) {
-                            bLight = driverInterOpAPI.getLight(mDriver.L2Map);
-                            DeviceLog("[mWallPadNotifyBR] define.DRIVER_LIGHT_BR -> getLight - L2Map (" + mDriver.L2Map + ") " + bLight + "  /  mDriver.status.L2.Now : " + mDriver.status.L2.Now);
-                            if (bLight) { if (mDriver.status.L2.Now != 0x01) bChanged = true; }
-                            else { if (mDriver.status.L2.Now != 0x02) bChanged = true; }
-                            if (bChanged) mDriver.Polling.StatusSinkTickReset();
-                        }
-                    }
-                }
-            }
-            else if (strActionName.equals(define.DRIVER_ISD_NOTIINFO)) {   // 인텐트로 수신한 알림 정보를 관리 array에 저장
-
-                // 공지사항 정보 업데이트
-                if (intent.hasExtra(define.NOTIBR_ISD_NOTICECNT)) {
-                    int numNoticeCnt = intent.getIntExtra(define.NOTIBR_ISD_NOTICECNT, 0);
-                    if (numNoticeCnt != 0) {
-                        NotiArr[0] = numNoticeCnt;
-                        DeviceLog("[mWallPadNotifyBR] define.DRIVER_ISD_NOTIINFO -> define.NOTIBR_ISD_NOTICECNT = " + numNoticeCnt);
-                    }
-                    else if (numNoticeCnt == 0) {
-                        NotiArr[0] = 0;
-                        DeviceLog("[mWallPadNotifyBR] define.DRIVER_ISD_NOTIINFO -> define.NOTIBR_ISD_NOTICECNT = " + numNoticeCnt);
-                    }
-                }
-
-                // 택배 정보 업데이트
-                if (intent.hasExtra(define.NOTIBR_ISD_PARCELCNT)) {
-                    int numParcelCnt = intent.getIntExtra(define.NOTIBR_ISD_PARCELCNT, 0);
-                    if (numParcelCnt != 0) {
-                        NotiArr[1] = numParcelCnt;
-                        DeviceLog("[mWallPadNotifyBR] define.DRIVER_ISD_NOTIINFO -> define.NOTIBR_ISD_PARCELCNT = " + numParcelCnt);
-                    }
-                    else if (numParcelCnt == 0) {
-                        NotiArr[1] = 0;
-                        DeviceLog("[mWallPadNotifyBR] define.DRIVER_ISD_NOTIINFO -> define.NOTIBR_ISD_PARCELCNT = " + numParcelCnt);
-                    }
-                }
-
-                // 방문자 정보 업데이트
-                if (intent.hasExtra(define.NOTIBR_ISD_VISITORCNT)) {
-                    int numVisitorCnt = intent.getIntExtra(define.NOTIBR_ISD_VISITORCNT, 0);
-                    if (numVisitorCnt != 0) {
-                        NotiArr[2] = numVisitorCnt;
-                        DeviceLog("[mWallPadNotifyBR] define.DRIVER_ISD_NOTIINFO -> define.NOTIBR_ISD_VISITORCNT = " + numVisitorCnt);
-                    }
-                    else if (numVisitorCnt == 0) {
-                        DeviceLog("[mWallPadNotifyBR] define.DRIVER_ISD_NOTIINFO -> define.NOTIBR_ISD_VISITORCNT = " + numVisitorCnt);
-                        DefaultVisitorCNT = 0;
-                        NotiArr[2] = 0;
-                    }
-                }
-
-                // 메모 정보 업데이트
-                if (intent.hasExtra(define.NOTIBR_ISD_MEMOCNT)) {
-                    int numMemoCnt = intent.getIntExtra(define.NOTIBR_ISD_MEMOCNT, 0);
-                    if (numMemoCnt != 0) {
-                        NotiArr[3] = numMemoCnt;
-                        DeviceLog("[mWallPadNotifyBR] define.DRIVER_ISD_NOTIINFO -> define.NOTIBR_ISD_MEMOCNT = " + numMemoCnt);
-                    }
-                    else if (numMemoCnt == 0) {
-                        DeviceLog("[mWallPadNotifyBR] define.DRIVER_ISD_NOTIINFO -> define.NOTIBR_ISD_MEMOCNT = " + numMemoCnt);
-                        DefaultMemoCNT = 0;
-                        NotiArr[3] = 0;
-                    }
-                }
-
-                // 초기 값과 현재 값 비교 (초기값: 부팅시, 이미 갖고 있던 값 / 현재값:intent로 받은 값)
-                if (isNotiDataChanged(NotiArr)) {
-                    mDriver.Polling.setNotiInfoUpdate(true);
-                    DeviceLog("[mWallPadNotifyBR] define.DRIVER_ISD_NOTIINFO -> isNotiDataChanged(NotiArr) = true");
-                }
-            }
-        }
-    };
-
-    private String NoTelemeteringValue = "NONE";
-    private String strElecUsage = NoTelemeteringValue;
-    private String strWaterUsage = NoTelemeteringValue;
-    private String strGasUsage = NoTelemeteringValue;
-    private String strHotwaterUsage = NoTelemeteringValue;
-    private String strHeatingUsage = NoTelemeteringValue;
-    private void procTelemeteringData(Intent mIntent) {
-        try {
-            DeviceLog("[procTelemeteringData] start");
-            String tempElect_used = mIntent.getStringExtra("elect_used");
-            if (tempElect_used != null) {
-                Log.i(TAG, "[procTelemeteringData] tempElect_used [" + tempElect_used + "]");
-                strElecUsage = tempElect_used;
-            }
-            else {
-                Log.w(TAG, "[procTelemeteringData] tempElect_used is null!!");
-            }
-
-            String tempWater_used = mIntent.getStringExtra("water_used");
-            if (tempWater_used != null) {
-                Log.i(TAG, "[procTelemeteringData] tempWater_used [" + tempWater_used + "]");
-                strWaterUsage = tempWater_used;
-            }
-            else {
-                Log.w(TAG, "[procTelemeteringData] tempElect_used is null!!");
-            }
-
-            String tempGas_used = mIntent.getStringExtra("gas_used");
-            if (tempGas_used != null) {
-                Log.i(TAG, "[procTelemeteringData] tempGas_used [" + tempGas_used + "]");
-                strGasUsage = tempGas_used;
-            }
-            else {
-                Log.w(TAG, "[procTelemeteringData] tempElect_used is null!!");
-            }
-            
-            String tempHotwater_used = mIntent.getStringExtra("hotwater_used");
-            if (tempHotwater_used != null) {
-                Log.i(TAG, "[procTelemeteringData] tempHotwater_used [" + tempHotwater_used + "]");
-                strHotwaterUsage = tempHotwater_used;
-            }
-            else {
-                Log.w(TAG, "[procTelemeteringData] tempElect_used is null!!");
-            }
-            
-            String tempHeating_used = mIntent.getStringExtra("heating_used");
-            if (tempHeating_used != null) {
-                Log.i(TAG, "[procTelemeteringData] tempHeating_used [" + tempHeating_used + "]");
-                strHeatingUsage = tempHeating_used;
-            }
-            else {
-                Log.w(TAG, "[procTelemeteringData] tempElect_used is null!!");
-            }
-
-            DeviceLog("[procTelemeteringData] strElecUsage [" + strElecUsage + "], strWaterUsage [" + strWaterUsage + "], strGasUsage [" + strGasUsage + "], strHotwaterUsage [" + strHotwaterUsage + "], strHeatingUsage [" + strHeatingUsage + "] ");
-            
-        } catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-        } catch (Exception e) {
-            Log.e(TAG, "[Exception] procTelemeteringData(Intent mIntent)");
-            //e.printStackTrace();
-            LogUtil.errorLogInfo("", TAG, e);
-        }
-    }
-
-    /**
-     * 로딩후 처음 폴링 시퀀스
-     */
-    @Override
-    protected void do_boot() {
-        driverInterOpAPI = new DriverInterOpAPI(MainHandler);
-    }
-
-    /**
-     * do_ctr : 폴링스케쥴러
-     */
-    @Override
-    protected void do_ctr() {
-        DeviceLog("Polling Status " + mDriver.Polling.Status);
-
-//        Log.w(TAG, "[do_ctr] Weather [" + mDriver.info.Support.Weather + "], Parking [" + mDriver.info.Support.Parking + "], Energy [" + mDriver.info.Support.Energy + "], NotiInfo [" + mDriver.info.Support.NotiInfo + "], HeatingInfo [" + mDriver.info.Support.HeatingInfo + "], bSubBatchOffDirCtrl [" + mDriver.bSubBatchOffDirCtrl + "]");
-
-        /////////////////////////////////////////////////////////////////////
-        // 1. First & FirstTimeOut - Polling
-        /////////////////////////////////////////////////////////////////////
-        if ((mDriver.Polling.Status == Driver.PollingList.STATUS.First) || (mDriver.Polling.Status == Driver.PollingList.STATUS.FirstTimeOut)) {
-            // 1.1. FirstTimeOut 체크
-            if (mDriver.Polling.Status == Driver.PollingList.STATUS.First) {
-                if (mDriver.Polling.SearchTryCount++ > MAX_SEARCH_COUNT) {
-                    mDriver.Polling.Status = Driver.PollingList.STATUS.FirstTimeOut;
-                    Log.i(TAG, "--------------------------------------------------");
-                    Log.i(TAG, "SearchDevice Fail... FirstTimeOut ");
-                    Log.i(TAG, "--------------------------------------------------");
-                    ServiceMain.deviceInitChecker.Remove(super.DeviceName);
-                }
-            }
-
-            // 1.2. 보드상태 가져오기
-            Info info = Send_GetBoardInfoRead();
-            if (info != null) {
-                mDriver.info = info;
-                Log.i(TAG, info.ToDebugString());
-                mDriver.Polling.Status = Driver.PollingList.STATUS.Normal;
-
-                ServiceMain.deviceInitChecker.Remove(super.DeviceName);
-
-                Device_BrRegistration();
-
-                if (mDriver.info.Support.Weather) mDriver.Polling.setWeatherUpdate(true);
-                if (mDriver.info.Support.Parking) mDriver.Polling.setParkingUpdate(true);
-                if (mDriver.info.Support.NotiInfo) mDriver.Polling.setNotiInfoUpdate(true);
-                if (mDriver.info.Support.HeatingInfo) mDriver.Polling.setHeatingInfoUpdate(true);
-
-                // 현산모델에서 일괄소등을 직접 제어하는경우에  [서브일괄소등 플래그] 를 설정한다.
-                if (Version.getGatewayUsage()) {
-                    if (mDriver.info.Support.BatchOffDirCtrl) {
-                        Log.i(TAG, "[do_ctr] bSubBatchOffDirCtrl  SETTING !!!");
-                        mDriver.bSubBatchOffDirCtrl = true;
-                    }
-                }
-            }
-        }
-        /////////////////////////////////////////////////////////////////////
-        // 2. Normal - Polling
-        /////////////////////////////////////////////////////////////////////
-        else if (mDriver.Polling.Status == Driver.PollingList.STATUS.Normal) {
-            long currentTimeMillis = 0;
-
-            // 2.1. 날씨정보 동기화
-            if (mDriver.info.Support.Weather) {
-                if (mDriver.Polling.getWeatherUpdate()) {
-                    int ret = WeatherUpdate();
-                    if(ret >= 0) mDriver.Polling.setWeatherUpdate(false);
-                    Sleep(100);
-                }
-            }
-
-            // 2.2. 주차정보 동기화
-            if (mDriver.info.Support.Parking) {
-                if (mDriver.Polling.getParkingUpdate()) {
-                    int ret = ParkingUpdate();
-                    if (ret >= 0) mDriver.Polling.setParkingUpdate(false);
-                    Sleep(100);
-                }
-            }
-
-            // 2.3. 에너지정보 동기화
-            if (mDriver.info.Support.Energy) {
-                currentTimeMillis = System.currentTimeMillis();
-                if (Math.abs(currentTimeMillis - mDriver.Polling.EnergySinkTick) > ENERGY_SYNC_TICK) {
-                    mDriver.Polling.EnergySinkTick = currentTimeMillis;
-                    updateEnergy();
-                    Sleep(100);
-                }
-            }
-
-            // 2.4 알림 정보
-            if (mDriver.info.Support.NotiInfo) {
-                if (mDriver.Polling.getNotiInfoUpdate()) {
-                    int ret = NotiInfoUpdate();
-                    //Log.i(TAG, "NotiInfo polling ret = " + ret);
-                    if (ret >= 0) {
-                        // 정상적으로 ret이 반환되면 ret == 0
-                        mDriver.Polling.setNotiInfoUpdate(false);
-                        //Log.i(TAG, "false NotiInfoUpdate = " + mDriver.Polling.getNotiInfoUpdate());
-                    }
-                    Sleep(100);
-                }
-            }
-
-            // 2.5 난방 정보
-            if (mDriver.info.Support.HeatingInfo) {
-                if (mDriver.Polling.getHeatingInfoUpdate()) {
-                    int ret = HeatingInfoUpdate();
-                    //Log.i(TAG, "HeatingInfo polling ret = " + ret);
-                    if (ret >= 0) {
-                        mDriver.Polling.setHeatingInfoUpdate(false);
-                        //Log.i(TAG, "false HeatingInfoUpdate = " + mDriver.Polling.getHeatingInfoUpdate());
-                    }
-                    Sleep(100);
-                }
-            }
-
-            // 2.6. 상태 동기화
-            currentTimeMillis = System.currentTimeMillis();
-//            Log.w(TAG, "[do_ctr] currentTimeMillis [" + currentTimeMillis + "], mDriver.Polling.StatusSinkTick [" + mDriver.Polling.StatusSinkTick + "]");
-//            Log.w(TAG, "[do_ctr] time [" + (Math.abs(currentTimeMillis - mDriver.Polling.StatusSinkTick) + "], STATUS_SYNC_TICK [" + STATUS_SYNC_TICK + "]"));
-            if (Math.abs(currentTimeMillis - mDriver.Polling.StatusSinkTick) > STATUS_SYNC_TICK) {
-                mDriver.Polling.StatusSinkTick = currentTimeMillis;
-                CtrlStatus ctrlStatus = new CtrlStatus();
-                Send_SetStatus(ctrlStatus);
-            }
-            // 2.7. 상태 읽기
-            else {
-                Send_GetStatus();
-            }
-
-            // 2.8. 서브일괄소등제어기 인경우,  메인일괄소등과 상태가 다를경우 동기화
-            if (mDriver.bSubBatchOffDirCtrl) {
-                if (mDriver.Polling.CheckAllLightSink()) {
-                    boolean MainAllLightStatus = driverInterOpAPI.getAllLight();
-                    boolean SmartSwAllLightStatus = false;
-                    if (mDriver.status.BatchOff.Now == 0x02) SmartSwAllLightStatus = true;
-
-                    if (MainAllLightStatus != SmartSwAllLightStatus) {
-                        Sleep(100);
-                        CtrlStatus ctrlStatus = new CtrlStatus();
-                        if (MainAllLightStatus) ctrlStatus.BatchOff = 0x02;
-                        else ctrlStatus.BatchOff = 0x01;
-
-                        Status status = Send_SetStatus(ctrlStatus);
-                        boolean bRet = false;
-                        if (status != null) bRet = true;
-
-                        Log.i(TAG, "[do_ctr] AllLightSink !!! (MainAllLightStatus:" + MainAllLightStatus + " , bRet:" + bRet + ")");
-                    }
-                }
-            }
-        }
-        else {
-            mDriver = new Driver();
-        }
-    }
-
-    ///////////////////////////////////////////////////////////////////////////////////////////////
-    // Ctrl
-    ///////////////////////////////////////////////////////////////////////////////////////////////
-    /**
-     * NoSink 제어
-     *
-     * @param StrArg
-     *
-     * @return
-     */
-    public String NoSinkCtrl(String StrArg) {
-        DeviceLog("[NoSinkCtrl] Start");
-
-        // 1. 디바이스 초기화시 에러리턴
-        if ((mDriver.Polling.Status == Driver.PollingList.STATUS.First) || (mDriver.Polling.Status == Driver.PollingList.STATUS.FirstTimeOut)) {
-            Log.w(TAG, "[NoSinkCtrl] - Not Yet !!!");
-            return "FAIL;" + APIErrorCode.DEVICEISNOTREADY;
-        }
-
-        CtrDevFormat ctrDevFormat = GetCtrDevParamParsing(StrArg, 5);
-        if (ctrDevFormat.ret != APIErrorCode.C_SUCCESS) {
-            Log.w(TAG, "[NoSinkCtrl] GetCtrDevParamParsing Error (ret:" + ctrDevFormat.ret + ")");
-            return "FAIL;" + APIErrorCode.DEFAULT_PARSING_ERR;
-        }
-
-        //////////////////////////////////////////////////////////
-        // Refresh : 데이터 갱신 (No Sink)
-        //////////////////////////////////////////////////////////
-        if (ctrDevFormat.CmdStr!=null && ctrDevFormat.CmdStr.equals("Refresh")) {
-            return RefreshResult();
-        }
-
-        return "FAIL;" + APIErrorCode.UNKNOWNCOMMAND;
-    }
-
-    /**
-     * do_ctrEmm : 싱크 제어
-     */
-    @Override
-    @SuppressLint("DefaultLocale")
-    protected String do_ctrEmm(DeviceCtrSHMem SHMem) {
-        DeviceLog("[do_ctrEmm] Start");
-        DeviceLog("cmd    : " + SHMem.cmd);
-        DeviceLog("StrArg : " + SHMem.StrArg);
-
-        // 1. 디바이스 초기화시 에러리턴
-        if ((mDriver.Polling.Status == Driver.PollingList.STATUS.First) || (mDriver.Polling.Status == Driver.PollingList.STATUS.FirstTimeOut)) {
-            Log.w(TAG, "[do_ctrEmm] - Not Yet !!!");
-            return SHMem.retVal = "FAIL;" + APIErrorCode.DEVICEISNOTREADY;
-        }
-
-        CtrDevFormat ctrDevFormat = GetCtrDevParamParsing(SHMem.StrArg, 5);
-        if (ctrDevFormat.ret != APIErrorCode.C_SUCCESS) {
-            Log.w(TAG, "[do_ctrEmm] GetCtrDevParamParsing Error (ret:" + ctrDevFormat.ret + ")");
-            return SHMem.retVal = "FAIL;" + APIErrorCode.DEFAULT_PARSING_ERR;
-        }
-
-        if(ctrDevFormat.CmdStr!=null)
-        {
-            //////////////////////////////////////////////////////////
-            // Refresh : 데이터 갱신 (Sink)
-            //////////////////////////////////////////////////////////
-            if (ctrDevFormat.CmdStr.equals("Refresh")) {
-                Status status = Send_GetStatus();
-                if (status != null) {
-                    return SHMem.retVal = RefreshResult();
-                }
-                else {
-                    return SHMem.retVal = "FAIL;" + APIErrorCode.DEVICEISNORESPONSE;
-                }
-            }
-            //////////////////////////////////////////////////////////
-            // SetAllLightOnOff : 일괄소등 제어 (Sink)
-            //////////////////////////////////////////////////////////
-            else if (ctrDevFormat.CmdStr.equals("SetAllLightOnOff")) {
-                // 일괄소등 직접제어가 아닌경우 제어할수 없음.
-                if (!mDriver.info.Support.BatchOffDirCtrl) {
-                    Log.w(TAG, "[do_ctrEmm] SetAllLightOnOff Not Support !!! (BatchOffDirCtrl=false)");
-                    return SHMem.retVal = "FAIL;" + APIErrorCode.NOT_SUPPORT;
-                }
-
-                // 서브 일괄소등제어 일 경우 내부 드라이버에서만 일괄소등제어처리.
-                if (mDriver.bSubBatchOffDirCtrl) {
-                    Log.w(TAG, "[do_ctrEmm] SetAllLightOnOff Not Support !!! (bSubBatchOffDirCtrl=true)");
-                    return SHMem.retVal = "FAIL;" + APIErrorCode.NOT_SUPPORT;
-                }
-
-                // 1. Param Check
-                byte ParamOnOff   = ctrDevFormat.param[0];
-
-                // 2. Make Packet Data
-                boolean OnOff = false;
-                if (ParamOnOff != 0x00) OnOff = true;
-
-                CtrlStatus ctrlStatus = new CtrlStatus();
-                if (OnOff) ctrlStatus.BatchOff = 0x02;
-                else ctrlStatus.BatchOff = 0x01;
-                Status status = Send_SetStatus(ctrlStatus);
-                if (status != null) {
-                    return SHMem.retVal = "SUCCESS";
-                }
-                else {
-                    return SHMem.retVal = "FAIL;" + APIErrorCode.DEVICEISNORESPONSE;
-                }
-            }
-            //////////////////////////////////////////////////////////
-
-        }
-
-        return SHMem.retVal = "UNKNOWNCMD";
-    }
-
-    ///////////////////////////////////////////////////////////////////////////////////////////////
-    // RefreshResult
-    ///////////////////////////////////////////////////////////////////////////////////////////////
-    /**
-     * Refresh 에 대한 응답포멧 정의
-     *
-     * @return (String) "SUCCESS; ..." 성공 , "FAIL; ... " 실패
-     */
-    private String RefreshResult() {
-        String result = null;
-
-        DeviceLog("RefreshResult call : ");
-
-        // 1. Check Polling Status
-        if ((mDriver.Polling.Status == Driver.PollingList.STATUS.First) || (mDriver.Polling.Status == Driver.PollingList.STATUS.FirstTimeOut)) {
-            result = "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
-            return result;
-        }
-
-        // 2. Param Range Check
-
-        // 3. Make Return String Format
-        try {
-            if (mDriver == null) return "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
-
-            boolean AllLightOnOff = false;
-            if (mDriver.status.BatchOff.Now == 0x02) AllLightOnOff = true;
-            else if (mDriver.status.BatchOff.Now == 0x01) AllLightOnOff = false;
-
-            /*
-             * [Format]
-             *
-             * SUCCESS       - (String) 성공
-             *
-             * AllLightOnOff  - (boolean) 일괄소등 상태 (true:일괄소등해제-조명ON , false:일괄소등-조명OFF)
-             */
-
-            result = APIErrorCode.SUCCESS + ";";
-            result += AllLightOnOff + ";";
-
-        } catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-            result = "FAIL;"+APIErrorCode.EXCEPTION;
-        } catch (Exception e) {
-            Log.e(TAG, "[Exception Error] RefreshResult");
-            //e.printStackTrace();
-            LogUtil.errorLogInfo("", TAG, e);
-            result = "FAIL;"+APIErrorCode.EXCEPTION;
-        }
-        DeviceLog("RefreshResult return : " + result);
-
-        return result;
-    }
-
-    ///////////////////////////////////////////////////////////////////////////////////////////////
-    // Protocol Command Send Func
-    ///////////////////////////////////////////////////////////////////////////////////////////////
-
-    /**
-     * 보드 상태 읽기 요청 응답.
-     *
-     * @return (Info) null - Error , Not null - OK
-     */
-    private Info Send_GetBoardInfoRead() {
-        DeviceLog("[Send_GetBoardInfoRead] Start");
-
-        // 1. In 파라미터 확인
-
-        // 2. 패킷 데이터 만들기
-        byte [] ReqData = null;
-
-        // 3. 데이터 전송 및 응답
-        byte [] Reply = SendNRead_Variable(DEVICE_ADDRESS, CMDList.Req.BOARD_INFO_RD, ReqData);
-
-        // 4. 수신데이터 파싱
-        //     4.1. Default Check
-        boolean bError = false;
-        byte LightCnt = 0;
-        while (true) {
-            if (Reply == null) {
-                DeviceLog("[Send_GetBoardInfoRead] Reply is null");
-                bError = true; break;
-            }
-
-            if (Reply.length == 1) {
-                if (Reply[0] == (byte)0x82) {
-                    Log.i(TAG, "[Send_GetBoardInfoRead] Device ReBoot Detect!!!");
-                    mDriver.Polling.Status = Driver.PollingList.STATUS.First;
-                    mDriver.Polling.StatusSinkTickReset();
-                    AddDoCount(true);
-                    return null;
-                }
-            }
-
-            if (Reply.length != 9) {
-                Log.w(TAG, "[Send_GetBoardInfoRead] Reply.length  fail ... " + Reply.length);
-                bError = true; break;
-            }
-
-            //     4.1. Details Data Check
-            //         - D1 : 조명개수
-            LightCnt = Reply[0];
-            if (!((LightCnt >= 0x00) && (LightCnt <= 0x04))) {
-                Log.w(TAG, "[Send_GetBoardInfoRead] D1:LightCnt  Out of Range !!! " + String.format("0x%02X", Reply[0]));
-                bError = true; break;
-            }
-
-            //         - D3 : 기능 제공 여부 2
-            if ((Reply[2] & (byte)(BIT5 | BIT6 | BIT7)) != 0x00) {
-                Log.w(TAG, "[Send_GetBoardInfoRead] D3:Unused Bit Set !!! " + String.format("0x%02X", Reply[2]));
-                bError = true; break;
-            }
-
-            //         - D5 : 펌웨어 Build Date (Month)
-            if (!((Reply[4] >= 0x01) && (Reply[4] <= 0x0C))) {
-                Log.w(TAG, "[Send_GetBoardInfoRead] Reply[4]  Out of Range !!! " + String.format("0x%02X", Reply[4]));
-                bError = true; break;
-            }
-
-            //         - D6 : 펌웨어 Build Date (Day)
-            if (!((Reply[5] >= 0x01) && (Reply[5] <= 0x1F))) {
-                Log.w(TAG, "[Send_GetBoardInfoRead] Reply[5]  Out of Range !!! " + String.format("0x%02X", Reply[5]));
-                bError = true; break;
-            }
-            break;
-        }
-
-        if (bError) {
-            AddDoCount(false);
-            return null;
-        }
-
-        AddDoCount(true);
-
-        // 5. Data return
-        Info info = new Info();
-
-        info.LightCnt = LightCnt;
-
-        if ((Reply[1] & BIT0) != 0x00) info.Support.Time = true;
-        else info.Support.Time = false;
-
-        if ((Reply[1] & BIT1) != 0x00) info.Support.Parking = true;
-        else info.Support.Parking = false;
-
-        if ((Reply[1] & BIT2) != 0x00) info.Support.Energy = true;
-        else info.Support.Energy = false;
-
-        if ((Reply[1] & BIT3) != 0x00) info.Support.Weather = true;
-        else info.Support.Weather = false;
-
-        if ((Reply[1] & BIT4) != 0x00) info.Support.BatchOff = true;
-        else info.Support.BatchOff = false;
-
-        if ((Reply[1] & BIT5) != 0x00) info.Support.Outing = true;
-        else info.Support.Outing = false;
-
-        if ((Reply[1] & BIT6) != 0x00) info.Support.Gas = true;
-        else info.Support.Gas = false;
-
-        if ((Reply[1] & BIT7) != 0x00) info.Support.Elevator = true;
-        else info.Support.Elevator = false;
-
-        if ((Reply[2] & BIT3) != 0x00) info.Support.HeatingInfo = true;
-        else info.Support.HeatingInfo = false;
-
-        if ((Reply[2] & BIT4) != 0x00) info.Support.NotiInfo = true;
-        else info.Support.NotiInfo = false;
-
-        if ((Reply[2] & BIT0) != 0x00) info.Support.BatchOffDirCtrl = true;
-        else info.Support.BatchOffDirCtrl = false;
-
-        if ((Reply[2] & BIT1) != 0x00) info.Support.NowWeather = true;
-        else info.Support.NowWeather = false;
-
-        if ((Reply[2] & BIT2) != 0x00) info.Support.ElevatorDir = true;
-        else info.Support.ElevatorDir = false;
-
-        info.FwVer_Year   = Reply[3];
-        info.FwVer_Month  = Reply[4];
-        info.FwVer_Day    = Reply[5];
-        info.FwVer_Number = Reply[6];
-
-        info.ProtocolVer_Main = Reply[7];
-        info.ProtocolVer_Sub  = Reply[8];
-
-        return info;
-    }
-
-    /**
-     * 보드 상태 읽기 요청 응답.
-     *
-     * @return (Status) null - Error , Not null - OK
-     */
-    private Status Send_GetStatus() {
-        DeviceLog("[Send_GetStatus] Start");
-
-        // 1. In 파라미터 확인
-
-        // 2. 패킷 데이터 만들기
-        byte [] ReqData = null;
-
-        // 3. 데이터 전송 및 응답
-        byte [] Reply = SendNRead_Variable(DEVICE_ADDRESS, CMDList.Req.GET_STATUS, ReqData);
-
-        // 4. 수신데이터 파싱
-        Status status = GetStatus_RepParsing(Reply);
-        if (status == null) {
-            DeviceLog("[Send_GetStatus] Reply is null");
-            if(mDriver.Polling.ReBootDetect) { mDriver.Polling.ReBootDetect = false; AddDoCount(true); }
-            else AddDoCount(false);
-            return null;
-        }
-        AddDoCount(true);
-        return status;
-    }
-
-    /**
-     * 제어 요청 수신 알림
-     *
-     * @return (Status) null - Error , Not null - OK
-     */
-    private Status Send_AckStatus(byte CtrlCnt, byte CtrlKind) {
-        DeviceLog("[Send_AckStatus] Start");
-
-        // 1. In 파라미터 확인
-        if ((CtrlCnt <= 0) || (CtrlCnt > 8)) {
-            Log.w(TAG, "[Send_AckStatus] param [CtrlCnt] Out of Range!!! " + CtrlCnt);
-            return null;
-        }
-
-        byte Cnt = 0;
-        for (int i=0 ; i<8 ; i++) {
-            if ((CtrlKind & BIT_ARRAY[i]) != 0x00) Cnt++;
-        }
-
-        if (CtrlCnt != Cnt) {
-            Log.w(TAG, "[Send_AckStatus] param [CtrlCnt & CtrlKind] Count Not Match !!! (CtrlCnt:" + CtrlCnt + ", CtrlKind:" + String.format("0x%02X", CtrlKind) + ")");
-            return null;
-        }
-
-        // 2. 패킷 데이터 만들기
-        byte [] ReqData = new byte [] { CtrlCnt, CtrlKind };
-
-        // 3. 데이터 전송 및 응답
-        byte [] Reply = SendNRead_Variable(DEVICE_ADDRESS, CMDList.Req.ACK_STATUS, ReqData);
-
-        // 4. 수신데이터 파싱
-        Status status = GetStatus_RepParsing(Reply);
-        if (status == null) {
-            DeviceLog("[Send_AckStatus] Reply is null");
-            if (mDriver.Polling.ReBootDetect) { mDriver.Polling.ReBootDetect = false; AddDoCount(true); }
-            else AddDoCount(false);
-            return null;
-        }
-        AddDoCount(true);
-        return status;
-    }
-
-    /**
-     * 기기 상태 변경 알림
-     *
-     * @param ctrlStatus     - (CtrlStatus) 제어용 클래스
-     *
-     * @return (Status) null - Error , Not null - OK
-     */
-    private Status Send_SetStatus(CtrlStatus ctrlStatus) {
-        DeviceLog("[Send_SetStatus] Start");
-        Log.w(TAG, "[Send_SetStatus] ========== 1 ==========");
-        // 1. In 파라미터 확인
-        if (ctrlStatus == null) {
-            Log.w(TAG, "[Send_SetStatus] param [ctrlStatus] is null!!!");
-            return null;
-        }
-
-        // 2. 패킷 데이터 만들기
-        byte [] ReqData = ctrlStatus.getByteArray();
-
-        // 3. 데이터 전송 및 응답
-        byte [] Reply = SendNRead_Variable(DEVICE_ADDRESS, CMDList.Req.SET_STATUS, ReqData);
-
-        // 4. 수신데이터 파싱
-        Status status = GetStatus_RepParsing(Reply);
-        if (status == null) {
-            DeviceLog("[Send_SetStatus] Reply is null");
-            if (mDriver.Polling.ReBootDetect) { mDriver.Polling.ReBootDetect = false; AddDoCount(true); }
-            else AddDoCount(false);
-            return null;
-        }
-        AddDoCount(true);
-        return status;
-    }
-
-
-    /**
-     * 날씨정보 알림
-     *
-     * @param ReqData - (byte) 날씨정보알림 데이터
-     *
-     * @return (Info) null - Error , Not null - OK
-     */
-    private Status Send_SetWeather(byte [] ReqData) {
-        DeviceLog("[Send_SetWeather] Start");
-
-        // 1. In 파라미터 확인
-        if (ReqData == null) {
-            Log.w(TAG, "[Send_SetWeather] param [ReqData] is null!!!");
-            return null;
-        }
-
-        int length = 10;
-        if (mDriver.info.Support.NowWeather) length = 11;
-        if (ReqData.length != length) {
-            Log.w(TAG, "[Send_SetWeather] param [ReqData.length] is length Not Match!!! (length:" + ReqData.length + ")");
-            return null;
-        }
-
-        // 2. 패킷 데이터 만들기
-
-        // 3. 데이터 전송 및 응답
-        byte [] Reply = SendNRead_Variable(DEVICE_ADDRESS, CMDList.Req.SET_WEATHER, ReqData);
-
-        // 4. 수신데이터 파싱
-        Status status = GetStatus_RepParsing(Reply);
-        if (status == null) {
-            DeviceLog("[Send_SetWeather] Reply is null");
-            if (mDriver.Polling.ReBootDetect) { mDriver.Polling.ReBootDetect = false; AddDoCount(true); }
-            else AddDoCount(false);
-            return null;
-        }
-
-        AddDoCount(true);
-        return status;
-    }
-
-
-    /**
-     * 주차정보 알림
-     *
-     * @param ReqData - (byte) 주차 데이터
-     *
-     * @return (Info) null - Error , Not null - OK
-     */
-    private Status Send_SetParking(byte [] ReqData) {
-        DeviceLog("[Send_SetParking] Start");
-
-        // 1. In 파라미터 확인
-        if (ReqData == null) {
-            Log.w(TAG, "[Send_SetParking] param [ReqData] is null!!!");
-            return null;
-        }
-        //        if(ReqData.length != 10)
-        //        {
-        //            Log.w(TAG, "[Send_SetParking] param [ReqData.length] is length Not Match!!! (length:" + ReqData.length + ")");
-        //            return null;
-        //        }
-
-        // 2. 패킷 데이터 만들기
-
-        // 3. 데이터 전송 및 응답
-        byte [] Reply = SendNRead_Variable(DEVICE_ADDRESS, CMDList.Req.SET_PARKING, ReqData);
-
-        // 4. 수신데이터 파싱
-        Status status = GetStatus_RepParsing(Reply);
-        if (status == null) {
-            DeviceLog("[Send_SetParking] Reply is null");
-            if (mDriver.Polling.ReBootDetect) { mDriver.Polling.ReBootDetect = false; AddDoCount(true); }
-            else AddDoCount(false);
-            return null;
-        }
-
-        AddDoCount(true);
-        return status;
-    }
-
-    /**
-     * 에너지정보 알림
-     *
-     * @param ReqData - (byte) 에너지데이터
-     *
-     * @return (Info) null - Error , Not null - OK
-     */
-    private Status Send_SetEnergy(byte [] ReqData) {
-        DeviceLog("[Send_SetEnergy] Start");
-
-        // 1. In 파라미터 확인
-        if (ReqData == null) {
-            Log.w(TAG, "[Send_SetEnergy] param [ReqData] is null!!!");
-            return null;
-        }
-        //        if(ReqData.length != 10)
-        //        {
-        //            Log.w(TAG, "[Send_SetParking] param [ReqData.length] is length Not Match!!! (length:" + ReqData.length + ")");
-        //            return null;
-        //        }
-
-        // 2. 패킷 데이터 만들기
-
-        // 3. 데이터 전송 및 응답
-        byte [] Reply = SendNRead_Variable(DEVICE_ADDRESS, CMDList.Req.SET_ENERGY, ReqData);
-
-        // 4. 수신데이터 파싱
-        Status status = GetStatus_RepParsing(Reply);
-        if (status == null) {
-            DeviceLog("[Send_SetEnergy] Reply is null");
-            if (mDriver.Polling.ReBootDetect) { mDriver.Polling.ReBootDetect = false; AddDoCount(true); }
-            else AddDoCount(false);
-            return null;
-        }
-        AddDoCount(true);
-        return status;
-    }
-
-    /**
-     * 알림정보 알림
-     *
-     * @param ReqData - (byte) 알림 데이터
-     *
-     * @return (Info) null - Error , Not null - OK
-     */
-    private Status Send_SetNotiInfo(byte[] ReqData) {
-        DeviceLog("[Send_SetNotiInfo] Start");
-
-        // 1. In 파라미터 확인
-        if (ReqData == null) {
-            Log.w(TAG, "[Send_SetNotiInfo] param [ReqData] is null!!!");
-            return null;
-        }
-        // 2. 패킷 데이터 만들기
-
-        // 3. 데이터 전송 및 응답
-        byte[] Reply = SendNRead_Variable(DEVICE_ADDRESS, CMDList.Req.SET_NotiInfo, ReqData);
-
-        // 4. 수신데이터 파싱
-        Status status = GetStatus_RepParsing(Reply);
-        if (status == null) {
-            DeviceLog("[Send_SetNotiInfo] Reply is null");
-            if (mDriver.Polling.ReBootDetect) { mDriver.Polling.ReBootDetect = false; AddDoCount(true); }
-            else AddDoCount(false);
-
-            return null;
-        }
-
-        AddDoCount(true);
-        return status;
-    }
-
-    /**
-     * 난방정보 알림
-     *
-     * @param ReqData - (byte) 난방 데이터
-     *
-     * @return (Info) null - Error , Not null - OK
-     */
-    private Status Send_SetHeatingInfo(byte[] ReqData) {
-        DeviceLog("[Send_SetHeatingInfo] Start");
-
-        // 1. In 파라미터 확인
-        if (ReqData == null) {
-            Log.w(TAG, "[Send_SetHeatingInfo] param [ReqData] is null!!!");
-            return null;
-        }
-        // 2. 패킷 데이터 만들기
-
-        // 3. 데이터 전송 및 응답
-        byte[] Reply = SendNRead_Variable(DEVICE_ADDRESS, CMDList.Req.SET_HeatingInfo, ReqData);
-
-        // 4. 수신데이터 파싱
-        Status status = GetStatus_RepParsing(Reply);
-        if (status == null) {
-            DeviceLog("[Send_SetHeatingInfo] Reply is null");
-            if (mDriver.Polling.ReBootDetect) { mDriver.Polling.ReBootDetect = false; AddDoCount(true); }
-            else AddDoCount(false);
-
-            return null;
-        }
-
-        AddDoCount(true);
-        return status;
-    }
-
-
-
-
-    /**
-     * {@link #Send_AckStatus(byte, byte)} <br>
-     * {@link #Send_GetStatus()} <br>
-     * {@link #Send_SetEnergy(byte[])} <br>
-     * {@link #Send_SetParking(byte[])} <br>
-     * {@link #Send_SetStatus(CtrlStatus)} <br>
-     * {@link #Send_SetWeather(byte[])} <br>
-     * 메소드의 응답 공통부분 메소드이다.
-     *
-     * @param Reply     - (byte []) 응답 Byte 배열
-     *
-     * @return (Status) null - Error , Not null - OK
-     */
-    private Status GetStatus_RepParsing(byte [] Reply) {
-        // 1. 수신데이터 파싱
-        //     1.1. Default Check
-        if (Reply == null) {
-            DeviceLog("[GetStatus_RepParsing] Reply is null");
-            return null;
-        }
-
-        if (Reply.length == 1) {
-            if (Reply[0] == (byte) 0x82) {
-                Log.i(TAG, "[GetStatus_RepParsing] Device ReBoot Detect!!!");
-                mDriver.Polling.Status = Driver.PollingList.STATUS.First;
-                mDriver.Polling.StatusSinkTickReset();
-                mDriver.Polling.ReBootDetect = true;
-                return null;
-            }
-        }
-
-        if (Reply.length < 5) {
-            Log.w(TAG, "[GetStatus_RepParsing] Reply.length  fail #1 ... " + Reply.length);
-            return null;
-        }
-
-        byte LightCnt = Reply[4];
-        if (Reply.length != (int)(5 + LightCnt)) {
-            Log.w(TAG, "[GetStatus_RepParsing] Reply.length  fail #2 ... " + Reply.length + " / LightCnt : " + LightCnt);
-            return null;
-        }
-
-        //     1.2. Details Data Check
-        for (int i = 0; i<Reply.length; i++) {
-            //          - D5 : 엘리베이터 정보
-            if (i==4) {
-                if (!((Reply[i] >= 0x00) && (Reply[i] <= 0x04))) {
-                    Log.w(TAG, "[GetStatus_RepParsing] D5:LightCnt  Out of Range !!! " + String.format("0x%02X", Reply[i]));
-                    return null;
-                }
-            }
-            //          - D1~D4 , D6~D9 : 각 버튼 정보
-            else {
-                if ((Reply[i] & (byte)(BIT2 | BIT3 | BIT6 )) != 0x00) {
-                    Log.w(TAG, "[GetStatus_RepParsing] D" + (i+1) + ":Unused Bit Set !!! " + String.format("0x%02X", Reply[i]));
-                    return null;
-                }
-            }
-        }
-
-        // 2. Data return
-        Status status = new Status();
-
-        status.Elevator.Now  = ConvertNowData(Reply[0]);
-        status.Elevator.Ctrl = ConvertCtrlData(Reply[0]);
-
-        status.Gas.Now       = ConvertNowData(Reply[1]);
-        status.Gas.Ctrl      = ConvertCtrlData(Reply[1]);
-
-        status.Outing.Now    = ConvertNowData(Reply[2]);
-        status.Outing.Ctrl   = ConvertCtrlData(Reply[2]);
-
-        status.BatchOff.Now  = ConvertNowData(Reply[3]);
-        status.BatchOff.Ctrl = ConvertCtrlData(Reply[3]);
-
-        status.HeatingInfo.Now = ConvertNowHeatingInfoData(Reply[3]);
-        status.HeatingInfo.Ctrl = ConvertCtrlHeatingInfoData(Reply[3]);
-        //Log.i(TAG, "[GetStatus_RepParsing] - HeatingInfo.Ctrl = " + status.HeatingInfo.Ctrl);
-
-        status.LightCnt = LightCnt;
-
-        if (LightCnt > 0) {
-            status.L1.Now  = ConvertNowData(Reply[5]);
-            status.L1.Ctrl = ConvertCtrlData(Reply[5]);
-        }
-
-        if (LightCnt > 1) {
-            status.L2.Now  = ConvertNowData(Reply[6]);
-            status.L2.Ctrl = ConvertCtrlData(Reply[6]);
-        }
-
-        if (LightCnt > 2) {
-            status.L3.Now  = ConvertNowData(Reply[7]);
-            status.L3.Ctrl = ConvertCtrlData(Reply[7]);
-        }
-
-        if (LightCnt > 3) {
-            status.L4.Now  = ConvertNowData(Reply[8]);
-            status.L4.Ctrl = ConvertCtrlData(Reply[8]);
-        }
-
-        UpdateVariables(status);
-
-        return status;
-    }
-
-    public byte ConvertNowData(byte data)  { return (byte)((data>>0) & (byte)(BIT0 | BIT1)); }
-    public byte ConvertCtrlData(byte data) { return (byte)((data>>4) & (byte)(BIT0 | BIT1)); }
-    public byte ConvertNowHeatingInfoData(byte data) { return (byte)((data>>4) & (byte)(BIT2 | BIT3));}
-    public byte ConvertCtrlHeatingInfoData(byte data) { return (byte)((data>>4) & (byte)(BIT2 | BIT3));}
-
-    /**
-     * 명령어 리스트
-     */
-    public static class CMDList {
-        public static final class Req {
-            /////////////////////////////////////////////////////////
-            // Board
-            /////////////////////////////////////////////////////////
-            /** 기기 상태 읽기 */
-            public final static byte BOARD_INFO_RD        = 0x01;
-
-            /////////////////////////////////////////////////////////
-            // Status
-            /////////////////////////////////////////////////////////
-            /** 기기 상태 요청 */
-            public final static byte GET_STATUS           = 0x11;
-
-            /** 스마트스위치 제어 요청 수신 알림 */
-            public final static byte ACK_STATUS           = 0x12;
-            ;
-            /** 기기 상태 변경 알림 */
-            public final static byte SET_STATUS           = 0x13;
-
-
-            /////////////////////////////////////////////////////////
-            // Weather
-            /////////////////////////////////////////////////////////
-            /** 날씨정보 알림 */
-            public final static byte SET_WEATHER          = 0x21;
-
-            /** 주차정보 알림 */
-            public final static byte SET_PARKING          = 0x22;
-
-            /** 에너지 정보 알림 */
-            public final static byte SET_ENERGY           = 0x23;
-
-            /** 알림 정보 알림   */
-            public final static byte SET_NotiInfo		  = 0x24;
-
-            /** 난방 정보 알림   */
-            public final static byte SET_HeatingInfo	  = 0x25;
-        }
-    }
-
-    /**
-     * 변동 데이터 처리부
-     *
-     * @param status - (Status) 신규 데이터
-     *
-     * @return (boolean) 데이터 변동여부 true : 변동 , false : 변동없음
-     */
-    private boolean UpdateVariables(Status status) {
-        // 1. 제어 요청 체크
-        byte CtrlKind = 0x00;
-        byte CtrlCnt = 0x00;
-
-        if (mDriver.info.Support.HeatingInfo) {
-            // Heating packet은 10XX/00XX임으로 0x80,81,82,90,91,92,A0,A1,A2로 확인
-            if (status.HeatingInfo.Ctrl == 0x08) {
-                mDriver.Polling.setHeatingInfoUpdate(true);
-            }
-            else {
-
-            }
-        }
-
-        if (mDriver.info.Support.Elevator) {
-            if (status.Elevator.Ctrl != 0x00) {
-                // 엘리베이터 요청
-                DeviceLog("UpdateVariables - Elevator.Ctrl : " + String.format("0x%02X", status.Elevator.Ctrl));
-
-                CtrlKind |= BIT7;
-                CtrlCnt++;
-
-                switch (status.Elevator.Ctrl) {
-                    case 0x01:
-                        // 하향호출
-                        Log.i(TAG, "[UpdateVariables] - ElevatorCtr 0x01");
-                        ElevatorCall(false);
-                        break;
-
-                    case 0x02:
-                        // 상향호출
-                        Log.i(TAG, "[UpdateVariables] - ElevatorCtr 0x02");
-                        ElevatorCall(true);
-                        break;
-
-                    case 0x03:
-                        // 상,하향 호출
-                        Log.i(TAG, "[UpdateVariables] - ElevatorCtr 0x03");
-                        ElevatorCall(false);
-                        ElevatorCall(true);
-                        break;
-                }
-            }
-        }
-
-        if (mDriver.info.Support.Gas) {
-            if (status.Gas.Ctrl != 0x00) {
-                if (status.Gas.Ctrl == 0x01) {
-                    // 가스제어 요청
-                    DeviceLog("UpdateVariables - Gas.Ctrl : " + String.format("0x%02X", status.Gas.Ctrl));
-
-                    CtrlKind |= BIT6;
-                    CtrlCnt++;
-
-                    int ret = driverInterOpAPI.Gas_SetClose(ServiceMain.MSG_DEV_CTR);
-                    DeviceLog("[UpdateVariables] Gas_SetClose() - " + ret);
-                }
-            }
-        }
-
-        if (mDriver.info.Support.Outing) {
-            if (status.Outing.Ctrl != 0x00) {
-                // 외출설정 요청
-                DeviceLog("UpdateVariables - Outing.Ctrl : " + String.format("0x%02X", status.Outing.Ctrl));
-
-                CtrlKind |= BIT5;
-                CtrlCnt++;
-
-                switch (status.Outing.Ctrl) {
-                    case 0x01:
-                        // 외출설정
-                        Log.i(TAG, "SendNotifyKindBR(NOTIFY_SMARTSW_SET_OUTING)");
-                        super.SendNotifyKindBR(define.NOTIFY_SMARTSW_SET_OUTING);
-                        break;
-
-                    case 0x02:
-                        // 외출해제
-                        Log.i(TAG, "SendNotifyKindBR(NOTIFY_SMARTSW_FREE_OUTING)");
-                        super.SendNotifyKindBR(define.NOTIFY_SMARTSW_FREE_OUTING);
-                        break;
-                }
-            }
-        }
-
-        if (mDriver.info.Support.BatchOff) {
-            if (!mDriver.info.Support.BatchOffDirCtrl) {
-                if (status.BatchOff.Ctrl != 0x00) {
-                    // 일괄소등 요청
-                    Log.i(TAG, "UpdateVariables - BatchOff.Ctrl : " + String.format("0x%02X", status.BatchOff.Ctrl));
-
-                    CtrlKind |= BIT4;
-                    CtrlCnt++;
-
-                    switch (status.BatchOff.Ctrl) {
-                        case 0x01:
-                            // 일괄소등
-                            driverInterOpAPI.setAllLight(false);
-                            break;
-
-                        case 0x02:
-                            // 일괄소등 해제
-                            driverInterOpAPI.setAllLight(true);
-                            break;
-                    }
-                }
-            }
-        }
-
-        if (mDriver.info.LightCnt > 0) {
-            if (status.L1.Ctrl != 0x00) {
-                // L1 제어 요청
-                DeviceLog("UpdateVariables - L1.Ctrl : " + String.format("0x%02X", status.L1.Ctrl));
-
-                CtrlKind |= BIT3;
-                CtrlCnt++;
-                int ret = 0;
-                switch (status.L1.Ctrl) {
-                    case 0x01:
-                        // 켜짐
-                        ret = driverInterOpAPI.setLight(ServiceMain.MSG_DEV_CTR, mDriver.L1Map+1, true);
-                        DeviceLog("[UpdateVariables] driverInterOpAPI.setLight(" + (int)(mDriver.L1Map+1) + ", " + "true)" + " = ret :" + ret);
-                        if(ret < 0) Log.w(TAG, "[UpdateVariables] driverInterOpAPI.setLight - ret Error : ret:" + ret);
-                        break;
-
-                    case 0x02:
-                        // 꺼짐
-                        ret = driverInterOpAPI.setLight(ServiceMain.MSG_DEV_CTR, mDriver.L1Map+1, false);
-                        DeviceLog("[UpdateVariables] driverInterOpAPI.setLight(" + (int)(mDriver.L1Map+1) + ", " + "false)" + " = ret :" + ret);
-                        if(ret < 0) Log.w(TAG, "[UpdateVariables] driverInterOpAPI.setLight - ret Error : ret:" + ret);
-                        break;
-                }
-            }
-        }
-
-        if (mDriver.info.LightCnt > 1) {
-            if (status.L2.Ctrl != 0x00) {
-                // L2 제어 요청
-                DeviceLog("UpdateVariables - L2.Ctrl : " + String.format("0x%02X", status.L2.Ctrl));
-
-                CtrlKind |= BIT2;
-                CtrlCnt++;
-                int ret = 0;
-                switch (status.L2.Ctrl) {
-                    case 0x01:
-                        // 켜짐
-                        ret = driverInterOpAPI.setLight(ServiceMain.MSG_DEV_CTR, mDriver.L2Map+1, true);
-                        DeviceLog("[UpdateVariables] driverInterOpAPI.setLight(" + (int)(mDriver.L2Map+1) + ", " + "true)" + " = ret :" + ret);
-                        if(ret < 0) Log.w(TAG, "[UpdateVariables] driverInterOpAPI.setLight - ret Error : ret:" + ret);
-                        break;
-
-                    case 0x02:
-                        // 꺼짐
-                        ret = driverInterOpAPI.setLight(ServiceMain.MSG_DEV_CTR, mDriver.L2Map+1, false);
-                        DeviceLog("[UpdateVariables] driverInterOpAPI.setLight(" + (int)(mDriver.L1Map+1) + ", " + "false)" + " = ret :" + ret);
-                        if(ret < 0) Log.w(TAG, "[UpdateVariables] driverInterOpAPI.setLight - ret Error : ret:" + ret);
-                        break;
-                }
-            }
-        }
-
-        if (mDriver.info.LightCnt > 2) {
-            if (status.L3.Ctrl != 0x00) {
-                // L3 제어 요청
-                DeviceLog("UpdateVariables - L3.Ctrl : " + String.format("0x%02X", status.L3.Ctrl));
-
-                CtrlKind |= BIT1;
-                CtrlCnt++;
-
-                switch (status.L3.Ctrl) {
-                    case 0x01:
-                        // 켜짐
-                        break;
-
-                    case 0x02:
-                        // 꺼짐
-                        break;
-                }
-            }
-        }
-
-        if (mDriver.info.LightCnt > 3) {
-            if (status.L4.Ctrl != 0x00) {
-                // L4 제어 요청
-                DeviceLog("UpdateVariables - L4.Ctrl : " + String.format("0x%02X", status.L4.Ctrl));
-
-                CtrlKind |= BIT0;
-                CtrlCnt++;
-
-                switch (status.L4.Ctrl) {
-                    case 0x01:
-                        // 켜짐
-                        break;
-
-                    case 0x02:
-                        // 꺼짐
-                        break;
-                }
-            }
-        }
-
-        if (CtrlCnt > 0) {
-            for (int i = 0; i < 3; i++) {
-                // 제어 요청 수신 알림
-                Status AckStatus = Send_AckStatus(CtrlCnt, CtrlKind);
-                if (AckStatus != null) {
-                    status = AckStatus;
-                    break;
-                }
-            }
-        }
-
-        // 2. 변동 데이터 체크
-        boolean bChanged = false;
-        if (status.Elevator.Now != mDriver.status.Elevator.Now) bChanged = true;
-        if (status.Gas.Now != mDriver.status.Gas.Now) bChanged = true;
-        if ((status.BatchOff.Now != mDriver.status.BatchOff.Now) || !(mDriver.bFirstBatchOffBRSend)) {
-            bChanged = true;
-
-            if (mDriver.info.Support.BatchOffDirCtrl) {
-                // 서브일괄소등이면서, 최초가 아닌경우에 일괄소등상태가 변경되면 메인 일괄소등제어기 제어
-                if (mDriver.bSubBatchOffDirCtrl) {
-                    if (mDriver.bFirstBatchOffBRSend) {
-                        if (status.BatchOff.Now == 0x02) {
-                            // 일괄소등 해제
-                            if (driverInterOpAPI.getAllLight() != true) {
-                                driverInterOpAPI.setAllLight(true);
-                                mDriver.Polling.SetAllLightSinkDelay();
-                                Log.i(TAG, "Change BatchOff.Now Status : bSubBatchOffDirCtrl - setAllLight(true)");
-                            }
-                        }
-                        else if (status.BatchOff.Now == 0x01) {
-                            // 일괄소등
-                            if (driverInterOpAPI.getAllLight() != false) {
-                                driverInterOpAPI.setAllLight(false);
-                                mDriver.Polling.SetAllLightSinkDelay();
-                                Log.i(TAG, "Change BatchOff.Now Status : bSubBatchOffDirCtrl - setAllLight(false)");
-                            }
-                        }
-                    }
-                }
-                else {
-                    int kind = 0;
-                    if (status.BatchOff.Now == 0x02) {
-                        kind = define.NOTIFY_ALL_LIGHT_ON;
-                        Log.i(TAG, "SendNotifyKindBR(NOTIFY_ALL_LIGHT_ON)");
-                    }
-                    else if (status.BatchOff.Now == 0x01) {
-                        kind = define.NOTIFY_ALL_LIGHT_OFF;
-                        Log.i(TAG, "SendNotifyKindBR(NOTIFY_ALL_LIGHT_OFF)");
-                    }
-
-                    if (kind != 0) SendNotifyKindBR(kind);
-                }
-            }
-            mDriver.bFirstBatchOffBRSend = true;
-        }
-
-        if (status.Outing.Now != mDriver.status.Outing.Now) bChanged = true;
-        if (status.LightCnt != mDriver.status.LightCnt) bChanged = true;
-
-        byte LightCnt = status.LightCnt;
-        if (LightCnt > 0) {
-            if (status.L1.Now != mDriver.status.L1.Now) bChanged = true;
-            if (LightCnt >= 2) {
-                if (status.L2.Now != mDriver.status.L2.Now) bChanged = true;
-                if (LightCnt >= 3) {
-                    if (status.L3.Now != mDriver.status.L3.Now) bChanged = true;
-                    if (LightCnt >= 4) {
-                        if(status.L4.Now != mDriver.status.L4.Now) bChanged = true;
-                    }
-                }
-            }
-        }
-
-        if (bChanged) {
-            DeviceLog("UpdateVariables Status Changed!!!");
-            DeviceLog(mDriver.status.ToDebugString("OLD"));
-            DeviceLog(status.ToDebugString("NEW"));
-
-            mDriver.status = status;
-            return true;
-        }
-
-        return false;
-    }
-
-    /**
-     * iMAP을 통하여 전달받은 날씨정보를 스마트스위치에<br>
-     * 전송할 데이터로 변환한다.
-     *
-     * @param code - (String) iMAP에서 전달받은 날씨데이터
-     * @return (byte) 스마트스위치에 전송할 날씨데이터
-     */
-    private byte GetWeatherCode(String code) {
-        if (mDriver.TargetModel == WallpadDeviceSet.BATCH_TYPE_HDC_LCD_SMART) {
-            return GetWeatherCode_iSS430(code);
-        }
-        else {
-            return GetWeatherCode_iSS201(code);
-        }
-    }
-
-    /**
-     * 모델명 : iSS430 의 날씨 데이터 변환
-     *
-     * @param code - (String) iMAP에서 전달받은 날씨데이터
-     * @return (byte) 스마트스위치에 전송할 날씨데이터
-     */
-    private byte GetWeatherCode_iSS430(String code) {
-        //X‘00’ (정보 없음), X‘01’ (맑음), X‘02’ (구름 조금), X‘03’ (구름 많음) X‘04’ (흐림), X‘05’ (비), X‘06’ (비 또는 흐림), X‘07’ (눈), X‘08’ (비 또는 눈)
-        try {
-            int Tcode = Integer.parseInt(code);
-            switch (Tcode) {
-                case 1:
-                    return 0x01;
-                case 2:
-                case 3:
-                case 5:
-                case 6:
-                    return 0x02;
-                case 4:
-                    return 0x03;
-                case 7:
-                case 8:
-                case 9:
-                case 15:
-                case 16:
-                case 17:
-                    return 0x05;
-                case 10:
-                case 11:
-                case 12:
-                case 13:
-                case 14:
-                    return 0x06;
-                case 18:
-                case 19:
-                case 20:
-                case 21:
-                case 22:
-                case 23:
-                case 24:
-                case 25:
-                    return 0x07;
-                case 26:
-                case 27:
-                case 28:
-                case 29:
-                case 30:
-                case 31:
-                case 32:
-                case 33:
-                case 34:
-                case 35:
-                case 36:
-                case 37:
-                case 38:
-                    return 0x08;
-                case 39:
-                    return 0x09;
-                case 40:
-                    return 0x0A;
-                case 41:
-                    return 0x0B;
-                default:
-                    break;
-            }
-        } catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-            return (byte)0x00;
-        } catch (Exception e) {
-            Log.e(TAG, "[Exception Error] GetWeatherCode_iSS430");
-            //e.printStackTrace();
-            LogUtil.errorLogInfo("", TAG, e);
-            return (byte)0x00;
-        }
-        return (byte)0x00;
-    }
-
-    /**
-     * 모델명 : iSS201 의 날씨 데이터 변환
-     *
-     * @param code - (String) iMAP에서 전달받은 날씨데이터
-     * @return (byte) 스마트스위치에 전송할 날씨데이터
-     */
-    private byte GetWeatherCode_iSS201(String code) {
-        //X‘00’ (정보 없음), X‘01’ (맑음), X‘02’ (구름 조금), X‘03’ (구름 많음) X‘04’ (흐림), X‘05’ (비), X‘06’ (비 또는 흐림), X‘07’ (눈), X‘08’ (비 또는 눈)
-        try {
-            int Tcode = Integer.parseInt(code);
-            switch (Tcode) {
-                case 1:
-                    return 0x01;
-                case 2:
-                case 3:
-                case 5:
-                case 6:
-                    return 0x02;
-                case 4:
-                    return 0x03;
-                case 40:
-                case 41:
-                    return 0x04;
-                case 7:
-                case 8:
-                case 9:
-                case 15:
-                case 16:
-                case 17:
-                case 39:
-                    return 0x05;
-                case 10:
-                case 11:
-                case 12:
-                case 13:
-                case 14:
-                    return 0x06;
-                case 18:
-                case 19:
-                case 20:
-                case 21:
-                case 22:
-                case 23:
-                case 24:
-                case 25:
-                    return 0x07;
-                case 26:
-                case 27:
-                case 28:
-                case 29:
-                case 30:
-                case 31:
-                case 32:
-                case 33:
-                case 34:
-                case 35:
-                case 36:
-                case 37:
-                case 38:
-                    return 0x08;
-                default:
-                    break;
-            }
-        } catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-            return (byte)0x00;
-        } catch (Exception e) {
-            Log.e(TAG, "[Exception Error] GetWeatherCode_iSS201");
-            //e.printStackTrace();
-            LogUtil.errorLogInfo("", TAG, e);
-            return (byte)0x00;
-        }
-        return (byte)0x00;
-    }
-
-    /**
-     * String Type 온도정보를 byte Type 으로 변환한다.
-     *
-     * @param TEMP - (String) 온도
-     * @return (byte) 변환된 온도
-     */
-    private byte GetTemp(String TEMP) {
-        if (TEMP==null) return (byte)0xFF;
-
-        try {
-            int temp = Integer.parseInt(TEMP);
-            byte retval = 0;
-            if (temp < 0) {
-                retval = (byte)(temp*(-1));
-                retval|=(byte)(0x80);
-            }
-            else {
-                retval = (byte)temp;
-            }
-            return retval;
-        } catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-            return (byte)0x00;
-        } catch (Exception e) {
-            //e.printStackTrace();
-            LogUtil.errorLogInfo("", TAG, e);
-            return (byte)0x00;
-        }
-    }
-
-    /**
-     * 날씨정보 동기화<br>
-     * DB에 저장되어있는 날씨 정보를 가져와서 스마트스위치에 전송한다.
-     *
-     * @return (int) - >=0 : 성공, <0 : 실패
-     */
-    private int WeatherUpdate() {
-        DeviceLog("WeatherUpdate");
-
-        try {
-            WallpadStatusData DBMGR = new WallpadStatusData(ServiceMain.svcContext);
-            String[] WeatherVer = DBMGR.GetWeatherVer().split(define.DEVCTR_DATA_SPLITER);
-            WeatherTable WeatherTBL = DBMGR.GetWeatherTableController();
-            WeatherTBL.GetWeatherList();
-            DBMGR.closeDB();
-
-            String[] weatherdate = WeatherVer[0].split("[.]");
-            if (weatherdate.length < 4 || WeatherVer.length < 3) return -1;
-
-            byte [] ReqData = null;
-            if (mDriver.info.Support.NowWeather) {
-                // 현재 날씨 정보를 지원하는 경우
-                ReqData = new byte[11];
-                //Log.i(TAG, "mDriver.info.Support.NowWeather = true!!!");
-            }
-            else {
-                // 현재 날씨 정보를 지원하지 않는경우
-                ReqData = new byte[10];
-                //Log.i(TAG, "mDriver.info.Support.NowWeather = false!!!");
-            }
-
-            for (int i = 0; i<ReqData.length; i++) ReqData[i] = 0x00;
-
-            Calendar cal = new GregorianCalendar();
-            int month = cal.get(Calendar.MONTH)+1;
-            int date  = cal.get(Calendar.DAY_OF_MONTH);
-            int StartLoc = 0;
-            if (Integer.parseInt(weatherdate[1]) == month && Integer.parseInt(weatherdate[2]) == date) {
-                //                Log.i(TAG, "## 1111");
-                //                for(int i=0 ; i<WeatherVer.length ; i++)
-                //                {
-                //                    Log.i(TAG, "N" + i + " : " + WeatherVer[i]);
-                //                }
-                ReqData[0] = GetTemp( WeatherVer[5]);
-                ReqData[1] = GetWeatherCode( WeatherTBL.GetWeatherList().get(StartLoc).code); //GetWeatherCode( WeatherVer[3]);
-                ReqData[2] = GetTemp( WeatherVer[6]);
-                ReqData[3] = GetTemp( WeatherVer[7]);
-
-                if (mDriver.info.Support.NowWeather) ReqData[10] = GetWeatherCode(WeatherVer[3]);
-            }
-            else {
-                //                Log.i(TAG, "## 2222");
-                if (WeatherTBL.GetWeatherList().size() > 0) {
-                    String Curdate = String.format("%02d%02d", month,date);
-
-                    //                    Log.i(TAG, "## 3333 - [" + Curdate + "]");
-                    for (int i = 0; i < WeatherTBL.GetWeatherList().size(); i++) {
-                        if (WeatherTBL.GetWeatherList().get(i).date.equals(Curdate)) {
-                            StartLoc = i;
-
-                            //                            Log.i(TAG, "## 4444 - [StartLoc:" + StartLoc + "]");
-                            //                            Log.i(TAG, "## 4444 - [StartLoc:" + StartLoc + "]");
-
-
-                            ReqData[0] = GetTemp( WeatherTBL.GetWeatherList().get(StartLoc).low);
-                            byte NowCode = GetWeatherCode( WeatherTBL.GetWeatherList().get(StartLoc).code);
-                            ReqData[1] = NowCode;
-                            ReqData[2] = GetTemp( WeatherTBL.GetWeatherList().get(StartLoc).low);
-                            ReqData[3] = GetTemp( WeatherTBL.GetWeatherList().get(StartLoc).high);
-
-                            if(mDriver.info.Support.NowWeather) ReqData[10] = NowCode;
-                            break;
-                        }
-                    }
-                }
-            }
-
-            DeviceLog("Get Data : "+WeatherTBL.GetWeatherList().size()+":");
-            if (StartLoc+1 < WeatherTBL.GetWeatherList().size()) {
-                StartLoc++;
-                ReqData[4] = GetWeatherCode( WeatherTBL.GetWeatherList().get(StartLoc).code);
-                ReqData[5] = GetTemp( WeatherTBL.GetWeatherList().get(StartLoc).low);
-                ReqData[6] = GetTemp( WeatherTBL.GetWeatherList().get(StartLoc).high);
-                if (StartLoc+1 < WeatherTBL.GetWeatherList().size()) {
-                    StartLoc++;
-                    ReqData[7] = GetWeatherCode( WeatherTBL.GetWeatherList().get(StartLoc).code);
-                    ReqData[8] = GetTemp( WeatherTBL.GetWeatherList().get(StartLoc).low );
-                    ReqData[9] = GetTemp( WeatherTBL.GetWeatherList().get(StartLoc).high);
-                }
-                else {
-                    ReqData[7] = 0;
-                    ReqData[8] = 0;
-                    ReqData[9] = 0;
-                }
-            }
-            else {
-                ReqData[4] = 0;
-                ReqData[5] = 0;
-                ReqData[6] = 0;
-                ReqData[7] = 0;
-                ReqData[8] = 0;
-                ReqData[9] = 0;
-            }
-
-            Status status = Send_SetWeather(ReqData);
-
-            if (status != null) return 0;
-        } catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-            return -2;
-        } catch (Exception e) {
-            Log.e(TAG, "[Exception Error] WeatherUpdate");
-            //e.printStackTrace();
-            LogUtil.errorLogInfo("", TAG, e);
-            return -2;
-        }
-
-        return -3;
-    }
-
-    /**
-     * 에너지정보 동기화<br>
-     * 실시간검침기의 현재 사용량을 가져와서 스마트스위치에 전송한다.
-     */
-    private void updateEnergy() {
-        DeviceLog("[updateEnergy] start");
-        try {
-            if (ServiceMain.realTimeMeter_Controller != null) {
-                byte [] RemoteMeterShareData = RealTimeMeter_Controller.GetShareData();
-                if (RemoteMeterShareData != null) {
-                    byte EnergyCount = RemoteMeterShareData[1];
-                    if ((EnergyCount <= 0) || (EnergyCount > 5)) return;
-
-                    byte UseEnergyCount = 0;
-                    int index = 2;
-                    for (int i=0 ; i<EnergyCount ; i++) {
-                        if ((RemoteMeterShareData[index] & BIT7) == 0x00) {
-                            UseEnergyCount++;
-                            index += 8;
-                        }
-                        else index += 1;
-                    }
-
-                    byte [] ReqData = new byte [(UseEnergyCount*4) + 1];
-
-                    ReqData[0] = UseEnergyCount;
-                    int ReqIndex = 1;
-                    index = 2;
-                    for (byte i=0 ; i<EnergyCount ; i++) {
-                        if ((RemoteMeterShareData[index] & BIT7) == 0x00) {
-                            ReqData[ReqIndex++] = RemoteMeterShareData[index + 0];
-                            ReqData[ReqIndex++] = RemoteMeterShareData[index + 5];
-                            ReqData[ReqIndex++] = RemoteMeterShareData[index + 6];
-                            ReqData[ReqIndex++] = RemoteMeterShareData[index + 7];
-
-                            index += 8;
-                        }
-                        else index += 1;
-                    }
-
-                    Send_SetEnergy(ReqData);
-                }
-                // 실시간검침이 있다가 없어진 경우, 신규 스마트스위치에게 "0"을 보내줘야 화면에서 사라진다.
-                else if (RemoteMeterShareData == null) {
-                    // 항상 이부분에 걸리는 것인가? 왜 Always TRUE 이지?
-                    byte [] ReqData = new byte [1];
-                    ReqData[0] = 0x00;
-
-                    Send_SetEnergy(ReqData);
-                }
-            }
-            else {
-                Log.w(TAG, "[updateEnergy] ServiceMain.realTimeMeter_Controller is null!!");
-                Send_SetEnergy(makeTelemeteringData());
-            }
-        } catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-        } catch (Exception e) {
-            Log.e(TAG, "[Exception] updateEnergy()");
-            //e.printStackTrace();
-            LogUtil.errorLogInfo("", TAG, e);
-        }
-    }
-
-    byte hEnergyType_Elec = (byte) 0x01;
-    byte hEnergyType_Water = (byte) 0x02;
-    byte hEnergyType_Hotwater = (byte) 0x03;
-    byte hEnergyType_Gas = (byte) 0x04;
-    byte hEnergyType_Heating = (byte) 0x05;
-    private byte[] makeTelemeteringData() {
-        try {
-            DeviceLog("[makeTelemeteringData] strElecUsage [" + strElecUsage + "], strWaterUsage [" + strWaterUsage + "], strGasUsage [" + strGasUsage + "], strHotwaterUsage [" + strHotwaterUsage + "], strHeatingUsage [" + strHeatingUsage + "] ");
-            int nCnt = 0;
-            if (!strElecUsage.equalsIgnoreCase(NoTelemeteringValue)) nCnt++;
-            if (!strWaterUsage.equalsIgnoreCase(NoTelemeteringValue)) nCnt++;
-            if (!strHotwaterUsage.equalsIgnoreCase(NoTelemeteringValue)) nCnt++;
-            if (!strGasUsage.equalsIgnoreCase(NoTelemeteringValue)) nCnt++;
-            if (!strHeatingUsage.equalsIgnoreCase(NoTelemeteringValue)) nCnt++;
-
-            // 데이터 배열 초기화
-            byte[] ahMeterData = new byte[(nCnt * 4) + 1];
-            for (int i = 0; i < ahMeterData.length; i++) ahMeterData[i] = (byte) 0x00;
-            DeviceLog("[makeTelemeteringData] ahMeterData.length [" + ahMeterData.length + "]");
-
-            // 데이터 생성
-            int nIndex = 0;
-            ahMeterData[0] = (byte) nCnt;
-            nIndex++;
-
-            // 전력
-            if (!strElecUsage.equalsIgnoreCase(NoTelemeteringValue)) {
-                ahMeterData[nIndex] = hEnergyType_Elec;
-                nIndex++;
-
-                /**
-                 * # 전력값 처리 방안안
-                * 1. 전력값은 KW기준이므로 W기준으로 변경한다.
-                 * 2. 서버에서 보내주는 전력값은 KW기준의 소수점 아래 한자리를 포함
-                 * 3. KW를 W로 변환시, X 1000을 하므로 소수점으로 인함 문제는 없다.
-                 * 4. 프로토콜상 전력값은 소수점을 포함하지 않으므로 이를 삭제한다.
-                 */
-                String strTempElecUsage = String.valueOf(Double.valueOf(strElecUsage) * 1000);
-                if (strTempElecUsage.contains(".")) {
-                    String[] strParsed = strTempElecUsage.split("\\.");
-                    strTempElecUsage = strParsed[0];
-                }
-
-                byte[] hValue = convertTelemeteringValue(strTempElecUsage);
-                for (int i = 0; i < hValue.length; i++) {
-                    ahMeterData[nIndex] = hValue[i];
-                    nIndex++;
-                }
-            }
-
-            // 수도
-            if (!strWaterUsage.equalsIgnoreCase(NoTelemeteringValue)) {
-                ahMeterData[nIndex] = hEnergyType_Water;
-                nIndex++;
-
-                byte[] hValue = convertTelemeteringValue(strWaterUsage);
-                for (int i = 0; i < hValue.length; i++) {
-                    ahMeterData[nIndex] = hValue[i];
-                    nIndex++;
-                }
-            }
-
-            // 온수
-            if (!strHotwaterUsage.equalsIgnoreCase(NoTelemeteringValue)) {
-                ahMeterData[nIndex] = hEnergyType_Hotwater;
-                nIndex++;
-
-                byte[] hValue = convertTelemeteringValue(strHotwaterUsage);
-                for (int i = 0; i < hValue.length; i++) {
-                    ahMeterData[nIndex] = hValue[i];
-                    nIndex++;
-                }
-            }
-
-            // 가스
-            if (!strGasUsage.equalsIgnoreCase(NoTelemeteringValue)) {
-                ahMeterData[nIndex] = hEnergyType_Gas;
-                nIndex++;
-
-                byte[] hValue = convertTelemeteringValue(strGasUsage);
-                for (int i = 0; i < hValue.length; i++) {
-                    ahMeterData[nIndex] = hValue[i];
-                    nIndex++;
-                }
-            }
-
-            // 열량(난방)
-            if (!strHeatingUsage.equalsIgnoreCase(NoTelemeteringValue)) {
-                ahMeterData[nIndex] = hEnergyType_Heating;
-                nIndex++;
-
-                byte[] hValue = convertTelemeteringValue(strHeatingUsage);
-                for (int i = 0; i < hValue.length; i++) {
-                    ahMeterData[nIndex] = hValue[i];
-                    nIndex++;
-                }
-            }
-
-            return ahMeterData;
-        } catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-            return null;
-        } catch (Exception e) {
-            Log.e(TAG, "[Exception] makeTelemeteringData()");
-            //e.printStackTrace();
-            LogUtil.errorLogInfo("", TAG, e);
-            return null;
-        }
-    }
-
-    /**
-     * 원격검침값을 스마트스위치로 보내기위한 데이터 변환 (String -> byte[3])
-     * @param strValue
-     * @return
-     */
-    private byte[] convertTelemeteringValue(String strValue) {
-        DeviceLog("[convertTelemeteringValue] strValue [" + strValue + "]");
-        byte [] ahResultData = new byte [3];
-        for (int i = 0; i < ahResultData.length; i++) ahResultData[i] = (byte) 0x00;
-
-        try {
-            if (strValue.length() > 7) {
-                // 숫자 6자리, 소수점 1자리
-                Log.w(TAG, "[convertTelemeteringValue] strValue is out of range!! strValue [" + strValue + "], strValue.length [" + strValue.length() + "]");
-                return ahResultData;
-            }
-
-            if (strValue.contains(".")) {
-                String[] strParsed = strValue.split("\\.");
-                String strUpper = doZeroPadding_Head(3, strParsed[0]);
-                String strLower = doZeroPadding_Tail(3, strParsed[1]);
-                int nValue = Integer.parseInt(strUpper + strLower);
-                ahResultData[0] = getDecToHex(nValue / 10000);
-                ahResultData[1] = getDecToHex((nValue / 100) % 100);
-                ahResultData[2] = getDecToHex(nValue % 100);
-            }
-            else {
-                int nValue = Integer.parseInt(strValue);
-                ahResultData[0] = getDecToHex(nValue / 10000);
-                ahResultData[1] = getDecToHex((nValue / 100) % 100);
-                ahResultData[2] = getDecToHex(nValue % 100);
-            }
-
-        } catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-        } catch (Exception e) {
-            Log.e(TAG, "[Exception] convertTelemeteringValue(String strValue)");
-            //e.printStackTrace();
-            LogUtil.errorLogInfo("", TAG, e);
-        }
-        return ahResultData;
-    }
-
-    // 10진수를 Byte로 변환 ex)12 -> 0x12
-    private byte getDecToHex(int nDec) {
-        try {
-            byte result = 0;
-            result += ((nDec / 10) << 4);
-            result += (nDec % 10);
-//            LOG("[getDexToHex] result [" + result + "]");
-            return result;
-        } catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-            return 0;
-        } catch (Exception e) {
-            Log.e(TAG, "[Exception] getDecToHex(int nDec)");
-            //e.printStackTrace();
-            LogUtil.errorLogInfo("", TAG, e);
-            return 0;
-        }
-    }
-
-    public static String doZeroPadding_Head(int nOutLength, String strOriginalString) {
-        String strResult = strOriginalString;
-//        Log.d(TAG, "[doZeroPadding_Head] (Length) strOriginalString [" + strOriginalString.length() +"], nOutLength [" + nOutLength + "]");
-        try {
-
-            if (strOriginalString.length() < nOutLength) {
-                for (int i = strOriginalString.length(); i < nOutLength; i++) {
-                    strResult = "0" + strResult;
-                }
-//                Log.d(TAG, "[doZeroPadding_Head] strResult : " + strResult);
-                return strResult;
-            }
-            else if (strOriginalString.length() == nOutLength) {
-//                Log.d(TAG, "[doZeroPadding_Head] same length!");
-                return strResult;
-            }
-            else {
-                Log.d(TAG, "[doZeroPadding_Head] strOriginalString(" + strOriginalString.length() + ") is longer than nOutLength(" + nOutLength + ")");
-                return strResult;
-            }
-        } catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-            return strResult;
-        } catch (Exception e) {
-            Log.e(TAG, "[Exception] doZeroPadding_Head(int nOutLength, String strOriginalString)");
-            //e.printStackTrace();
-            LogUtil.errorLogInfo("", TAG, e);
-            return strResult;
-        }
-    }
-
-    public static String doZeroPadding_Tail(int nOutLength, String strOriginalString) {
-        String strResult = strOriginalString;
-//        Log.d(TAG, "[doZeroPadding_Tail] (Length) strOriginalString [" + strOriginalString.length() +"], nOutLength [" + nOutLength + "]");
-        try {
-
-            if (strOriginalString.length() < nOutLength) {
-                for (int i = strOriginalString.length(); i < nOutLength; i++) {
-                    strResult = strResult + "0";
-                }
-//                Log.d(TAG, "[doZeroPadding_Tail] strResult : " + strResult);
-                return strResult;
-            }
-            else if (strOriginalString.length() == nOutLength) {
-//                Log.d(TAG, "[doZeroPadding_Tail] same length!");
-                return strResult;
-            }
-            else {
-                Log.d(TAG, "[doZeroPadding_Tail] strOriginalString(" + strOriginalString.length() + ") is longer than nOutLength(" + nOutLength + ")");
-                return strResult;
-            }
-        } catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-            return strResult;
-        } catch (Exception e) {
-            Log.e(TAG, "[Exception] doZeroPadding_Tail(int nOutLength, String strOriginalString)");
-            //e.printStackTrace();
-            LogUtil.errorLogInfo("", TAG, e);
-            return strResult;
-        }
-    }
-
-    /**
-     * 주차정보 동기화<br>
-     * 단지서버가 저장한 주차정보를 DB에서 읽어 전송한다.
-     *
-     * @return (int) - >=0 : 성공, <0 : 실패
-     */
-    private int ParkingUpdate() {
-        DeviceLog("[ParkingUpdate] - START");
-
-        WallpadParkInfo parkdb = null;
-        try {
-            // 0. 주차정보 사용 유무 체크한다.
-            if (Get_DBInfo_Parking() == false) {
-                mDriver.Polling.setParkingUpdate(false); //추가
-                return -1;
-            }
-
-            // 1. 주차정보 DB 을 OPEN 한다.
-            parkdb = new WallpadParkInfo(ServiceMain.svcContext);
-
-            // 2. 주차정보 개수를 가져온다.
-            int RowCountCarParking = parkdb.RowCountCarParking();
-
-            DeviceLog("[ParkingUpdate] RowCountCarParking - " + RowCountCarParking);
-
-            if (RowCountCarParking == 0) {
-                parkdb.closeDB();
-
-                // 주차정보 알림 전송 (주차정보 삭제)
-                Status status = Send_SetParking(new byte [] { 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 });
-                if (status != null) return 0;
-                return -2;
-            }
-            else if (RowCountCarParking < 0) {
-                parkdb.closeDB();
-                Log.w(TAG, "[ParkingUpdate] parkdb.RowCountCarParking Error (ret:" + RowCountCarParking + ")");
-                return -3;
-            }
-
-            // 3. 주차정보 리스트를 가져온다.
-            CarParkingData carParkingData[] = parkdb.getCarParkingData();
-            parkdb.closeDB();
-            if (carParkingData == null) {
-                Log.w(TAG, "[ParkingUpdate] parkdb.getCarParkingData Error - null !!!");
-                return -4;
-            }
-
-            // TEST
-            //            CarParkingData [] carParkingData = new CarParkingData[3];
-            //            for(int i=0 ; i<carParkingData.length ; i++)
-            //            {
-            //                carParkingData[i] = new CarParkingData();
-            //                switch(i)
-            //                {
-            //                    case 0:
-            //                        carParkingData[i].location_text = "B2A11abcdee5trgdfg";
-            //                        carParkingData[i].vehicle_info = "d/1234";
-            //                        break;
-            //                    case 1:
-            //                        carParkingData[i].location_text = "C3D11abcdee5trgdfg";
-            //                        carParkingData[i].vehicle_info = "s/12가5678";
-            //                        break;
-            //                    case 2:
-            //                        carParkingData[i].location_text = "D4E11abcdee5trgdfg";
-            //                        carParkingData[i].vehicle_info = "s/12가9999";
-            //                        break;
-            //                }
-            //            }
-
-            // 4. 디버그 메시지 출력
-            //for(int i=0; i<carParkingData.length; i++) DeviceLog(carParkingData[i].ToDebugString());
-
-            // 5. 기기 지원 정보개수는 2개이다 2개 이상일시 2개로 조정
-            byte CarCount = 0;
-            if (carParkingData.length >= 2) CarCount = 2;
-            else CarCount = (byte) carParkingData.length;
-
-            // 6. 리스트 개수만큼 전송
-            for (byte carindex = 0; carindex < CarCount; carindex++) {
-                DeviceLog("[ParkingUpdate] - carindex : " + carindex);
-                String LocationStr = carParkingData[carindex].location_text;
-                String CarNumberStr = carParkingData[carindex].vehicle_info;
-
-                DeviceLog("[ParkingUpdate] - LocationStr  : " + LocationStr);
-                DeviceLog("[ParkingUpdate] - CarNumberStr : " + CarNumberStr);
-                // 주차 위치 정보
-                byte [] LocByteArray = CarLocationParsing(LocationStr);
-                if (LocByteArray == null) LocByteArray = new byte[] { 0x00 };
-                byte LocationLength = (byte) LocByteArray.length;
-                if (LocationLength > MAX_PARKING_INFO_STR_COUNT) LocationLength = MAX_PARKING_INFO_STR_COUNT;
-
-                // 차량번호
-                byte [] CarNumber = CarNumberParsing(CarNumberStr);
-                if (CarNumber == null) CarNumber = new byte[] { 0x00, 0x00, 0x00, 0x00 };
-
-                // 전송 데이터 생성
-                byte [] ReqData = new byte [7+LocationLength];
-                int index = 0;
-
-                ReqData[index++] = CarCount;             // 세대에 등록된 차량 대수 n
-                ReqData[index++] = (byte)(carindex+1);   // 세대에 등록된 차량 대수 중 일련 번호
-
-                ReqData[index++] = CarNumber[0]; // 차량 번호 첫번째 자리
-                ReqData[index++] = CarNumber[1]; // 차량 번호 두번째 자리
-                ReqData[index++] = CarNumber[2]; // 차량 번호 세번째 자리
-                ReqData[index++] = CarNumber[3]; // 차량 번호 네번째 자리
-
-                ReqData[index++] = LocationLength;        // 주차 위치 정보 문자열 개수 m
-                for (byte i = 0; i < LocationLength; i++) {
-                    ReqData[index++] = LocByteArray[i];   // 주차 위치 정보의 문자 복사
-                }
-
-                // 주차정보 알림 전송
-                Send_SetParking(ReqData);
-
-                if ((CarCount == 2) && (carindex == 0)) {
-                    Sleep(100);
-                }
-            }
-
-            DeviceLog("ParkingUpdate - END");
-            return 0;
-
-        } catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-            if(parkdb != null) parkdb.closeDB();
-            return -100;
-        } catch (Exception e) {
-            Log.e(TAG, "[Exception Error] ParkingUpdate");
-            //e.printStackTrace();
-            LogUtil.errorLogInfo("", TAG, e);
-            if(parkdb != null) parkdb.closeDB();
-            return -100;
-        }
-    }
-
-    /**
-     * 차량번호 4자리를 byte 로 반환한다.
-     *
-     * @param CarNumStr - (String) 차량번호
-     *
-     * @return (byte []) 차량번호 4자리 (Length : 4)
-     */
-    private byte [] CarNumberParsing(String CarNumStr) {
-        try {
-            if (CarNumStr == null) return null;
-            byte [] bytes = CarNumStr.getBytes();
-            if (bytes == null) return null;
-            if (bytes.length < 4) return null;
-
-            byte [] CarNum = new byte[4];
-            int index = bytes.length-4;
-            for (int i = 0; i < 4; i++) {
-                CarNum[i] = bytes[index++];
-                if (!((CarNum[i] >= 0x30) && (CarNum[i] <= 0x39))) return null;
-                CarNum[i] &= 0x0F;
-            }
-            return CarNum;
-        } catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-            return null;
-        } catch (Exception e) {
-            Log.e(TAG, "[Exception Error] CarNumberParsing");
-            //e.printStackTrace();
-            LogUtil.errorLogInfo("", TAG, e);
-            return null;
-        }
-    }
-
-    /**
-     * 차량위치 String 을 byte 배열로 변환한다.</br>
-     * 변환시 표현범위 이탈을 체크하여 변환한다.
-     *
-     * @param CarLocStr - (String) 차량위치
-     * @return (byte []) 변환된 차량위치 정보
-     */
-    private byte [] CarLocationParsing(String CarLocStr) {
-        try {
-            if (CarLocStr == null) return null;
-            byte [] bytes = CarLocStr.getBytes();
-            if (bytes == null) return null;
-
-            for (int i = 0; i < bytes.length; i++) {
-                if (!(bytes[i] == ' ') &&       // 공백
-                        !(bytes[i] == '-') &&       // '-'
-                        !(bytes[i] == '_') &&       // '_'
-                        !((bytes[i] >= '0') && (bytes[i] <= '9')) &&     // '0' ~ '9'
-                        !((bytes[i] >= 'A') && (bytes[i] <= 'Z')) &&     // 'A' ~ 'Z'
-                        !((bytes[i] >= 'a') && (bytes[i] <= 'z')))      // 'a' ~ 'z'
-                {
-                    bytes[i] = ' ';
-                }
-            }
-
-            return bytes;
-        } catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-            return null;
-        } catch (Exception e) {
-            Log.e(TAG, "[Exception Error] CarLocationParsing");
-            //e.printStackTrace();
-            LogUtil.errorLogInfo("", TAG, e);
-            return null;
-        }
-    }
-
-    /**
-     * 알람상태를 가져온다.
-     *
-     * @return (int) 외출상태 <br>
-     *               WallpadStatusData.ALARM_NONE     : 평상시<br>
-     *               WallpadStatusData.GUARD_OUT_WAIT : 외출 대기중 (설정진행중)<br>
-     *               WallpadStatusData.GUARD_OUT      : 외출
-     */
-    private int DB_GetAlarmStatus() {
-        int ret = WallpadStatusData.ALARM_NONE;
-        try {
-            WallpadStatusData wdb = new WallpadStatusData(ServiceMain.svcContext);
-            ret = wdb.GetAlarmStatus();
-            wdb.closeDB();
-            switch (ret) {
-                case WallpadStatusData.ALARM_NONE:
-                case WallpadStatusData.GUARD_OUT_WAIT:
-                case WallpadStatusData.GUARD_OUT:
-                case WallpadStatusData.OUT_MODE:
-                    break;
-
-                default:
-                    ret = WallpadStatusData.ALARM_NONE;
-                    break;
-            }
-        } catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-        } catch (Exception e) {
-            Log.e(TAG, "[DB_GetAlarmStatus] Exception Error");
-            //e.printStackTrace();
-            LogUtil.errorLogInfo("", TAG, e);
-        }
-        return ret;
-    }
-
-    /***
-     * 주차정보 사용 유무를 가져온다.
-     *
-     * @return (boolean)주차정보 사용 유무 <br>
-     *                  true = 사용 <br>
-     *                  false = 미사용 <br>
-     */
-    private boolean Get_DBInfo_Parking() {
-        boolean bUseofNot_ParkingInfo = false;
-
-        try {
-            WallpadDeviceSet devSet = new WallpadDeviceSet(ServiceMain.svcContext);
-            String[] ParkingDB = devSet.GetSettingData("주차확인");
-            devSet.closeDB();
-
-            if (ParkingDB != null) {
-                String devInfo = ParkingDB[1];
-
-                devInfo = devInfo.replace('(', '_');
-                devInfo = devInfo.replace(':', '_');
-                devInfo = devInfo.replace(')', '_');
-
-                String[] ParkingInfo = devInfo.split("_");
-
-                // ParkingInfo[3] -> 사용여부 <사용함 / else>
-                // ParkingInfo[5] -> 종류 <기본 / 아이콘트롤스 / NEXPA / UPIS / ETC / else />
-                // ParkingInfo[7] -> IP정보
-                // ParkingInfo[8] -> 포트번호
-
-                if (ParkingInfo[3].equalsIgnoreCase("사용함") == true) {
-                    bUseofNot_ParkingInfo = true;
-                }
-            }
-            else {
-                bUseofNot_ParkingInfo = false;
-            }
-        } catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-            return false;
-        } catch (Exception e) {
-            Log.e(TAG, "[Exception Error] Get_DBInfo_Parking()");
-            //e.printStackTrace();
-            LogUtil.errorLogInfo("", TAG, e);
-            return false;
-        }
-        return bUseofNot_ParkingInfo;
-    }
-
-    /**
-     * 알림정보 비교<br>
-     * 초기 값과 현재 값 비교 (초기값: 부팅시, 이미 갖고 있던 값 / 현재값:intent로 받은 값)
-     *
-     * @param arr - BroadcastReceiver새로 수신받은 알림정보 array
-     *
-     * @return true | false
-     */
-    public boolean isNotiDataChanged(int[] arr) {
-        boolean retbool = false;
-
-        if (arr[0] != DefaultNotiCNT) {
-            Log.d(TAG , "[isNotiDataChanged] - notice changed : "+ arr[0]);
-            DefaultNotiCNT = arr[0];
-
-            retbool = true;
-        }
-        else if (arr[0] == 0) {
-            Log.d(TAG , "[isNotiDataChanged] - default notice zero");
-            DefaultNotiCNT = 0;
-            retbool = true;
-        }
-
-        if (arr[1] != DefaultParcelCNT) {
-            Log.d(TAG , "[isNotiDataChanged] - parcel changed : "+ arr[1]);
-            DefaultParcelCNT = arr[1];
-
-            retbool = true;
-        }
-        else if (arr[1] == 0) {
-            Log.d(TAG , "[isNotiDataChanged] - default parcel zero");
-            DefaultParcelCNT= 0;
-            retbool = true;
-        }
-
-        if (arr[2] != DefaultVisitorCNT) {
-            Log.d(TAG , "[isNotiDataChanged] - visitor changed : "+ arr[2]);
-            DefaultVisitorCNT = arr[2];
-
-            retbool = true;
-        }
-        else if (arr[2] == 0) {
-            Log.d(TAG , "[isNotiDataChanged] - default visitor zero");
-            DefaultVisitorCNT= 0;
-            retbool = true;
-        }
-
-        if (arr[3] != DefaultMemoCNT) {
-            Log.d(TAG , "[isNotiDataChanged] - memo changed : "+ arr[3]);
-            DefaultMemoCNT = arr[3];
-
-            retbool = true;
-        }
-        else if (arr[3] == 0) {
-            Log.d(TAG , "default memo zero");
-            DefaultMemoCNT= 0;
-            retbool = true;
-        }
-
-        return retbool;
-    }
-
-
-    /**
-     * 알림정보 동기화<br>
-     * 공지사항, 택배, 방문자, 메모의 수가 증가하면 스마트스위치에 전송한다.<br>
-     * 공지사항, 택배, 메모 카운트는 WallpadStatusData에서 가져온다.<br>
-     * 방문자 카운트는 BroadcastReceiver의 onReceive()로 얻는다.
-     *
-     */
-    private int NotiInfoUpdate() {
-        byte [] ReqData = {0x00, 0x00}; // {요청받은 제어 개수,
-        // 알림 정보(BIT 0:공지사항, 1:택배, 2:방문자, 3:메모)}
-        try {
-            if (NotiArr[0] > 0) {
-                // 공지사항
-                Log.i(TAG, "[NotiInfoUpdate] notifyCount = " + NotiArr[0]);
-                ReqData[0]++;
-                ReqData[1] += BIT0;
-            }
-            else if (NotiArr[0] == 0) {
-                // 0개로 수신하면 스마트 스위치에게 0으로 보내준다.(신규 스마트스위치를 위해서)
-                Log.i(TAG, "[NotiInfoUpdate] notifyCount zero= " + NotiArr[0]);
-                ReqData[0]++;
-            }
-
-            if (NotiArr[1] > 0) {
-                // 택배
-                Log.i(TAG, "[NotiInfoUpdate] parcelCount = " + NotiArr[1]);
-                ReqData[0]++;
-                ReqData[1] += BIT1;
-            }
-            else if (NotiArr[1] == 0) {
-                Log.i(TAG, "[NotiInfoUpdate] parcelCount zero= " + NotiArr[1]);
-                ReqData[0]++;
-            }
-
-            if (NotiArr[2] > 0) {
-                // 방문자
-                Log.i(TAG, "[NotiInfoUpdate] vistorCount = " + NotiArr[2]);
-                ReqData[0]++;
-                ReqData[1] += BIT2;
-            }
-            else if (NotiArr[2] == 0) {
-                Log.i(TAG, "[NotiInfoUpdate] vistorCount zero= " + NotiArr[2]);
-                ReqData[0]++;
-            }
-
-            if (NotiArr[3] > 0) {
-                // 메모
-                Log.i(TAG, "[NotiInfoUpdate] memoCount = " + NotiArr[3]);
-                ReqData[0]++;
-                ReqData[1] += BIT3;
-            }
-            else if (NotiArr[3] == 0) {
-                Log.i(TAG, "[NotiInfoUpdate] memoCount zero= " + NotiArr[3]);
-                ReqData[0]++;
-            }
-
-            Log.i(TAG, "[NotiInfoUpdate] Noti REQUEST count = " + ReqData[0] + " / data =  " + ReqData[1]);
-
-            // Send data
-            Status st = Send_SetNotiInfo(ReqData);
-
-            if (st != null) {
-                Log.i(TAG, "[NotiInfoUpdate] return 0! --> GOOD");
-                return 0;
-            }
-            else {
-                Log.i(TAG, "[NotiInfoUpdate] return -2! --> BAD");
-                return -2;
-            }
-        } catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-            return -3;
-        } catch (Exception e) {
-            Log.e(TAG, "[Exception Error] NotiInfoUpdate");
-            //e.printStackTrace();
-            LogUtil.errorLogInfo("", TAG, e);
-            return -3;
-        }
-    }
-
-    /**
-     * 난방정보 동기화<br>
-     * 난방정보 패킷을 HeatingV2의 데이터로 만들고, 스마트스위치에게 전송한다.
-     *
-     */
-    private int HeatingInfoUpdate() {
-        DeviceLog("HeatingInfoUpdate");
-
-        try {
-            byte [] ReqData = null;
-
-            if (ServiceMain.heatingV2_Controller != null) {
-                H2Cont = ServiceMain.heatingV2_Controller;
-                byte roomCount = H2Cont.GetRoomCount();
-                //Log.i(TAG,"SmartSwitch Room Count = " + roomCount);
-
-                ReqData = new byte[1 + (roomCount*4)];
-                for (int i = 0; i < ReqData.length; i++) {
-                    ReqData[i] = (byte) 0x00; // ReqData Initialize
-                }
-                //Log.i(TAG,"ReqData Length = " + ReqData.length);
-
-                ReqData[0] = roomCount; // (D1)
-
-                // 각 방의 정보를 얻어서 전송할 데이터 패킷 만들기
-                // make ReqData
-                for (int i = 0; i < roomCount; i++) {
-                    byte mode = H2Cont.GetRoomMode(i);
-                    String valve = H2Cont.GetRoomValve(i);
-                    byte nowTemp = H2Cont.GetRoomNowTemp(i);
-                    byte setTemp = H2Cont.GetRoomSetTemp(i);
-
-                    //Log.i(TAG,"Room " + i + " Mode = " + mode);
-                    //Log.i(TAG,"Room " + i + " valve = " + valve);
-                    //Log.i(TAG,"Room " + i + " nowTemp = " + nowTemp);
-                    //Log.i(TAG,"Room " + i + " setTemp = " + setTemp);
-
-                    if(valve!=null)
-                    {
-                        // Add Valve BIT ( D2 + (4*i) )
-                        if (valve.equals("true")) {
-                            ReqData[1+(i*4)] += define.BIT4;
-                        }
-                        else if (valve.equals("false")) {
-                            ReqData[1+(i*4)] += 0;
-                        }
-                    }
-
-                    //Log.i(TAG,"middle valve " + i + " = " + valve);
-
-                    // Add Mode BIT ( D2 + (4*i) )
-                    if (mode == 1) {
-                        // Mode : ON
-                        ReqData[1+(i*4)] += define.BIT0;
-                    }
-                    else if (mode == 2) {
-                        // Mode : OFF
-                        ReqData[1+(i*4)] += define.BIT1;
-                    }
-                    else if (mode == 3) {
-                        // Mode : Outting
-                        ReqData[1+(i*4)] = (define.BIT0 + define.BIT1);
-                    }
-                    else if (mode == 5) {
-                        // Mode : Sleep
-                        ReqData[1+(i*4)] = (define.BIT0 + define.BIT2);
-                    }
-                    else if (mode == 6) {
-                        // Mode : Reserve
-                        ReqData[1+(i*4)] = (define.BIT1 + define.BIT2);
-                    }
-                    else if (mode == 7) {
-                        // Mode : Pause
-                        ReqData[1+(i*4)] = (define.BIT0 + define.BIT1 + define.BIT2);
-                    }
-                    //Log.i(TAG,"HeatingInfo mode  " + i + " = " + mode);
-
-                    // Add SetTemp BIT ( D3 + (4*i) )
-                    if (setTemp != 0) {
-                        ReqData[2+(i*4)] += setTemp; // 선언 시, 0.5 설정도 되어 있는 값을 return 받음
-                    }
-                    //Log.i(TAG,"HeatingInfo setTemp  " + i + " = " + setTemp);
-
-                    // Add NowTemp BIT
-                    if (nowTemp != 0) {
-                        int nowTempTen = nowTemp * 10;
-                        String sendNowTemp = Integer.toHexString(nowTempTen);
-
-                        if (sendNowTemp.length() == 1) {
-                            sendNowTemp = "000" + sendNowTemp; // 000/1
-                        }
-                        else if (sendNowTemp.length() == 2) {
-                            sendNowTemp = "00" + sendNowTemp; // 00/12
-                        }
-                        else if (sendNowTemp.length() == 3) {
-                            sendNowTemp = "0" + sendNowTemp; // 0/123
-                        }
-                        //Log.i(TAG,"sendNowTemp  " + i + " = " + sendNowTemp);
-
-                        int upper = Integer.parseInt(sendNowTemp.substring(0, 2), 16);
-                        int lowwer = Integer.parseInt(sendNowTemp.substring(2), 16);
-
-                        //Log.i(TAG,"upper  " + i + " = " + upper);
-                        //Log.i(TAG,"lowwer  " + i + " = " + lowwer);
-
-                        ReqData[3+(i*4)] += (byte) upper;  // NowTemp High BIT 2  ( D4 + (4*i) )
-                        ReqData[4+(i*4)] += (byte) lowwer; // NowTemp Low  BIT 2  ( D5 + (4*i) )
-                    }
-                }
-
-            }
-            else {
-                Log.w(TAG,"[HeatingInfoUpdate] - ServiceMain.heatingV2_Controller is NULL");
-            }
-
-            // Send data
-            Status st = Send_SetHeatingInfo(ReqData);
-
-            if (st != null) {
-                //Log.i(TAG, "[HeatingInfoUpdate] return ! --> GOOD");
-                return 0;
-            }
-            else {
-                //Log.i(TAG, "[HeatingInfoUpdate] return ! --> BAD");
-                return -1;
-            }
-        } catch (RuntimeException re) {
-            LogUtil.errorLogInfo("", TAG, re);
-            return -2;
-        } catch (Exception e) {
-            Log.e(TAG, "[Exception Error] HeatingInfoUpdate");
-            //e.printStackTrace();
-            LogUtil.errorLogInfo("", TAG, e);
-            return -2;
-        }
-
-
-    }
-
-
-
-
-}
+/*
+ * Copyright (C) 2014 Android WallPad Project
+ *
+ * FileName  : SmartSwitchPol_Controller.java
+ * Project   : Android WallPad Project
+ * Company   : HDC I-CONTROLS ( www.icontrols.co.kr )
+ * Author    : Kang Sang Ho  , lairu@icontrols.co.kr
+ */
+
+package com.artncore.wallpaddevservice.driver;
+
+import android.annotation.SuppressLint;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.util.Log;
+
+import com.artncore.WallPadDataMgr.WallpadDeviceSet;
+import com.artncore.WallPadDataMgr.WallpadParkInfo;
+import com.artncore.WallPadDataMgr.WallpadStatusData;
+import com.artncore.WallPadDataMgr.WallpadStatusData.WeatherTable;
+import com.artncore.WallPadDataMgr.wallpaddbmgr.AddressSet;
+import com.artncore.commons.APIErrorCode;
+import com.artncore.commons.DataClasses.CarParkingData;
+import com.artncore.commons.define;
+import com.artncore.wallpaddevservice.ServiceMain;
+import com.util.LogUtil;
+
+import java.util.Calendar;
+import java.util.GregorianCalendar;
+
+import kr.co.icontrols.wallpadsupport.Version;
+
+
+/**
+ * 스마트스위치 (폴링) 드라이버 모듈이다.<br>
+ * 모델명 : ISS-430(LCD type), ISS-201
+ */
+@SuppressLint("HandlerLeak")
+public class SmartSwitchPol_Controller extends DeviceManager
+{
+    private final static String TAG = "SmartSwitchPol";
+
+    private final byte ELE_CALL_DOWN = BIT0;
+    private final byte ELE_CALL_UP   = BIT1;
+    private final byte ELE_ARR_DOWN  = BIT2;
+    private final byte ELE_ARR_UP    = BIT3;
+
+    /** 디바이스 주소 */
+    private final byte DEVICE_ADDRESS  = (byte) 0xC1;
+
+    /** 초기 기기 검색 횟수  */
+    private final int MAX_SEARCH_COUNT   = 6;
+
+    /** 시간 및 상태 동기화 시간 (초)  (시간, 엘리베이터 정보, 가스상태, 외출, 일괄소등, 조명상태) */
+    private final long STATUS_SYNC_TICK   = (long)(20 * TIME_SEC);
+
+    /** 에너지 정보 동기화 시간 (초) */
+    private final long ENERGY_SYNC_TICK    = (long)(30 * TIME_SEC);
+
+    /** 스마트스위치로 부터 일괄소등 변경 정보를 받은후 일정시간 동기화 하지 않는시간 (초) */
+    private final long ALLLIGHT_SYNC_TICK    = (long)(2 * TIME_SEC);
+
+    /** 주차위치 정보 문자열 최대 길이 */
+    private final byte MAX_PARKING_INFO_STR_COUNT   = 10;
+
+    private byte   ELEStatus = 0;
+    private String ELELoc    = "NONE";
+    private int    ELEMove   = define.NOTIFY_DEVICE_ELE_MOVE_DIR_ERROR;
+
+    private DriverInterOpAPI driverInterOpAPI;
+
+    private int mModelType = Version.MODEL_TYPE.OTHER;
+
+    /** 부팅 시에 이미 가지고 있던 공지사항 수 */
+    private int DefaultNotiCNT = 0;    // 공지사항 수는 IC_WallPadMain의 DrawEventAlarm에서 인텐트 수신하여 저장
+
+    /** 부팅 시에 이미 가지고 있던 방문자 수 */
+    private int DefaultVisitorCNT = 0; // 방문자 수는 IC_WallPadMain의 DrawEventAlarm에서 인텐트 수신하여 저장
+
+    /** 부팅 시에 이미 가지고 있던 택배 수 */
+    private int DefaultParcelCNT = 0;  // 택배 수는 IC_WallPadMain의 DrawEventAlarm에서 인텐트 수신하여 저장
+
+    /** 부팅 시에 이미 가지고 있던 메모 수 */
+    private int DefaultMemoCNT = 0;    // 메모 수는 WallPadAddService의 memo관련 class에서 인텐트 수신하여 저장
+
+    /** BroadcastReceiver에서 수신한 알림정보들을 관리하는 array */
+    private int NotiArr[] = {0, 0, 0, 0}; // (0: notice / 1: parcel / 2: visitor / 3: memo)
+
+    /** 난방정보를 얻기 위한 컨트롤러 */
+    HeatingV2_Controller H2Cont;
+
+
+    /** 기기정보 */
+    public class Info
+    {
+        /** 조명개수( 범위 : 0~4) */
+        public byte LightCnt;
+
+        /** 기능 지원 여부 */
+        public class SupportClass
+        {
+            /** 시간정보 */
+            public boolean Time = false;
+            /** 주차정보 */
+            public boolean Parking = false;
+            /** 에너지 사용량 */
+            public boolean Energy = false;
+            /** 날씨정보 */
+            public boolean Weather = false;
+            /** 일괄소등 */
+            public boolean BatchOff = false;
+            /** 외출설정 */
+            public boolean Outing = false;
+            /** 가스 */
+            public boolean Gas = false;
+            /** 엘리베이터 */
+            public boolean Elevator = false;
+            /** 일괄소등 직접제어 */
+            public boolean BatchOffDirCtrl = false;
+            /** 현재 날씨 */
+            public boolean NowWeather = false;
+            /** 엘리베이터 운행방향 */
+            public boolean ElevatorDir = false;
+            /** 알림 정보 */
+            public boolean NotiInfo = false;
+            /** 난방 정보 */
+            public boolean HeatingInfo = false;
+            /** 공기질 정보 */
+            public boolean AirQualityInfo = true;
+        }
+        /** 기능 지원 여부 */
+        SupportClass Support;
+
+        /** 펌웨어 Build Date (년) */
+        public byte FwVer_Year;
+        /** 펌웨어 Build Date (월) */
+        public byte FwVer_Month;
+        /** 펌웨어 Build Date (일) */
+        public byte FwVer_Day;
+        /** 펌웨어 Build Date (일련번호) */
+        public byte FwVer_Number;
+
+        /** 지원 프로토콜 버전 Main */
+        public byte ProtocolVer_Main;
+        /** 지원 프로토콜 버전 Sub */
+        public byte ProtocolVer_Sub;
+
+        /** 생성자 */
+        public Info()
+        {
+            LightCnt = 0;
+            Support = new SupportClass();
+        }
+
+        /** 본 클래스 디버깅 메시지 */
+        public String ToDebugString()
+        {
+            String retStr =
+                    "==========================\r\n" +
+                            " Info\r\n" +
+                            "==========================\r\n" +
+                            "LightCnt     : " + LightCnt + "\r\n" +
+                            "FwVer        : " + (int)(FwVer_Year+2000) + "." + FwVer_Month + "." + FwVer_Day + "." + FwVer_Number + "\r\n" +
+                            "ProtocolVer  : " +  "V" + ProtocolVer_Main + "." + ProtocolVer_Sub + "\r\n" +
+
+                            "[Support]" + "\r\n" +
+                            "Time            : " + Support.Time + "\r\n" +
+                            "Parking         : " + Support.Parking + "\r\n" +
+                            "Energy          : " + Support.Energy + "\r\n" +
+                            "Weather         : " + Support.Weather + "\r\n" +
+                            "BatchOff        : " + Support.BatchOff + "\r\n" +
+                            "Outing          : " + Support.Outing + "\r\n" +
+                            "Gas             : " + Support.Gas + "\r\n" +
+                            "Elevator        : " + Support.Elevator + "\r\n" +
+                            "BatchOffDirCtrl : " + Support.BatchOffDirCtrl + "\r\n" +
+                            "NowWeather      : " + Support.NowWeather + "\r\n" +
+                            "ElevatorDir     : " + Support.ElevatorDir + "\r\n" +
+                            "NotiInfo        : " + Support.NotiInfo + "\r\n" +
+                            "HeatingInfo     : " + Support.HeatingInfo + "\r\n" +
+                            "AirQuality      : " + Support.AirQualityInfo + "\r\n" +
+                            "==========================";
+            return retStr;
+        }
+    }
+
+    /** 기기 상태 */
+    private class Status
+    {
+        /** 엘리베이터 */
+        public EachStatus Elevator;
+        /** 가스 */
+        public EachStatus Gas;
+        /** 일괄소등 */
+        public EachStatus BatchOff;
+        /** 외출설정 */
+        public EachStatus Outing;
+        /** 난방 정보 */
+        public EachStatus HeatingInfo;
+        /** 조명개수( 범위 : 0~4) */
+        public byte LightCnt;
+
+        /** 조명 1 정보 */
+        public EachStatus L1;
+        /** 조명 2 정보 */
+        public EachStatus L2;
+        /** 조명 3 정보 */
+        public EachStatus L3;
+        /** 조명 4 정보 */
+        public EachStatus L4;
+
+        public Status()
+        {
+            Elevator = new EachStatus();
+            Gas      = new EachStatus();
+            BatchOff = new EachStatus();
+            Outing   = new EachStatus();
+            HeatingInfo = new EachStatus();
+
+            LightCnt = 0;
+
+            L1 = new EachStatus();
+            L2 = new EachStatus();
+            L3 = new EachStatus();
+            L4 = new EachStatus();
+        }
+
+        /** 본 클래스 디버깅 메시지 */
+        public String ToDebugString(String name)
+        {
+            String retStr =
+                    "==========================\r\n" +
+                            name + " - Status\r\n" +
+                            "==========================\r\n" +
+                            "Elevator - Now(" + ToByteString(Elevator.Now) + ")  Ctrl(" + ToByteString(Elevator.Ctrl) + ")" + "\r\n" +
+                            "Gas      - Now(" + ToByteString(Gas.Now)      + ")  Ctrl(" + ToByteString(Gas.Ctrl)      + ")" + "\r\n" +
+                            "BatchOff - Now(" + ToByteString(BatchOff.Now) + ")  Ctrl(" + ToByteString(BatchOff.Ctrl) + ")" + "\r\n" +
+                            "Outing   - Now(" + ToByteString(Outing.Now)   + ")  Ctrl(" + ToByteString(Outing.Ctrl)   + ")" + "\r\n" +
+                            "HeatInfo - Now(" + ToByteString(HeatingInfo.Now)   + ")  Ctrl(" + ToByteString(HeatingInfo.Ctrl)   + ")" + "\r\n" +
+                            "\r\n" +
+                            "LightCnt - " + LightCnt + "\r\n" +
+                            "L1       - Now(" + ToByteString(L1.Now) + ")  Ctrl(" + ToByteString(L1.Ctrl) + ")" + "\r\n" +
+                            "L2       - Now(" + ToByteString(L2.Now) + ")  Ctrl(" + ToByteString(L2.Ctrl) + ")" + "\r\n" +
+                            "L3       - Now(" + ToByteString(L3.Now) + ")  Ctrl(" + ToByteString(L3.Ctrl) + ")" + "\r\n" +
+                            "L4       - Now(" + ToByteString(L4.Now) + ")  Ctrl(" + ToByteString(L4.Ctrl) + ")" + "\r\n";
+            return retStr;
+        }
+
+        private String ToByteString(byte data) { return String.format("0x%02X", data); }
+
+    }
+
+    /** 각 상태 구분 클래스 */
+    private class EachStatus
+    {
+        public byte Now;
+        public byte Ctrl;
+        public EachStatus()
+        {
+            Now = 0x00;
+            Ctrl = 0x00;
+        }
+    }
+
+    /** 기기 제어 */
+    private class CtrlStatus
+    {
+        public byte ElevatorCall;
+        public byte ElevatorDir;
+        public byte ElevatorLayer;
+
+        public byte Gas;
+
+        public byte Outing;
+
+        public byte BatchOff;
+
+        public byte LightCnt;
+
+        public byte [] LightStatus;
+
+        public CtrlStatus()
+        {
+            ElevatorCall  = 0x00;
+            ElevatorDir   = 0x00;
+            ElevatorLayer = 0x00;
+            Gas = 0x00;
+            Outing = 0x00;
+            BatchOff = 0x00;
+
+            LightCnt = mDriver.info.LightCnt;
+            LightStatus = new byte[LightCnt];
+            for(int i=0 ; i<LightStatus.length ; i++) LightStatus[i] = 0x00;
+        }
+
+        /**
+         * 기기 상태 변경 알림 명령어 0x13 - 에서 사용할 데이터 byte array 를 반환한다.
+         * 시간데이터는 자동으로 현재시간으로 체워진다. <br>
+         * 그외 엘리베이터 정보등은 지원을 할경우에 자동으로 현재 상태로 체워진다.<br>
+         * 단, 각 데이터를 0x00 초기값에서 설정하지 않을 경우에 한하여 현재상태로 체워진다.
+         *
+         * @return byte [] 명령어 0x13 용 데이터
+         */
+        public byte [] getByteArray()
+        {
+            if(mDriver == null) return null;
+            if(mDriver.info == null) return null;
+
+            byte [] retData = new byte [12 + LightCnt];
+            int index = 0;
+
+            // D1 ~ D6 : 현재날짜
+            // 년,월,일,시,분,초
+            if(mDriver.info.Support.Time)
+            {
+                Calendar cal = new GregorianCalendar();
+                retData[index++] = (byte) (cal.get(Calendar.YEAR) - 2000);
+                retData[index++] = (byte) (cal.get(Calendar.MONTH) + 1);
+                retData[index++] = (byte) cal.get(Calendar.DAY_OF_MONTH);
+                retData[index++] = (byte) cal.get(Calendar.HOUR_OF_DAY);
+                retData[index++] = (byte) cal.get(Calendar.MINUTE);
+                retData[index++] = (byte) cal.get(Calendar.SECOND);
+            }
+            else
+            {
+                retData[index++] = 0x00;
+                retData[index++] = 0x00;
+                retData[index++] = 0x00;
+                retData[index++] = 0x00;
+                retData[index++] = 0x00;
+                retData[index++] = 0x00;
+            }
+
+            // D7 : 엘리베이터 정보
+            byte Elevator = 0x00;
+            if(mDriver.info.Support.Elevator)
+            {
+                if(this.ElevatorCall == 0x00)
+                {
+                    this.ElevatorCall = ELEStatus;
+                    if (((ELEStatus&(byte)ELE_CALL_DOWN) == 0) && ((ELEStatus&(byte)ELE_ARR_DOWN)>0))
+                        ELEStatus^=(byte)ELE_ARR_DOWN;
+                    if (((ELEStatus&(byte)ELE_CALL_UP) == 0) && ((ELEStatus&(byte)ELE_ARR_UP)>0))
+                        ELEStatus^=(byte)ELE_ARR_UP;
+                    if (ELEStatus==0) ELELoc = "NONE";
+
+                    if(mDriver.info.Support.ElevatorDir)
+                    {
+                        if (ELEStatus == 0)
+                        {
+                            ELEMove = define.NOTIFY_DEVICE_ELE_MOVE_DIR_ERROR;
+                        }
+                    }
+                }
+                Elevator = this.ElevatorCall;
+            }
+            if(mDriver.info.Support.ElevatorDir)
+            {
+                if(this.ElevatorDir == 0x00)
+                {
+                    switch(ELEMove)
+                    {
+                        case define.NOTIFY_DEVICE_ELE_MOVE_DIR_UP:      this.ElevatorDir = define.BIT4; break;
+                        case define.NOTIFY_DEVICE_ELE_MOVE_DIR_DOWN:    this.ElevatorDir = define.BIT5; break;
+                        case define.NOTIFY_DEVICE_ELE_MOVE_DIR_STOP:    this.ElevatorDir = define.BIT4 | define.BIT5; break;
+                        case define.NOTIFY_DEVICE_ELE_MOVE_DIR_ERROR:   break;
+                    }
+                }
+                Elevator |= this.ElevatorDir;
+            }
+            retData[index++] = Elevator;
+
+            // D8 : 엘리베이터층 정보
+            if(mDriver.info.Support.Elevator)
+            {
+                if(ElevatorLayer == 0x00)
+                {
+                    byte floorinfo = 0;
+
+                    if( ((Elevator & ELE_ARR_DOWN) != 0x00) || ((Elevator & ELE_ARR_UP) != 0x00) )
+                    {
+                        // 엘리베이터 도착일 경우
+                        floorinfo = mDriver.HomeFloorNumber;
+                    }
+                    else
+                    {
+                        try {
+                            if (ELELoc.equals("NONE"))
+                            {
+                                floorinfo = (byte)0xFF;
+                            }
+                            else if (ELELoc.startsWith("B"))
+                            {
+                                floorinfo = Byte.parseByte(ELELoc.replace("B", ""));
+                                floorinfo|=(byte)0x80;
+                            }
+                            else
+                                floorinfo = Byte.parseByte(ELELoc);
+                        }
+                        catch (RuntimeException re) {
+                            LogUtil.errorLogInfo("", TAG, re);
+                            floorinfo = (byte)0xFF;
+                        }
+                        catch (Exception E) {
+                            LogUtil.errorLogInfo("", TAG, E);//
+                            floorinfo = (byte)0xFF;
+                        }
+                    }
+                    ElevatorLayer = floorinfo;
+                }
+            }
+            retData[index++] = ElevatorLayer;
+
+            // D9 : 가스 현재상태
+            if(mDriver.info.Support.Gas)
+            {
+                if(Gas == 0x00)
+                {
+                    byte GasValveStatus = GasValve_Controller.GetGasStatus();
+                    if (ServiceMain.gasValve_Controller != null && GasValveStatus != -1)
+                        Gas = (byte) (GasValveStatus == 0 ? 1 :(GasValveStatus == 2 ? 3 : 2));
+                }
+            }
+            retData[index++] = Gas;
+
+            // D10 : 외출설정 현재상태
+            if(mDriver.info.Support.Outing)
+            {
+                if(Outing == 0x00)
+                {
+                    int AlarmStatus = DB_GetAlarmStatus();
+                    switch(AlarmStatus)
+                    {
+                        case WallpadStatusData.ALARM_NONE:
+                            Outing = 0x02; // 외출설정 해제상태
+                            break;
+                        case WallpadStatusData.GUARD_OUT_WAIT:
+                            Outing = 0x03; // 외출설정 대기상태
+                            break;
+                        case WallpadStatusData.GUARD_OUT:
+                        case WallpadStatusData.OUT_MODE:
+                            Outing = 0x01; // 외출설정 상태
+                            break;
+                    }
+                }
+            }
+            retData[index++] = Outing;
+
+            // D11 : 일괄소등 현재상태
+            if(mDriver.info.Support.BatchOff)
+            {
+                if(!mDriver.info.Support.BatchOffDirCtrl)
+                {
+                    if(BatchOff == 0x00)
+                    {
+                        if(driverInterOpAPI.getAllLight())
+                        {
+                            BatchOff = 0x02;
+                        }
+                        else
+                        {
+                            BatchOff = 0x01;
+                        }
+                    }
+                }
+            }
+            retData[index++] = BatchOff;
+
+            // D12 : 조명 버튼 개수
+            retData[index++] = LightCnt;
+
+            // D13 ~ D16
+            if(LightCnt > 0)
+            {
+                byte Status = 0x00;
+                if(LightStatus[0] == 0x00)
+                {
+                    if(driverInterOpAPI.getLight(mDriver.L1Map)) Status = 0x01;
+                    else Status = 0x02;
+                    LightStatus[0] = Status;
+                }
+
+                if(LightCnt > 1)
+                {
+                    if(driverInterOpAPI.getLight(mDriver.L2Map)) Status = 0x01;
+                    else Status = 0x02;
+                    LightStatus[1] = Status;
+                }
+
+                for(byte i=0 ; i<LightCnt ; i++)
+                {
+                    retData[index++] = LightStatus[i];
+                }
+            }
+
+            return retData;
+        }
+    }
+
+    /** 드라이버 내부 변수     */
+    public class Driver
+    {
+        private Info info;           // 기기 정보
+
+        private Status status;       // 기기 상태
+
+        private PollingList Polling; // 폴링 상태
+
+        /** 서브일괄소등인 경우 (※일괄소등을 직접제어 하지만 메인 일괄소등제어기가 존재함) */
+        private boolean bSubBatchOffDirCtrl;
+
+        private byte L1Map;
+        private byte L2Map;
+
+        private int TargetModel;
+
+        /** 최초 일괄소등 상태 BR 송신 상태 */
+        private boolean bFirstBatchOffBRSend;
+
+        private byte HomeFloorNumber;
+
+        public Driver()
+        {
+            info = new Info();
+            status = new Status();
+            Polling = new PollingList();
+
+            bSubBatchOffDirCtrl = false;
+
+            L1Map = 0;
+            L2Map = 1;
+
+            TargetModel = WallpadDeviceSet.BATCH_TYPE_HDC_LCD_SMART;
+
+            bFirstBatchOffBRSend = false;
+
+            //세대 층정보 최초 입력 시작
+            int numberHo = 0;
+            String myHo = null;
+            try
+            {
+                WallpadStatusData DBMGR = new WallpadStatusData(ServiceMain.svcContext);
+                AddressSet addc =  DBMGR.getAddressMGR();
+                myHo = addc.Ho;
+                if(addc.UseOrNotRentHouse == true)
+                {
+                    numberHo = addc.Ho_Integer;
+                }
+                else
+                {
+                    numberHo = Integer.parseInt(myHo)/100;
+                }
+                DBMGR.closeDB();
+            }
+            catch (RuntimeException re) {
+                LogUtil.errorLogInfo("", TAG, re);
+            }
+            catch (Exception e) {
+                Log.e(TAG, "[Exception Error] Get addc.Ho");
+            }
+            HomeFloorNumber = (byte)(numberHo);
+            Log.i(TAG, "My Ho :" + myHo + ", HomeFloorNumber :+"+HomeFloorNumber);
+        }
+
+        /** Polling 관련 */
+        private class PollingList
+        {
+            private final class STATUS
+            {
+                public final static int First = 0;
+                public final static int FirstTimeOut = 1;
+                public final static int Normal = 2;
+            }
+
+            public int Status;
+            public int SearchTryCount;
+            public long StatusSinkTick;
+            public long EnergySinkTick;
+            public boolean ReBootDetect;
+
+            private boolean WeatherUpdate;
+            public void setWeatherUpdate(boolean set)    { WeatherUpdate = set; }
+            public boolean getWeatherUpdate() { return WeatherUpdate; }
+
+            private boolean ParkingUpdate;
+            public void setParkingUpdate(boolean set)    { ParkingUpdate = set; }
+            public boolean getParkingUpdate() { return ParkingUpdate; }
+
+            private boolean NotiInfoUpdate; // 알림 정보 사용 여부
+            public void setNotiInfoUpdate(boolean set)      { NotiInfoUpdate = set; }
+            public boolean getNotiInfoUpdate()   { return NotiInfoUpdate; }
+
+            private boolean HeatingInfoUpdate; // 난방 정보 사용 여부
+            public void setHeatingInfoUpdate(boolean set)    { HeatingInfoUpdate = set; }
+            public boolean getHeatingInfoUpdate()    { return HeatingInfoUpdate; }
+
+            private boolean AirQualityInfoUpdate; // 공기질 정보 사용 여부
+            public void setAirQualityInfoUpdate(boolean set)    { AirQualityInfoUpdate = set; }
+            public boolean getAirQualityInfoUpdate()    { return AirQualityInfoUpdate; }
+
+
+
+            private boolean AllLightSinkStart;
+            private boolean AllLightSinkDelay;
+            private long AllLightSinkTick;
+
+            private PollingList()
+            {
+                Status = STATUS.First;
+                SearchTryCount = 0;
+                StatusSinkTick = 0;
+                EnergySinkTick = 0;
+                ReBootDetect = false;
+
+                WeatherUpdate = false;
+                ParkingUpdate = false;
+
+                AllLightSinkStart = false;
+                AllLightSinkDelay = false;
+                AllLightSinkTick = 0;
+            }
+
+            public void StatusSinkTickReset()
+            {
+                StatusSinkTick = 0;
+            }
+
+            /**
+             * 일괄소등 동기화 딜레이를 설정한다.
+             */
+            public void SetAllLightSinkDelay()
+            {
+                AllLightSinkTick = System.currentTimeMillis();
+                AllLightSinkDelay = true;
+            }
+
+            /**
+             * 일괄소등 동기화를 해도되는지 체크한다.
+             *
+             * @return (boolean) 일괄소등 동기화 여부  true : 동기화가능,  false:동기화 불능
+             */
+            public boolean CheckAllLightSink()
+            {
+                // 1. 일괄소등 제어기가 연결이 완료되었는지 체크
+                if(!AllLightSinkStart)
+                {
+                    return false;
+                }
+
+                // 2. 동기화 시간 딜레이 체크
+                if(AllLightSinkDelay)
+                {
+                    long currentTimeMillis = System.currentTimeMillis();
+                    if(Math.abs(currentTimeMillis - mDriver.Polling.AllLightSinkTick) > ALLLIGHT_SYNC_TICK)
+                    {
+                        AllLightSinkDelay = false;
+                        return true;
+                    }
+                    else
+                    {
+                        return false;
+                    }
+                }
+                return true;
+            }
+        }
+    }
+    private Driver mDriver = null;
+
+    /**
+     * 생성자
+     */
+    public SmartSwitchPol_Controller() {
+        /** 로그 초기상태 */
+        log_sw = true;
+        SerialLog = true;
+
+        /** 모델정보 가져오기 */
+        mModelType = Version.getModelType();
+
+        /** 통신성공률 변수 초기화 */
+        CommDataGeneration(1);
+
+        /** 드라이버 내부 변수 초기화 */
+        mDriver = new Driver();
+
+        /** 스마트스위치 L1 & L2 맵핑 데이터 가져오기 */
+        GetBatchSwInfo();
+
+        /** 월패드 설정 - 스마트스위치 모델명 가져오기 */
+        int [] Get_BatchSW_Info = ServiceMain.dataBaseLoader.data.wallpadDeviceSet.Get_BatchSW_Info;
+        if (Get_BatchSW_Info != null) {
+            if (Get_BatchSW_Info.length >= 2) {
+                mDriver.TargetModel = Get_BatchSW_Info[1];
+                Log.i(TAG, "[SmartSwitchPol_Controller] WallpadDeviceSet - OK!!!");
+            }
+        }
+
+        Log.i(TAG, "[SmartSwitchPol_Controller] mDriver.TargetModel: " + mDriver.TargetModel);
+
+        // 부팅 시, 월패드가 이미 가지고 있던 각 알림정보 요소들의 개수를 가져온다.
+        // 초기 값을 설정하여 인텐트로 수신받은 각 알림정보 요소들이 증가,감소 하는지 확인하기 위해 사용한다.
+        WallpadStatusData OriginWsd = new WallpadStatusData(ServiceMain.svcContext);
+        DefaultNotiCNT = OriginWsd.GetNoticeCNT();
+        DefaultParcelCNT = OriginWsd.GetParcelCNT();
+        DefaultMemoCNT = OriginWsd.GetMemoCNT();
+
+        Log.i(TAG, "default Noti = " + DefaultNotiCNT);
+        Log.i(TAG, "default Parcel = " + DefaultParcelCNT);
+        Log.i(TAG, "default Memo = " + DefaultMemoCNT);
+        OriginWsd.closeDB();
+
+        Log.i(TAG, "=========================================");
+        Log.i(TAG, "SmartSwitchPol_Controller - create");
+        Log.i(TAG, "=========================================");
+    }
+
+    /**
+     * 스마트스위치 L1 & L2 맵핑 데이터 가져온다.
+     *
+     * @return (int) - >=0 : 성공, <0 : 실패
+     */
+    private int GetBatchSwInfo() {
+        try {
+            int [] Get_BatchSW_Info = ServiceMain.dataBaseLoader.data.wallpadDeviceSet.Get_BatchSW_Info;
+            DeviceLog("GetBatchSwInfo "+Get_BatchSW_Info[0]+" : "+Get_BatchSW_Info[1]+" : "+Get_BatchSW_Info[2]+" : "+Get_BatchSW_Info[3]);
+
+            if ((Get_BatchSW_Info[2] > 0) && (Get_BatchSW_Info[2] <= 6)) {
+                mDriver.L1Map = (byte)(Get_BatchSW_Info[2]-1);
+            }
+
+            if ((Get_BatchSW_Info[3] > 0) && (Get_BatchSW_Info[3] <= 6)) {
+                mDriver.L2Map = (byte)(Get_BatchSW_Info[3]-1);
+            }
+
+            DeviceLog("GetBatchSwInfo  L1Map : " + mDriver.L1Map + " / L2Map : " + mDriver.L2Map);
+        } catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+            return -1;
+        } catch (Exception e) {
+            Log.e(TAG, "[Exception Error] GetBatchSwInfo()");
+            //e.printStackTrace();
+            LogUtil.errorLogInfo("", TAG, e);
+            return -1;
+        }
+        return 0;
+    }
+
+    /**
+     * BroadcastReceiver 용 필터를 등록한다.
+     *
+     * @return (boolean) true : 성공 , false : 실패
+     */
+    private boolean Device_BrRegistration() {
+        DeviceLog("Device_BrRegistration - Start");
+
+        if (mDriver == null) return false;
+        if (mDriver.Polling.Status != Driver.PollingList.STATUS.Normal) return false;
+
+        IntentFilter filter = new IntentFilter();
+
+        // 1. NOTIFY_ACNAME
+        if (mDriver.info.Support.Weather || mDriver.info.Support.Parking || mDriver.info.Support.Elevator || mDriver.info.Support.Energy || mDriver.info.Support.Time || mDriver.info.Support.Outing || mDriver.info.Support.BatchOff) {
+            DeviceLog("Device_BrRegistration - filter.addAction - " + define.NOTIFY_ACNAME);
+            filter.addAction(define.NOTIFY_ACNAME);
+        }
+
+        // 2. DRIVER_LIGHT_BR
+        if (mDriver.info.LightCnt > 0) {
+            DeviceLog("Device_BrRegistration - filter.addAction - " + define.DRIVER_LIGHT_BR);
+            driverInterOpAPI.setLightRegBR(define.DRIVER_LIGHT_BR);
+            filter.addAction(define.DRIVER_LIGHT_BR);
+        }
+
+        // 3. DRIVER_GAS_BR
+        if (mDriver.info.Support.Gas) {
+            DeviceLog("Device_BrRegistration - filter.addAction - " + define.DRIVER_GAS_BR);
+            driverInterOpAPI.GasRegBR(define.DRIVER_GAS_BR);
+            filter.addAction(define.DRIVER_GAS_BR);
+        }
+
+        // 4. ISD의 알림정보 제공을 위한 Action 추가
+        if (mDriver.info.Support.NotiInfo) {
+            DeviceLog("Device_BrRegistration - filter.addAction - " + "ISD_NotiInfo");
+            filter.addAction(define.DRIVER_ISD_NOTIINFO);
+        }
+
+        // 5. 공기질 정보 알림정보 제공을 위한 Action 추가
+        if (mDriver.info.Support.AirQualityInfo) {
+            DeviceLog("Device_BrRegistration - filter.addAction - " + "ISD_NotiInfo");
+            //아래 스트링은 define에 추가해야함.
+            filter.addAction("AIRQUALITYCHANGEDForSVC");
+        }
+
+        ServiceMain.svcContext.registerReceiver(mWallPadNotifyBR, filter);
+        DeviceLog("Device_BrRegistration - OK");
+
+        return true;
+    }
+
+    @Override
+    public void DeviceLog(String msg) {
+        if (!log_sw) return;
+        Log.d(TAG, msg);
+    }
+
+    /**
+     * BroadcastReceiver
+     */
+    private BroadcastReceiver mWallPadNotifyBR = new BroadcastReceiver() {
+        public void onReceive(Context context, Intent intent) {
+            String strActionName = intent.getAction();
+            DeviceLog("[mWallPadNotifyBR] strActionName ["+ strActionName + "]");
+
+            if (mDriver.Polling.Status != Driver.PollingList.STATUS.Normal) return;
+
+            if (strActionName.equals(define.NOTIFY_ACNAME)) {
+                int kind = intent.getIntExtra("KIND", 0);
+                DeviceLog("[mWallPadNotifyBR] "+ define.NOTIFY_ACNAME + " : " + kind);
+
+                switch (kind) {
+                    case define.NOTIFY_UPDATEWEATHER:
+                        if (mDriver.info.Support.Weather) {
+                            mDriver.Polling.setWeatherUpdate(true);
+                        }
+                        break;
+
+                    case define.NOTIFY_UPDATEPARKING:
+                        if (mDriver.info.Support.Parking) {
+                            mDriver.Polling.setParkingUpdate(true);
+                        }
+                        break;
+
+                    //////////////////////////////////////////////////////////////
+                    // 엘리베이터 관련
+                    //////////////////////////////////////////////////////////////
+                    case define.NOTIFY_ELE_MOVE:
+                        // 엘리베이터 이동 알림
+                        if (mDriver.info.Support.Elevator) {
+                            ELELoc = intent.getStringExtra(define.NOTIBR_FLOOR);
+                            DeviceLog("[mWallPadNotifyBR] define.NOTIFY_ELE_MOVE -> ELELoc:" + ELELoc);
+                            mDriver.Polling.StatusSinkTickReset();
+                        }
+
+                        if (mDriver.info.Support.ElevatorDir) {
+                            ELEMove = intent.getIntExtra(define.NOTIBR_MOVEDIR, define.NOTIFY_DEVICE_ELE_MOVE_DIR_ERROR);
+                            DeviceLog("[mWallPadNotifyBR] define.NOTIFY_ELE_MOVE -> ELEMove:" + ELEMove);
+                            mDriver.Polling.StatusSinkTickReset();
+                        }
+                        break;
+
+                    case define.NOTIFY_ELE_CALL_UP:
+                        // 상향 - 엘리베이터 호출 성공
+                        if (mDriver.info.Support.Elevator) {
+                            DeviceLog("[mWallPadNotifyBR] define.NOTIFY_ELE_CALL_UP");
+                            ELEStatus|=(byte)ELE_CALL_UP;
+                            mDriver.Polling.StatusSinkTickReset();
+                        }
+                        break;
+
+                    case define.NOTIFY_ELE_CALL_DOWN:
+                        // 하향 - 엘리베이터 호출 성공
+                        if (mDriver.info.Support.Elevator) {
+                            DeviceLog("[mWallPadNotifyBR] define.NOTIFY_ELE_CALL_DOWN");
+                            ELEStatus|=(byte)ELE_CALL_DOWN;
+                            mDriver.Polling.StatusSinkTickReset();
+                        }
+                        break;
+
+                    case define.NOTIFY_ELE_ARRIVAL_UP:
+                        // 상향 - 엘리베이터 도착
+                        if (mDriver.info.Support.Elevator) {
+                            DeviceLog("[mWallPadNotifyBR] define.NOTIFY_ELE_ARRIVAL_UP");
+
+                            if ((ELEStatus&ELE_CALL_UP)>0) ELEStatus^=(byte)ELE_CALL_UP;
+                            ELEStatus |= ELE_ARR_UP;
+                            mDriver.Polling.StatusSinkTickReset();
+                        }
+                        break;
+
+                    case define.NOTIFY_ELE_ARRIVAL_DOWN:
+                        // 하향 - 엘리베이터 도착
+                        if (mDriver.info.Support.Elevator) {
+                            DeviceLog("[mWallPadNotifyBR] define.NOTIFY_ELE_ARRIVAL_DOWN");
+                            if ((ELEStatus&ELE_CALL_DOWN)>0) ELEStatus^=(byte)ELE_CALL_DOWN;
+                            ELEStatus |= ELE_ARR_DOWN;
+                            mDriver.Polling.StatusSinkTickReset();
+                        }
+                        break;
+
+                    case define.NOTIFY_ELE_CALL_UP_ERROR:
+                        // 상향 - 엘리베이터 호출 에러
+                        if (mDriver.info.Support.Elevator) {
+                            DeviceLog("[mWallPadNotifyBR] define.NOTIFY_ELE_CALL_UP_ERROR");
+
+                            if ((ELEStatus&ELE_CALL_UP)>0) {
+                                ELEStatus^=(byte)ELE_CALL_UP;
+                                mDriver.Polling.StatusSinkTickReset();
+                            }
+                        }
+                        break;
+
+                    case define.NOTIFY_ELE_CALL_DOWN_ERROR:
+                        // 하향 - 엘리베이터 호출 에러
+                        if (mDriver.info.Support.Elevator) {
+                            DeviceLog("[mWallPadNotifyBR] define.NOTIFY_ELE_CALL_DOWN_ERROR");
+
+                            if ((ELEStatus&ELE_CALL_DOWN)>0) {
+                                ELEStatus^=(byte)ELE_CALL_DOWN;
+                                mDriver.Polling.StatusSinkTickReset();
+                            }
+                        }
+                        break;
+
+                    case define.NOTIFY_ELE_CALL_UP_TIMEOUT:
+                        // 상향 - 엘리베이터 호출 타임아웃
+                        if (mDriver.info.Support.Elevator) {
+                            DeviceLog("[mWallPadNotifyBR] define.NOTIFY_ELE_CALL_UP_TIMEOUT");
+
+                            if ((ELEStatus&ELE_CALL_UP)>0) {
+                                ELEStatus^=(byte)ELE_CALL_UP;
+                                mDriver.Polling.StatusSinkTickReset();
+                            }
+                        }
+                        break;
+
+                    case define.NOTIFY_ELE_CALL_DOWN_TIMEOUT:
+                        // 하향 - 엘리베이터 호출 타임아웃
+                        if (mDriver.info.Support.Elevator) {
+                            if ((ELEStatus&ELE_CALL_DOWN)>0) {
+                                ELEStatus^=(byte)ELE_CALL_DOWN;
+                                mDriver.Polling.StatusSinkTickReset();
+                            }
+                        }
+                        break;
+
+                    case define.NOTIFY_ENERGYUPDATE:
+                        // 에너지 사용량 업데이트
+                        if (mDriver.info.Support.Energy) {
+                        }
+                        break;
+
+                    case define.NOTIFY_SYSTEMTIMESETTED:
+                        // 시스템시간 업데이트
+                        if (mDriver.info.Support.Time) {
+                            DeviceLog("[mWallPadNotifyBR] define.NOTIFY_SYSTEMTIMESETTED");
+                            mDriver.Polling.StatusSinkTickReset();
+                        }
+                        break;
+
+                    case define.NOTIFY_ALL_LIGHT_ON:
+                        // 일괄소등 해제
+                        mDriver.Polling.AllLightSinkStart = true;
+                        if (mDriver.info.Support.BatchOff && !mDriver.info.Support.BatchOffDirCtrl) {
+                            if (mDriver.status.BatchOff.Now != 0x02) mDriver.Polling.StatusSinkTickReset();
+                        }
+                        break;
+
+                    case define.NOTIFY_ALL_LIGHT_OFF:
+                        // 일괄소등 설정
+                        mDriver.Polling.AllLightSinkStart = true;
+                        if (mDriver.info.Support.BatchOff && !mDriver.info.Support.BatchOffDirCtrl) {
+                            if (mDriver.status.BatchOff.Now != 0x01) mDriver.Polling.StatusSinkTickReset();
+                        }
+                        break;
+
+                    case define.NOTIFY_ALARM_CHANGE:
+                        // 알람상태가 DB에서 갱신되었을 경우
+                        if (mDriver.info.Support.Outing) {
+                            mDriver.Polling.StatusSinkTickReset();
+                        }
+                        break;
+
+                    case define.NOTIFY_TELEMETERING_DAILY_USAGE:
+                        // 원격검침값이 갱신된 경우
+                        DeviceLog("[mWallPadNotifyBR] define.NOTIFY_TELEMETERING_DAILY_USAGE");
+                        if (ServiceMain.realTimeMeter_Controller != null) {
+                            DeviceLog("[mWallPadNotifyBR] define.NOTIFY_TELEMETERING_DAILY_USAGE -> ServiceMain.realTimeMeter_Controller is not null!!!");
+                        }
+                        else  {
+                            DeviceLog("[mWallPadNotifyBR] define.NOTIFY_TELEMETERING_DAILY_USAGE -> ServiceMain.realTimeMeter_Controller is null!!!");
+                            procTelemeteringData(intent);
+                        }
+                        break;
+                }
+            }
+            else if (strActionName.equals(define.DRIVER_GAS_BR)) {
+                if (mDriver.info.Support.Gas) {
+                    mDriver.Polling.StatusSinkTickReset();
+                }
+            }
+            else if (strActionName.equals(define.DRIVER_LIGHT_BR)) {
+                if (mDriver.info.LightCnt > 0) {
+                    byte RoomIdx = intent.getByteExtra("STATUS", (byte)0xF0);
+                    if ((RoomIdx == (byte)0) || (RoomIdx == (byte)0xF0)) {
+                        // 현산일체형조명제어기 or 대외향 거실조명 의 경우 STATUS 값이 없으므로 0xF0
+                        // 멀티스위치일 경우에는 0번 (거실) 만 처리 하도록
+                        boolean bLight = false;
+                        boolean bChanged = false;
+
+                        // L1
+                        bLight = driverInterOpAPI.getLight(mDriver.L1Map);
+                        DeviceLog("[mWallPadNotifyBR] define.DRIVER_LIGHT_BR -> getLight - L1Map (" + mDriver.L1Map + ") " + bLight + "  /  mDriver.status.L1.Now : " + mDriver.status.L1.Now);
+                        if (bLight) { if (mDriver.status.L1.Now != 0x01) bChanged = true; }
+                        else { if (mDriver.status.L1.Now != 0x02) bChanged = true; }
+                        if (bChanged) mDriver.Polling.StatusSinkTickReset();
+
+                        if (mDriver.info.LightCnt > 1) {
+                            bLight = driverInterOpAPI.getLight(mDriver.L2Map);
+                            DeviceLog("[mWallPadNotifyBR] define.DRIVER_LIGHT_BR -> getLight - L2Map (" + mDriver.L2Map + ") " + bLight + "  /  mDriver.status.L2.Now : " + mDriver.status.L2.Now);
+                            if (bLight) { if (mDriver.status.L2.Now != 0x01) bChanged = true; }
+                            else { if (mDriver.status.L2.Now != 0x02) bChanged = true; }
+                            if (bChanged) mDriver.Polling.StatusSinkTickReset();
+                        }
+                    }
+                }
+            }
+            else if (strActionName.equals(define.DRIVER_ISD_NOTIINFO)) {   // 인텐트로 수신한 알림 정보를 관리 array에 저장
+
+                // 공지사항 정보 업데이트
+                if (intent.hasExtra(define.NOTIBR_ISD_NOTICECNT)) {
+                    int numNoticeCnt = intent.getIntExtra(define.NOTIBR_ISD_NOTICECNT, 0);
+                    if (numNoticeCnt != 0) {
+                        NotiArr[0] = numNoticeCnt;
+                        DeviceLog("[mWallPadNotifyBR] define.DRIVER_ISD_NOTIINFO -> define.NOTIBR_ISD_NOTICECNT = " + numNoticeCnt);
+                    }
+                    else if (numNoticeCnt == 0) {
+                        NotiArr[0] = 0;
+                        DeviceLog("[mWallPadNotifyBR] define.DRIVER_ISD_NOTIINFO -> define.NOTIBR_ISD_NOTICECNT = " + numNoticeCnt);
+                    }
+                }
+
+                // 택배 정보 업데이트
+                if (intent.hasExtra(define.NOTIBR_ISD_PARCELCNT)) {
+                    int numParcelCnt = intent.getIntExtra(define.NOTIBR_ISD_PARCELCNT, 0);
+                    if (numParcelCnt != 0) {
+                        NotiArr[1] = numParcelCnt;
+                        DeviceLog("[mWallPadNotifyBR] define.DRIVER_ISD_NOTIINFO -> define.NOTIBR_ISD_PARCELCNT = " + numParcelCnt);
+                    }
+                    else if (numParcelCnt == 0) {
+                        NotiArr[1] = 0;
+                        DeviceLog("[mWallPadNotifyBR] define.DRIVER_ISD_NOTIINFO -> define.NOTIBR_ISD_PARCELCNT = " + numParcelCnt);
+                    }
+                }
+
+                // 방문자 정보 업데이트
+                if (intent.hasExtra(define.NOTIBR_ISD_VISITORCNT)) {
+                    int numVisitorCnt = intent.getIntExtra(define.NOTIBR_ISD_VISITORCNT, 0);
+                    if (numVisitorCnt != 0) {
+                        NotiArr[2] = numVisitorCnt;
+                        DeviceLog("[mWallPadNotifyBR] define.DRIVER_ISD_NOTIINFO -> define.NOTIBR_ISD_VISITORCNT = " + numVisitorCnt);
+                    }
+                    else if (numVisitorCnt == 0) {
+                        DeviceLog("[mWallPadNotifyBR] define.DRIVER_ISD_NOTIINFO -> define.NOTIBR_ISD_VISITORCNT = " + numVisitorCnt);
+                        DefaultVisitorCNT = 0;
+                        NotiArr[2] = 0;
+                    }
+                }
+
+                // 메모 정보 업데이트
+                if (intent.hasExtra(define.NOTIBR_ISD_MEMOCNT)) {
+                    int numMemoCnt = intent.getIntExtra(define.NOTIBR_ISD_MEMOCNT, 0);
+                    if (numMemoCnt != 0) {
+                        NotiArr[3] = numMemoCnt;
+                        DeviceLog("[mWallPadNotifyBR] define.DRIVER_ISD_NOTIINFO -> define.NOTIBR_ISD_MEMOCNT = " + numMemoCnt);
+                    }
+                    else if (numMemoCnt == 0) {
+                        DeviceLog("[mWallPadNotifyBR] define.DRIVER_ISD_NOTIINFO -> define.NOTIBR_ISD_MEMOCNT = " + numMemoCnt);
+                        DefaultMemoCNT = 0;
+                        NotiArr[3] = 0;
+                    }
+                }
+
+                // 초기 값과 현재 값 비교 (초기값: 부팅시, 이미 갖고 있던 값 / 현재값:intent로 받은 값)
+                if (isNotiDataChanged(NotiArr)) {
+                    mDriver.Polling.setNotiInfoUpdate(true);
+                    DeviceLog("[mWallPadNotifyBR] define.DRIVER_ISD_NOTIINFO -> isNotiDataChanged(NotiArr) = true");
+                }
+            }
+            //공기질 정보 변경 체크
+            else if (strActionName.equals("AIRQUALITYCHANGEDForSVC")) {
+                if (mDriver.info.Support.AirQualityInfo) {
+                    mDriver.Polling.setAirQualityInfoUpdate(true);
+                }
+            }
+        }
+    };
+
+    private String NoTelemeteringValue = "NONE";
+    private String strElecUsage = NoTelemeteringValue;
+    private String strWaterUsage = NoTelemeteringValue;
+    private String strGasUsage = NoTelemeteringValue;
+    private String strHotwaterUsage = NoTelemeteringValue;
+    private String strHeatingUsage = NoTelemeteringValue;
+    private void procTelemeteringData(Intent mIntent) {
+        try {
+            DeviceLog("[procTelemeteringData] start");
+            String tempElect_used = mIntent.getStringExtra("elect_used");
+            if (tempElect_used != null) {
+                Log.i(TAG, "[procTelemeteringData] tempElect_used [" + tempElect_used + "]");
+                strElecUsage = tempElect_used;
+            }
+            else {
+                Log.w(TAG, "[procTelemeteringData] tempElect_used is null!!");
+            }
+
+            String tempWater_used = mIntent.getStringExtra("water_used");
+            if (tempWater_used != null) {
+                Log.i(TAG, "[procTelemeteringData] tempWater_used [" + tempWater_used + "]");
+                strWaterUsage = tempWater_used;
+            }
+            else {
+                Log.w(TAG, "[procTelemeteringData] tempElect_used is null!!");
+            }
+
+            String tempGas_used = mIntent.getStringExtra("gas_used");
+            if (tempGas_used != null) {
+                Log.i(TAG, "[procTelemeteringData] tempGas_used [" + tempGas_used + "]");
+                strGasUsage = tempGas_used;
+            }
+            else {
+                Log.w(TAG, "[procTelemeteringData] tempElect_used is null!!");
+            }
+
+            String tempHotwater_used = mIntent.getStringExtra("hotwater_used");
+            if (tempHotwater_used != null) {
+                Log.i(TAG, "[procTelemeteringData] tempHotwater_used [" + tempHotwater_used + "]");
+                strHotwaterUsage = tempHotwater_used;
+            }
+            else {
+                Log.w(TAG, "[procTelemeteringData] tempElect_used is null!!");
+            }
+
+            String tempHeating_used = mIntent.getStringExtra("heating_used");
+            if (tempHeating_used != null) {
+                Log.i(TAG, "[procTelemeteringData] tempHeating_used [" + tempHeating_used + "]");
+                strHeatingUsage = tempHeating_used;
+            }
+            else {
+                Log.w(TAG, "[procTelemeteringData] tempElect_used is null!!");
+            }
+
+            DeviceLog("[procTelemeteringData] strElecUsage [" + strElecUsage + "], strWaterUsage [" + strWaterUsage + "], strGasUsage [" + strGasUsage + "], strHotwaterUsage [" + strHotwaterUsage + "], strHeatingUsage [" + strHeatingUsage + "] ");
+
+        } catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+        } catch (Exception e) {
+            Log.e(TAG, "[Exception] procTelemeteringData(Intent mIntent)");
+            //e.printStackTrace();
+            LogUtil.errorLogInfo("", TAG, e);
+        }
+    }
+
+    /**
+     * 로딩후 처음 폴링 시퀀스
+     */
+    @Override
+    protected void do_boot() {
+        driverInterOpAPI = new DriverInterOpAPI(MainHandler);
+    }
+
+    /**
+     * do_ctr : 폴링스케쥴러
+     */
+    @Override
+    protected void do_ctr() {
+        DeviceLog("Polling Status " + mDriver.Polling.Status);
+
+//        Log.w(TAG, "[do_ctr] Weather [" + mDriver.info.Support.Weather + "], Parking [" + mDriver.info.Support.Parking + "], Energy [" + mDriver.info.Support.Energy + "], NotiInfo [" + mDriver.info.Support.NotiInfo + "], HeatingInfo [" + mDriver.info.Support.HeatingInfo + "], bSubBatchOffDirCtrl [" + mDriver.bSubBatchOffDirCtrl + "]");
+
+        /////////////////////////////////////////////////////////////////////
+        // 1. First & FirstTimeOut - Polling
+        /////////////////////////////////////////////////////////////////////
+        if ((mDriver.Polling.Status == Driver.PollingList.STATUS.First) || (mDriver.Polling.Status == Driver.PollingList.STATUS.FirstTimeOut)) {
+            // 1.1. FirstTimeOut 체크
+            if (mDriver.Polling.Status == Driver.PollingList.STATUS.First) {
+                if (mDriver.Polling.SearchTryCount++ > MAX_SEARCH_COUNT) {
+                    mDriver.Polling.Status = Driver.PollingList.STATUS.FirstTimeOut;
+                    Log.i(TAG, "--------------------------------------------------");
+                    Log.i(TAG, "SearchDevice Fail... FirstTimeOut ");
+                    Log.i(TAG, "--------------------------------------------------");
+                    ServiceMain.deviceInitChecker.Remove(super.DeviceName);
+                }
+            }
+
+            // 1.2. 보드상태 가져오기
+            Info info = Send_GetBoardInfoRead();
+            if (info != null) {
+                mDriver.info = info;
+                Log.i(TAG, info.ToDebugString());
+                mDriver.Polling.Status = Driver.PollingList.STATUS.Normal;
+
+                ServiceMain.deviceInitChecker.Remove(super.DeviceName);
+
+                Device_BrRegistration();
+
+                if (mDriver.info.Support.Weather) mDriver.Polling.setWeatherUpdate(true);
+                if (mDriver.info.Support.Parking) mDriver.Polling.setParkingUpdate(true);
+                if (mDriver.info.Support.NotiInfo) mDriver.Polling.setNotiInfoUpdate(true);
+                if (mDriver.info.Support.HeatingInfo) mDriver.Polling.setHeatingInfoUpdate(true);
+
+                // 현산모델에서 일괄소등을 직접 제어하는경우에  [서브일괄소등 플래그] 를 설정한다.
+                if (Version.getGatewayUsage()) {
+                    if (mDriver.info.Support.BatchOffDirCtrl) {
+                        Log.i(TAG, "[do_ctr] bSubBatchOffDirCtrl  SETTING !!!");
+                        mDriver.bSubBatchOffDirCtrl = true;
+                    }
+                }
+            }
+        }
+        /////////////////////////////////////////////////////////////////////
+        // 2. Normal - Polling
+        /////////////////////////////////////////////////////////////////////
+        else if (mDriver.Polling.Status == Driver.PollingList.STATUS.Normal) {
+            long currentTimeMillis = 0;
+
+            // 2.1. 날씨정보 동기화
+            if (mDriver.info.Support.Weather) {
+                if (mDriver.Polling.getWeatherUpdate()) {
+                    int ret = WeatherUpdate();
+                    if(ret >= 0) mDriver.Polling.setWeatherUpdate(false);
+                    Sleep(100);
+                }
+            }
+
+            // 2.2. 주차정보 동기화
+            if (mDriver.info.Support.Parking) {
+                if (mDriver.Polling.getParkingUpdate()) {
+                    int ret = ParkingUpdate();
+                    if (ret >= 0) mDriver.Polling.setParkingUpdate(false);
+                    Sleep(100);
+                }
+            }
+
+            // 2.3. 에너지정보 동기화
+            if (mDriver.info.Support.Energy) {
+                currentTimeMillis = System.currentTimeMillis();
+                if (Math.abs(currentTimeMillis - mDriver.Polling.EnergySinkTick) > ENERGY_SYNC_TICK) {
+                    mDriver.Polling.EnergySinkTick = currentTimeMillis;
+                    updateEnergy();
+                    Sleep(100);
+                }
+            }
+
+            // 2.4 알림 정보
+            if (mDriver.info.Support.NotiInfo) {
+                if (mDriver.Polling.getNotiInfoUpdate()) {
+                    int ret = NotiInfoUpdate();
+                    //Log.i(TAG, "NotiInfo polling ret = " + ret);
+                    if (ret >= 0) {
+                        // 정상적으로 ret이 반환되면 ret == 0
+                        mDriver.Polling.setNotiInfoUpdate(false);
+                        //Log.i(TAG, "false NotiInfoUpdate = " + mDriver.Polling.getNotiInfoUpdate());
+                    }
+                    Sleep(100);
+                }
+            }
+
+
+            //2.5 공기질 정보
+            if (mDriver.info.Support.AirQualityInfo) {
+                int ret = AirQualityInfoUpdate();
+                if(ret >= 0){
+                    Log.i(TAG, "[do_ctr] AirQualityInfoUpdate  success !!!");
+                }
+                Sleep(100);
+            }
+
+
+            // 2.5 난방 정보
+            if (mDriver.info.Support.HeatingInfo) {
+                if (mDriver.Polling.getHeatingInfoUpdate()) {
+                    int ret = HeatingInfoUpdate();
+                    //Log.i(TAG, "HeatingInfo polling ret = " + ret);
+                    if (ret >= 0) {
+                        mDriver.Polling.setHeatingInfoUpdate(false);
+                        //Log.i(TAG, "false HeatingInfoUpdate = " + mDriver.Polling.getHeatingInfoUpdate());
+                    }
+                    Sleep(100);
+                }
+            }
+
+
+            // 2.6. 상태 동기화
+            currentTimeMillis = System.currentTimeMillis();
+//            Log.w(TAG, "[do_ctr] currentTimeMillis [" + currentTimeMillis + "], mDriver.Polling.StatusSinkTick [" + mDriver.Polling.StatusSinkTick + "]");
+//            Log.w(TAG, "[do_ctr] time [" + (Math.abs(currentTimeMillis - mDriver.Polling.StatusSinkTick) + "], STATUS_SYNC_TICK [" + STATUS_SYNC_TICK + "]"));
+            if (Math.abs(currentTimeMillis - mDriver.Polling.StatusSinkTick) > STATUS_SYNC_TICK) {
+                mDriver.Polling.StatusSinkTick = currentTimeMillis;
+                CtrlStatus ctrlStatus = new CtrlStatus();
+                Send_SetStatus(ctrlStatus);
+            }
+            // 2.7. 상태 읽기
+            else {
+                Send_GetStatus();
+            }
+
+            // 2.8. 서브일괄소등제어기 인경우,  메인일괄소등과 상태가 다를경우 동기화
+            if (mDriver.bSubBatchOffDirCtrl) {
+                if (mDriver.Polling.CheckAllLightSink()) {
+                    boolean MainAllLightStatus = driverInterOpAPI.getAllLight();
+                    boolean SmartSwAllLightStatus = false;
+                    if (mDriver.status.BatchOff.Now == 0x02) SmartSwAllLightStatus = true;
+
+                    if (MainAllLightStatus != SmartSwAllLightStatus) {
+                        Sleep(100);
+                        CtrlStatus ctrlStatus = new CtrlStatus();
+                        if (MainAllLightStatus) ctrlStatus.BatchOff = 0x02;
+                        else ctrlStatus.BatchOff = 0x01;
+
+                        Status status = Send_SetStatus(ctrlStatus);
+                        boolean bRet = false;
+                        if (status != null) bRet = true;
+
+                        Log.i(TAG, "[do_ctr] AllLightSink !!! (MainAllLightStatus:" + MainAllLightStatus + " , bRet:" + bRet + ")");
+                    }
+                }
+            }
+        }
+        else {
+            mDriver = new Driver();
+        }
+    }
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    // Ctrl
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+     * NoSink 제어
+     *
+     * @param StrArg
+     *
+     * @return
+     */
+    public String NoSinkCtrl(String StrArg) {
+        DeviceLog("[NoSinkCtrl] Start");
+
+        // 1. 디바이스 초기화시 에러리턴
+        if ((mDriver.Polling.Status == Driver.PollingList.STATUS.First) || (mDriver.Polling.Status == Driver.PollingList.STATUS.FirstTimeOut)) {
+            Log.w(TAG, "[NoSinkCtrl] - Not Yet !!!");
+            return "FAIL;" + APIErrorCode.DEVICEISNOTREADY;
+        }
+
+        CtrDevFormat ctrDevFormat = GetCtrDevParamParsing(StrArg, 5);
+        if (ctrDevFormat.ret != APIErrorCode.C_SUCCESS) {
+            Log.w(TAG, "[NoSinkCtrl] GetCtrDevParamParsing Error (ret:" + ctrDevFormat.ret + ")");
+            return "FAIL;" + APIErrorCode.DEFAULT_PARSING_ERR;
+        }
+
+        //////////////////////////////////////////////////////////
+        // Refresh : 데이터 갱신 (No Sink)
+        //////////////////////////////////////////////////////////
+        if (ctrDevFormat.CmdStr!=null && ctrDevFormat.CmdStr.equals("Refresh")) {
+            return RefreshResult();
+        }
+
+        return "FAIL;" + APIErrorCode.UNKNOWNCOMMAND;
+    }
+
+    /**
+     * do_ctrEmm : 싱크 제어
+     */
+    @Override
+    @SuppressLint("DefaultLocale")
+    protected String do_ctrEmm(DeviceCtrSHMem SHMem) {
+        DeviceLog("[do_ctrEmm] Start");
+        DeviceLog("cmd    : " + SHMem.cmd);
+        DeviceLog("StrArg : " + SHMem.StrArg);
+
+        // 1. 디바이스 초기화시 에러리턴
+        if ((mDriver.Polling.Status == Driver.PollingList.STATUS.First) || (mDriver.Polling.Status == Driver.PollingList.STATUS.FirstTimeOut)) {
+            Log.w(TAG, "[do_ctrEmm] - Not Yet !!!");
+            return SHMem.retVal = "FAIL;" + APIErrorCode.DEVICEISNOTREADY;
+        }
+
+        CtrDevFormat ctrDevFormat = GetCtrDevParamParsing(SHMem.StrArg, 5);
+        if (ctrDevFormat.ret != APIErrorCode.C_SUCCESS) {
+            Log.w(TAG, "[do_ctrEmm] GetCtrDevParamParsing Error (ret:" + ctrDevFormat.ret + ")");
+            return SHMem.retVal = "FAIL;" + APIErrorCode.DEFAULT_PARSING_ERR;
+        }
+
+        if(ctrDevFormat.CmdStr!=null)
+        {
+            //////////////////////////////////////////////////////////
+            // Refresh : 데이터 갱신 (Sink)
+            //////////////////////////////////////////////////////////
+            if (ctrDevFormat.CmdStr.equals("Refresh")) {
+                Status status = Send_GetStatus();
+                if (status != null) {
+                    return SHMem.retVal = RefreshResult();
+                }
+                else {
+                    return SHMem.retVal = "FAIL;" + APIErrorCode.DEVICEISNORESPONSE;
+                }
+            }
+            //////////////////////////////////////////////////////////
+            // SetAllLightOnOff : 일괄소등 제어 (Sink)
+            //////////////////////////////////////////////////////////
+            else if (ctrDevFormat.CmdStr.equals("SetAllLightOnOff")) {
+                // 일괄소등 직접제어가 아닌경우 제어할수 없음.
+                if (!mDriver.info.Support.BatchOffDirCtrl) {
+                    Log.w(TAG, "[do_ctrEmm] SetAllLightOnOff Not Support !!! (BatchOffDirCtrl=false)");
+                    return SHMem.retVal = "FAIL;" + APIErrorCode.NOT_SUPPORT;
+                }
+
+                // 서브 일괄소등제어 일 경우 내부 드라이버에서만 일괄소등제어처리.
+                if (mDriver.bSubBatchOffDirCtrl) {
+                    Log.w(TAG, "[do_ctrEmm] SetAllLightOnOff Not Support !!! (bSubBatchOffDirCtrl=true)");
+                    return SHMem.retVal = "FAIL;" + APIErrorCode.NOT_SUPPORT;
+                }
+
+                // 1. Param Check
+                byte ParamOnOff   = ctrDevFormat.param[0];
+
+                // 2. Make Packet Data
+                boolean OnOff = false;
+                if (ParamOnOff != 0x00) OnOff = true;
+
+                CtrlStatus ctrlStatus = new CtrlStatus();
+                if (OnOff) ctrlStatus.BatchOff = 0x02;
+                else ctrlStatus.BatchOff = 0x01;
+                Status status = Send_SetStatus(ctrlStatus);
+                if (status != null) {
+                    return SHMem.retVal = "SUCCESS";
+                }
+                else {
+                    return SHMem.retVal = "FAIL;" + APIErrorCode.DEVICEISNORESPONSE;
+                }
+            }
+            //////////////////////////////////////////////////////////
+
+        }
+
+        return SHMem.retVal = "UNKNOWNCMD";
+    }
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    // RefreshResult
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    /**
+     * Refresh 에 대한 응답포멧 정의
+     *
+     * @return (String) "SUCCESS; ..." 성공 , "FAIL; ... " 실패
+     */
+    private String RefreshResult() {
+        String result = null;
+
+        DeviceLog("RefreshResult call : ");
+
+        // 1. Check Polling Status
+        if ((mDriver.Polling.Status == Driver.PollingList.STATUS.First) || (mDriver.Polling.Status == Driver.PollingList.STATUS.FirstTimeOut)) {
+            result = "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
+            return result;
+        }
+
+        // 2. Param Range Check
+
+        // 3. Make Return String Format
+        try {
+            if (mDriver == null) return "FAIL;"+APIErrorCode.DEVICEISNOTREADY;
+
+            boolean AllLightOnOff = false;
+            if (mDriver.status.BatchOff.Now == 0x02) AllLightOnOff = true;
+            else if (mDriver.status.BatchOff.Now == 0x01) AllLightOnOff = false;
+
+            /*
+             * [Format]
+             *
+             * SUCCESS       - (String) 성공
+             *
+             * AllLightOnOff  - (boolean) 일괄소등 상태 (true:일괄소등해제-조명ON , false:일괄소등-조명OFF)
+             */
+
+            result = APIErrorCode.SUCCESS + ";";
+            result += AllLightOnOff + ";";
+
+        } catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+            result = "FAIL;"+APIErrorCode.EXCEPTION;
+        } catch (Exception e) {
+            Log.e(TAG, "[Exception Error] RefreshResult");
+            //e.printStackTrace();
+            LogUtil.errorLogInfo("", TAG, e);
+            result = "FAIL;"+APIErrorCode.EXCEPTION;
+        }
+        DeviceLog("RefreshResult return : " + result);
+
+        return result;
+    }
+
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+    // Protocol Command Send Func
+    ///////////////////////////////////////////////////////////////////////////////////////////////
+
+    /**
+     * 보드 상태 읽기 요청 응답.
+     *
+     * @return (Info) null - Error , Not null - OK
+     */
+    private Info Send_GetBoardInfoRead() {
+        DeviceLog("[Send_GetBoardInfoRead] Start");
+
+        // 1. In 파라미터 확인
+
+        // 2. 패킷 데이터 만들기
+        byte [] ReqData = null;
+
+        // 3. 데이터 전송 및 응답
+        byte [] Reply = SendNRead_Variable(DEVICE_ADDRESS, CMDList.Req.BOARD_INFO_RD, ReqData);
+
+        // 4. 수신데이터 파싱
+        //     4.1. Default Check
+        boolean bError = false;
+        byte LightCnt = 0;
+        while (true) {
+            if (Reply == null) {
+                DeviceLog("[Send_GetBoardInfoRead] Reply is null");
+                bError = true; break;
+            }
+
+            if (Reply.length == 1) {
+                if (Reply[0] == (byte)0x82) {
+                    Log.i(TAG, "[Send_GetBoardInfoRead] Device ReBoot Detect!!!");
+                    mDriver.Polling.Status = Driver.PollingList.STATUS.First;
+                    mDriver.Polling.StatusSinkTickReset();
+                    AddDoCount(true);
+                    return null;
+                }
+            }
+
+            if (Reply.length != 9) {
+                Log.w(TAG, "[Send_GetBoardInfoRead] Reply.length  fail ... " + Reply.length);
+                bError = true; break;
+            }
+
+            //     4.1. Details Data Check
+            //         - D1 : 조명개수
+            LightCnt = Reply[0];
+            if (!((LightCnt >= 0x00) && (LightCnt <= 0x04))) {
+                Log.w(TAG, "[Send_GetBoardInfoRead] D1:LightCnt  Out of Range !!! " + String.format("0x%02X", Reply[0]));
+                bError = true; break;
+            }
+
+            //         - D3 : 기능 제공 여부 2
+            //if ((Reply[2] & (byte)(BIT5 | BIT6 | BIT7)) != 0x00) {
+            //    Log.w(TAG, "[Send_GetBoardInfoRead] D3:Unused Bit Set !!! " + String.format("0x%02X", Reply[2]));
+            //    bError = true; break;
+            //}
+
+            //madeinlab BIT5 공기질 정보가 있으므로, BIT5 는 제거한다.
+            if ((Reply[2] & (byte)(BIT6 | BIT7)) != 0x00) {
+                Log.w(TAG, "[Send_GetBoardInfoRead] D3:Unused Bit Set !!! " + String.format("0x%02X", Reply[2]));
+                bError = true; break;
+            }
+
+            //         - D5 : 펌웨어 Build Date (Month)
+            if (!((Reply[4] >= 0x01) && (Reply[4] <= 0x0C))) {
+                Log.w(TAG, "[Send_GetBoardInfoRead] Reply[4]  Out of Range !!! " + String.format("0x%02X", Reply[4]));
+                bError = true; break;
+            }
+
+            //         - D6 : 펌웨어 Build Date (Day)
+            if (!((Reply[5] >= 0x01) && (Reply[5] <= 0x1F))) {
+                Log.w(TAG, "[Send_GetBoardInfoRead] Reply[5]  Out of Range !!! " + String.format("0x%02X", Reply[5]));
+                bError = true; break;
+            }
+            break;
+        }
+
+        if (bError) {
+            AddDoCount(false);
+            return null;
+        }
+
+        AddDoCount(true);
+
+        // 5. Data return
+        Info info = new Info();
+
+        info.LightCnt = LightCnt;
+
+        if ((Reply[1] & BIT0) != 0x00) info.Support.Time = true;
+        else info.Support.Time = false;
+
+        if ((Reply[1] & BIT1) != 0x00) info.Support.Parking = true;
+        else info.Support.Parking = false;
+
+        if ((Reply[1] & BIT2) != 0x00) info.Support.Energy = true;
+        else info.Support.Energy = false;
+
+        if ((Reply[1] & BIT3) != 0x00) info.Support.Weather = true;
+        else info.Support.Weather = false;
+
+        if ((Reply[1] & BIT4) != 0x00) info.Support.BatchOff = true;
+        else info.Support.BatchOff = false;
+
+        if ((Reply[1] & BIT5) != 0x00) info.Support.Outing = true;
+        else info.Support.Outing = false;
+
+        if ((Reply[1] & BIT6) != 0x00) info.Support.Gas = true;
+        else info.Support.Gas = false;
+
+        if ((Reply[1] & BIT7) != 0x00) info.Support.Elevator = true;
+        else info.Support.Elevator = false;
+
+        if ((Reply[2] & BIT3) != 0x00) info.Support.HeatingInfo = true;
+        else info.Support.HeatingInfo = false;
+
+        if ((Reply[2] & BIT4) != 0x00) info.Support.NotiInfo = true;
+        else info.Support.NotiInfo = false;
+
+        //공기질 정보는 Reply[2] BIT5
+        //테스트를 위하여 일단 true
+        if ((Reply[2] & BIT5) != 0x00) info.Support.AirQualityInfo = true;
+        else info.Support.AirQualityInfo = true;
+
+        if ((Reply[2] & BIT0) != 0x00) info.Support.BatchOffDirCtrl = true;
+        else info.Support.BatchOffDirCtrl = false;
+
+        if ((Reply[2] & BIT1) != 0x00) info.Support.NowWeather = true;
+        else info.Support.NowWeather = false;
+
+        if ((Reply[2] & BIT2) != 0x00) info.Support.ElevatorDir = true;
+        else info.Support.ElevatorDir = false;
+
+        info.FwVer_Year   = Reply[3];
+        info.FwVer_Month  = Reply[4];
+        info.FwVer_Day    = Reply[5];
+        info.FwVer_Number = Reply[6];
+
+        info.ProtocolVer_Main = Reply[7];
+        info.ProtocolVer_Sub  = Reply[8];
+
+        return info;
+    }
+
+    /**
+     * 보드 상태 읽기 요청 응답.
+     *
+     * @return (Status) null - Error , Not null - OK
+     */
+    private Status Send_GetStatus() {
+        DeviceLog("[Send_GetStatus] Start");
+
+        // 1. In 파라미터 확인
+
+        // 2. 패킷 데이터 만들기
+        byte [] ReqData = null;
+
+        // 3. 데이터 전송 및 응답
+        byte [] Reply = SendNRead_Variable(DEVICE_ADDRESS, CMDList.Req.GET_STATUS, ReqData);
+
+        // 4. 수신데이터 파싱
+        Status status = GetStatus_RepParsing(Reply);
+        if (status == null) {
+            DeviceLog("[Send_GetStatus] Reply is null");
+            if(mDriver.Polling.ReBootDetect) { mDriver.Polling.ReBootDetect = false; AddDoCount(true); }
+            else AddDoCount(false);
+            return null;
+        }
+        AddDoCount(true);
+        return status;
+    }
+
+    /**
+     * 제어 요청 수신 알림
+     *
+     * @return (Status) null - Error , Not null - OK
+     */
+    private Status Send_AckStatus(byte CtrlCnt, byte CtrlKind) {
+        DeviceLog("[Send_AckStatus] Start");
+
+        // 1. In 파라미터 확인
+        if ((CtrlCnt <= 0) || (CtrlCnt > 8)) {
+            Log.w(TAG, "[Send_AckStatus] param [CtrlCnt] Out of Range!!! " + CtrlCnt);
+            return null;
+        }
+
+        byte Cnt = 0;
+        for (int i=0 ; i<8 ; i++) {
+            if ((CtrlKind & BIT_ARRAY[i]) != 0x00) Cnt++;
+        }
+
+        if (CtrlCnt != Cnt) {
+            Log.w(TAG, "[Send_AckStatus] param [CtrlCnt & CtrlKind] Count Not Match !!! (CtrlCnt:" + CtrlCnt + ", CtrlKind:" + String.format("0x%02X", CtrlKind) + ")");
+            return null;
+        }
+
+        // 2. 패킷 데이터 만들기
+        byte [] ReqData = new byte [] { CtrlCnt, CtrlKind };
+
+        // 3. 데이터 전송 및 응답
+        byte [] Reply = SendNRead_Variable(DEVICE_ADDRESS, CMDList.Req.ACK_STATUS, ReqData);
+
+        // 4. 수신데이터 파싱
+        Status status = GetStatus_RepParsing(Reply);
+        if (status == null) {
+            DeviceLog("[Send_AckStatus] Reply is null");
+            if (mDriver.Polling.ReBootDetect) { mDriver.Polling.ReBootDetect = false; AddDoCount(true); }
+            else AddDoCount(false);
+            return null;
+        }
+        AddDoCount(true);
+        return status;
+    }
+
+    /**
+     * 기기 상태 변경 알림
+     *
+     * @param ctrlStatus     - (CtrlStatus) 제어용 클래스
+     *
+     * @return (Status) null - Error , Not null - OK
+     */
+    private Status Send_SetStatus(CtrlStatus ctrlStatus) {
+        DeviceLog("[Send_SetStatus] Start");
+        Log.w(TAG, "[Send_SetStatus] ========== 1 ==========");
+        // 1. In 파라미터 확인
+        if (ctrlStatus == null) {
+            Log.w(TAG, "[Send_SetStatus] param [ctrlStatus] is null!!!");
+            return null;
+        }
+
+        // 2. 패킷 데이터 만들기
+        byte [] ReqData = ctrlStatus.getByteArray();
+
+        // 3. 데이터 전송 및 응답
+        byte [] Reply = SendNRead_Variable(DEVICE_ADDRESS, CMDList.Req.SET_STATUS, ReqData);
+
+        // 4. 수신데이터 파싱
+        Status status = GetStatus_RepParsing(Reply);
+        if (status == null) {
+            DeviceLog("[Send_SetStatus] Reply is null");
+            if (mDriver.Polling.ReBootDetect) { mDriver.Polling.ReBootDetect = false; AddDoCount(true); }
+            else AddDoCount(false);
+            return null;
+        }
+        AddDoCount(true);
+        return status;
+    }
+
+
+    /**
+     * 날씨정보 알림
+     *
+     * @param ReqData - (byte) 날씨정보알림 데이터
+     *
+     * @return (Info) null - Error , Not null - OK
+     */
+    private Status Send_SetWeather(byte [] ReqData) {
+        DeviceLog("[Send_SetWeather] Start");
+
+        // 1. In 파라미터 확인
+        if (ReqData == null) {
+            Log.w(TAG, "[Send_SetWeather] param [ReqData] is null!!!");
+            return null;
+        }
+
+        int length = 10;
+        if (mDriver.info.Support.NowWeather) length = 11;
+        if (ReqData.length != length) {
+            Log.w(TAG, "[Send_SetWeather] param [ReqData.length] is length Not Match!!! (length:" + ReqData.length + ")");
+            return null;
+        }
+
+        // 2. 패킷 데이터 만들기
+
+        // 3. 데이터 전송 및 응답
+        byte [] Reply = SendNRead_Variable(DEVICE_ADDRESS, CMDList.Req.SET_WEATHER, ReqData);
+
+        // 4. 수신데이터 파싱
+        Status status = GetStatus_RepParsing(Reply);
+        if (status == null) {
+            DeviceLog("[Send_SetWeather] Reply is null");
+            if (mDriver.Polling.ReBootDetect) { mDriver.Polling.ReBootDetect = false; AddDoCount(true); }
+            else AddDoCount(false);
+            return null;
+        }
+
+        AddDoCount(true);
+        return status;
+    }
+
+
+    /**
+     * 주차정보 알림
+     *
+     * @param ReqData - (byte) 주차 데이터
+     *
+     * @return (Info) null - Error , Not null - OK
+     */
+    private Status Send_SetParking(byte [] ReqData) {
+        DeviceLog("[Send_SetParking] Start");
+
+        // 1. In 파라미터 확인
+        if (ReqData == null) {
+            Log.w(TAG, "[Send_SetParking] param [ReqData] is null!!!");
+            return null;
+        }
+        //        if(ReqData.length != 10)
+        //        {
+        //            Log.w(TAG, "[Send_SetParking] param [ReqData.length] is length Not Match!!! (length:" + ReqData.length + ")");
+        //            return null;
+        //        }
+
+        // 2. 패킷 데이터 만들기
+
+        // 3. 데이터 전송 및 응답
+        byte [] Reply = SendNRead_Variable(DEVICE_ADDRESS, CMDList.Req.SET_PARKING, ReqData);
+
+        // 4. 수신데이터 파싱
+        Status status = GetStatus_RepParsing(Reply);
+        if (status == null) {
+            DeviceLog("[Send_SetParking] Reply is null");
+            if (mDriver.Polling.ReBootDetect) { mDriver.Polling.ReBootDetect = false; AddDoCount(true); }
+            else AddDoCount(false);
+            return null;
+        }
+
+        AddDoCount(true);
+        return status;
+    }
+
+    /**
+     * 에너지정보 알림
+     *
+     * @param ReqData - (byte) 에너지데이터
+     *
+     * @return (Info) null - Error , Not null - OK
+     */
+    private Status Send_SetEnergy(byte [] ReqData) {
+        DeviceLog("[Send_SetEnergy] Start");
+
+        // 1. In 파라미터 확인
+        if (ReqData == null) {
+            Log.w(TAG, "[Send_SetEnergy] param [ReqData] is null!!!");
+            return null;
+        }
+        //        if(ReqData.length != 10)
+        //        {
+        //            Log.w(TAG, "[Send_SetParking] param [ReqData.length] is length Not Match!!! (length:" + ReqData.length + ")");
+        //            return null;
+        //        }
+
+        // 2. 패킷 데이터 만들기
+
+        // 3. 데이터 전송 및 응답
+        byte [] Reply = SendNRead_Variable(DEVICE_ADDRESS, CMDList.Req.SET_ENERGY, ReqData);
+
+        // 4. 수신데이터 파싱
+        Status status = GetStatus_RepParsing(Reply);
+        if (status == null) {
+            DeviceLog("[Send_SetEnergy] Reply is null");
+            if (mDriver.Polling.ReBootDetect) { mDriver.Polling.ReBootDetect = false; AddDoCount(true); }
+            else AddDoCount(false);
+            return null;
+        }
+        AddDoCount(true);
+        return status;
+    }
+
+    /**
+     * 알림정보 알림
+     *
+     * @param ReqData - (byte) 알림 데이터
+     *
+     * @return (Info) null - Error , Not null - OK
+     */
+    private Status Send_SetNotiInfo(byte[] ReqData) {
+        DeviceLog("[Send_SetNotiInfo] Start");
+
+        // 1. In 파라미터 확인
+        if (ReqData == null) {
+            Log.w(TAG, "[Send_SetNotiInfo] param [ReqData] is null!!!");
+            return null;
+        }
+        // 2. 패킷 데이터 만들기
+
+        // 3. 데이터 전송 및 응답
+        byte[] Reply = SendNRead_Variable(DEVICE_ADDRESS, CMDList.Req.SET_NotiInfo, ReqData);
+
+        // 4. 수신데이터 파싱
+        Status status = GetStatus_RepParsing(Reply);
+        if (status == null) {
+            DeviceLog("[Send_SetNotiInfo] Reply is null");
+            if (mDriver.Polling.ReBootDetect) { mDriver.Polling.ReBootDetect = false; AddDoCount(true); }
+            else AddDoCount(false);
+
+            return null;
+        }
+
+        AddDoCount(true);
+        return status;
+    }
+
+    /**
+     * 난방정보 알림
+     *
+     * @param ReqData - (byte) 난방 데이터
+     *
+     * @return (Info) null - Error , Not null - OK
+     */
+    private Status Send_SetHeatingInfo(byte[] ReqData) {
+        DeviceLog("[Send_SetHeatingInfo] Start");
+
+        // 1. In 파라미터 확인
+        if (ReqData == null) {
+            Log.w(TAG, "[Send_SetHeatingInfo] param [ReqData] is null!!!");
+            return null;
+        }
+        // 2. 패킷 데이터 만들기
+
+        // 3. 데이터 전송 및 응답
+        byte[] Reply = SendNRead_Variable(DEVICE_ADDRESS, CMDList.Req.SET_HeatingInfo, ReqData);
+
+        // 4. 수신데이터 파싱
+        Status status = GetStatus_RepParsing(Reply);
+        if (status == null) {
+            DeviceLog("[Send_SetHeatingInfo] Reply is null");
+            if (mDriver.Polling.ReBootDetect) { mDriver.Polling.ReBootDetect = false; AddDoCount(true); }
+            else AddDoCount(false);
+
+            return null;
+        }
+
+        AddDoCount(true);
+        return status;
+    }
+
+
+
+
+    /**
+     * 공기질정보 알림
+     *
+     * @param ReqData - (byte) 공기질 데이터
+     *
+     * @return (Info) null - Error , Not null - OK
+     */
+    private Status Send_SetAirQuailtyInfo(byte[] ReqData) {
+        DeviceLog("[Send_SetAirQuailtyInfo] Start");
+
+        // 1. In 파라미터 확인
+        if (ReqData == null) {
+            Log.w(TAG, "[Send_SetAirQuailtyInfo] param [ReqData] is null!!!");
+            return null;
+        }
+        // 2. 패킷 데이터 만들기
+
+        // 3. 데이터 전송 및 응답
+        byte[] Reply = SendNRead_Variable(DEVICE_ADDRESS, CMDList.Req.SET_AirQualityInfo, ReqData);
+
+        // 4. 수신데이터 파싱
+        Status status = GetStatus_RepParsing(Reply);
+        if (status == null) {
+            DeviceLog("[Send_SetAirQuailtyInfo] Reply is null");
+            if (mDriver.Polling.ReBootDetect) { mDriver.Polling.ReBootDetect = false; AddDoCount(true); }
+            else AddDoCount(false);
+
+            return null;
+        }
+
+        AddDoCount(true);
+        return status;
+    }
+
+
+
+    /**
+     * {@link #Send_AckStatus(byte, byte)} <br>
+     * {@link #Send_GetStatus()} <br>
+     * {@link #Send_SetEnergy(byte[])} <br>
+     * {@link #Send_SetParking(byte[])} <br>
+     * {@link #Send_SetStatus(CtrlStatus)} <br>
+     * {@link #Send_SetWeather(byte[])} <br>
+     * 메소드의 응답 공통부분 메소드이다.
+     *
+     * @param Reply     - (byte []) 응답 Byte 배열
+     *
+     * @return (Status) null - Error , Not null - OK
+     */
+    private Status GetStatus_RepParsing(byte [] Reply) {
+        // 1. 수신데이터 파싱
+        //     1.1. Default Check
+        if (Reply == null) {
+            DeviceLog("[GetStatus_RepParsing] Reply is null");
+            return null;
+        }
+
+        if (Reply.length == 1) {
+            if (Reply[0] == (byte) 0x82) {
+                Log.i(TAG, "[GetStatus_RepParsing] Device ReBoot Detect!!!");
+                mDriver.Polling.Status = Driver.PollingList.STATUS.First;
+                mDriver.Polling.StatusSinkTickReset();
+                mDriver.Polling.ReBootDetect = true;
+                return null;
+            }
+        }
+
+        if (Reply.length < 5) {
+            Log.w(TAG, "[GetStatus_RepParsing] Reply.length  fail #1 ... " + Reply.length);
+            return null;
+        }
+
+        byte LightCnt = Reply[4];
+        if (Reply.length != (int)(5 + LightCnt)) {
+            Log.w(TAG, "[GetStatus_RepParsing] Reply.length  fail #2 ... " + Reply.length + " / LightCnt : " + LightCnt);
+            return null;
+        }
+
+        //     1.2. Details Data Check
+        for (int i = 0; i<Reply.length; i++) {
+            //          - D5 : 엘리베이터 정보
+            if (i==4) {
+                if (!((Reply[i] >= 0x00) && (Reply[i] <= 0x04))) {
+                    Log.w(TAG, "[GetStatus_RepParsing] D5:LightCnt  Out of Range !!! " + String.format("0x%02X", Reply[i]));
+                    return null;
+                }
+            }
+            //          - D1~D4 , D6~D9 : 각 버튼 정보
+            else {
+                if ((Reply[i] & (byte)(BIT2 | BIT3 | BIT6 )) != 0x00) {
+                    Log.w(TAG, "[GetStatus_RepParsing] D" + (i+1) + ":Unused Bit Set !!! " + String.format("0x%02X", Reply[i]));
+                    return null;
+                }
+            }
+        }
+
+        // 2. Data return
+        Status status = new Status();
+
+        status.Elevator.Now  = ConvertNowData(Reply[0]);
+        status.Elevator.Ctrl = ConvertCtrlData(Reply[0]);
+
+        status.Gas.Now       = ConvertNowData(Reply[1]);
+        status.Gas.Ctrl      = ConvertCtrlData(Reply[1]);
+
+        status.Outing.Now    = ConvertNowData(Reply[2]);
+        status.Outing.Ctrl   = ConvertCtrlData(Reply[2]);
+
+        status.BatchOff.Now  = ConvertNowData(Reply[3]);
+        status.BatchOff.Ctrl = ConvertCtrlData(Reply[3]);
+
+        status.HeatingInfo.Now = ConvertNowHeatingInfoData(Reply[3]);
+        status.HeatingInfo.Ctrl = ConvertCtrlHeatingInfoData(Reply[3]);
+        //Log.i(TAG, "[GetStatus_RepParsing] - HeatingInfo.Ctrl = " + status.HeatingInfo.Ctrl);
+
+        status.LightCnt = LightCnt;
+
+        if (LightCnt > 0) {
+            status.L1.Now  = ConvertNowData(Reply[5]);
+            status.L1.Ctrl = ConvertCtrlData(Reply[5]);
+        }
+
+        if (LightCnt > 1) {
+            status.L2.Now  = ConvertNowData(Reply[6]);
+            status.L2.Ctrl = ConvertCtrlData(Reply[6]);
+        }
+
+        if (LightCnt > 2) {
+            status.L3.Now  = ConvertNowData(Reply[7]);
+            status.L3.Ctrl = ConvertCtrlData(Reply[7]);
+        }
+
+        if (LightCnt > 3) {
+            status.L4.Now  = ConvertNowData(Reply[8]);
+            status.L4.Ctrl = ConvertCtrlData(Reply[8]);
+        }
+
+        UpdateVariables(status);
+
+        return status;
+    }
+
+    public byte ConvertNowData(byte data)  { return (byte)((data>>0) & (byte)(BIT0 | BIT1)); }
+    public byte ConvertCtrlData(byte data) { return (byte)((data>>4) & (byte)(BIT0 | BIT1)); }
+    public byte ConvertNowHeatingInfoData(byte data) { return (byte)((data>>4) & (byte)(BIT2 | BIT3));}
+    public byte ConvertCtrlHeatingInfoData(byte data) { return (byte)((data>>4) & (byte)(BIT2 | BIT3));}
+
+    /**
+     * 명령어 리스트
+     */
+    public static class CMDList {
+        public static final class Req {
+            /////////////////////////////////////////////////////////
+            // Board
+            /////////////////////////////////////////////////////////
+            /** 기기 상태 읽기 */
+            public final static byte BOARD_INFO_RD        = 0x01;
+
+            /////////////////////////////////////////////////////////
+            // Status
+            /////////////////////////////////////////////////////////
+            /** 기기 상태 요청 */
+            public final static byte GET_STATUS           = 0x11;
+
+            /** 스마트스위치 제어 요청 수신 알림 */
+            public final static byte ACK_STATUS           = 0x12;
+            ;
+            /** 기기 상태 변경 알림 */
+            public final static byte SET_STATUS           = 0x13;
+
+
+            /////////////////////////////////////////////////////////
+            // Weather
+            /////////////////////////////////////////////////////////
+            /** 날씨정보 알림 */
+            public final static byte SET_WEATHER          = 0x21;
+
+            /** 주차정보 알림 */
+            public final static byte SET_PARKING          = 0x22;
+
+            /** 에너지 정보 알림 */
+            public final static byte SET_ENERGY           = 0x23;
+
+            /** 알림 정보 알림   */
+            public final static byte SET_NotiInfo		  = 0x24;
+
+            /** 난방 정보 알림   */
+            public final static byte SET_HeatingInfo	  = 0x25;
+
+            //21.03.17 공기질 추가 정보
+            /**
+             * 공기질 정보
+             */
+            public final static byte SET_AirQualityInfo	  = 0x26;
+
+        }
+    }
+
+    /**
+     * 변동 데이터 처리부
+     *
+     * @param status - (Status) 신규 데이터
+     *
+     * @return (boolean) 데이터 변동여부 true : 변동 , false : 변동없음
+     */
+    private boolean UpdateVariables(Status status) {
+        // 1. 제어 요청 체크
+        byte CtrlKind = 0x00;
+        byte CtrlCnt = 0x00;
+
+        if (mDriver.info.Support.HeatingInfo) {
+            // Heating packet은 10XX/00XX임으로 0x80,81,82,90,91,92,A0,A1,A2로 확인
+            if (status.HeatingInfo.Ctrl == 0x08) {
+                mDriver.Polling.setHeatingInfoUpdate(true);
+            }
+            else {
+
+            }
+        }
+
+        if (mDriver.info.Support.Elevator) {
+            if (status.Elevator.Ctrl != 0x00) {
+                // 엘리베이터 요청
+                DeviceLog("UpdateVariables - Elevator.Ctrl : " + String.format("0x%02X", status.Elevator.Ctrl));
+
+                CtrlKind |= BIT7;
+                CtrlCnt++;
+
+                switch (status.Elevator.Ctrl) {
+                    case 0x01:
+                        // 하향호출
+                        Log.i(TAG, "[UpdateVariables] - ElevatorCtr 0x01");
+                        ElevatorCall(false);
+                        break;
+
+                    case 0x02:
+                        // 상향호출
+                        Log.i(TAG, "[UpdateVariables] - ElevatorCtr 0x02");
+                        ElevatorCall(true);
+                        break;
+
+                    case 0x03:
+                        // 상,하향 호출
+                        Log.i(TAG, "[UpdateVariables] - ElevatorCtr 0x03");
+                        ElevatorCall(false);
+                        ElevatorCall(true);
+                        break;
+                }
+            }
+        }
+
+        if (mDriver.info.Support.Gas) {
+            if (status.Gas.Ctrl != 0x00) {
+                if (status.Gas.Ctrl == 0x01) {
+                    // 가스제어 요청
+                    DeviceLog("UpdateVariables - Gas.Ctrl : " + String.format("0x%02X", status.Gas.Ctrl));
+
+                    CtrlKind |= BIT6;
+                    CtrlCnt++;
+
+                    int ret = driverInterOpAPI.Gas_SetClose(ServiceMain.MSG_DEV_CTR);
+                    DeviceLog("[UpdateVariables] Gas_SetClose() - " + ret);
+                }
+            }
+        }
+
+        if (mDriver.info.Support.Outing) {
+            if (status.Outing.Ctrl != 0x00) {
+                // 외출설정 요청
+                DeviceLog("UpdateVariables - Outing.Ctrl : " + String.format("0x%02X", status.Outing.Ctrl));
+
+                CtrlKind |= BIT5;
+                CtrlCnt++;
+
+                switch (status.Outing.Ctrl) {
+                    case 0x01:
+                        // 외출설정
+                        Log.i(TAG, "SendNotifyKindBR(NOTIFY_SMARTSW_SET_OUTING)");
+                        super.SendNotifyKindBR(define.NOTIFY_SMARTSW_SET_OUTING);
+                        break;
+
+                    case 0x02:
+                        // 외출해제
+                        Log.i(TAG, "SendNotifyKindBR(NOTIFY_SMARTSW_FREE_OUTING)");
+                        super.SendNotifyKindBR(define.NOTIFY_SMARTSW_FREE_OUTING);
+                        break;
+                }
+            }
+        }
+
+        if (mDriver.info.Support.BatchOff) {
+            if (!mDriver.info.Support.BatchOffDirCtrl) {
+                if (status.BatchOff.Ctrl != 0x00) {
+                    // 일괄소등 요청
+                    Log.i(TAG, "UpdateVariables - BatchOff.Ctrl : " + String.format("0x%02X", status.BatchOff.Ctrl));
+
+                    CtrlKind |= BIT4;
+                    CtrlCnt++;
+
+                    switch (status.BatchOff.Ctrl) {
+                        case 0x01:
+                            // 일괄소등
+                            driverInterOpAPI.setAllLight(false);
+                            break;
+
+                        case 0x02:
+                            // 일괄소등 해제
+                            driverInterOpAPI.setAllLight(true);
+                            break;
+                    }
+                }
+            }
+        }
+
+        if (mDriver.info.LightCnt > 0) {
+            if (status.L1.Ctrl != 0x00) {
+                // L1 제어 요청
+                DeviceLog("UpdateVariables - L1.Ctrl : " + String.format("0x%02X", status.L1.Ctrl));
+
+                CtrlKind |= BIT3;
+                CtrlCnt++;
+                int ret = 0;
+                switch (status.L1.Ctrl) {
+                    case 0x01:
+                        // 켜짐
+                        ret = driverInterOpAPI.setLight(ServiceMain.MSG_DEV_CTR, mDriver.L1Map+1, true);
+                        DeviceLog("[UpdateVariables] driverInterOpAPI.setLight(" + (int)(mDriver.L1Map+1) + ", " + "true)" + " = ret :" + ret);
+                        if(ret < 0) Log.w(TAG, "[UpdateVariables] driverInterOpAPI.setLight - ret Error : ret:" + ret);
+                        break;
+
+                    case 0x02:
+                        // 꺼짐
+                        ret = driverInterOpAPI.setLight(ServiceMain.MSG_DEV_CTR, mDriver.L1Map+1, false);
+                        DeviceLog("[UpdateVariables] driverInterOpAPI.setLight(" + (int)(mDriver.L1Map+1) + ", " + "false)" + " = ret :" + ret);
+                        if(ret < 0) Log.w(TAG, "[UpdateVariables] driverInterOpAPI.setLight - ret Error : ret:" + ret);
+                        break;
+                }
+            }
+        }
+
+        if (mDriver.info.LightCnt > 1) {
+            if (status.L2.Ctrl != 0x00) {
+                // L2 제어 요청
+                DeviceLog("UpdateVariables - L2.Ctrl : " + String.format("0x%02X", status.L2.Ctrl));
+
+                CtrlKind |= BIT2;
+                CtrlCnt++;
+                int ret = 0;
+                switch (status.L2.Ctrl) {
+                    case 0x01:
+                        // 켜짐
+                        ret = driverInterOpAPI.setLight(ServiceMain.MSG_DEV_CTR, mDriver.L2Map+1, true);
+                        DeviceLog("[UpdateVariables] driverInterOpAPI.setLight(" + (int)(mDriver.L2Map+1) + ", " + "true)" + " = ret :" + ret);
+                        if(ret < 0) Log.w(TAG, "[UpdateVariables] driverInterOpAPI.setLight - ret Error : ret:" + ret);
+                        break;
+
+                    case 0x02:
+                        // 꺼짐
+                        ret = driverInterOpAPI.setLight(ServiceMain.MSG_DEV_CTR, mDriver.L2Map+1, false);
+                        DeviceLog("[UpdateVariables] driverInterOpAPI.setLight(" + (int)(mDriver.L1Map+1) + ", " + "false)" + " = ret :" + ret);
+                        if(ret < 0) Log.w(TAG, "[UpdateVariables] driverInterOpAPI.setLight - ret Error : ret:" + ret);
+                        break;
+                }
+            }
+        }
+
+        if (mDriver.info.LightCnt > 2) {
+            if (status.L3.Ctrl != 0x00) {
+                // L3 제어 요청
+                DeviceLog("UpdateVariables - L3.Ctrl : " + String.format("0x%02X", status.L3.Ctrl));
+
+                CtrlKind |= BIT1;
+                CtrlCnt++;
+
+                switch (status.L3.Ctrl) {
+                    case 0x01:
+                        // 켜짐
+                        break;
+
+                    case 0x02:
+                        // 꺼짐
+                        break;
+                }
+            }
+        }
+
+        if (mDriver.info.LightCnt > 3) {
+            if (status.L4.Ctrl != 0x00) {
+                // L4 제어 요청
+                DeviceLog("UpdateVariables - L4.Ctrl : " + String.format("0x%02X", status.L4.Ctrl));
+
+                CtrlKind |= BIT0;
+                CtrlCnt++;
+
+                switch (status.L4.Ctrl) {
+                    case 0x01:
+                        // 켜짐
+                        break;
+
+                    case 0x02:
+                        // 꺼짐
+                        break;
+                }
+            }
+        }
+
+        if (CtrlCnt > 0) {
+            for (int i = 0; i < 3; i++) {
+                // 제어 요청 수신 알림
+                Status AckStatus = Send_AckStatus(CtrlCnt, CtrlKind);
+                if (AckStatus != null) {
+                    status = AckStatus;
+                    break;
+                }
+            }
+        }
+
+        // 2. 변동 데이터 체크
+        boolean bChanged = false;
+        if (status.Elevator.Now != mDriver.status.Elevator.Now) bChanged = true;
+        if (status.Gas.Now != mDriver.status.Gas.Now) bChanged = true;
+        if ((status.BatchOff.Now != mDriver.status.BatchOff.Now) || !(mDriver.bFirstBatchOffBRSend)) {
+            bChanged = true;
+
+            if (mDriver.info.Support.BatchOffDirCtrl) {
+                // 서브일괄소등이면서, 최초가 아닌경우에 일괄소등상태가 변경되면 메인 일괄소등제어기 제어
+                if (mDriver.bSubBatchOffDirCtrl) {
+                    if (mDriver.bFirstBatchOffBRSend) {
+                        if (status.BatchOff.Now == 0x02) {
+                            // 일괄소등 해제
+                            if (driverInterOpAPI.getAllLight() != true) {
+                                driverInterOpAPI.setAllLight(true);
+                                mDriver.Polling.SetAllLightSinkDelay();
+                                Log.i(TAG, "Change BatchOff.Now Status : bSubBatchOffDirCtrl - setAllLight(true)");
+                            }
+                        }
+                        else if (status.BatchOff.Now == 0x01) {
+                            // 일괄소등
+                            if (driverInterOpAPI.getAllLight() != false) {
+                                driverInterOpAPI.setAllLight(false);
+                                mDriver.Polling.SetAllLightSinkDelay();
+                                Log.i(TAG, "Change BatchOff.Now Status : bSubBatchOffDirCtrl - setAllLight(false)");
+                            }
+                        }
+                    }
+                }
+                else {
+                    int kind = 0;
+                    if (status.BatchOff.Now == 0x02) {
+                        kind = define.NOTIFY_ALL_LIGHT_ON;
+                        Log.i(TAG, "SendNotifyKindBR(NOTIFY_ALL_LIGHT_ON)");
+                    }
+                    else if (status.BatchOff.Now == 0x01) {
+                        kind = define.NOTIFY_ALL_LIGHT_OFF;
+                        Log.i(TAG, "SendNotifyKindBR(NOTIFY_ALL_LIGHT_OFF)");
+                    }
+
+                    if (kind != 0) SendNotifyKindBR(kind);
+                }
+            }
+            mDriver.bFirstBatchOffBRSend = true;
+        }
+
+        if (status.Outing.Now != mDriver.status.Outing.Now) bChanged = true;
+        if (status.LightCnt != mDriver.status.LightCnt) bChanged = true;
+
+        byte LightCnt = status.LightCnt;
+        if (LightCnt > 0) {
+            if (status.L1.Now != mDriver.status.L1.Now) bChanged = true;
+            if (LightCnt >= 2) {
+                if (status.L2.Now != mDriver.status.L2.Now) bChanged = true;
+                if (LightCnt >= 3) {
+                    if (status.L3.Now != mDriver.status.L3.Now) bChanged = true;
+                    if (LightCnt >= 4) {
+                        if(status.L4.Now != mDriver.status.L4.Now) bChanged = true;
+                    }
+                }
+            }
+        }
+
+        if (bChanged) {
+            DeviceLog("UpdateVariables Status Changed!!!");
+            DeviceLog(mDriver.status.ToDebugString("OLD"));
+            DeviceLog(status.ToDebugString("NEW"));
+
+            mDriver.status = status;
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * iMAP을 통하여 전달받은 날씨정보를 스마트스위치에<br>
+     * 전송할 데이터로 변환한다.
+     *
+     * @param code - (String) iMAP에서 전달받은 날씨데이터
+     * @return (byte) 스마트스위치에 전송할 날씨데이터
+     */
+    private byte GetWeatherCode(String code) {
+        if (mDriver.TargetModel == WallpadDeviceSet.BATCH_TYPE_HDC_LCD_SMART) {
+            return GetWeatherCode_iSS430(code);
+        }
+        else {
+            return GetWeatherCode_iSS201(code);
+        }
+    }
+
+    /**
+     * 모델명 : iSS430 의 날씨 데이터 변환
+     *
+     * @param code - (String) iMAP에서 전달받은 날씨데이터
+     * @return (byte) 스마트스위치에 전송할 날씨데이터
+     */
+    private byte GetWeatherCode_iSS430(String code) {
+        //X‘00’ (정보 없음), X‘01’ (맑음), X‘02’ (구름 조금), X‘03’ (구름 많음) X‘04’ (흐림), X‘05’ (비), X‘06’ (비 또는 흐림), X‘07’ (눈), X‘08’ (비 또는 눈)
+        try {
+            int Tcode = Integer.parseInt(code);
+            switch (Tcode) {
+                case 1:
+                    return 0x01;
+                case 2:
+                case 3:
+                case 5:
+                case 6:
+                    return 0x02;
+                case 4:
+                    return 0x03;
+                case 7:
+                case 8:
+                case 9:
+                case 15:
+                case 16:
+                case 17:
+                    return 0x05;
+                case 10:
+                case 11:
+                case 12:
+                case 13:
+                case 14:
+                    return 0x06;
+                case 18:
+                case 19:
+                case 20:
+                case 21:
+                case 22:
+                case 23:
+                case 24:
+                case 25:
+                    return 0x07;
+                case 26:
+                case 27:
+                case 28:
+                case 29:
+                case 30:
+                case 31:
+                case 32:
+                case 33:
+                case 34:
+                case 35:
+                case 36:
+                case 37:
+                case 38:
+                    return 0x08;
+                case 39:
+                    return 0x09;
+                case 40:
+                    return 0x0A;
+                case 41:
+                    return 0x0B;
+                default:
+                    break;
+            }
+        } catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+            return (byte)0x00;
+        } catch (Exception e) {
+            Log.e(TAG, "[Exception Error] GetWeatherCode_iSS430");
+            //e.printStackTrace();
+            LogUtil.errorLogInfo("", TAG, e);
+            return (byte)0x00;
+        }
+        return (byte)0x00;
+    }
+
+    /**
+     * 모델명 : iSS201 의 날씨 데이터 변환
+     *
+     * @param code - (String) iMAP에서 전달받은 날씨데이터
+     * @return (byte) 스마트스위치에 전송할 날씨데이터
+     */
+    private byte GetWeatherCode_iSS201(String code) {
+        //X‘00’ (정보 없음), X‘01’ (맑음), X‘02’ (구름 조금), X‘03’ (구름 많음) X‘04’ (흐림), X‘05’ (비), X‘06’ (비 또는 흐림), X‘07’ (눈), X‘08’ (비 또는 눈)
+        try {
+            int Tcode = Integer.parseInt(code);
+            switch (Tcode) {
+                case 1:
+                    return 0x01;
+                case 2:
+                case 3:
+                case 5:
+                case 6:
+                    return 0x02;
+                case 4:
+                    return 0x03;
+                case 40:
+                case 41:
+                    return 0x04;
+                case 7:
+                case 8:
+                case 9:
+                case 15:
+                case 16:
+                case 17:
+                case 39:
+                    return 0x05;
+                case 10:
+                case 11:
+                case 12:
+                case 13:
+                case 14:
+                    return 0x06;
+                case 18:
+                case 19:
+                case 20:
+                case 21:
+                case 22:
+                case 23:
+                case 24:
+                case 25:
+                    return 0x07;
+                case 26:
+                case 27:
+                case 28:
+                case 29:
+                case 30:
+                case 31:
+                case 32:
+                case 33:
+                case 34:
+                case 35:
+                case 36:
+                case 37:
+                case 38:
+                    return 0x08;
+                default:
+                    break;
+            }
+        } catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+            return (byte)0x00;
+        } catch (Exception e) {
+            Log.e(TAG, "[Exception Error] GetWeatherCode_iSS201");
+            //e.printStackTrace();
+            LogUtil.errorLogInfo("", TAG, e);
+            return (byte)0x00;
+        }
+        return (byte)0x00;
+    }
+
+    /**
+     * String Type 온도정보를 byte Type 으로 변환한다.
+     *
+     * @param TEMP - (String) 온도
+     * @return (byte) 변환된 온도
+     */
+    private byte GetTemp(String TEMP) {
+        if (TEMP==null) return (byte)0xFF;
+
+        try {
+            int temp = Integer.parseInt(TEMP);
+            byte retval = 0;
+            if (temp < 0) {
+                retval = (byte)(temp*(-1));
+                retval|=(byte)(0x80);
+            }
+            else {
+                retval = (byte)temp;
+            }
+            return retval;
+        } catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+            return (byte)0x00;
+        } catch (Exception e) {
+            //e.printStackTrace();
+            LogUtil.errorLogInfo("", TAG, e);
+            return (byte)0x00;
+        }
+    }
+
+    /**
+     * 날씨정보 동기화<br>
+     * DB에 저장되어있는 날씨 정보를 가져와서 스마트스위치에 전송한다.
+     *
+     * @return (int) - >=0 : 성공, <0 : 실패
+     */
+    private int WeatherUpdate() {
+        DeviceLog("WeatherUpdate");
+
+        try {
+            WallpadStatusData DBMGR = new WallpadStatusData(ServiceMain.svcContext);
+            String[] WeatherVer = DBMGR.GetWeatherVer().split(define.DEVCTR_DATA_SPLITER);
+            WeatherTable WeatherTBL = DBMGR.GetWeatherTableController();
+            WeatherTBL.GetWeatherList();
+            DBMGR.closeDB();
+
+            String[] weatherdate = WeatherVer[0].split("[.]");
+            if (weatherdate.length < 4 || WeatherVer.length < 3) return -1;
+
+            byte [] ReqData = null;
+            if (mDriver.info.Support.NowWeather) {
+                // 현재 날씨 정보를 지원하는 경우
+                ReqData = new byte[11];
+                //Log.i(TAG, "mDriver.info.Support.NowWeather = true!!!");
+            }
+            else {
+                // 현재 날씨 정보를 지원하지 않는경우
+                ReqData = new byte[10];
+                //Log.i(TAG, "mDriver.info.Support.NowWeather = false!!!");
+            }
+
+            for (int i = 0; i<ReqData.length; i++) ReqData[i] = 0x00;
+
+            Calendar cal = new GregorianCalendar();
+            int month = cal.get(Calendar.MONTH)+1;
+            int date  = cal.get(Calendar.DAY_OF_MONTH);
+            int StartLoc = 0;
+            if (Integer.parseInt(weatherdate[1]) == month && Integer.parseInt(weatherdate[2]) == date) {
+                //                Log.i(TAG, "## 1111");
+                //                for(int i=0 ; i<WeatherVer.length ; i++)
+                //                {
+                //                    Log.i(TAG, "N" + i + " : " + WeatherVer[i]);
+                //                }
+                ReqData[0] = GetTemp( WeatherVer[5]);
+                ReqData[1] = GetWeatherCode( WeatherTBL.GetWeatherList().get(StartLoc).code); //GetWeatherCode( WeatherVer[3]);
+                ReqData[2] = GetTemp( WeatherVer[6]);
+                ReqData[3] = GetTemp( WeatherVer[7]);
+
+                if (mDriver.info.Support.NowWeather) ReqData[10] = GetWeatherCode(WeatherVer[3]);
+            }
+            else {
+                //                Log.i(TAG, "## 2222");
+                if (WeatherTBL.GetWeatherList().size() > 0) {
+                    String Curdate = String.format("%02d%02d", month,date);
+
+                    //                    Log.i(TAG, "## 3333 - [" + Curdate + "]");
+                    for (int i = 0; i < WeatherTBL.GetWeatherList().size(); i++) {
+                        if (WeatherTBL.GetWeatherList().get(i).date.equals(Curdate)) {
+                            StartLoc = i;
+
+                            //                            Log.i(TAG, "## 4444 - [StartLoc:" + StartLoc + "]");
+                            //                            Log.i(TAG, "## 4444 - [StartLoc:" + StartLoc + "]");
+
+
+                            ReqData[0] = GetTemp( WeatherTBL.GetWeatherList().get(StartLoc).low);
+                            byte NowCode = GetWeatherCode( WeatherTBL.GetWeatherList().get(StartLoc).code);
+                            ReqData[1] = NowCode;
+                            ReqData[2] = GetTemp( WeatherTBL.GetWeatherList().get(StartLoc).low);
+                            ReqData[3] = GetTemp( WeatherTBL.GetWeatherList().get(StartLoc).high);
+
+                            if(mDriver.info.Support.NowWeather) ReqData[10] = NowCode;
+                            break;
+                        }
+                    }
+                }
+            }
+
+            DeviceLog("Get Data : "+WeatherTBL.GetWeatherList().size()+":");
+            if (StartLoc+1 < WeatherTBL.GetWeatherList().size()) {
+                StartLoc++;
+                ReqData[4] = GetWeatherCode( WeatherTBL.GetWeatherList().get(StartLoc).code);
+                ReqData[5] = GetTemp( WeatherTBL.GetWeatherList().get(StartLoc).low);
+                ReqData[6] = GetTemp( WeatherTBL.GetWeatherList().get(StartLoc).high);
+                if (StartLoc+1 < WeatherTBL.GetWeatherList().size()) {
+                    StartLoc++;
+                    ReqData[7] = GetWeatherCode( WeatherTBL.GetWeatherList().get(StartLoc).code);
+                    ReqData[8] = GetTemp( WeatherTBL.GetWeatherList().get(StartLoc).low );
+                    ReqData[9] = GetTemp( WeatherTBL.GetWeatherList().get(StartLoc).high);
+                }
+                else {
+                    ReqData[7] = 0;
+                    ReqData[8] = 0;
+                    ReqData[9] = 0;
+                }
+            }
+            else {
+                ReqData[4] = 0;
+                ReqData[5] = 0;
+                ReqData[6] = 0;
+                ReqData[7] = 0;
+                ReqData[8] = 0;
+                ReqData[9] = 0;
+            }
+
+            Status status = Send_SetWeather(ReqData);
+
+            if (status != null) return 0;
+        } catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+            return -2;
+        } catch (Exception e) {
+            Log.e(TAG, "[Exception Error] WeatherUpdate");
+            //e.printStackTrace();
+            LogUtil.errorLogInfo("", TAG, e);
+            return -2;
+        }
+
+        return -3;
+    }
+
+    /**
+     * 에너지정보 동기화<br>
+     * 실시간검침기의 현재 사용량을 가져와서 스마트스위치에 전송한다.
+     */
+    private void updateEnergy() {
+        DeviceLog("[updateEnergy] start");
+        try {
+            if (ServiceMain.realTimeMeter_Controller != null) {
+                byte [] RemoteMeterShareData = RealTimeMeter_Controller.GetShareData();
+                if (RemoteMeterShareData != null) {
+                    byte EnergyCount = RemoteMeterShareData[1];
+                    if ((EnergyCount <= 0) || (EnergyCount > 5)) return;
+
+                    byte UseEnergyCount = 0;
+                    int index = 2;
+                    for (int i=0 ; i<EnergyCount ; i++) {
+                        if ((RemoteMeterShareData[index] & BIT7) == 0x00) {
+                            UseEnergyCount++;
+                            index += 8;
+                        }
+                        else index += 1;
+                    }
+
+                    byte [] ReqData = new byte [(UseEnergyCount*4) + 1];
+
+                    ReqData[0] = UseEnergyCount;
+                    int ReqIndex = 1;
+                    index = 2;
+                    for (byte i=0 ; i<EnergyCount ; i++) {
+                        if ((RemoteMeterShareData[index] & BIT7) == 0x00) {
+                            ReqData[ReqIndex++] = RemoteMeterShareData[index + 0];
+                            ReqData[ReqIndex++] = RemoteMeterShareData[index + 5];
+                            ReqData[ReqIndex++] = RemoteMeterShareData[index + 6];
+                            ReqData[ReqIndex++] = RemoteMeterShareData[index + 7];
+
+                            index += 8;
+                        }
+                        else index += 1;
+                    }
+
+                    Send_SetEnergy(ReqData);
+                }
+                // 실시간검침이 있다가 없어진 경우, 신규 스마트스위치에게 "0"을 보내줘야 화면에서 사라진다.
+                else if (RemoteMeterShareData == null) {
+                    // 항상 이부분에 걸리는 것인가? 왜 Always TRUE 이지?
+                    byte [] ReqData = new byte [1];
+                    ReqData[0] = 0x00;
+
+                    Send_SetEnergy(ReqData);
+                }
+            }
+            else {
+                Log.w(TAG, "[updateEnergy] ServiceMain.realTimeMeter_Controller is null!!");
+                Send_SetEnergy(makeTelemeteringData());
+            }
+        } catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+        } catch (Exception e) {
+            Log.e(TAG, "[Exception] updateEnergy()");
+            //e.printStackTrace();
+            LogUtil.errorLogInfo("", TAG, e);
+        }
+    }
+
+    byte hEnergyType_Elec = (byte) 0x01;
+    byte hEnergyType_Water = (byte) 0x02;
+    byte hEnergyType_Hotwater = (byte) 0x03;
+    byte hEnergyType_Gas = (byte) 0x04;
+    byte hEnergyType_Heating = (byte) 0x05;
+    private byte[] makeTelemeteringData() {
+        try {
+            DeviceLog("[makeTelemeteringData] strElecUsage [" + strElecUsage + "], strWaterUsage [" + strWaterUsage + "], strGasUsage [" + strGasUsage + "], strHotwaterUsage [" + strHotwaterUsage + "], strHeatingUsage [" + strHeatingUsage + "] ");
+            int nCnt = 0;
+            if (!strElecUsage.equalsIgnoreCase(NoTelemeteringValue)) nCnt++;
+            if (!strWaterUsage.equalsIgnoreCase(NoTelemeteringValue)) nCnt++;
+            if (!strHotwaterUsage.equalsIgnoreCase(NoTelemeteringValue)) nCnt++;
+            if (!strGasUsage.equalsIgnoreCase(NoTelemeteringValue)) nCnt++;
+            if (!strHeatingUsage.equalsIgnoreCase(NoTelemeteringValue)) nCnt++;
+
+            // 데이터 배열 초기화
+            byte[] ahMeterData = new byte[(nCnt * 4) + 1];
+            for (int i = 0; i < ahMeterData.length; i++) ahMeterData[i] = (byte) 0x00;
+            DeviceLog("[makeTelemeteringData] ahMeterData.length [" + ahMeterData.length + "]");
+
+            // 데이터 생성
+            int nIndex = 0;
+            ahMeterData[0] = (byte) nCnt;
+            nIndex++;
+
+            // 전력
+            if (!strElecUsage.equalsIgnoreCase(NoTelemeteringValue)) {
+                ahMeterData[nIndex] = hEnergyType_Elec;
+                nIndex++;
+
+                /**
+                 * # 전력값 처리 방안안
+                 * 1. 전력값은 KW기준이므로 W기준으로 변경한다.
+                 * 2. 서버에서 보내주는 전력값은 KW기준의 소수점 아래 한자리를 포함
+                 * 3. KW를 W로 변환시, X 1000을 하므로 소수점으로 인함 문제는 없다.
+                 * 4. 프로토콜상 전력값은 소수점을 포함하지 않으므로 이를 삭제한다.
+                 */
+                String strTempElecUsage = String.valueOf(Double.valueOf(strElecUsage) * 1000);
+                if (strTempElecUsage.contains(".")) {
+                    String[] strParsed = strTempElecUsage.split("\\.");
+                    strTempElecUsage = strParsed[0];
+                }
+
+                byte[] hValue = convertTelemeteringValue(strTempElecUsage);
+                for (int i = 0; i < hValue.length; i++) {
+                    ahMeterData[nIndex] = hValue[i];
+                    nIndex++;
+                }
+            }
+
+            // 수도
+            if (!strWaterUsage.equalsIgnoreCase(NoTelemeteringValue)) {
+                ahMeterData[nIndex] = hEnergyType_Water;
+                nIndex++;
+
+                byte[] hValue = convertTelemeteringValue(strWaterUsage);
+                for (int i = 0; i < hValue.length; i++) {
+                    ahMeterData[nIndex] = hValue[i];
+                    nIndex++;
+                }
+            }
+
+            // 온수
+            if (!strHotwaterUsage.equalsIgnoreCase(NoTelemeteringValue)) {
+                ahMeterData[nIndex] = hEnergyType_Hotwater;
+                nIndex++;
+
+                byte[] hValue = convertTelemeteringValue(strHotwaterUsage);
+                for (int i = 0; i < hValue.length; i++) {
+                    ahMeterData[nIndex] = hValue[i];
+                    nIndex++;
+                }
+            }
+
+            // 가스
+            if (!strGasUsage.equalsIgnoreCase(NoTelemeteringValue)) {
+                ahMeterData[nIndex] = hEnergyType_Gas;
+                nIndex++;
+
+                byte[] hValue = convertTelemeteringValue(strGasUsage);
+                for (int i = 0; i < hValue.length; i++) {
+                    ahMeterData[nIndex] = hValue[i];
+                    nIndex++;
+                }
+            }
+
+            // 열량(난방)
+            if (!strHeatingUsage.equalsIgnoreCase(NoTelemeteringValue)) {
+                ahMeterData[nIndex] = hEnergyType_Heating;
+                nIndex++;
+
+                byte[] hValue = convertTelemeteringValue(strHeatingUsage);
+                for (int i = 0; i < hValue.length; i++) {
+                    ahMeterData[nIndex] = hValue[i];
+                    nIndex++;
+                }
+            }
+
+            return ahMeterData;
+        } catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+            return null;
+        } catch (Exception e) {
+            Log.e(TAG, "[Exception] makeTelemeteringData()");
+            //e.printStackTrace();
+            LogUtil.errorLogInfo("", TAG, e);
+            return null;
+        }
+    }
+
+    /**
+     * 원격검침값을 스마트스위치로 보내기위한 데이터 변환 (String -> byte[3])
+     * @param strValue
+     * @return
+     */
+    private byte[] convertTelemeteringValue(String strValue) {
+        DeviceLog("[convertTelemeteringValue] strValue [" + strValue + "]");
+        byte [] ahResultData = new byte [3];
+        for (int i = 0; i < ahResultData.length; i++) ahResultData[i] = (byte) 0x00;
+
+        try {
+            if (strValue.length() > 7) {
+                // 숫자 6자리, 소수점 1자리
+                Log.w(TAG, "[convertTelemeteringValue] strValue is out of range!! strValue [" + strValue + "], strValue.length [" + strValue.length() + "]");
+                return ahResultData;
+            }
+
+            if (strValue.contains(".")) {
+                String[] strParsed = strValue.split("\\.");
+                String strUpper = doZeroPadding_Head(3, strParsed[0]);
+                String strLower = doZeroPadding_Tail(3, strParsed[1]);
+                int nValue = Integer.parseInt(strUpper + strLower);
+                ahResultData[0] = getDecToHex(nValue / 10000);
+                ahResultData[1] = getDecToHex((nValue / 100) % 100);
+                ahResultData[2] = getDecToHex(nValue % 100);
+            }
+            else {
+                int nValue = Integer.parseInt(strValue);
+                ahResultData[0] = getDecToHex(nValue / 10000);
+                ahResultData[1] = getDecToHex((nValue / 100) % 100);
+                ahResultData[2] = getDecToHex(nValue % 100);
+            }
+
+        } catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+        } catch (Exception e) {
+            Log.e(TAG, "[Exception] convertTelemeteringValue(String strValue)");
+            //e.printStackTrace();
+            LogUtil.errorLogInfo("", TAG, e);
+        }
+        return ahResultData;
+    }
+
+    // 10진수를 Byte로 변환 ex)12 -> 0x12
+    private byte getDecToHex(int nDec) {
+        try {
+            byte result = 0;
+            result += ((nDec / 10) << 4);
+            result += (nDec % 10);
+//            LOG("[getDexToHex] result [" + result + "]");
+            return result;
+        } catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+            return 0;
+        } catch (Exception e) {
+            Log.e(TAG, "[Exception] getDecToHex(int nDec)");
+            //e.printStackTrace();
+            LogUtil.errorLogInfo("", TAG, e);
+            return 0;
+        }
+    }
+
+    public static String doZeroPadding_Head(int nOutLength, String strOriginalString) {
+        String strResult = strOriginalString;
+//        Log.d(TAG, "[doZeroPadding_Head] (Length) strOriginalString [" + strOriginalString.length() +"], nOutLength [" + nOutLength + "]");
+        try {
+
+            if (strOriginalString.length() < nOutLength) {
+                for (int i = strOriginalString.length(); i < nOutLength; i++) {
+                    strResult = "0" + strResult;
+                }
+//                Log.d(TAG, "[doZeroPadding_Head] strResult : " + strResult);
+                return strResult;
+            }
+            else if (strOriginalString.length() == nOutLength) {
+//                Log.d(TAG, "[doZeroPadding_Head] same length!");
+                return strResult;
+            }
+            else {
+                Log.d(TAG, "[doZeroPadding_Head] strOriginalString(" + strOriginalString.length() + ") is longer than nOutLength(" + nOutLength + ")");
+                return strResult;
+            }
+        } catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+            return strResult;
+        } catch (Exception e) {
+            Log.e(TAG, "[Exception] doZeroPadding_Head(int nOutLength, String strOriginalString)");
+            //e.printStackTrace();
+            LogUtil.errorLogInfo("", TAG, e);
+            return strResult;
+        }
+    }
+
+    public static String doZeroPadding_Tail(int nOutLength, String strOriginalString) {
+        String strResult = strOriginalString;
+//        Log.d(TAG, "[doZeroPadding_Tail] (Length) strOriginalString [" + strOriginalString.length() +"], nOutLength [" + nOutLength + "]");
+        try {
+
+            if (strOriginalString.length() < nOutLength) {
+                for (int i = strOriginalString.length(); i < nOutLength; i++) {
+                    strResult = strResult + "0";
+                }
+//                Log.d(TAG, "[doZeroPadding_Tail] strResult : " + strResult);
+                return strResult;
+            }
+            else if (strOriginalString.length() == nOutLength) {
+//                Log.d(TAG, "[doZeroPadding_Tail] same length!");
+                return strResult;
+            }
+            else {
+                Log.d(TAG, "[doZeroPadding_Tail] strOriginalString(" + strOriginalString.length() + ") is longer than nOutLength(" + nOutLength + ")");
+                return strResult;
+            }
+        } catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+            return strResult;
+        } catch (Exception e) {
+            Log.e(TAG, "[Exception] doZeroPadding_Tail(int nOutLength, String strOriginalString)");
+            //e.printStackTrace();
+            LogUtil.errorLogInfo("", TAG, e);
+            return strResult;
+        }
+    }
+
+    /**
+     * 주차정보 동기화<br>
+     * 단지서버가 저장한 주차정보를 DB에서 읽어 전송한다.
+     *
+     * @return (int) - >=0 : 성공, <0 : 실패
+     */
+    private int ParkingUpdate() {
+        DeviceLog("[ParkingUpdate] - START");
+
+        WallpadParkInfo parkdb = null;
+        try {
+            // 0. 주차정보 사용 유무 체크한다.
+            if (Get_DBInfo_Parking() == false) {
+                mDriver.Polling.setParkingUpdate(false); //추가
+                return -1;
+            }
+
+            // 1. 주차정보 DB 을 OPEN 한다.
+            parkdb = new WallpadParkInfo(ServiceMain.svcContext);
+
+            // 2. 주차정보 개수를 가져온다.
+            int RowCountCarParking = parkdb.RowCountCarParking();
+
+            DeviceLog("[ParkingUpdate] RowCountCarParking - " + RowCountCarParking);
+
+            if (RowCountCarParking == 0) {
+                parkdb.closeDB();
+
+                // 주차정보 알림 전송 (주차정보 삭제)
+                Status status = Send_SetParking(new byte [] { 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 });
+                if (status != null) return 0;
+                return -2;
+            }
+            else if (RowCountCarParking < 0) {
+                parkdb.closeDB();
+                Log.w(TAG, "[ParkingUpdate] parkdb.RowCountCarParking Error (ret:" + RowCountCarParking + ")");
+                return -3;
+            }
+
+            // 3. 주차정보 리스트를 가져온다.
+            CarParkingData carParkingData[] = parkdb.getCarParkingData();
+            parkdb.closeDB();
+            if (carParkingData == null) {
+                Log.w(TAG, "[ParkingUpdate] parkdb.getCarParkingData Error - null !!!");
+                return -4;
+            }
+
+            // TEST
+            //            CarParkingData [] carParkingData = new CarParkingData[3];
+            //            for(int i=0 ; i<carParkingData.length ; i++)
+            //            {
+            //                carParkingData[i] = new CarParkingData();
+            //                switch(i)
+            //                {
+            //                    case 0:
+            //                        carParkingData[i].location_text = "B2A11abcdee5trgdfg";
+            //                        carParkingData[i].vehicle_info = "d/1234";
+            //                        break;
+            //                    case 1:
+            //                        carParkingData[i].location_text = "C3D11abcdee5trgdfg";
+            //                        carParkingData[i].vehicle_info = "s/12가5678";
+            //                        break;
+            //                    case 2:
+            //                        carParkingData[i].location_text = "D4E11abcdee5trgdfg";
+            //                        carParkingData[i].vehicle_info = "s/12가9999";
+            //                        break;
+            //                }
+            //            }
+
+            // 4. 디버그 메시지 출력
+            //for(int i=0; i<carParkingData.length; i++) DeviceLog(carParkingData[i].ToDebugString());
+
+            // 5. 기기 지원 정보개수는 2개이다 2개 이상일시 2개로 조정
+            byte CarCount = 0;
+            if (carParkingData.length >= 2) CarCount = 2;
+            else CarCount = (byte) carParkingData.length;
+
+            // 6. 리스트 개수만큼 전송
+            for (byte carindex = 0; carindex < CarCount; carindex++) {
+                DeviceLog("[ParkingUpdate] - carindex : " + carindex);
+                String LocationStr = carParkingData[carindex].location_text;
+                String CarNumberStr = carParkingData[carindex].vehicle_info;
+
+                DeviceLog("[ParkingUpdate] - LocationStr  : " + LocationStr);
+                DeviceLog("[ParkingUpdate] - CarNumberStr : " + CarNumberStr);
+                // 주차 위치 정보
+                byte [] LocByteArray = CarLocationParsing(LocationStr);
+                if (LocByteArray == null) LocByteArray = new byte[] { 0x00 };
+                byte LocationLength = (byte) LocByteArray.length;
+                if (LocationLength > MAX_PARKING_INFO_STR_COUNT) LocationLength = MAX_PARKING_INFO_STR_COUNT;
+
+                // 차량번호
+                byte [] CarNumber = CarNumberParsing(CarNumberStr);
+                if (CarNumber == null) CarNumber = new byte[] { 0x00, 0x00, 0x00, 0x00 };
+
+                // 전송 데이터 생성
+                byte [] ReqData = new byte [7+LocationLength];
+                int index = 0;
+
+                ReqData[index++] = CarCount;             // 세대에 등록된 차량 대수 n
+                ReqData[index++] = (byte)(carindex+1);   // 세대에 등록된 차량 대수 중 일련 번호
+
+                ReqData[index++] = CarNumber[0]; // 차량 번호 첫번째 자리
+                ReqData[index++] = CarNumber[1]; // 차량 번호 두번째 자리
+                ReqData[index++] = CarNumber[2]; // 차량 번호 세번째 자리
+                ReqData[index++] = CarNumber[3]; // 차량 번호 네번째 자리
+
+                ReqData[index++] = LocationLength;        // 주차 위치 정보 문자열 개수 m
+                for (byte i = 0; i < LocationLength; i++) {
+                    ReqData[index++] = LocByteArray[i];   // 주차 위치 정보의 문자 복사
+                }
+
+                // 주차정보 알림 전송
+                Send_SetParking(ReqData);
+
+                if ((CarCount == 2) && (carindex == 0)) {
+                    Sleep(100);
+                }
+            }
+
+            DeviceLog("ParkingUpdate - END");
+            return 0;
+
+        } catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+            if(parkdb != null) parkdb.closeDB();
+            return -100;
+        } catch (Exception e) {
+            Log.e(TAG, "[Exception Error] ParkingUpdate");
+            //e.printStackTrace();
+            LogUtil.errorLogInfo("", TAG, e);
+            if(parkdb != null) parkdb.closeDB();
+            return -100;
+        }
+    }
+
+    /**
+     * 차량번호 4자리를 byte 로 반환한다.
+     *
+     * @param CarNumStr - (String) 차량번호
+     *
+     * @return (byte []) 차량번호 4자리 (Length : 4)
+     */
+    private byte [] CarNumberParsing(String CarNumStr) {
+        try {
+            if (CarNumStr == null) return null;
+            byte [] bytes = CarNumStr.getBytes();
+            if (bytes == null) return null;
+            if (bytes.length < 4) return null;
+
+            byte [] CarNum = new byte[4];
+            int index = bytes.length-4;
+            for (int i = 0; i < 4; i++) {
+                CarNum[i] = bytes[index++];
+                if (!((CarNum[i] >= 0x30) && (CarNum[i] <= 0x39))) return null;
+                CarNum[i] &= 0x0F;
+            }
+            return CarNum;
+        } catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+            return null;
+        } catch (Exception e) {
+            Log.e(TAG, "[Exception Error] CarNumberParsing");
+            //e.printStackTrace();
+            LogUtil.errorLogInfo("", TAG, e);
+            return null;
+        }
+    }
+
+    /**
+     * 차량위치 String 을 byte 배열로 변환한다.</br>
+     * 변환시 표현범위 이탈을 체크하여 변환한다.
+     *
+     * @param CarLocStr - (String) 차량위치
+     * @return (byte []) 변환된 차량위치 정보
+     */
+    private byte [] CarLocationParsing(String CarLocStr) {
+        try {
+            if (CarLocStr == null) return null;
+            byte [] bytes = CarLocStr.getBytes();
+            if (bytes == null) return null;
+
+            for (int i = 0; i < bytes.length; i++) {
+                if (!(bytes[i] == ' ') &&       // 공백
+                        !(bytes[i] == '-') &&       // '-'
+                        !(bytes[i] == '_') &&       // '_'
+                        !((bytes[i] >= '0') && (bytes[i] <= '9')) &&     // '0' ~ '9'
+                        !((bytes[i] >= 'A') && (bytes[i] <= 'Z')) &&     // 'A' ~ 'Z'
+                        !((bytes[i] >= 'a') && (bytes[i] <= 'z')))      // 'a' ~ 'z'
+                {
+                    bytes[i] = ' ';
+                }
+            }
+
+            return bytes;
+        } catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+            return null;
+        } catch (Exception e) {
+            Log.e(TAG, "[Exception Error] CarLocationParsing");
+            //e.printStackTrace();
+            LogUtil.errorLogInfo("", TAG, e);
+            return null;
+        }
+    }
+
+    /**
+     * 알람상태를 가져온다.
+     *
+     * @return (int) 외출상태 <br>
+     *               WallpadStatusData.ALARM_NONE     : 평상시<br>
+     *               WallpadStatusData.GUARD_OUT_WAIT : 외출 대기중 (설정진행중)<br>
+     *               WallpadStatusData.GUARD_OUT      : 외출
+     */
+    private int DB_GetAlarmStatus() {
+        int ret = WallpadStatusData.ALARM_NONE;
+        try {
+            WallpadStatusData wdb = new WallpadStatusData(ServiceMain.svcContext);
+            ret = wdb.GetAlarmStatus();
+            wdb.closeDB();
+            switch (ret) {
+                case WallpadStatusData.ALARM_NONE:
+                case WallpadStatusData.GUARD_OUT_WAIT:
+                case WallpadStatusData.GUARD_OUT:
+                case WallpadStatusData.OUT_MODE:
+                    break;
+
+                default:
+                    ret = WallpadStatusData.ALARM_NONE;
+                    break;
+            }
+        } catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+        } catch (Exception e) {
+            Log.e(TAG, "[DB_GetAlarmStatus] Exception Error");
+            //e.printStackTrace();
+            LogUtil.errorLogInfo("", TAG, e);
+        }
+        return ret;
+    }
+
+    /***
+     * 주차정보 사용 유무를 가져온다.
+     *
+     * @return (boolean)주차정보 사용 유무 <br>
+     *                  true = 사용 <br>
+     *                  false = 미사용 <br>
+     */
+    private boolean Get_DBInfo_Parking() {
+        boolean bUseofNot_ParkingInfo = false;
+
+        try {
+            WallpadDeviceSet devSet = new WallpadDeviceSet(ServiceMain.svcContext);
+            String[] ParkingDB = devSet.GetSettingData("주차확인");
+            devSet.closeDB();
+
+            if (ParkingDB != null) {
+                String devInfo = ParkingDB[1];
+
+                devInfo = devInfo.replace('(', '_');
+                devInfo = devInfo.replace(':', '_');
+                devInfo = devInfo.replace(')', '_');
+
+                String[] ParkingInfo = devInfo.split("_");
+
+                // ParkingInfo[3] -> 사용여부 <사용함 / else>
+                // ParkingInfo[5] -> 종류 <기본 / 아이콘트롤스 / NEXPA / UPIS / ETC / else />
+                // ParkingInfo[7] -> IP정보
+                // ParkingInfo[8] -> 포트번호
+
+                if (ParkingInfo[3].equalsIgnoreCase("사용함") == true) {
+                    bUseofNot_ParkingInfo = true;
+                }
+            }
+            else {
+                bUseofNot_ParkingInfo = false;
+            }
+        } catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+            return false;
+        } catch (Exception e) {
+            Log.e(TAG, "[Exception Error] Get_DBInfo_Parking()");
+            //e.printStackTrace();
+            LogUtil.errorLogInfo("", TAG, e);
+            return false;
+        }
+        return bUseofNot_ParkingInfo;
+    }
+
+    /**
+     * 알림정보 비교<br>
+     * 초기 값과 현재 값 비교 (초기값: 부팅시, 이미 갖고 있던 값 / 현재값:intent로 받은 값)
+     *
+     * @param arr - BroadcastReceiver새로 수신받은 알림정보 array
+     *
+     * @return true | false
+     */
+    public boolean isNotiDataChanged(int[] arr) {
+        boolean retbool = false;
+
+        if (arr[0] != DefaultNotiCNT) {
+            Log.d(TAG , "[isNotiDataChanged] - notice changed : "+ arr[0]);
+            DefaultNotiCNT = arr[0];
+
+            retbool = true;
+        }
+        else if (arr[0] == 0) {
+            Log.d(TAG , "[isNotiDataChanged] - default notice zero");
+            DefaultNotiCNT = 0;
+            retbool = true;
+        }
+
+        if (arr[1] != DefaultParcelCNT) {
+            Log.d(TAG , "[isNotiDataChanged] - parcel changed : "+ arr[1]);
+            DefaultParcelCNT = arr[1];
+
+            retbool = true;
+        }
+        else if (arr[1] == 0) {
+            Log.d(TAG , "[isNotiDataChanged] - default parcel zero");
+            DefaultParcelCNT= 0;
+            retbool = true;
+        }
+
+        if (arr[2] != DefaultVisitorCNT) {
+            Log.d(TAG , "[isNotiDataChanged] - visitor changed : "+ arr[2]);
+            DefaultVisitorCNT = arr[2];
+
+            retbool = true;
+        }
+        else if (arr[2] == 0) {
+            Log.d(TAG , "[isNotiDataChanged] - default visitor zero");
+            DefaultVisitorCNT= 0;
+            retbool = true;
+        }
+
+        if (arr[3] != DefaultMemoCNT) {
+            Log.d(TAG , "[isNotiDataChanged] - memo changed : "+ arr[3]);
+            DefaultMemoCNT = arr[3];
+
+            retbool = true;
+        }
+        else if (arr[3] == 0) {
+            Log.d(TAG , "default memo zero");
+            DefaultMemoCNT= 0;
+            retbool = true;
+        }
+
+        return retbool;
+    }
+
+
+    /**
+     * 알림정보 동기화<br>
+     * 공지사항, 택배, 방문자, 메모의 수가 증가하면 스마트스위치에 전송한다.<br>
+     * 공지사항, 택배, 메모 카운트는 WallpadStatusData에서 가져온다.<br>
+     * 방문자 카운트는 BroadcastReceiver의 onReceive()로 얻는다.
+     *
+     */
+    private int NotiInfoUpdate() {
+        byte [] ReqData = {0x00, 0x00}; // {요청받은 제어 개수,
+        // 알림 정보(BIT 0:공지사항, 1:택배, 2:방문자, 3:메모)}
+        try {
+            if (NotiArr[0] > 0) {
+                // 공지사항
+                Log.i(TAG, "[NotiInfoUpdate] notifyCount = " + NotiArr[0]);
+                ReqData[0]++;
+                ReqData[1] += BIT0;
+            }
+            else if (NotiArr[0] == 0) {
+                // 0개로 수신하면 스마트 스위치에게 0으로 보내준다.(신규 스마트스위치를 위해서)
+                Log.i(TAG, "[NotiInfoUpdate] notifyCount zero= " + NotiArr[0]);
+                ReqData[0]++;
+            }
+
+            if (NotiArr[1] > 0) {
+                // 택배
+                Log.i(TAG, "[NotiInfoUpdate] parcelCount = " + NotiArr[1]);
+                ReqData[0]++;
+                ReqData[1] += BIT1;
+            }
+            else if (NotiArr[1] == 0) {
+                Log.i(TAG, "[NotiInfoUpdate] parcelCount zero= " + NotiArr[1]);
+                ReqData[0]++;
+            }
+
+            if (NotiArr[2] > 0) {
+                // 방문자
+                Log.i(TAG, "[NotiInfoUpdate] vistorCount = " + NotiArr[2]);
+                ReqData[0]++;
+                ReqData[1] += BIT2;
+            }
+            else if (NotiArr[2] == 0) {
+                Log.i(TAG, "[NotiInfoUpdate] vistorCount zero= " + NotiArr[2]);
+                ReqData[0]++;
+            }
+
+            if (NotiArr[3] > 0) {
+                // 메모
+                Log.i(TAG, "[NotiInfoUpdate] memoCount = " + NotiArr[3]);
+                ReqData[0]++;
+                ReqData[1] += BIT3;
+            }
+            else if (NotiArr[3] == 0) {
+                Log.i(TAG, "[NotiInfoUpdate] memoCount zero= " + NotiArr[3]);
+                ReqData[0]++;
+            }
+
+            Log.i(TAG, "[NotiInfoUpdate] Noti REQUEST count = " + ReqData[0] + " / data =  " + ReqData[1]);
+
+            // Send data
+            Status st = Send_SetNotiInfo(ReqData);
+
+            if (st != null) {
+                Log.i(TAG, "[NotiInfoUpdate] return 0! --> GOOD");
+                return 0;
+            }
+            else {
+                Log.i(TAG, "[NotiInfoUpdate] return -2! --> BAD");
+                return -2;
+            }
+        } catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+            return -3;
+        } catch (Exception e) {
+            Log.e(TAG, "[Exception Error] NotiInfoUpdate");
+            //e.printStackTrace();
+            LogUtil.errorLogInfo("", TAG, e);
+            return -3;
+        }
+    }
+
+    /**
+     * 난방정보 동기화<br>
+     * 난방정보 패킷을 HeatingV2의 데이터로 만들고, 스마트스위치에게 전송한다.
+     *
+     */
+    private int HeatingInfoUpdate() {
+        DeviceLog("HeatingInfoUpdate");
+
+        try {
+            byte [] ReqData = null;
+
+            if (ServiceMain.heatingV2_Controller != null) {
+                H2Cont = ServiceMain.heatingV2_Controller;
+                byte roomCount = H2Cont.GetRoomCount();
+                //Log.i(TAG,"SmartSwitch Room Count = " + roomCount);
+
+                ReqData = new byte[1 + (roomCount*4)];
+                for (int i = 0; i < ReqData.length; i++) {
+                    ReqData[i] = (byte) 0x00; // ReqData Initialize
+                }
+                //Log.i(TAG,"ReqData Length = " + ReqData.length);
+
+                ReqData[0] = roomCount; // (D1)
+
+                // 각 방의 정보를 얻어서 전송할 데이터 패킷 만들기
+                // make ReqData
+                for (int i = 0; i < roomCount; i++) {
+                    byte mode = H2Cont.GetRoomMode(i);
+                    String valve = H2Cont.GetRoomValve(i);
+                    byte nowTemp = H2Cont.GetRoomNowTemp(i);
+                    byte setTemp = H2Cont.GetRoomSetTemp(i);
+
+                    //Log.i(TAG,"Room " + i + " Mode = " + mode);
+                    //Log.i(TAG,"Room " + i + " valve = " + valve);
+                    //Log.i(TAG,"Room " + i + " nowTemp = " + nowTemp);
+                    //Log.i(TAG,"Room " + i + " setTemp = " + setTemp);
+
+                    if(valve!=null)
+                    {
+                        // Add Valve BIT ( D2 + (4*i) )
+                        if (valve.equals("true")) {
+                            ReqData[1+(i*4)] += define.BIT4;
+                        }
+                        else if (valve.equals("false")) {
+                            ReqData[1+(i*4)] += 0;
+                        }
+                    }
+
+                    //Log.i(TAG,"middle valve " + i + " = " + valve);
+
+                    // Add Mode BIT ( D2 + (4*i) )
+                    if (mode == 1) {
+                        // Mode : ON
+                        ReqData[1+(i*4)] += define.BIT0;
+                    }
+                    else if (mode == 2) {
+                        // Mode : OFF
+                        ReqData[1+(i*4)] += define.BIT1;
+                    }
+                    else if (mode == 3) {
+                        // Mode : Outting
+                        ReqData[1+(i*4)] = (define.BIT0 + define.BIT1);
+                    }
+                    else if (mode == 5) {
+                        // Mode : Sleep
+                        ReqData[1+(i*4)] = (define.BIT0 + define.BIT2);
+                    }
+                    else if (mode == 6) {
+                        // Mode : Reserve
+                        ReqData[1+(i*4)] = (define.BIT1 + define.BIT2);
+                    }
+                    else if (mode == 7) {
+                        // Mode : Pause
+                        ReqData[1+(i*4)] = (define.BIT0 + define.BIT1 + define.BIT2);
+                    }
+                    //Log.i(TAG,"HeatingInfo mode  " + i + " = " + mode);
+
+                    // Add SetTemp BIT ( D3 + (4*i) )
+                    if (setTemp != 0) {
+                        ReqData[2+(i*4)] += setTemp; // 선언 시, 0.5 설정도 되어 있는 값을 return 받음
+                    }
+                    //Log.i(TAG,"HeatingInfo setTemp  " + i + " = " + setTemp);
+
+                    // Add NowTemp BIT
+                    if (nowTemp != 0) {
+                        int nowTempTen = nowTemp * 10;
+                        String sendNowTemp = Integer.toHexString(nowTempTen);
+
+                        if (sendNowTemp.length() == 1) {
+                            sendNowTemp = "000" + sendNowTemp; // 000/1
+                        }
+                        else if (sendNowTemp.length() == 2) {
+                            sendNowTemp = "00" + sendNowTemp; // 00/12
+                        }
+                        else if (sendNowTemp.length() == 3) {
+                            sendNowTemp = "0" + sendNowTemp; // 0/123
+                        }
+                        //Log.i(TAG,"sendNowTemp  " + i + " = " + sendNowTemp);
+
+                        int upper = Integer.parseInt(sendNowTemp.substring(0, 2), 16);
+                        int lowwer = Integer.parseInt(sendNowTemp.substring(2), 16);
+
+                        //Log.i(TAG,"upper  " + i + " = " + upper);
+                        //Log.i(TAG,"lowwer  " + i + " = " + lowwer);
+
+                        ReqData[3+(i*4)] += (byte) upper;  // NowTemp High BIT 2  ( D4 + (4*i) )
+                        ReqData[4+(i*4)] += (byte) lowwer; // NowTemp Low  BIT 2  ( D5 + (4*i) )
+                    }
+                }
+
+            }
+            else {
+                Log.w(TAG,"[HeatingInfoUpdate] - ServiceMain.heatingV2_Controller is NULL");
+            }
+
+            // Send data
+            Status st = Send_SetHeatingInfo(ReqData);
+
+            if (st != null) {
+                //Log.i(TAG, "[HeatingInfoUpdate] return ! --> GOOD");
+                return 0;
+            }
+            else {
+                //Log.i(TAG, "[HeatingInfoUpdate] return ! --> BAD");
+                return -1;
+            }
+        } catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+            return -2;
+        } catch (Exception e) {
+            Log.e(TAG, "[Exception Error] HeatingInfoUpdate");
+            //e.printStackTrace();
+            LogUtil.errorLogInfo("", TAG, e);
+            return -2;
+        }
+    }
+
+    int count = 0;
+
+    /**
+     * 스마트스위치에서 사용하기 위한 데이터값 생성
+     * @return
+     */
+    public byte[] MakeAirQualityInfo_For_SmartSwitch()
+    {
+        //공기질 정보 종류 만들기
+        int index = 0;
+        byte TotalType = 0;
+        byte[] return_Array = new byte[4*3 + 2];//(공기질 정보 + 공기질 상태 단계 종류
+
+        count++;
+        if(count>4) count = 0;
+
+        index = 2;
+        TotalType = (byte) (TotalType | 1);
+        //미세먼지 PM10 단계
+        //단계정보 수정
+        byte level = (byte)count;
+        return_Array[index++] = level;
+        //미세먼지 PM10 (상위)
+        return_Array[index++] = 0;
+        //미세먼지 PM10 (하위)
+        return_Array[index++] = 29;
+        TotalType = (byte) (TotalType | 2);
+        //초미세먼지 PM10 단계
+        level++;
+        if(level>4)level=0;
+        return_Array[index++] = level;
+        //초미세먼지 PM10 (상위)
+        return_Array[index++] = 1;
+        //초미세먼지 PM10 (하위)
+        return_Array[index++] = 29;
+        TotalType = (byte) (TotalType | 4);
+        //극초미세먼지 PM10 단계
+        level++;
+        if(level>4)level=0;
+        return_Array[index++] = level;
+        //극초미세먼지 PM10 (상위)
+        return_Array[index++] = 1;
+        //극초미세먼지 PM10 (하위)
+        return_Array[index++] = 29;
+        TotalType = (byte) (TotalType | 8);
+        //이산화탄소 PM10 단계
+        level++;
+        if(level>4)level=0;
+        return_Array[index++] = level;
+        //이산화탄소 PM10 (상위)
+        return_Array[index++] = 1;
+        //이산화탄소 PM10 (하위)
+        return_Array[index++] = 29;
+
+        index = 0;
+        return_Array[index++] = TotalType;
+        //madeinlab
+        //D2 정보는 공기질 상태 단계 종류인데, 아래 코드는 changeTypeCount로 되어 있음. 테스트 후 수정해야 함.
+        //return_Array[index++] = (byte) cur_Status.iChangedTypeCount;
+        return_Array[index++] = 4;
+
+        return return_Array;
+    }
+
+
+    /**
+     * 공기질정보 동기화<br>
+     * 공기질 정보를 가져와서 데이터로 만들고, 스마트스위치에게 전송한다.
+     */
+    private int AirQualityInfoUpdate() {
+        DeviceLog("AirQualityInfoUpdate");
+        try {
+            byte [] ReqData = null;
+            //현재 공기질 정보를 가져온다.
+            ReqData = MakeAirQualityInfo_For_SmartSwitch();
+            // Send data
+            Status st = Send_SetAirQuailtyInfo(ReqData);
+            if (st != null) {
+                return 0;
+            }
+            else {
+                return -1;
+            }
+        } catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+            return -2;
+        } catch (Exception e) {
+            Log.e(TAG, "[Exception Error] AirQualityInfoUpdate");
+            //e.printStackTrace();
+            LogUtil.errorLogInfo("", TAG, e);
+            return -2;
+        }
+    }
+
+}

+ 26 - 0
WallPadDevService/src/main/java/kr/co/icontrols/v40ioctl/V40IF.java

@@ -388,6 +388,32 @@ public class V40IF {
     }
     }
 
 
 
 
+    /**
+     * 삼성SDS 도어락 연동 기능 추가
+     *  기존소스에도 있지만, 검증할 시간이 부족하여, 임시로 따로 구분하여 구현함 (jeff, 2021.04.09)
+     * @param nValue 0: 등록, 1: 문열림, 2: 문열림 대기 미설정, 3: 문열림 대기 3초, 4: 문열리 대기 5초, 5: 문열림 대기 10초
+     */
+    public boolean ctrlDoorlockOpenStandbyMode(int nValue) {
+        try {
+            if (nValue < 0 || 5 < nValue) {
+                Log.w(TAG, "[ctrlDoorlockOpenStandbyMode] Out of range!!! nValue [" + nValue + "]");
+                return false;
+            }
+
+            if (WpdInterfaceOpen() >= 0) {
+                WpdInterfaceControl(0xFF09, nValue);
+                WpdInterfaceClose();
+            }
+        } catch (RuntimeException re) {
+            LogUtil.errorLogInfo("", TAG, re);
+        } catch (Exception e) {
+            //e.printStackTrace();
+            LogUtil.errorLogInfo("", TAG, e);
+        }
+        return true;
+    }
+
+
 
 
 
 
 }
 }

+ 4 - 2
WallPadDevService/src/main/java/kr/co/icontrols/v40ioctl/V40IOInterface.java

@@ -72,7 +72,8 @@ public class V40IOInterface {
 	public void Emergency_Type_Set() {
 	public void Emergency_Type_Set() {
 		WpdInterfaceOpen();
 		WpdInterfaceOpen();
 		if (Version.getModelType() == Version.MODEL_TYPE.IHN_D101 || Version.getModelType() == Version.MODEL_TYPE.IHN_D101_I
 		if (Version.getModelType() == Version.MODEL_TYPE.IHN_D101 || Version.getModelType() == Version.MODEL_TYPE.IHN_D101_I
-				|| Version.getModelType() == Version.MODEL_TYPE.IHN_D101K || Version.getModelType() == Version.MODEL_TYPE.IHN_D101K_I) {
+				|| Version.getModelType() == Version.MODEL_TYPE.IHN_D101K || Version.getModelType() == Version.MODEL_TYPE.IHN_D101K_I
+				|| Version.getModelType() == Version.MODEL_TYPE.IHN_D101_I_OCF) {
 			Log.d(TAG, "[Emergency_Type_Set] V40 - D101 mode");
 			Log.d(TAG, "[Emergency_Type_Set] V40 - D101 mode");
 
 
 			WpdInterfaceControl(IOCTL_EMR_TYPE, 0);
 			WpdInterfaceControl(IOCTL_EMR_TYPE, 0);
@@ -98,7 +99,8 @@ public class V40IOInterface {
 		WpdInterfaceControl(IOCTL_LEDNEMR_ONOFF, 0);
 		WpdInterfaceControl(IOCTL_LEDNEMR_ONOFF, 0);
 
 
 		if (Version.getModelType() != Version.MODEL_TYPE.IHN_D101 && Version.getModelType() != Version.MODEL_TYPE.IHN_D101_I
 		if (Version.getModelType() != Version.MODEL_TYPE.IHN_D101 && Version.getModelType() != Version.MODEL_TYPE.IHN_D101_I
-				&& Version.getModelType() != Version.MODEL_TYPE.IHN_D101K && Version.getModelType() != Version.MODEL_TYPE.IHN_D101K_I) {
+				&& Version.getModelType() != Version.MODEL_TYPE.IHN_D101K && Version.getModelType() != Version.MODEL_TYPE.IHN_D101K_I
+				&& Version.getModelType() != Version.MODEL_TYPE.IHN_D101_I_OCF) {
 			WpdInterfaceControl(IOCTL_EMR_OFF, 0);
 			WpdInterfaceControl(IOCTL_EMR_OFF, 0);
 		}
 		}
 
 

+ 4 - 2
WallPadDevService/src/main/java/kr/co/icontrols/v40ioctl/V40IOInterface2.java

@@ -72,7 +72,8 @@ public class V40IOInterface2 {
     public void Emergency_Type_Set() {
     public void Emergency_Type_Set() {
         WpdInterfaceOpen();
         WpdInterfaceOpen();
         if (Version.getModelType() == Version.MODEL_TYPE.IHN_D101 || Version.getModelType() == Version.MODEL_TYPE.IHN_D101_I
         if (Version.getModelType() == Version.MODEL_TYPE.IHN_D101 || Version.getModelType() == Version.MODEL_TYPE.IHN_D101_I
-                || Version.getModelType() == Version.MODEL_TYPE.IHN_D101K || Version.getModelType() == Version.MODEL_TYPE.IHN_D101K_I) {
+                || Version.getModelType() == Version.MODEL_TYPE.IHN_D101K || Version.getModelType() == Version.MODEL_TYPE.IHN_D101K_I
+                || Version.getModelType() == Version.MODEL_TYPE.IHN_D101_I_OCF) {
             Log.d(TAG, "[Emergency_Type_Set] V40 - D101 mode");
             Log.d(TAG, "[Emergency_Type_Set] V40 - D101 mode");
 
 
             WpdInterfaceControl(IOCTL_EMR_TYPE, 0);
             WpdInterfaceControl(IOCTL_EMR_TYPE, 0);
@@ -98,7 +99,8 @@ public class V40IOInterface2 {
         WpdInterfaceControl(IOCTL_LEDNEMR_ONOFF, 0);
         WpdInterfaceControl(IOCTL_LEDNEMR_ONOFF, 0);
 
 
         if (Version.getModelType() != Version.MODEL_TYPE.IHN_D101 && Version.getModelType() != Version.MODEL_TYPE.IHN_D101_I
         if (Version.getModelType() != Version.MODEL_TYPE.IHN_D101 && Version.getModelType() != Version.MODEL_TYPE.IHN_D101_I
-                && Version.getModelType() != Version.MODEL_TYPE.IHN_D101K && Version.getModelType() != Version.MODEL_TYPE.IHN_D101K_I) {
+                && Version.getModelType() != Version.MODEL_TYPE.IHN_D101K && Version.getModelType() != Version.MODEL_TYPE.IHN_D101K_I
+                && Version.getModelType() != Version.MODEL_TYPE.IHN_D101_I_OCF) {
             WpdInterfaceControl(IOCTL_EMR_OFF, 0);
             WpdInterfaceControl(IOCTL_EMR_OFF, 0);
         }
         }