Forráskód Böngészése

배터리 45V 이하로 떨어지면 15%로 강재 변경 기능 추가
DriveViewModel Timer 추가 Steer 상태 1sec interval 로 확인

SWGroupSetup01 4 éve
szülő
commit
968dcd6a81

+ 82 - 82
Dev/OHV/OHV.LanguageHalper/Languages/Chinese.xaml

@@ -9,39 +9,39 @@
     <system:String x:Key="Common_Save">保存数据</system:String>
 
     <!-->Q&A</-->
-    <system:String x:Key="Question_ProgramExit">确定要结束程序吗?</system:String>
-    <system:String x:Key="VehicleModeChange">Vehicle Mode Change to</system:String>
+    <system:String x:Key="Question_ProgramExit">结束程序</system:String>
+    <system:String x:Key="VehicleModeChange">Vehicle模式转向网络模式?</system:String>
     <system:String x:Key="VehicleOnRailStateChange">Vehicle On Rail Change To</system:String>
-    <system:String x:Key="VehicleAutoMode">要换成自动模式吗 ?</system:String>
-    <system:String x:Key="VehicleManualMode">要换成手动模式吗 ? &#x0a; 注意:Vehicle可能稍微向前行驶</system:String>
+    <system:String x:Key="VehicleAutoMode">Vehicle自动模式</system:String>
+    <system:String x:Key="VehicleManualMode">Vehicle手动模式 注意:Vehicle可能稍微向前行驶</system:String>
 
     <!-->Notification</-->
-    <system:String x:Key="AutoModeChangeWranOnRailState">车辆不是 Installed 状态 !</system:String>
-    <system:String x:Key="CurrentTagZeroWarn">当前标签为零, 无法更改自动模式</system:String>
+    <system:String x:Key="AutoModeChangeWranOnRailState">切换自动模式需要车辆在轨道上 !</system:String>
+    <system:String x:Key="CurrentTagZeroWarn">当前二维码为零, 无法更改自动模式</system:String>
 
     <!-->Main View</-->
-    <system:String x:Key="MainView_Main">主</system:String>
+    <system:String x:Key="MainView_Main">主界面</system:String>
     <system:String x:Key="MainView_Teach">操纵</system:String>
-    <system:String x:Key="MainView_Setting">准备</system:String>
+    <system:String x:Key="MainView_Setting">设置</system:String>
     <system:String x:Key="MainView_Control">控制</system:String>
-    <system:String x:Key="MainView_History">記錄</system:String>
-    <system:String x:Key="MainView_Language">言</system:String>
-    <system:String x:Key="MainView_Exit">终了</system:String>
+    <system:String x:Key="MainView_History">历史</system:String>
+    <system:String x:Key="MainView_Language">言</system:String>
+    <system:String x:Key="MainView_Exit">退出</system:String>
 
-    <system:String x:Key="MainView_BuzzerStop">蜂鸣器  解决</system:String>
-    <system:String x:Key="MainView_EmergencyStop">紧急停</system:String>
+    <system:String x:Key="MainView_BuzzerStop">蜂鸣器靜音</system:String>
+    <system:String x:Key="MainView_EmergencyStop">紧急停</system:String>
 
     <system:String x:Key="MainView_AutoMode">自动模式</system:String>
     <system:String x:Key="MainView_ManualMode">手动模式</system:String>
 
-    <system:String x:Key="MainView_LocalMode">Local Mode</system:String>
-    <system:String x:Key="MainView_HostMode">Host Mode</system:String>
+    <system:String x:Key="MainView_LocalMode">本地模式</system:String>
+    <system:String x:Key="MainView_HostMode">网络模式</system:String>
 
-    <system:String x:Key="MainView_AlarmReset">闹钟 消去</system:String>
+    <system:String x:Key="MainView_AlarmReset">报警复位</system:String>
 
     <!-->Setting View</-->
-    <system:String x:Key="SettingView_Config">Config</system:String>
-    <system:String x:Key="SettingView_Parameter">参数</system:String>
+    <system:String x:Key="SettingView_Config">配置</system:String>
+    <system:String x:Key="SettingView_Parameter">程序参数</system:String>
     <system:String x:Key="SettingView_Drive">行驶</system:String>
     <system:String x:Key="SettingView_Clamp">夹子</system:String>
     <system:String x:Key="SettingView_DriveWarning">不连接OCS进行操作很危险</system:String>
@@ -50,105 +50,105 @@
     <!-->Control View</-->
     <system:String x:Key="ControlView_PIO">PIO</system:String>
     <system:String x:Key="ControlView_InOut">In/Out</system:String>
-    <system:String x:Key="ControlView_Detect">察觉</system:String>
+    <system:String x:Key="ControlView_Detect">查明</system:String>
     <system:String x:Key="ControlView_Conveyor">输送机</system:String>
 
     <!--BatteryConfigView-->
-    <system:String x:Key="BatterConfig_Title">电池 察觉 View</system:String>
-    <system:String x:Key="BatterConfig_Voltage">伏特</system:String>
-    <system:String x:Key="BatterConfig_Current">电流</system:String>
-    <system:String x:Key="BatterConfig_BatteryState">电池察觉</system:String>
-    <system:String x:Key="BatterConfig_Temperrature">Temperrature</system:String>
-    <system:String x:Key="BatterConfig_ChargeTime">充电时间</system:String>
-    <system:String x:Key="BatterConfig_DisChargeTime">喷射时间</system:String>
+    <system:String x:Key="BatterConfig_Title">标题查明 View</system:String>
+    <system:String x:Key="BatterConfig_Voltage">电压查明</system:String>
+    <system:String x:Key="BatterConfig_Current">电流查明</system:String>
+    <system:String x:Key="BatterConfig_BatteryState">电池查明</system:String>
+    <system:String x:Key="BatterConfig_Temperrature">温度查明</system:String>
+    <system:String x:Key="BatterConfig_ChargeTime">充电时间查明</system:String>
+    <system:String x:Key="BatterConfig_DisChargeTime">非充电时间查明</system:String>
     <system:String x:Key="BatterConfig_SOC">SOC</system:String>
     <system:String x:Key="BatterConfig_SOH">SOH</system:String>
     <system:String x:Key="BatterConfig_Capacity">容量</system:String>
-    <system:String x:Key="BatterConfig_Energy">活力</system:String>
+    <system:String x:Key="BatterConfig_Energy">能量</system:String>
 
     <!--ConveyorControlView-->
     <system:String x:Key="Conveyor_Title">输送机 Control View</system:String>
-    <system:String x:Key="Conveyor_UnitCommand">Unit Command</system:String>
-    <system:String x:Key="Conveyor_BatchCommand">Batch Command</system:String>
+    <system:String x:Key="Conveyor_UnitCommand">单位命令 </system:String>
+    <system:String x:Key="Conveyor_BatchCommand">分批命令</system:String>
 
-    <system:String x:Key="Conveyor_CW">CW (搬下)</system:String>
-    <system:String x:Key="Conveyor_CCW">CCW (装)</system:String>
-    <system:String x:Key="Conveyor_Stop"></system:String>
+    <system:String x:Key="Conveyor_CW">CW (卸载)</system:String>
+    <system:String x:Key="Conveyor_CCW">CCW (装)</system:String>
+    <system:String x:Key="Conveyor_Stop">停止</system:String>
 
-    <system:String x:Key="Conveyor_TrayLoad">Box Load</system:String>
-    <system:String x:Key="Conveyor_TrayUnload">Box Unload</system:String>
-    <system:String x:Key="Conveyor_PIOLoad">PIO Box Load</system:String>
-    <system:String x:Key="Conveyor_PIOUnlaod">PIO Box Unload</system:String>
+    <system:String x:Key="Conveyor_TrayLoad">Box装载</system:String>
+    <system:String x:Key="Conveyor_TrayUnload">Box卸载</system:String>
+    <system:String x:Key="Conveyor_PIOLoad">PIO Box装载</system:String>
+    <system:String x:Key="Conveyor_PIOUnlaod">PIO Box卸载</system:String>
 
-    <system:String x:Key="Conveyor_ClampLock">Clamp Lock</system:String>
-    <system:String x:Key="Conveyor_ClampUnlock">Clamp Unlock</system:String>
+    <system:String x:Key="Conveyor_ClampLock">夹子上锁</system:String>
+    <system:String x:Key="Conveyor_ClampUnlock">夹子开锁</system:String>
 
     <!--ConveyorControlView-->
-    <system:String x:Key="DriveView_Title">Drive Control View</system:String>
+    <system:String x:Key="DriveView_Title">行驶控制标题</system:String>
 
-    <system:String x:Key="DriveView_ServoOn">Servo On</system:String>
-    <system:String x:Key="DriveView_ServoOff">Servo Off</system:String>
-    <system:String x:Key="DriveView_ServoFaultReset">Fault Reset</system:String>
-    <system:String x:Key="DriveView_BreakOff">Break Off</system:String>
+    <system:String x:Key="DriveView_ServoOn">伺服电机开</system:String>
+    <system:String x:Key="DriveView_ServoOff">伺服电机关</system:String>
+    <system:String x:Key="DriveView_ServoFaultReset">错误 复位</system:String>
+    <system:String x:Key="DriveView_BreakOff">抱闸 关闭</system:String>
 
-    <system:String x:Key="DriveView_SteerHandle">Steer Handle</system:String>
-    <system:String x:Key="DriveView_SteerLeft">左</system:String>
-    <system:String x:Key="DriveView_SteerRight">右</system:String>
+    <system:String x:Key="DriveView_SteerHandle">转向手柄</system:String>
+    <system:String x:Key="DriveView_SteerLeft">转向手柄左</system:String>
+    <system:String x:Key="DriveView_SteerRight">转向手柄右</system:String>
 
-    <system:String x:Key="DriveView_Jog">Jog Control</system:String>
-    <system:String x:Key="DriveView_JogFront">前</system:String>
-    <system:String x:Key="DriveView_JogBack">後進</system:String>
-    <system:String x:Key="DriveView_JogSpeed">Jog Speed</system:String>
+    <system:String x:Key="DriveView_Jog">手动操作</system:String>
+    <system:String x:Key="DriveView_JogFront">前</system:String>
+    <system:String x:Key="DriveView_JogBack">后退</system:String>
+    <system:String x:Key="DriveView_JogSpeed">手动速度</system:String>
 
     <!--ClampSetting-->
-    <system:String x:Key="ClampView_Title">Clamp Setting View</system:String>
+    <system:String x:Key="ClampView_Title">夹子设置</system:String>
 
-    <system:String x:Key="ClampView_LeftAxis">左 Axis</system:String>
-    <system:String x:Key="ClampView_RightAxis">右 Axis</system:String>
+    <system:String x:Key="ClampView_LeftAxis">左</system:String>
+    <system:String x:Key="ClampView_RightAxis">右</system:String>
 
-    <system:String x:Key="ClampView_LeftAxisState">左 State</system:String>
-    <system:String x:Key="ClampView_RightAxisState">右 State</system:String>
+    <system:String x:Key="ClampView_LeftAxisState">左 位置 </system:String>
+    <system:String x:Key="ClampView_RightAxisState">右 位置 </system:String>
 
-    <system:String x:Key="ClampView_ServoOn">Servo On</system:String>
-    <system:String x:Key="ClampView_ServoOff">Servo Off</system:String>
-    <system:String x:Key="ClampView_ServoFault">Servo Fault</system:String>
-    <system:String x:Key="ClampView_ServoFaultReset">Servo Fault Reset</system:String>
-    <system:String x:Key="ClampView_ServoOrigin">Servo Origin</system:String>
+    <system:String x:Key="ClampView_ServoOn">伺服电机 开</system:String>
+    <system:String x:Key="ClampView_ServoOff">伺服电机 关</system:String>
+    <system:String x:Key="ClampView_ServoFault">伺服电机 错误</system:String>
+    <system:String x:Key="ClampView_ServoFaultReset">伺服错误 复位</system:String>
+    <system:String x:Key="ClampView_ServoOrigin">伺服 原点</system:String>
 
-    <system:String x:Key="ClampView_TargetPos">Target Pos</system:String>
-    <system:String x:Key="ClampView_CurrentPos">Current Pos</system:String>
-    <system:String x:Key="ClampView_DiffPos">Diff Pos</system:String>
+    <system:String x:Key="ClampView_TargetPos">目标位置</system:String>
+    <system:String x:Key="ClampView_CurrentPos">当前位置</system:String>
+    <system:String x:Key="ClampView_DiffPos">位置差</system:String>
 
-    <system:String x:Key="ClampView_JogSpeed">Jog Speed</system:String>
-    <system:String x:Key="ClampView_JogPositive">Jog (+)</system:String>
-    <system:String x:Key="ClampView_JogNagertive">Jog (-)</system:String>
+    <system:String x:Key="ClampView_JogSpeed">手动 速度</system:String>
+    <system:String x:Key="ClampView_JogPositive">手动上升(+)</system:String>
+    <system:String x:Key="ClampView_JogNagertive">手动下降(-)</system:String>
 
-    <system:String x:Key="ClampView_ClampLockPos">Clamp Lock</system:String>
-    <system:String x:Key="ClampView_ClampUnlockPos">Clamp Unlock</system:String>
+    <system:String x:Key="ClampView_ClampLockPos">夹子 上锁</system:String>
+    <system:String x:Key="ClampView_ClampUnlockPos">夹子 开锁</system:String>
 
-    <system:String x:Key="ClampView_Moveto">Move To</system:String>
-    <system:String x:Key="ClampView_ToTarget">Current To Target</system:String>
-    <system:String x:Key="ClampView_AllOrigin">All Axis Origin</system:String>
+    <system:String x:Key="ClampView_Moveto">移动</system:String>
+    <system:String x:Key="ClampView_ToTarget">向目标位置移动</system:String>
+    <system:String x:Key="ClampView_AllOrigin">所有轴原点</system:String>
 
     <!--PIO Control View-->
-    <system:String x:Key="PIOControlView_Title">PIO Control View</system:String>
+    <system:String x:Key="PIOControlView_Title">PIO控制</system:String>
 
-    <system:String x:Key="PIOControlView_PIOLoad">PIO Box Load</system:String>
-    <system:String x:Key="PIOControlView_PIOUnlaod">PIO Box Unload</system:String>
+    <system:String x:Key="PIOControlView_PIOLoad">PIO Box 装载</system:String>
+    <system:String x:Key="PIOControlView_PIOUnlaod">PIO Box 卸载</system:String>
 
-    <system:String x:Key="PIOControlView_PIOChargeStart">PIO Battery &#x0a; 充電  开始</system:String>
-    <system:String x:Key="PIOControlView_PIOChargeStop">PIO Battery &#10; 充電 完了</system:String>
+    <system:String x:Key="PIOControlView_PIOChargeStart">PIO Battery &#x0a; 开始充电</system:String>
+    <system:String x:Key="PIOControlView_PIOChargeStop">PIO Battery &#xA; 停止充电</system:String>
 
     <!--Drive Config View-->
-    <system:String x:Key="DriveConfigView_Title">Drive Config View</system:String>
+    <system:String x:Key="DriveConfigView_Title">行驶配置参数</system:String>
 
-    <system:String x:Key="DriveConfigView_Linear">直[m/s]</system:String>
-    <system:String x:Key="DriveConfigView_Curve">曲線 [m/s]</system:String>
+    <system:String x:Key="DriveConfigView_Linear">直线[m/s]</system:String>
+    <system:String x:Key="DriveConfigView_Curve">转弯[m/s]</system:String>
 
-    <system:String x:Key="DriveConfigView_Acc">Acceleration [m/s]</system:String>
-    <system:String x:Key="DriveConfigView_Dec">Deceleration [m/s]</system:String>
+    <system:String x:Key="DriveConfigView_Acc">加速[m/s]</system:String>
+    <system:String x:Key="DriveConfigView_Dec">减速[m/s]</system:String>
     <system:String x:Key="DriveConfigView_Creep">Creep Speed [m/s]</system:String>
     <system:String x:Key="DriveConfigView_CreepDistence">CreepDistance [m/s]</system:String>
-    <system:String x:Key="DriveConfigView_JogSpeed">Jog Speed [m/s]</system:String>
+    <system:String x:Key="DriveConfigView_JogSpeed">手动速度[m/s]</system:String>
 
 </ResourceDictionary>

+ 2 - 2
Dev/OHV/OHV.LanguageHalper/Languages/English.xaml

@@ -13,7 +13,7 @@
     <system:String x:Key="Question_ProgramExit">Program Exit ?</system:String>
     <system:String x:Key="VehicleModeChange">Vehicle Mode Change to </system:String>
     <system:String x:Key="VehicleOnRailStateChange">Vehicle On Rail Change To</system:String>
-    <system:String x:Key="VehicleAutoMode">Vehicle Auto Mode &#x0a; Warning : The vehicle may move a little to forward</system:String>
+    <system:String x:Key="VehicleAutoMode">Vehicle Auto Mode &#xA; Warning : The vehicle may move a little to forward</system:String>
     <system:String x:Key="VehicleManualMode">Vehicle Manual Mode</system:String>
 
     <!-->Notification</-->
@@ -139,7 +139,7 @@
     <system:String x:Key="PIOControlView_PIOUnlaod">PIO Box Unload</system:String>
 
     <system:String x:Key="PIOControlView_PIOChargeStart">PIO Battery &#x0a; Charge Start</system:String>
-    <system:String x:Key="PIOControlView_PIOChargeStop">PIO Battery &#10; Charge Stop</system:String>
+    <system:String x:Key="PIOControlView_PIOChargeStop">PIO Battery &#xA; Charge Stop</system:String>
 
     <!--Drive Config View-->
     <system:String x:Key="DriveConfigView_Title">Drive Config View</system:String>

+ 4 - 0
Dev/OHV/OHV.Module.Interactivity/OHV.Module.Interactivity.csproj

@@ -127,6 +127,10 @@
     <Reference Include="Prism.Wpf, Version=7.2.0.1422, Culture=neutral, PublicKeyToken=40ee6c3a2184dc59, processorArchitecture=MSIL">
       <HintPath>..\packages\Prism.Wpf.7.2.0.1422\lib\net45\Prism.Wpf.dll</HintPath>
     </Reference>
+    <Reference Include="Quartz, Version=1.0.3.2, Culture=neutral, PublicKeyToken=f6b8c98a402cc8a4, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>..\Assambly\Quartz.dll</HintPath>
+    </Reference>
     <Reference Include="System" />
     <Reference Include="System.Configuration" />
     <Reference Include="System.Core" />

+ 65 - 17
Dev/OHV/OHV.Module.Interactivity/PopUp/DriveServoViewModel.cs

@@ -19,6 +19,7 @@ using System.Threading.Tasks;
 using System.Windows.Controls;
 using System.Windows.Input;
 using System.Windows.Media;
+using System.Windows.Threading;
 using VehicleControlSystem;
 using VehicleControlSystem.ControlLayer;
 using VehicleControlSystem.ControlLayer.IO;
@@ -259,6 +260,15 @@ namespace OHV.Module.Interactivity.PopUp
             get { return this.operationMode; }
             set { this.SetProperty(ref this.operationMode, value); }
         }
+
+        private eSteeringState steerState;
+
+        public eSteeringState SteerState
+        {
+            get { return steerState; }
+            set { SetProperty(ref this.steerState, value); }
+        }
+
         #endregion
 
         VCSystem vcSystem;
@@ -269,6 +279,8 @@ namespace OHV.Module.Interactivity.PopUp
         SqliteManager sql;
         MessageController messageController;
 
+        DispatcherTimer steerStateTimer = null;
+
         public DriveServoViewModel(IEventAggregator _ea, SqliteManager _sql, MessageController _messageController, VCSystem system)
         {
             this.eventAggregator = _ea;
@@ -321,6 +333,23 @@ namespace OHV.Module.Interactivity.PopUp
             ezIO.OnChangedIO += EzIO_OnChangedIO;
 
             this.JogSpeed = zmqManager.JogSpeed;
+
+            //GSG.NET.Quartz.QuartzUtils.Invoke("STEER_GET_STATE", GSG.NET.Quartz.QuartzUtils.GetExpnSecond(1), Quartz_GetSteerState);
+            steerStateTimer = new DispatcherTimer();
+            steerStateTimer.Tick += (object sender, EventArgs e) =>
+            {
+                var state = this.steerControl.GetSteerDirection();
+                this.ChangeSteeringDirection(state);
+
+            };
+            steerStateTimer.Interval = TimeSpan.FromMilliseconds(1000);
+            steerStateTimer.Start();
+        }
+
+        private void Quartz_GetSteerState()
+        {
+            var state = this.steerControl.GetSteerDirection();
+            this.ChangeSteeringDirection(state);
         }
 
         private void ExecuteBreakOffCommand()
@@ -350,7 +379,13 @@ namespace OHV.Module.Interactivity.PopUp
                 case "IN_F_STEERING_DETECT_RIGHT":
                 case "IN_R_STEERING_DETECT_LEFT":
                 case "IN_R_STEERING_DETECT_RIGHT":
-                    //this.ChangeSteeringDirection(this.steerControl.GetSteerDirection());
+                    {
+                        //if (bit.IsBitOn)
+                        //{
+                        //    var state = this.steerControl.GetSteerDirection();
+                        //    this.ChangeSteeringDirection(state);
+                        //}
+                    }
                     break;
 
                 default:
@@ -369,7 +404,7 @@ namespace OHV.Module.Interactivity.PopUp
 
             this.IsBreakOff = this.vcSystem.IO.IsOn("OUT_DRIVE_BRAKE_OFF", false);
 
-            if ( this.vcSystem.IO.IsOn("IN_LIFTER_POSITION_DETECT"))
+            if (this.vcSystem.IO.IsOn("IN_LIFTER_POSITION_DETECT"))
                 this.VehiclePositionBrush = Brushes.LimeGreen;
             else
                 this.VehiclePositionBrush = Brushes.Gray;
@@ -479,8 +514,8 @@ namespace OHV.Module.Interactivity.PopUp
                         case "SteeringState":
                             {
                                 //2021.08.12. Kang. 센서 상태를 이용해서 표시 방식으로 변경.
-                                var dir = CastTo<eSteeringState>.From<object>(obj.Args);
-                                this.ChangeSteeringDirection(dir);
+                                //    var dir = CastTo<eSteeringState>.From<object>(obj.Args);
+                                //    this.ChangeSteeringDirection(dir);
                             }
                             break;
                         case "VehicleStateProperty":
@@ -561,8 +596,10 @@ namespace OHV.Module.Interactivity.PopUp
                     case DriveControlEventArgs.eControlKind.MOVE:
                         ResponseMove(args);
                         break;
+
                     case DriveControlEventArgs.eControlKind.STOP:
                         break;
+
                     case DriveControlEventArgs.eControlKind.Steering:
                         //if ( args.Result.IsSuccess )
                         //{
@@ -570,6 +607,7 @@ namespace OHV.Module.Interactivity.PopUp
                         //    this.ChangeSteeringDirection( dir );
                         //}
                         break;
+
                     case DriveControlEventArgs.eControlKind.SteeringState:
                         if (args.Result.IsSuccess)
                         {
@@ -581,18 +619,21 @@ namespace OHV.Module.Interactivity.PopUp
                             this.ChangeSteeringDirection(eSteeringState.None);
                         }
                         break;
+
                     case DriveControlEventArgs.eControlKind.ReqCurrentPos:
                         this.CurrentPosition = args.CurrentPosition;
                         break;
 
                     case DriveControlEventArgs.eControlKind.ReqStopCurrentPos:
                         break;
+
                     case DriveControlEventArgs.eControlKind.FaultReset:
                         if (args.Result.IsSuccess)
                             this.messageController.ShowNotificationView("Fault Reset Success");
                         else
                             this.messageController.ShowNotificationView("Fault Reset Fail", false);
                         break;
+
                     case DriveControlEventArgs.eControlKind.DriveON:
                         if (args.Result.IsSuccess)
                         {
@@ -603,13 +644,17 @@ namespace OHV.Module.Interactivity.PopUp
                             this.messageController.ShowNotificationView("Drive On Fail", false);
                         }
                         break;
+
                     case DriveControlEventArgs.eControlKind.DriveOFF:
                         break;
+
                     case DriveControlEventArgs.eControlKind.JOG:
                         break;
+
                     case DriveControlEventArgs.eControlKind.VehicleState:
                         ResponseVehicleState(args);
                         break;
+
                     default:
                         break;
                 }
@@ -626,6 +671,7 @@ namespace OHV.Module.Interactivity.PopUp
         private void ResponseMove(DriveControlEventArgs args)
         {
             var msg = string.Empty;
+
             if (args.Result.IsSuccess)
             {
                 msg = "Move Success";
@@ -728,7 +774,7 @@ namespace OHV.Module.Interactivity.PopUp
         {
             var numPad = new CalcuratorView();
             var result = numPad.ShowDialog(0);
-            
+
             if (result < 0 || result > 0.4)
             {
                 this.messageController.ShowNotificationView("Value Error ! [0 ~ 0.4]");
@@ -754,7 +800,7 @@ namespace OHV.Module.Interactivity.PopUp
         {
             this.SelectDirection = obj.ToString();
         }
-        
+
         private void ExecutePositionSaveCommand()
         {
             this.messageController.ShowConfirmationPopupView("Save To Data ?", r =>
@@ -910,6 +956,9 @@ namespace OHV.Module.Interactivity.PopUp
 
         public void OnDialogClosed()
         {
+            this.steerStateTimer.Stop();
+            this.steerStateTimer = null;
+
             this.eventAggregator.GetEvent<DriveControlPubSubEvent>().Publish(new DriveControlEventArgs { EventDir = DriveControlEventArgs.eEventDir.ToBack, ControlKind = DriveControlEventArgs.eControlKind.ReqStopCurrentPos });
             this.eventAggregator.GetEvent<DriveControlPubSubEvent>().Unsubscribe(DriveControlCallBack);
             this.eventAggregator.GetEvent<GUIMessagePubSubEvent>().Unsubscribe(UICallBackCommunication);
@@ -919,23 +968,22 @@ namespace OHV.Module.Interactivity.PopUp
         {
             Task task = Task.Run(() =>
            {
-               var msg = new DriveControlEventArgs
-               {
-                   EventDir = DriveControlEventArgs.eEventDir.ToBack,
-                   ControlKind = DriveControlEventArgs.eControlKind.SteeringState,
-               };
-               this.PublishEvent(msg);
+               //var msg = new DriveControlEventArgs
+               //{
+               //    EventDir = DriveControlEventArgs.eEventDir.ToBack,
+               //    ControlKind = DriveControlEventArgs.eControlKind.SteeringState,
+               //};
+               //this.PublishEvent(msg);
 
                this.eventAggregator.GetEvent<DriveControlPubSubEvent>().Publish(new DriveControlEventArgs { EventDir = DriveControlEventArgs.eEventDir.ToBack, ControlKind = DriveControlEventArgs.eControlKind.VehicleState });
 
                var vcsMsg = new VCSMessageEventArgs() { Kind = VCSMessageEventArgs.eVCSMessageKind.ReqRouteManager };
                this.eventAggregator.GetEvent<VCSMessagePubSubEvent>().Publish(vcsMsg);
 
-                //var sT = SwUtils.CurrentTimeMillis;
-                //this.RouteList = new ObservableCollection<Route>(sql.RouteDal.GetAll());
-                //Console.WriteLine( SwUtils.Elapsed( sT ) );
-
-            });
+               //var sT = SwUtils.CurrentTimeMillis;
+               //this.RouteList = new ObservableCollection<Route>(sql.RouteDal.GetAll());
+               //Console.WriteLine( SwUtils.Elapsed( sT ) );
+           });
 
             this.InitializeData();
 

+ 2 - 2
Dev/OHV/OHV.Module.ListViews/Views/CommandListView.xaml

@@ -127,8 +127,8 @@
                 </Grid>
 
                 <StackPanel Orientation="Horizontal" HorizontalAlignment="Center" Grid.Row="2" VerticalAlignment="Top" Margin="0,15,0,0">
-                    <Button Margin="0,0,10,0" Height="45" Content="Add" Command="{Binding SaveCommand}" Width="100" IsEnabled="{c:Binding 'MachineMode == Shared:eMachineMode.LocalMode'}" />
-                    <Button Height="45" Content="Delete" Command="{Binding DeleteCommand}" Width="100"/>
+                    <!--<Button Margin="0,0,10,0" Height="45" Content="Add" Command="{Binding SaveCommand}" Width="100" IsEnabled="{c:Binding 'MachineMode == Shared:eMachineMode.LocalMode'}" />
+                    <Button Height="45" Content="Delete" Command="{Binding DeleteCommand}" Width="100"/>-->
                 </StackPanel>
             </Grid>
 

+ 1 - 1
Dev/OHV/OHV.Vehicle/OHV.Vehicle.csproj

@@ -65,7 +65,7 @@
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Remote1|AnyCPU'">
     <DebugSymbols>true</DebugSymbols>
-    <OutputPath>\\192.168.0.100\VCS\</OutputPath>
+    <OutputPath>\\192.168.0.100\vcs\</OutputPath>
     <DefineConstants>TRACE;DEBUG</DefineConstants>
     <DebugType>full</DebugType>
     <PlatformTarget>AnyCPU</PlatformTarget>

+ 1 - 1
Dev/OHV/VehicleControlSystem/ControlLayer/Motion/GSIDrive.cs

@@ -210,7 +210,7 @@ namespace VehicleControlSystem.ControlLayer.Drive
         }
 
         public bool IsDriveStop() => !zmq.IsDriveMoving;
-        public bool IsDriveMoving() => zmq.IsDriveMoving;
+        public bool IsDriveMoving() => zmq.IsDriveMoving && zmq.GetCurrentDriveState() == eDriveState.ServoOn;
 
         /// <summary>
         /// Drive 측 초기화 기능

+ 1 - 1
Dev/OHV/VehicleControlSystem/ControlLayer/Serial/BatteryTabos/Peak/Peak.cs

@@ -353,7 +353,7 @@ namespace VehicleControlSystem.ControlLayer.Serial.BatteryTabos
                     break;
                 case eCanRecvCase.CASE1:
                     this.manager.ReceivedDataDic[eDataKind.Voltage].Value = mb.ReadLeShort();
-                    this.manager.   ReceivedDataDic[eDataKind.Current].Value = mb.ReadLeShort();
+                    this.manager.ReceivedDataDic[eDataKind.Current].Value = mb.ReadLeShort();
                     this.manager.ReceivedDataDic[eDataKind.BatteryState].Value = mb.ReadLeShort();
                     break;
                 case eCanRecvCase.CASE2:

+ 27 - 6
Dev/OHV/VehicleControlSystem/ControlLayer/Steering.cs

@@ -91,6 +91,7 @@ namespace VehicleControlSystem.ControlLayer
             bool isCheckedOutput = false;
             var currentDirection = eSteeringState.None;
             long eT = 0;
+
             while (true)
             {
                 LockUtils.Wait(10);
@@ -303,13 +304,33 @@ namespace VehicleControlSystem.ControlLayer
 
         public eSteeringState GetSteerDirection()
         {
-            if (this.IsLeft())
-                return eSteeringState.Left;
-            if (this.IsRight())
-                return eSteeringState.Right;
+            eSteeringState rtValue = eSteeringState.None;
 
-            return eSteeringState.None;
-        }
+            var st = SwUtils.CurrentTimeMillis;
+            while (true)
+            {
+                LockUtils.Wait(5);
+
+                if ( this.IsLeft())
+                {
+                    rtValue = eSteeringState.Left;
+                    break;
+                }
+
+                if (this.IsRight())
+                {
+                    rtValue = eSteeringState.Right;
+                    break;
+                }
+
+                if ( SwUtils.Gt(st, 500))
+                {
+                    logger.E("[Steer] - Get State Timeout [500ms]");
+                    break;
+                }
+            }
+            return rtValue;
+       }
 
         public void RequestControl(eSteeringState state)
         {

+ 89 - 31
Dev/OHV/VehicleControlSystem/ControlLayer/Vehicle.cs

@@ -3,7 +3,10 @@ using System.Collections;
 using System.Collections.Generic;
 using System.Diagnostics;
 using System.Linq;
+using System.Net;
+using System.Net.NetworkInformation;
 using System.Runtime.Remoting.Messaging;
+using System.Text;
 using System.Threading;
 using System.Threading.Tasks;
 using FluentResults;
@@ -799,7 +802,7 @@ namespace VehicleControlSystem.ControlLayer
 
 
             //C/V Sensor 가 Load Start 만 감지면 Tray 가 설비 와 Vehicle 사이에 있는걸로 판단.
-            if ( !this.refObjects.Conveyor.IsDetectedCenter() && this.refObjects.Conveyor.IsDetectedLoadStart())
+            if (!this.refObjects.Conveyor.IsDetectedCenter() && this.refObjects.Conveyor.IsDetectedLoadStart())
                 return 46;
 
             if (this.refObjects.Conveyor.IsDetectedCenter()) //자제가 있으면 Lock
@@ -816,7 +819,7 @@ namespace VehicleControlSystem.ControlLayer
                 result = this.refObjects.Clamp.Unlock_Sync();
             }
 
-            if ( result != ConstInt.EXECUTE_SUCCESS)
+            if (result != ConstInt.EXECUTE_SUCCESS)
                 return result;
 
             if (result != ConstInt.EXECUTE_SUCCESS)
@@ -910,12 +913,72 @@ namespace VehicleControlSystem.ControlLayer
 
         void ReqJog(DriveControlEventArgs _args)
         {
+            //var sessionInfo = TermServicesManager.ListSessions("").FirstOrDefault(_ => _.SessionId == 1);
+            //if (sessionInfo == null)
+            //{
+            //    logger.W("RDP not Connected!");
+            //    return;
+            //}
+
+            //if (sessionInfo != null)
+            //{
+            //    if (sessionInfo.ConnectionState != TermServicesManager.WTS_CONNECTSTATE_CLASS.Active)
+            //    {
+            //        logger.W("RDP is not Active!");
+            //        return;
+            //    }
+            //}
+
+            //logger.I($"sessionInfo id -{sessionInfo.SessionId} / {sessionInfo.StationName} / {sessionInfo.ConnectionState}");
+
+            //int portNo = 3389;
+            //if ( !IsPortBeingUsed(portNo))
+            //{
+            //    logger.W($"Port {portNo} Not Used");
+            //    return;
+            //}
+
+            if (!CheckPing())
+            {
+                logger.W("Tablet is Disconnected");
+                return;
+            }
+
             if (_args.JogDir == DriveControlEventArgs.eJogMoveDir.Positive)
                 this.refObjects.Drive.JogForword();
             else
                 this.refObjects.Drive.JogBackword();
         }
 
+        //bool IsPortBeingUsed(int portNo)
+        //{
+        //    return IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpListeners().Any(tcp => tcp.Port == portNo);
+        //}
+
+        bool CheckPing()
+        {
+            bool result = false;
+            PingOptions option = new PingOptions();
+            Ping ping = new Ping();
+
+            byte[] buffer = ASCIIEncoding.ASCII.GetBytes("");
+            int timeout = 100;
+            try
+            {
+                var pingReply = ping.Send(IPAddress.Parse("109.19.25.240"), timeout, buffer, option);
+                if (pingReply.Status == IPStatus.Success)
+                    result = true;
+                else
+                    result = false;
+            }
+            catch (Exception ex)
+            {
+                logger.E(ex);
+            }
+
+            return result;
+        }
+
         Logger batteryLogger = Logger.GetLogger("BatteryLogger");
         void ReqCurrentPos()
         {
@@ -1497,7 +1560,7 @@ namespace VehicleControlSystem.ControlLayer
             if (result != ConstInt.EXECUTE_SUCCESS)
             {
                 this.OccurVehicleAlarm(result);
-                if ( !IsChargeCylinderForword() )
+                if (!IsChargeCylinderForword())
                     this.OnChargingFull?.Invoke();
             }
 
@@ -1771,12 +1834,12 @@ namespace VehicleControlSystem.ControlLayer
                 this.ObstacleStateProperty = eObstacleState.Normal;
             }
 
-            if ( this.ObstacleStateProperty == eObstacleState.Blocked)          //210812 Kkm
+            if (this.ObstacleStateProperty == eObstacleState.Blocked)          //210812 Kkm
             {
                 if (this.IsMoving)
                     this.refObjects.AutoManager.IsBlockedMoving = true;
             }
-            else if(this.ObstacleStateProperty == eObstacleState.Normal)          //210812 Kkm
+            else if (this.ObstacleStateProperty == eObstacleState.Normal)          //210812 Kkm
             {
                 if (this.IsMoving)
                     this.refObjects.AutoManager.IsBlockedMoving = false;
@@ -1883,9 +1946,9 @@ namespace VehicleControlSystem.ControlLayer
             if (result != 0)
                 return result;
 
-            if (!this.refObjects.IO.WaitChangeInputIO(true, 40 * ConstUtils.ONE_SECOND, "IN_LIFTER_POSITION_DETECT"))
+            if (!this.refObjects.IO.WaitChangeInputIO(true, pioTimeout * ConstUtils.ONE_SECOND, "IN_LIFTER_POSITION_DETECT"))
             {
-                loggerPIO.E($"Load Action / [Port {targetName}] - Lift Position Check Error / Timeout[40sec]");
+                loggerPIO.E($"Load Action / [Port {targetName}] - Lift Position Check Error / Timeout[{pioTimeout}sec]");
                 TimerUtils.Once(1000, this.OnFailReport, eFailCode.LoadPIOInterlockTimeout);
                 //this.OnFailReport?.Invoke( eFailCode.LoadPIOInterlockTimeout );
                 return 0; //14
@@ -1913,7 +1976,7 @@ namespace VehicleControlSystem.ControlLayer
             if (!this.refObjects.IO.WaitChangeInputIO(true, pioTimeout * ConstUtils.ONE_SECOND, "IN_PIO_SENDABLE"))
             {
                 PIOClear();
-                loggerPIO.E($"Load Action / [Port {targetName}] - 4 Ready Time Out / Timeout[{pioTimeout}]");
+                loggerPIO.E($"Load Action / [Port {targetName}] - 4 Ready Time Out / Timeout[{pioTimeout}sec]");
                 TimerUtils.Once(1000, this.OnFailReport, eFailCode.LoadPIOInterlockTimeout);
                 //this.OnFailReport?.Invoke( eFailCode.LoadPIOInterlockTimeout );
                 return 0;
@@ -1933,7 +1996,7 @@ namespace VehicleControlSystem.ControlLayer
             {
                 this.refObjects.Conveyor.OnOffConveyor(false, true);
                 PIOClear();
-                loggerPIO.E($"Load Action / [Port {targetName}] - 5 Sending Run Time Out");
+                loggerPIO.E($"Load Action / [Port {targetName}] - 5 Sending Run Time Out / Timeout[10sec]");
                 TimerUtils.Once(1000, this.OnFailReport, eFailCode.LoadPIOInterlockTimeout);
                 //this.OnFailReport?.Invoke( eFailCode.LoadPIOInterlockTimeout );
                 return 0;
@@ -1976,7 +2039,6 @@ namespace VehicleControlSystem.ControlLayer
                 this.OnCarrierDetected?.Invoke(true);
 
             this.refObjects.Conveyor.OnOffConveyor(false); //Stop
-            PIOClear();
             this.OnConveyorStop?.Invoke(true);
             loggerPIO.I("Load Action / [Vehicle] Conveyor Stop");
 
@@ -1990,8 +2052,8 @@ namespace VehicleControlSystem.ControlLayer
             }
             loggerPIO.I("[Port] Send Complete On");
 
-            this.refObjects.IO.WriteOutputIO("OUT_PIO_RECIVE_COMPLITE", false, 1000);
-
+            LockUtils.Wait(1 * ConstUtils.ONE_SECOND);
+            PIOClear();
             loggerPIO.I($"Load Action / End Load PIO - [{targetName}]");
 
             result = this.refObjects.Clamp.Lock_Sync();
@@ -2053,15 +2115,13 @@ namespace VehicleControlSystem.ControlLayer
             if (!this.refObjects.Conveyor.IsDetectedCenter())
             {
                 TimerUtils.Once(1000, this.OnFailReport, eFailCode.Unload_VehicleHasNotCarrier);
-                //this.OnFailReport?.Invoke( eFailCode.Unload_VehicleHasNotCarrier );
                 return 0;
             }
 
-            if (!this.refObjects.IO.WaitChangeInputIO(true, 40 * ConstUtils.ONE_SECOND, "IN_LIFTER_POSITION_DETECT"))
+            if (!this.refObjects.IO.WaitChangeInputIO(true, pioTimeout * ConstUtils.ONE_SECOND, "IN_LIFTER_POSITION_DETECT"))
             {
-                loggerPIO.E($"Unload Action / [Port {targetName}] - Lift Position Check Error");
+                loggerPIO.E($"Unload Action / [Port {targetName}] - Lift Position Check Error / Timeout[{pioTimeout}sec]");
                 TimerUtils.Once(1000, this.OnFailReport, eFailCode.UnlaodPIOInterlockTimeout);
-                //this.OnFailReport?.Invoke( eFailCode.UnlaodPIOInterlockTimeout );
                 return 0;
             }
 
@@ -2072,14 +2132,12 @@ namespace VehicleControlSystem.ControlLayer
             //    return 0; //13 -> Alarm Code 보고 없음. 경알람 상태 이므로 한번 보고 후 정상 동작
             //}
 
-            PIOClear();
             this.OnPIOStart?.Invoke(false);
 
             if (!this.refObjects.IO.WaitChangeInputIO(true, pioTimeout * ConstUtils.ONE_SECOND, "IN_PIO_READY"))
             {
-                loggerPIO.E($"Unload Action / [Port {targetName}] - 1 Ready not On");
+                loggerPIO.E($"Unload Action / [Port {targetName}] - 1 Ready not On / Timeout[{pioTimeout}sec]");
                 TimerUtils.Once(1000, this.OnFailReport, eFailCode.UnlaodPIOInterlockTimeout);
-                //this.OnFailReport?.Invoke( eFailCode.UnlaodPIOInterlockTimeout );
                 return 0;
             }
 
@@ -2089,9 +2147,8 @@ namespace VehicleControlSystem.ControlLayer
             if (!this.refObjects.IO.WaitChangeInputIO(true, 10 * ConstUtils.ONE_SECOND, "IN_PIO_RECEIVE_RUN"))
             {
                 PIOClear();
-                loggerPIO.E($"Unload Action / [Port {targetName}] - 2 Receive CV Run Timeout");
+                loggerPIO.E($"Unload Action / [Port {targetName}] - 2 Receive CV Run Timeout / Timeout[10sec]");
                 TimerUtils.Once(1000, this.OnFailReport, eFailCode.UnlaodPIOInterlockTimeout);
-                //this.OnFailReport?.Invoke( eFailCode.UnlaodPIOInterlockTimeout );
                 return 0;
             }
             loggerPIO.I("Unload Action / [Port] - 2 Receive CV Run On");
@@ -2103,7 +2160,6 @@ namespace VehicleControlSystem.ControlLayer
             this.refObjects.IO.WriteOutputIO("OUT_PIO_SENDING_RUN", true);
             loggerPIO.I("Unload Action / [Vehicle] - 2 Send Run On");
 
-            //this.conveyor.SetConveyorSpeed( true );
             this.refObjects.Conveyor.OnOffConveyor(true);
             this.OnConveyorStart?.Invoke(false);
 
@@ -2117,7 +2173,7 @@ namespace VehicleControlSystem.ControlLayer
                     this.refObjects.IO.WriteOutputIO("OUT_PIO_INTERLOCK", true);
 
                     this.refObjects.Conveyor.OnOffConveyor(false, true);
-                    loggerPIO.E($"Unload Action / [Port {targetName}] Conveyor Wait Time Out");
+                    loggerPIO.E($"Unload Action / [Port {targetName}] Conveyor Wait Time Out / Timeout[30sec]");
                     //TimerUtils.Once( 1000, this.OnFailReport, eFailCode.UnlaodPIOInterlockTimeout );
 
                     return 12; // 2020.07.18 Kang. 센서에 걸리지 않아도 중간에 걸려 있을 가능성 때문에 알람 처리.
@@ -2162,13 +2218,12 @@ namespace VehicleControlSystem.ControlLayer
 
             this.refObjects.Conveyor.OnOffConveyor(false); //Stop
             this.OnConveyorStop?.Invoke(false);
-            PIOClear();
 
             this.refObjects.IO.WriteOutputIO("OUT_PIO_SEND_COMPLITE", true);
             Thread.Sleep(1000);
-            this.refObjects.IO.WriteOutputIO("OUT_PIO_SEND_COMPLITE", false);
             loggerPIO.I("Unload Action / [Vehicle] - 3 Send Complete OnOff");
 #endif
+            PIOClear();
             loggerPIO.I($"Unload Action / End Unload PIO - [{targetName}]");
 
             //2020.08.18.Kang. Conveyor 작동후 OCS 연결이 끊어지면 알람 처리
@@ -2185,7 +2240,6 @@ namespace VehicleControlSystem.ControlLayer
             loggerPIO.I($"Start Load PIO - [{this.CurrentTag}]");
 
             PIOClear();
-
             this.PIOSensorOn();
 
             int result = ConstInt.EXECUTE_SUCCESS;
@@ -2270,7 +2324,6 @@ namespace VehicleControlSystem.ControlLayer
             }
 
             this.refObjects.Conveyor.OnOffConveyor(false); //Stop
-            PIOClear();
             loggerPIO.I("[Vehicle] Conveyor Stop");
 
             this.refObjects.IO.WriteOutputIO("OUT_PIO_RECIVE_COMPLITE", true);
@@ -2283,7 +2336,7 @@ namespace VehicleControlSystem.ControlLayer
             }
             loggerPIO.I("[Port] Send Complete On");
 
-            this.refObjects.IO.WriteOutputIO("OUT_PIO_RECIVE_COMPLITE", false, 1000);
+            PIOClear();
 
             loggerPIO.I($"End Load PIO - [{this.CurrentTag}]");
 
@@ -2367,11 +2420,10 @@ namespace VehicleControlSystem.ControlLayer
             }
 
             this.refObjects.Conveyor.OnOffConveyor(false); //Stop
-            PIOClear();
 
             this.refObjects.IO.WriteOutputIO("OUT_PIO_SEND_COMPLITE", true);
             LockUtils.Wait(1000);
-            this.refObjects.IO.WriteOutputIO("OUT_PIO_SEND_COMPLITE", false);
+            PIOClear();
             loggerPIO.I("[Vehicle] - 3 Send Complete OnOff");
             loggerPIO.I($"End Unload PIO - [{CurrentTag}]");
 
@@ -2660,7 +2712,13 @@ namespace VehicleControlSystem.ControlLayer
                     break;
 
                 case eDataKind.SOC:
-                    this.BatteryStateOfCharge = (double)obj.Value;
+                    if (this.BatteryVoltage <= 45 && obj.Value > 15) //2021.09.03 Kang. Battery 통신 Module % 계산이 안맞아 최저 수치 이하로 내려 가면 강재로 15%로 설정
+                    {
+                        this.batteryStateOfCharge = 15;
+                        logger.D($"[BMS] - Real SOC is {obj.Value} / Votage is {this.BatteryVoltage} - Changed SOC -> 15%");
+                    }
+                    else
+                        this.BatteryStateOfCharge = (double)obj.Value;
                     break;
 
                 case eDataKind.SOH:

+ 2 - 0
Dev/OHV/VehicleControlSystem/Managers/AutoManager.cs

@@ -66,6 +66,8 @@ namespace VehicleControlSystem.Managers
             get { return this.isBlockedMoving; }
             set
             {
+                if (this.isBlockedMoving == value) return;
+
                 this.isBlockedMoving = value;
 
                 if (value)

+ 94 - 0
Dev/OHV/VehicleControlSystem/RDPInfo.cs

@@ -0,0 +1,94 @@
+using System;
+using System.Runtime.InteropServices;
+
+namespace VehicleControlSystem
+{
+    public static class RDPInfo
+    {
+        const int WTS_CURRENT_SERVER_HANDLE = -1;
+
+        public static string GetTerminalServerClientNameWTSAPI()
+        {
+            IntPtr buffer = IntPtr.Zero;
+            uint bytesReturned;
+            string strReturnValue;
+
+            try
+            {
+                WTSQuerySessionInformation(IntPtr.Zero, WTS_CURRENT_SERVER_HANDLE, WTS_INFO_CLASS.WTSClientName, out buffer, out bytesReturned);
+                strReturnValue = System.Runtime.InteropServices.Marshal.PtrToStringAnsi(buffer);
+            }
+            finally
+            {
+                buffer = IntPtr.Zero;
+            }
+            return strReturnValue;
+        }
+
+        public static bool IsTermianlServerclientConnected()
+        {
+            IntPtr buffer = IntPtr.Zero;
+            uint bytesReturned;
+
+            WTS_CONNECTSTATE_CLASS state = WTS_CONNECTSTATE_CLASS.WTSIdle;
+
+            try
+            {
+                WTSQuerySessionInformation(IntPtr.Zero, WTS_CURRENT_SERVER_HANDLE, WTS_INFO_CLASS.WTSConnectState, out buffer, out bytesReturned);
+                var rtv = (WTSConnectStateStruct)Marshal.PtrToStructure(buffer, typeof(WTSConnectStateStruct));
+                state = rtv.State;
+            }
+            finally
+            {
+                buffer = IntPtr.Zero;
+            }
+
+            return state == WTS_CONNECTSTATE_CLASS.WTSConnected ? true : false;
+        }
+
+        [StructLayout(LayoutKind.Sequential)]
+        public struct WTSConnectStateStruct
+        {
+            public WTS_CONNECTSTATE_CLASS State;
+        }
+
+        public enum WTS_CONNECTSTATE_CLASS
+        {
+            WTSNone = -1,
+            WTSActive,
+            WTSConnected,
+            WTSConnectQuery,
+            WTSShadow,
+            WTSDisconnected,
+            WTSIdle,
+            WTSListen,
+            WTSReset,
+            WTSDown,
+            WTSInit,
+        }
+
+        enum WTS_INFO_CLASS
+        {
+            WTSInitialProgram,
+            WTSApplicationName,
+            WTSWorkingDirectory,
+            WTSOEMId,
+            WTSSessionId,
+            WTSUserName,
+            WTSWinStationName,
+            WTSDomainName,
+            WTSConnectState,
+            WTSClientBuildNumber,
+            WTSClientName,
+            WTSClientDirctory,
+            WTSClientProductId,
+            WTSClientHardwareId,
+            WTSClientAddress,
+            WTSClientDisplay,
+            WTSClientProtocolType,
+        }
+
+        [System.Runtime.InteropServices.DllImport("Wtsapi32.dll")]
+        static extern bool WTSQuerySessionInformation(System.IntPtr hServer, int sessionId, WTS_INFO_CLASS wtsInfoClass, out System.IntPtr ppBuffer, out uint pBytesReturned);
+    }
+}

+ 300 - 0
Dev/OHV/VehicleControlSystem/TermServicesManager.cs

@@ -0,0 +1,300 @@
+using System;
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+
+namespace VehicleControlSystem
+{
+    public class TermServicesManager
+    {
+        [DllImport("wtsapi32.dll")]
+        static extern IntPtr WTSOpenServer([MarshalAs(UnmanagedType.LPStr)] String pServerName);
+
+        [DllImport("wtsapi32.dll")]
+        static extern void WTSCloseServer(IntPtr hServer);
+
+        [DllImport("Wtsapi32.dll")]
+        public static extern bool WTSQuerySessionInformation(IntPtr hServer, int sessionId, WTS_INFO_CLASS wtsInfoClass,
+            out System.IntPtr ppBuffer, out uint pBytesReturned);
+
+        [DllImport("wtsapi32.dll")]
+        static extern Int32 WTSEnumerateSessions(IntPtr hServer, [MarshalAs(UnmanagedType.U4)] Int32 Reserved,
+            [MarshalAs(UnmanagedType.U4)] Int32 Version, ref IntPtr ppSessionInfo, [MarshalAs(UnmanagedType.U4)] ref Int32 pCount);
+
+        [DllImport("wtsapi32.dll")]
+        static extern void WTSFreeMemory(IntPtr pMemory);
+
+        [StructLayout(LayoutKind.Sequential)]
+        private struct WTS_SESSION_INFO
+        {
+            public Int32 SessionID;
+            [MarshalAs(UnmanagedType.LPStr)]
+            public String pWinStationName;
+            public WTS_CONNECTSTATE_CLASS State;
+        }
+
+        [StructLayout(LayoutKind.Sequential)]
+        public struct WTS_CLIENT_ADDRESS
+        {
+            public uint AddressFamily;
+            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)]
+            public byte[] Address; } [StructLayout(LayoutKind.Sequential)] public struct WTS_CLIENT_DISPLAY
+        {
+            public uint HorizontalResolution;
+            public uint VerticalResolution;
+            public uint ColorDepth;
+        }
+
+        public enum WTS_CONNECTSTATE_CLASS
+        {
+            Active,
+            Connected,
+            ConnectQuery,
+            Shadow,
+            Disconnected,
+            Idle,
+            Listen,
+            Reset,
+            Down,
+            Init
+        }
+
+        public enum WTS_INFO_CLASS
+        {
+            InitialProgram = 0,
+            ApplicationName = 1,
+            WorkingDirectory = 2,
+            OEMId = 3,
+            SessionId = 4,
+            UserName = 5,
+            WinStationName = 6,
+            DomainName = 7,
+            ConnectState = 8,
+            ClientBuildNumber = 9,
+            ClientName = 10,
+            ClientDirectory = 11,
+            ClientProductId = 12,
+            ClientHardwareId = 13,
+            ClientAddress = 14,
+            ClientDisplay = 15,
+            ClientProtocolType = 16
+        }
+
+        private static IntPtr OpenServer(string Name)
+        {
+            IntPtr server = WTSOpenServer(Name);
+            return server;
+        }
+
+        private static void CloseServer(IntPtr ServerHandle)
+        {
+            WTSCloseServer(ServerHandle);
+        }
+
+        public static List<TerminalSessionData> ListSessions(string ServerName)
+        {
+            IntPtr server = IntPtr.Zero;
+            List<TerminalSessionData> ret = new List<TerminalSessionData>();
+            server = OpenServer(ServerName);
+
+            try
+            {
+                IntPtr ppSessionInfo = IntPtr.Zero;
+
+                Int32 count = 0;
+                Int32 retval = WTSEnumerateSessions(server, 0, 1, ref ppSessionInfo, ref count);
+                Int32 dataSize = Marshal.SizeOf(typeof(WTS_SESSION_INFO));
+
+                Int64 current = (int)ppSessionInfo;
+
+                if (retval != 0)
+                {
+                    for (int i = 0; i < count; i++)
+                    {
+                        WTS_SESSION_INFO si = (WTS_SESSION_INFO)Marshal.PtrToStructure((System.IntPtr)current, typeof(WTS_SESSION_INFO));
+                        current += dataSize;
+
+                        ret.Add(new TerminalSessionData(si.SessionID, si.State, si.pWinStationName));
+                    }
+
+                    WTSFreeMemory(ppSessionInfo);
+                }
+            }
+            finally
+            {
+                CloseServer(server);
+            }
+
+            return ret;
+        }
+
+        public static TerminalSessionInfo GetSessionInfo(string ServerName, int SessionId)
+        {
+            IntPtr server = IntPtr.Zero;
+            server = OpenServer(ServerName);
+            System.IntPtr buffer = IntPtr.Zero;
+            uint bytesReturned;
+            TerminalSessionInfo data = new TerminalSessionInfo();
+
+            try
+            {
+                bool worked = WTSQuerySessionInformation(server, SessionId,
+                    WTS_INFO_CLASS.ApplicationName, out buffer, out bytesReturned);
+
+                if (!worked)
+                    return data;
+
+                string strData = Marshal.PtrToStringAnsi(buffer);
+                data.ApplicationName = strData;
+
+                worked = WTSQuerySessionInformation(server, SessionId,
+                    WTS_INFO_CLASS.ClientAddress, out buffer, out bytesReturned);
+
+                if (!worked)
+                    return data;
+
+                WTS_CLIENT_ADDRESS si = (WTS_CLIENT_ADDRESS)Marshal.PtrToStructure((System.IntPtr)buffer, typeof(WTS_CLIENT_ADDRESS));
+                data.ClientAddress = si;
+
+                worked = WTSQuerySessionInformation(server, SessionId,
+                    WTS_INFO_CLASS.ClientBuildNumber, out buffer, out bytesReturned);
+
+                if (!worked)
+                    return data;
+
+                int lData = Marshal.ReadInt32(buffer);
+                data.ClientBuildNumber = lData;
+
+                worked = WTSQuerySessionInformation(server, SessionId,
+                    WTS_INFO_CLASS.ClientDirectory, out buffer, out bytesReturned);
+
+                if (!worked)
+                    return data;
+
+                strData = Marshal.PtrToStringAnsi(buffer);
+                data.ClientDirectory = strData;
+
+                worked = WTSQuerySessionInformation(server, SessionId,
+                    WTS_INFO_CLASS.ClientDisplay, out buffer, out bytesReturned);
+
+                if (!worked)
+                    return data;
+
+                WTS_CLIENT_DISPLAY cd = (WTS_CLIENT_DISPLAY)Marshal.PtrToStructure((System.IntPtr)buffer, typeof(WTS_CLIENT_DISPLAY));
+                data.ClientDisplay = cd;
+
+                worked = WTSQuerySessionInformation(server, SessionId,
+                    WTS_INFO_CLASS.ClientHardwareId, out buffer, out bytesReturned);
+
+                if (!worked)
+                    return data;
+
+                lData = Marshal.ReadInt32(buffer);
+                data.ClientHardwareId = lData;
+
+                worked = WTSQuerySessionInformation(server, SessionId,
+                    WTS_INFO_CLASS.ClientName, out buffer, out bytesReturned);
+                strData = Marshal.PtrToStringAnsi(buffer);
+                data.ClientName = strData;
+
+                worked = WTSQuerySessionInformation(server, SessionId,
+                    WTS_INFO_CLASS.ClientProductId, out buffer, out bytesReturned);
+                Int16 intData = Marshal.ReadInt16(buffer);
+                data.ClientProductId = intData;
+
+                worked = WTSQuerySessionInformation(server, SessionId,
+                    WTS_INFO_CLASS.ClientProtocolType, out buffer, out bytesReturned);
+                intData = Marshal.ReadInt16(buffer);
+                data.ClientProtocolType = intData;
+
+                worked = WTSQuerySessionInformation(server, SessionId,
+                    WTS_INFO_CLASS.ConnectState, out buffer, out bytesReturned);
+                lData = Marshal.ReadInt32(buffer);
+                data.ConnectState = (WTS_CONNECTSTATE_CLASS)Enum.ToObject(typeof(WTS_CONNECTSTATE_CLASS), lData);
+
+                worked = WTSQuerySessionInformation(server, SessionId,
+                    WTS_INFO_CLASS.DomainName, out buffer, out bytesReturned);
+                strData = Marshal.PtrToStringAnsi(buffer);
+                data.DomainName = strData;
+
+                worked = WTSQuerySessionInformation(server, SessionId,
+                    WTS_INFO_CLASS.InitialProgram, out buffer, out bytesReturned);
+                strData = Marshal.PtrToStringAnsi(buffer);
+                data.InitialProgram = strData;
+
+                worked = WTSQuerySessionInformation(server, SessionId,
+                    WTS_INFO_CLASS.OEMId, out buffer, out bytesReturned);
+                strData = Marshal.PtrToStringAnsi(buffer);
+                data.OEMId = strData;
+
+                worked = WTSQuerySessionInformation(server, SessionId,
+                    WTS_INFO_CLASS.SessionId, out buffer, out bytesReturned);
+                lData = Marshal.ReadInt32(buffer);
+                data.SessionId = lData;
+
+                worked = WTSQuerySessionInformation(server, SessionId,
+                    WTS_INFO_CLASS.UserName, out buffer, out bytesReturned);
+                strData = Marshal.PtrToStringAnsi(buffer);
+                data.UserName = strData;
+
+                worked = WTSQuerySessionInformation(server, SessionId,
+                    WTS_INFO_CLASS.WinStationName, out buffer, out bytesReturned);
+                strData = Marshal.PtrToStringAnsi(buffer);
+                data.WinStationName = strData;
+
+                worked = WTSQuerySessionInformation(server, SessionId,
+                    WTS_INFO_CLASS.WorkingDirectory, out buffer, out bytesReturned);
+                strData = Marshal.PtrToStringAnsi(buffer);
+                data.WorkingDirectory = strData;
+            }
+            finally
+            {
+                WTSFreeMemory(buffer);
+                buffer = IntPtr.Zero;
+                CloseServer(server);
+            }
+
+            return data;
+        }
+
+    }
+
+    public class TerminalSessionData
+    {
+        public int SessionId;
+        public TermServicesManager.WTS_CONNECTSTATE_CLASS ConnectionState;
+        public string StationName;
+
+        public TerminalSessionData(int sessionId, TermServicesManager.WTS_CONNECTSTATE_CLASS connState, string stationName)
+        {
+            SessionId = sessionId;
+            ConnectionState = connState;
+            StationName = stationName;
+        }
+
+        public override string ToString()
+        {
+            return String.Format("{0} {1} {2}", SessionId, ConnectionState, StationName);
+        }
+    }
+
+    public class TerminalSessionInfo
+    {
+        public string InitialProgram;
+        public string ApplicationName;
+        public string WorkingDirectory;
+        public string OEMId;
+        public int SessionId;
+        public string UserName;
+        public string WinStationName;
+        public string DomainName;
+        public TermServicesManager.WTS_CONNECTSTATE_CLASS ConnectState;
+        public int ClientBuildNumber;
+        public string ClientName;
+        public string ClientDirectory;
+        public int ClientProductId;
+        public int ClientHardwareId;
+        public TermServicesManager.WTS_CLIENT_ADDRESS ClientAddress;
+        public TermServicesManager.WTS_CLIENT_DISPLAY ClientDisplay;
+        public int ClientProtocolType;
+    }
+}

+ 9 - 0
Dev/OHV/VehicleControlSystem/VCSystem.cs

@@ -383,6 +383,7 @@ namespace VehicleControlSystem
             //refresh Parameter.
             this.ZmqManager.SynchronizedParmeter();
         }
+
         private void ReqSetJogSpeed(VCSMessageEventArgs msg)
         {
             var reply = new GUIMessageEventArgs
@@ -465,6 +466,7 @@ namespace VehicleControlSystem
 
             GUIMessageEventPublish(reply);
         }
+
         private void ReqConveyorMove(VCSMessageEventArgs msg)
         {
             this.vehicle.ReqConveyorMove(msg.MessageText);
@@ -839,7 +841,14 @@ namespace VehicleControlSystem
             
             return result;
         }
+        
+        bool IsPortBeingUsed(int portNo)
+        {
+            return IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpListeners().Any(tcp => tcp.Port == portNo);
+        }
+
         #endregion
+
         /// <summary>
         /// GUI 로 보내는 Event
         /// </summary>

+ 2 - 0
Dev/OHV/VehicleControlSystem/VehicleControlSystem.csproj

@@ -212,6 +212,8 @@
     <Compile Include="Managers\HostManager.cs" />
     <Compile Include="Managers\RouteManager.cs" />
     <Compile Include="Managers\Scheduler.cs" />
+    <Compile Include="RDPInfo.cs" />
+    <Compile Include="TermServicesManager.cs" />
     <Compile Include="VCSystem.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
   </ItemGroup>

BIN
Documents/Manual/OHV.OperatorManual_2021ver.docx