Browse Source

Monitoring Module Add

SK.Kang 6 years ago
parent
commit
d3d5981c44
36 changed files with 1298 additions and 336 deletions
  1. BIN
      Dev/OHV/Assambly/GSG.NET.WPF.dll
  2. 0 19
      Dev/OHV/OHV.Common.Interface/IModelBase.cs
  3. 0 48
      Dev/OHV/OHV.Common.Interface/OHV.Common.Interface.csproj
  4. 0 36
      Dev/OHV/OHV.Common.Interface/Properties/AssemblyInfo.cs
  5. 28 0
      Dev/OHV/OHV.Common/Events/MessageEventArgs.cs
  6. 3 3
      Dev/OHV/OHV.Common/Events/PubSubEvent.cs
  7. 144 0
      Dev/OHV/OHV.Common/Model/SelectionItem.cs
  8. 139 0
      Dev/OHV/OHV.Common/Model/SelectionList.cs
  9. 2 0
      Dev/OHV/OHV.Common/OHV.Common.csproj
  10. 1 0
      Dev/OHV/OHV.Common/Shareds/SharedEnumType.cs
  11. 0 21
      Dev/OHV/OHV.Model/DataModel/Config.cs
  12. 0 23
      Dev/OHV/OHV.Model/DataModel/Route.cs
  13. 0 52
      Dev/OHV/OHV.Model/OHV.Model.csproj
  14. 166 0
      Dev/OHV/OHV.Module.Monitoring/Interactivity/InOutIOView.xaml
  15. 41 0
      Dev/OHV/OHV.Module.Monitoring/Interactivity/InOutIOView.xaml.cs
  16. 277 0
      Dev/OHV/OHV.Module.Monitoring/Interactivity/InOutIOViewModel.cs
  17. 25 0
      Dev/OHV/OHV.Module.Monitoring/MonitoringModules.cs
  18. 99 0
      Dev/OHV/OHV.Module.Monitoring/OHV.Module.Monitoring.csproj
  19. 3 3
      Dev/OHV/OHV.Model/Properties/AssemblyInfo.cs
  20. 7 0
      Dev/OHV/OHV.Module.Monitoring/packages.config
  21. 40 3
      Dev/OHV/OHV.SqliteDAL/OHVDbInitializer.cs
  22. 5 0
      Dev/OHV/OHV.Vehicle/App.xaml
  23. 1 0
      Dev/OHV/OHV.Vehicle/App.xaml.cs
  24. 8 2
      Dev/OHV/OHV.Vehicle/MainWindow.xaml
  25. 2 2
      Dev/OHV/OHV.Vehicle/MainWindow.xaml.cs
  26. 0 6
      Dev/OHV/OHV.Vehicle/MainWindowViewModel.cs
  27. 6 1
      Dev/OHV/OHV.Vehicle/OHV.Vehicle.csproj
  28. 7 7
      Dev/OHV/OHV.sln
  29. 1 0
      Dev/OHV/VehicleControlSystem/ControlLayer/IO/BitBlock.cs
  30. 23 0
      Dev/OHV/VehicleControlSystem/ControlLayer/IO/Delegates.cs
  31. 195 105
      Dev/OHV/VehicleControlSystem/ControlLayer/IO/EzIO.cs
  32. 20 0
      Dev/OHV/VehicleControlSystem/ControlLayer/IO/QueueObjects.cs
  33. 6 2
      Dev/OHV/VehicleControlSystem/Managers/AutoManager.cs
  34. 3 3
      Dev/OHV/VehicleControlSystem/Managers/Scheduler.cs
  35. 44 0
      Dev/OHV/VehicleControlSystem/VCSystem.cs
  36. 2 0
      Dev/OHV/VehicleControlSystem/VehicleControlSystem.csproj

BIN
Dev/OHV/Assambly/GSG.NET.WPF.dll


+ 0 - 19
Dev/OHV/OHV.Common.Interface/IModelBase.cs

@@ -1,19 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace OHV.Common.Interface
-{
-    public interface IModelBase
-    {
-        bool AlarmExists { get; set; }
-        string Description { get; set; }
-        //object IOData { get; set; }
-        string UnitID { get; set; }
-        string ModuleID { get; set; }
-        string ModuleKey { get; set; }
-        string Title { get; set; }
-    }
-}

+ 0 - 48
Dev/OHV/OHV.Common.Interface/OHV.Common.Interface.csproj

@@ -1,48 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
-  <PropertyGroup>
-    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
-    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
-    <ProjectGuid>{F6F52400-550A-481B-87F5-D697C0852641}</ProjectGuid>
-    <OutputType>Library</OutputType>
-    <AppDesignerFolder>Properties</AppDesignerFolder>
-    <RootNamespace>OHV.Common.Interface</RootNamespace>
-    <AssemblyName>OHV.Common.Interface</AssemblyName>
-    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
-    <FileAlignment>512</FileAlignment>
-    <Deterministic>true</Deterministic>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
-    <DebugSymbols>true</DebugSymbols>
-    <DebugType>full</DebugType>
-    <Optimize>false</Optimize>
-    <OutputPath>bin\Debug\</OutputPath>
-    <DefineConstants>DEBUG;TRACE</DefineConstants>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
-    <DebugType>pdbonly</DebugType>
-    <Optimize>true</Optimize>
-    <OutputPath>bin\Release\</OutputPath>
-    <DefineConstants>TRACE</DefineConstants>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-  </PropertyGroup>
-  <ItemGroup>
-    <Reference Include="System" />
-    <Reference Include="System.Core" />
-    <Reference Include="System.Xml.Linq" />
-    <Reference Include="System.Data.DataSetExtensions" />
-    <Reference Include="Microsoft.CSharp" />
-    <Reference Include="System.Data" />
-    <Reference Include="System.Net.Http" />
-    <Reference Include="System.Xml" />
-  </ItemGroup>
-  <ItemGroup>
-    <Compile Include="IModelBase.cs" />
-    <Compile Include="Properties\AssemblyInfo.cs" />
-  </ItemGroup>
-  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
-</Project>

+ 0 - 36
Dev/OHV/OHV.Common.Interface/Properties/AssemblyInfo.cs

@@ -1,36 +0,0 @@
-using System.Reflection;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-
-// 어셈블리에 대한 일반 정보는 다음 특성 집합을 통해 
-// 제어됩니다. 어셈블리와 관련된 정보를 수정하려면
-// 이러한 특성 값을 변경하세요.
-[assembly: AssemblyTitle("OHV.Common.Interface")]
-[assembly: AssemblyDescription("")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("")]
-[assembly: AssemblyProduct("OHV.Common.Interface")]
-[assembly: AssemblyCopyright("Copyright ©  2020")]
-[assembly: AssemblyTrademark("")]
-[assembly: AssemblyCulture("")]
-
-// ComVisible을 false로 설정하면 이 어셈블리의 형식이 COM 구성 요소에 
-// 표시되지 않습니다. COM에서 이 어셈블리의 형식에 액세스하려면
-// 해당 형식에 대해 ComVisible 특성을 true로 설정하세요.
-[assembly: ComVisible(false)]
-
-// 이 프로젝트가 COM에 노출되는 경우 다음 GUID는 typelib의 ID를 나타냅니다.
-[assembly: Guid("f6f52400-550a-481b-87f5-d697c0852641")]
-
-// 어셈블리의 버전 정보는 다음 네 가지 값으로 구성됩니다.
-//
-//      주 버전
-//      부 버전 
-//      빌드 번호
-//      수정 버전
-//
-// 모든 값을 지정하거나 아래와 같이 '*'를 사용하여 빌드 번호 및 수정 번호를
-// 기본값으로 할 수 있습니다.
-// [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("1.0.0.0")]
-[assembly: AssemblyFileVersion("1.0.0.0")]

+ 28 - 0
Dev/OHV/OHV.Common/Events/MessageEventArgs.cs

@@ -9,15 +9,43 @@ namespace OHV.Common.Events
 {
     public class GUIMessageEventArgs : EventArgs
     {
+        public enum eGUIMessageKind
+        {
+            RspIOObject,
+            RspIOMapList,
+        }
+
+        public eGUIMessageKind Kind { get; set; }
         public int MessageKey { get; set; }
         public string MessageText { get; set; }
         public Command Command { get; set; }
+        public Dictionary<string, object> Dic { get; set; }
+        public object Args { get; set; }
+
+        public GUIMessageEventArgs(eGUIMessageKind kind, object args)
+        {
+            this.Kind = kind;
+            this.Args = args;
+        }
     }
 
     public class VCSMessageEventArgs : EventArgs
     {
+        public enum eVCSMessageKind
+        {
+            ReqIOObject,
+            ReqIOMapList,
+        }
+
+        public eVCSMessageKind Kind { get; set; }
         public int MessageKey { get; set; }
         public string MessageText { get; set; }
         public Command Command { get; set; }
+        public Dictionary<string, object> Args { get; set; }
+    }
+
+    public class IOChangedMessageEventArgs: EventArgs
+    {
+        public object Args { get; set; }
     }
 }

+ 3 - 3
Dev/OHV/OHV.Common/Events/PubSubEvent.cs

@@ -8,9 +8,9 @@ using Prism.Events;
 namespace OHV.Common.Events
 {
     public class ApplicationExitEvent : PubSubEvent<string> { }
-    public class VCSMessagePubSubEvent : PubSubEvent<VCSMessageEventArgs>
-    {
-    }
+    public class VCSMessagePubSubEvent : PubSubEvent<VCSMessageEventArgs> { }
 
     public class GUIMessagePubSubEvent : PubSubEvent<GUIMessageEventArgs> { }
+
+    public class IOChangedPubSubEvent : PubSubEvent<IOChangedMessageEventArgs> { }
 }

+ 144 - 0
Dev/OHV/OHV.Common/Model/SelectionItem.cs

@@ -0,0 +1,144 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Linq;
+using System.Runtime.CompilerServices;
+
+namespace OHV.Common.Model
+{
+    public enum MotorState
+    {
+        None,
+        Falut,
+        Off,
+        On,
+        OriginReturn,
+    }
+
+    /// <summary>
+    /// an item that will be selected in the multi check box
+    /// </summary>
+    /// <typeparam name="T"></typeparam>
+    public class SelectionItem<T> : INotifyPropertyChanged
+    {
+        #region privat fields
+        int row;
+        int col;
+        string tag;
+        MotorState motorState = MotorState.None;
+        bool isOn;
+
+        /// <summary>
+        /// indicates if the item is selected
+        /// </summary>
+        private bool _isSelected;
+        #endregion
+
+        public SelectionItem( T element, bool isSelected )
+        {
+            Element = element;
+            IsSelected = IsSelected;
+        }
+
+        public SelectionItem( T element ) : this( element, false )
+        {
+        }
+
+        #region public properties
+        /// <summary>
+        /// this UI-aware indicates if the element is selected or not
+        /// </summary>
+        public bool IsSelected
+        {
+            get
+            {
+                return _isSelected;
+            }
+            set
+            {
+                if ( SetField( ref this._isSelected, value ) ) { }
+            }
+        }
+
+        /// <summary>
+        /// Use Grid Colum
+        /// </summary>
+        public int Col
+        {
+            get { return col; }
+            set
+            {
+                if ( SetField( ref this.col, value ) ) { }
+            }
+        }
+        
+        /// <summary>
+        /// Use Grid Row
+        /// </summary>
+        public int Row
+        {
+            get { return row; }
+            set
+            {
+                if ( SetField( ref this.row, value ) ) { }
+            }
+        }
+
+        public string Tag
+        {
+            get { return tag; }
+            set
+            {
+                if( SetField( ref this.tag, value ) ) { }
+            }
+        }
+
+        public MotorState MotorState { get => this.motorState; set { SetField(ref this.motorState, value); } }
+        public bool IsOn { get => this.isOn; set { SetField( ref this.isOn, value ); } }
+
+        /// <summary>
+        /// the element itself
+        /// </summary>
+        public T Element { get; set; }
+
+        #endregion
+
+        public event PropertyChangedEventHandler PropertyChanged;
+
+        protected void OnPropertyChanged( string name )
+        {
+            PropertyChangedEventHandler handler = PropertyChanged;
+            if( handler != null )
+            {
+                handler?.Invoke( this, new PropertyChangedEventArgs( name ) );
+            }
+        }
+
+        /// <summary>
+        /// 
+        /// </summary>
+        /// <typeparam name="T"></typeparam>
+        /// <param name="field">필드 변수</param>
+        /// <param name="newValue"></param>
+        /// <param name="isComparer">이전 값과 비교를 할지 Default = true</param>
+        /// <param name="propertyName"></param>
+        /// <returns></returns>
+        protected bool SetField<T>( ref T field, T newValue = default( T ), bool isComparer = true, [CallerMemberName] string propertyName = null )
+        {
+            if( isComparer )
+                if( EqualityComparer<T>.Default.Equals( field, newValue ) ) return false;
+
+            field = newValue;
+
+            if( propertyName != null )
+            {
+                OnPropertyChanged( propertyName );
+
+                return true;
+            }
+
+            return false;
+        }
+
+    }
+}

+ 139 - 0
Dev/OHV/OHV.Common/Model/SelectionList.cs

@@ -0,0 +1,139 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace OHV.Common.Model
+
+{
+    /// <summary>
+    /// a list that will include the elements that will be selected
+    /// </summary>
+    /// <typeparam name="T"></typeparam>
+    public class SelectionList<T> : List<SelectionItem<T>>, INotifyPropertyChanged
+    {
+        #region private fields
+        /// <summary>
+        /// the number of selected elements
+        /// </summary>
+        private int _selectionCount;
+        string _selectedItemTag = string.Empty;
+        #endregion
+
+        #region private methods
+        /// <summary>
+        /// this events responds to the "IsSelectedEvent"
+        /// </summary>
+        /// <param name="sender"></param>
+        /// <param name="e"></param>
+        void item_PropertyChanged( object sender, PropertyChangedEventArgs e )
+        {
+            var item = sender as SelectionItem<T>;
+
+            if ( (item != null) && e.PropertyName == "IsSelected" )
+            {
+                if ( item.IsSelected )
+                    SelectionCount = SelectionCount + 1;
+                else
+                    SelectionCount = SelectionCount - 1;
+            }
+
+            if ((item != null) && e.PropertyName == "MotorState")
+            {
+                if (PropertyChanged != null)
+                    PropertyChanged(item, new PropertyChangedEventArgs("MotorState"));
+            }
+            //this.SelectedItemTag = item.Tag;
+        }
+
+        #endregion
+
+        public SelectionList()
+        { }
+
+        /// <summary>
+        /// creates the selection list from an existing simple list
+        /// </summary>
+        /// <param name="elements"></param>
+        public SelectionList( IEnumerable<T> elements )
+        {
+            foreach ( T element in elements )
+                AddItem( element );
+        }
+
+        #region public methods
+        /// <summary>
+        /// adds an element to the element and listens to its "IsSelected" property to update the SelectionCount property
+        /// use this method insteand of the "Add" one
+        /// </summary>
+        /// <param name="element"></param>
+        public void AddItem( T element )
+        {
+            var item = new SelectionItem<T>( element );
+            item.PropertyChanged += item_PropertyChanged;
+
+            Add( item );
+        }
+
+        /// <summary>
+        /// gets the selected elements
+        /// </summary>
+        /// <returns></returns>
+        public IEnumerable<T> GetSelection()
+        {
+            return this.Where( e => e.IsSelected ).Select( e => e.Element );
+        }
+
+        /// <summary>
+        /// uses linq expression to select a part of an object (for example, only id)
+        /// </summary>
+        /// <typeparam name="U"></typeparam>
+        /// <param name="expression"></param>
+        /// <returns></returns>
+        public IEnumerable<U> GetSelection<U>( Func<SelectionItem<T>, U> expression )
+        {
+            return this.Where( e => e.IsSelected ).Select( expression );
+        }
+
+        #endregion
+
+        #region public properties
+        /// <summary>
+        /// the selection count property is ui-bindable, returns the number of selected elements
+        /// </summary>
+        public int SelectionCount
+        {
+            get { return _selectionCount; }
+
+            private set
+            {
+                _selectionCount = value;
+                if ( PropertyChanged != null )
+                    PropertyChanged( this, new PropertyChangedEventArgs( "SelectionCount" ) );
+            }
+        }
+
+        public string SelectedItemTag
+        {
+            get => this._selectedItemTag;
+            private set
+            {
+                //if( this._selectedItemTag.Equals( value ) )
+                //    return;
+
+                this._selectedItemTag = value;
+                PropertyChanged?.Invoke( "SelectedItemTag", new PropertyChangedEventArgs( this.SelectedItemTag ) );
+
+            }
+        }
+        #endregion
+
+        #region INotifyPropertyChanged Members
+
+        public event PropertyChangedEventHandler PropertyChanged;
+
+        #endregion
+    }
+}

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

@@ -64,6 +64,8 @@
     <Compile Include="Model\Command.cs" />
     <Compile Include="Model\Config.cs" />
     <Compile Include="Model\Route.cs" />
+    <Compile Include="Model\SelectionItem.cs" />
+    <Compile Include="Model\SelectionList.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="Shareds\SharedEnumType.cs" />
   </ItemGroup>

+ 1 - 0
Dev/OHV/OHV.Common/Shareds/SharedEnumType.cs

@@ -55,6 +55,7 @@
 		ErrorStop,
 		StartRun,
 		Run,
+		Stop,
 	}
 
     #endregion

+ 0 - 21
Dev/OHV/OHV.Model/DataModel/Config.cs

@@ -1,21 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace OHV.Model.DataModel
-{
-    public class Config
-    {
-        public Config()
-        {
-        }
-
-        public string ID { get; set; }
-        public string Name { get; set; }
-        public string Value { get; set; }
-        public string Desc { get; set; }
-        public DateTime EditTime { get; set; }
-    }
-}

+ 0 - 23
Dev/OHV/OHV.Model/DataModel/Route.cs

@@ -1,23 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace OHV.Model.DataModel
-{
-    public class Route
-    {
-        public Route()
-        {
-        }
-
-        public int Id { get; set; }
-        public string Source { get; set; }
-        public string Dest { get; set; }
-        public string Via1 { get; set; }
-        public string Via2 { get; set; }
-        public string Via3 { get; set; }
-        public string Via4 { get; set; }
-    }
-}

+ 0 - 52
Dev/OHV/OHV.Model/OHV.Model.csproj

@@ -1,52 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
-  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
-  <PropertyGroup>
-    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
-    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
-    <ProjectGuid>{4D200545-043F-47FC-8DA5-317AE12C3F1A}</ProjectGuid>
-    <OutputType>Library</OutputType>
-    <AppDesignerFolder>Properties</AppDesignerFolder>
-    <RootNamespace>OHV.Model</RootNamespace>
-    <AssemblyName>OHV.Model</AssemblyName>
-    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
-    <FileAlignment>512</FileAlignment>
-    <Deterministic>true</Deterministic>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
-    <DebugSymbols>true</DebugSymbols>
-    <DebugType>full</DebugType>
-    <Optimize>false</Optimize>
-    <OutputPath>bin\Debug\</OutputPath>
-    <DefineConstants>DEBUG;TRACE</DefineConstants>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-  </PropertyGroup>
-  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
-    <DebugType>pdbonly</DebugType>
-    <Optimize>true</Optimize>
-    <OutputPath>bin\Release\</OutputPath>
-    <DefineConstants>TRACE</DefineConstants>
-    <ErrorReport>prompt</ErrorReport>
-    <WarningLevel>4</WarningLevel>
-  </PropertyGroup>
-  <ItemGroup>
-    <Reference Include="System" />
-    <Reference Include="System.Core" />
-    <Reference Include="System.Xml.Linq" />
-    <Reference Include="System.Data.DataSetExtensions" />
-    <Reference Include="Microsoft.CSharp" />
-    <Reference Include="System.Data" />
-    <Reference Include="System.Net.Http" />
-    <Reference Include="System.Xml" />
-  </ItemGroup>
-  <ItemGroup>
-    <Compile Include="DataModel\Config.cs" />
-    <Compile Include="DataModel\Route.cs" />
-    <Compile Include="Properties\AssemblyInfo.cs" />
-  </ItemGroup>
-  <ItemGroup>
-    <Folder Include="ViewDataModel\" />
-  </ItemGroup>
-  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
-</Project>

+ 166 - 0
Dev/OHV/OHV.Module.Monitoring/Interactivity/InOutIOView.xaml

@@ -0,0 +1,166 @@
+<UserControl 
+            x:Class="OHV.Module.Monitoring.Interactivity.InOutIOView"
+            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
+            xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
+            mc:Ignorable="d"
+            xmlns:local="clr-namespace:OHV.Module.Monitoring.Interactivity"
+            xmlns:IOBtn="clr-namespace:GSG.NET.WPF.ControlResources;assembly=GSG.NET.WPF"
+            xmlns:prism="http://prismlibrary.com/"
+            prism:ViewModelLocator.AutoWireViewModel="True"
+            d:DesignHeight="1000" d:DesignWidth="1000"
+        >
+
+    <Grid>
+        <Grid.RowDefinitions>
+            <RowDefinition Height="50" />
+            <RowDefinition Height="1*" />
+            <RowDefinition Height="60" />
+        </Grid.RowDefinitions>
+
+        <Grid x:Name="gridHeader" Grid.Row="0" Background="#FF646464">
+            <StackPanel
+                Margin="5,0,0,0"
+                HorizontalAlignment="Left"
+                IsHitTestVisible="False"
+                Orientation="Horizontal" >
+                <Rectangle Fill="{DynamicResource DrawingBrushMonitoring}" Height="40" Width="40"></Rectangle>
+                <TextBlock 
+                    Margin="10,10,0,0"
+                    FontSize="22"
+                    Foreground="White" Text="IN / OUT Monitoring">
+                </TextBlock>
+            </StackPanel>
+
+            <StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Width="320">
+                <Button Width="89" Margin="20, 0" FontWeight="Bold" Command="{Binding ChangePageCommand}" CommandParameter="Pre">
+                    <TextBlock><Run Text="Pre Page"/></TextBlock>
+                </Button>
+                <Label Width="60" Content="{Binding CurrentPage, FallbackValue=1 }" FontSize="20" HorizontalAlignment="Center" VerticalAlignment="Center" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" FontWeight="Bold">
+                </Label>
+                <Button Width="89" Margin="20, 0" HorizontalAlignment="Right" FontWeight="Bold" Command="{Binding ChangePageCommand}" CommandParameter="Next" >
+                    <TextBlock><Run Text="Next Page"/></TextBlock>
+                </Button>
+            </StackPanel>
+
+        </Grid>
+
+        <Grid x:Name="gridBody" Grid.Row="1" Background="#FFB9B7B7">
+            <Grid.ColumnDefinitions>
+                <ColumnDefinition Width="1*"/>
+                <ColumnDefinition Width="1*"/>
+            </Grid.ColumnDefinitions>
+
+            <Border Grid.Column="0" CornerRadius="5" BorderBrush="Black" BorderThickness="3">
+
+                <ItemsControl ItemsSource="{Binding InIOList}" >
+                    <ItemsControl.ItemTemplate>
+                        <DataTemplate>
+                            <IOBtn:LEDIO_Button OffColor="Red" OnColor="Green" Content="{Binding Tag}" IsOnOff="{Binding IsOn}" VerticalContentAlignment="Center"/>
+                        </DataTemplate>
+                    </ItemsControl.ItemTemplate>
+                    <ItemsControl.ItemsPanel>
+                        <ItemsPanelTemplate>
+                            <Grid>
+                                <Grid.RowDefinitions>
+                                    <RowDefinition Height="1*"/>
+                                    <RowDefinition Height="1*"/>
+                                    <RowDefinition Height="1*"/>
+                                    <RowDefinition Height="1*"/>
+                                    <RowDefinition Height="1*"/>
+                                    <RowDefinition Height="1*"/>
+                                    <RowDefinition Height="1*"/>
+                                    <RowDefinition Height="1*"/>
+                                    <RowDefinition Height="1*"/>
+                                    <RowDefinition Height="1*"/>
+                                    <RowDefinition Height="1*"/>
+                                    <RowDefinition Height="1*"/>
+                                    <RowDefinition Height="1*"/>
+                                    <RowDefinition Height="1*"/>
+                                    <RowDefinition Height="1*"/>
+                                    <RowDefinition Height="1*"/>
+                                </Grid.RowDefinitions>
+
+                                <Grid.ColumnDefinitions>
+                                    <ColumnDefinition/>
+                                </Grid.ColumnDefinitions>
+
+                            </Grid>
+                        </ItemsPanelTemplate>
+                    </ItemsControl.ItemsPanel>
+                    <ItemsControl.ItemContainerStyle>
+                        <Style TargetType="ContentPresenter">
+                            <Setter Property="Grid.Row" Value="{Binding Row}"/>
+                            <Setter Property="Grid.Column" Value="{Binding Col}"/>
+                            <Setter Property="HorizontalAlignment" Value="Stretch"/>
+                            <Setter Property="VerticalAlignment" Value="Stretch"/>
+                        </Style>
+                    </ItemsControl.ItemContainerStyle>
+                </ItemsControl>
+
+            </Border>
+
+            <Border Grid.Column="1" CornerRadius="5" BorderBrush="Black" BorderThickness="3">
+                <ItemsControl ItemsSource="{Binding OutIOList}" >
+                    <ItemsControl.ItemTemplate>
+                        <DataTemplate>
+                            <IOBtn:LEDIO_Button OffColor="Red" OnColor="Green" Content="{Binding Tag}" IsOnOff="{Binding IsOn}" VerticalContentAlignment="Center"
+                                               Command="{Binding DataContext.OutPutCommand, RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type ItemsControl}}}" CommandParameter="{Binding Element}"/>
+                        </DataTemplate>
+
+                    </ItemsControl.ItemTemplate>
+                    <ItemsControl.ItemsPanel>
+                        <ItemsPanelTemplate>
+                            <Grid>
+                                <Grid.RowDefinitions>
+                                    <RowDefinition Height="1*"/>
+                                    <RowDefinition Height="1*"/>
+                                    <RowDefinition Height="1*"/>
+                                    <RowDefinition Height="1*"/>
+                                    <RowDefinition Height="1*"/>
+                                    <RowDefinition Height="1*"/>
+                                    <RowDefinition Height="1*"/>
+                                    <RowDefinition Height="1*"/>
+                                    <RowDefinition Height="1*"/>
+                                    <RowDefinition Height="1*"/>
+                                    <RowDefinition Height="1*"/>
+                                    <RowDefinition Height="1*"/>
+                                    <RowDefinition Height="1*"/>
+                                    <RowDefinition Height="1*"/>
+                                    <RowDefinition Height="1*"/>
+                                    <RowDefinition Height="1*"/>
+                                </Grid.RowDefinitions>
+
+                                <Grid.ColumnDefinitions>
+                                    <ColumnDefinition/>
+                                </Grid.ColumnDefinitions>
+
+                            </Grid>
+                        </ItemsPanelTemplate>
+                    </ItemsControl.ItemsPanel>
+                    <ItemsControl.ItemContainerStyle>
+                        <Style TargetType="ContentPresenter">
+                            <Setter Property="Grid.Row" Value="{Binding Row}"/>
+                            <Setter Property="Grid.Column" Value="{Binding Col}"/>
+                            <Setter Property="HorizontalAlignment" Value="Stretch"/>
+                            <Setter Property="VerticalAlignment" Value="Stretch"/>
+                        </Style>
+                    </ItemsControl.ItemContainerStyle>
+                </ItemsControl>
+
+            </Border>
+
+        </Grid>
+
+        <Grid x:Name="gridFooter" Grid.Row="2" Background="#FF646464">
+            <!--<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Margin="5,5" Width="120">
+                <Button Width="89" Margin="20, 0" HorizontalAlignment="Right" Click="Button_Click"  >
+                    <TextBlock><Run Text="Close"/></TextBlock>
+                </Button>
+            </StackPanel>-->
+        </Grid>
+
+    </Grid>
+
+</UserControl>

+ 41 - 0
Dev/OHV/OHV.Module.Monitoring/Interactivity/InOutIOView.xaml.cs

@@ -0,0 +1,41 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Shapes;
+
+namespace OHV.Module.Monitoring.Interactivity
+{
+    /// <summary>
+    /// InOutIOView.xaml에 대한 상호 작용 논리
+    /// </summary>
+    public partial class InOutIOView : UserControl
+    {
+        public InOutIOViewModel ViewModel { get => this.DataContext as InOutIOViewModel; }
+
+        public InOutIOView()
+        {
+            InitializeComponent();
+
+            this.Loaded += InOutIOView_Loaded;
+        }
+
+        private void InOutIOView_Loaded(object sender, RoutedEventArgs e)
+        {
+            this.ViewModel.Init();
+        }
+
+        private void Button_Click( object sender, RoutedEventArgs e )
+        {
+            //this.Close();
+        }
+    }
+}

+ 277 - 0
Dev/OHV/OHV.Module.Monitoring/Interactivity/InOutIOViewModel.cs

@@ -0,0 +1,277 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Windows;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Threading;
+using OHV.Common.Events;
+using OHV.Common.Model;
+using Prism.Commands;
+using Prism.Events;
+using Prism.Mvvm;
+using VehicleControlSystem.ControlLayer.IO;
+
+namespace OHV.Module.Monitoring.Interactivity
+{
+    public class InOutIOViewModel : BindableBase
+    {
+        SelectionList<BitBlock> inIOList = null;
+        public SelectionList<BitBlock> InIOList
+        {
+            get { return this.inIOList; }
+            set
+            {
+                if(SetProperty( ref this.inIOList, value ) ) { }
+            }
+        }
+
+        SelectionList<BitBlock> outIOList = null;
+        public SelectionList<BitBlock> OutIOList
+        {
+            get { return this.outIOList; }
+            set
+            {
+                if(SetProperty( ref this.outIOList, value ) ) { }
+            }
+        }
+
+        List<BitBlock> allIOList = new List<BitBlock>();
+
+        int currentPage = 1;
+        public int CurrentPage
+        {
+            get => this.currentPage;
+            set
+            {
+                if(SetProperty( ref this.currentPage, value ) )
+                {
+                    var input = this.allIOList.Where(i => i.BoardNo == this.currentPage && i.IOType.Equals("IN")).ToArray();
+                    this.InIOList = new SelectionList<BitBlock>( input );
+                    this.InIOList.ForEach( i =>
+                    {
+                        i.Row = i.Element.Index;
+                        i.Col = 0;
+                        i.Tag = $"[{i.Element.Address}] {i.Element.Tag}";
+                        i.IsSelected = i.Element.IsBitOn;
+                    } );
+
+                    var output = this.allIOList.Where(i => i.BoardNo == this.currentPage && i.IOType.Equals("OUT")).ToArray();
+                    this.OutIOList = new SelectionList<BitBlock>( output );
+                    this.OutIOList.PropertyChanged += OutIOList_PropertyChanged;
+                    this.OutIOList.ForEach( o =>
+                    {
+                        o.Row = o.Element.Index;
+                        o.Col = 0;
+                        o.Tag = $"[{o.Element.Address}] {o.Element.Tag}";
+                        o.IsSelected = o.Element.IsBitOn;
+                    } );
+                }
+            }
+        }
+
+        //Command
+        public ICommand ChangePageCommand { get; set; }
+        public ICommand OutPutCommand { get; set; }
+
+        DispatcherTimer dispatcherTimer;
+
+        public EzIO IO { get; set; }
+
+        IEventAggregator eventAggregator;
+
+        public InOutIOViewModel(IEventAggregator ea)
+        {
+            this.InIOList = new SelectionList<BitBlock>();
+            this.OutIOList = new SelectionList<BitBlock>();
+
+            this.ChangePageCommand = new DelegateCommand<object>( this.ExecutePageChange );
+            this.OutPutCommand = new DelegateCommand<object>( this.ExecuteOutPut );
+
+            eventAggregator = ea;
+            eventAggregator.GetEvent<GUIMessagePubSubEvent>().Unsubscribe(UICallbackCommunication);
+            eventAggregator.GetEvent<GUIMessagePubSubEvent>().Subscribe(UICallbackCommunication, ThreadOption.UIThread);
+        }
+
+        void UICallbackCommunication(GUIMessageEventArgs args)
+        {
+            switch (args.Kind)
+            {
+                case GUIMessageEventArgs.eGUIMessageKind.RspIOObject:
+                    var ezIO = args.Args as EzIO;
+                    this.IO = ezIO;
+                    ezIO.OnChangedIO += EzIO_OnChangedIO;
+                    ezIO.OnContd += EzIO_OnContd;
+                    ezIO.OnDiscontd += EzIO_OnDiscontd;
+
+                    this.allIOList = new List<BitBlock>(ezIO.InPutIOList);
+                    this.allIOList.AddRange(ezIO.OutPutIOList);
+
+                    var input = this.allIOList.Where(i => i.BoardNo == this.currentPage && i.IOType.Equals("IN")).ToArray();
+                    this.InIOList = new SelectionList<BitBlock>(input);
+                    this.InIOList.ForEach(i =>
+                    {
+                        i.Row = i.Element.Index;
+                        i.Col = 0;
+                        i.Tag = $"[{i.Element.Address}] {i.Element.Tag}";
+                        i.IsSelected = i.Element.IsBitOn;
+                    });
+
+                    var output = this.allIOList.Where(i => i.BoardNo == this.currentPage && i.IOType.Equals("OUT")).ToArray();
+                    this.OutIOList = new SelectionList<BitBlock>(output);
+                    this.OutIOList.PropertyChanged += OutIOList_PropertyChanged;
+                    this.OutIOList.ForEach(o =>
+                    {
+                        o.Row = o.Element.Index;
+                        o.Col = 0;
+                        o.Tag = $"[{o.Element.Address}] {o.Element.Tag}";
+                        o.IsSelected = o.Element.IsBitOn;
+                    });
+                    break;
+
+                case GUIMessageEventArgs.eGUIMessageKind.RspIOMapList:
+                    break;
+                default:
+                    break;
+            }
+        }
+
+        private void EzIO_OnDiscontd(string ID)
+        {
+            //throw new NotImplementedException();
+        }
+
+        private void EzIO_OnContd(string ID)
+        {
+            //throw new NotImplementedException();
+        }
+
+        private void EzIO_OnChangedIO(BitBlock bit)
+        {
+            var b = this.allIOList.Where(io => io.Tag.Equals(bit.Tag)).FirstOrDefault();
+
+            if (b.IOType.Equals("IN"))
+                this.InIOList.Where(x => x.Element.Tag.Equals(b.Tag)).SingleOrDefault().IsOn = b.IsBitOn;
+            else
+                this.OutIOList.Where(x => x.Element.Tag.Equals(b.Tag)).SingleOrDefault().IsOn = b.IsBitOn;
+        }
+
+        public void Init()
+        {
+            var msg = new VCSMessageEventArgs() { Kind = VCSMessageEventArgs.eVCSMessageKind.ReqIOObject };
+            this.eventAggregator.GetEvent<VCSMessagePubSubEvent>().Publish(msg);
+
+            //var input = (MPlatformSystem.Instance.IIO as EzIO).InPutIOList.Where( x => x.BoardNo == this.CurrentPage ).ToArray();
+            //this.InIOList = new SelectionList<BitBlock>( input );
+            //this.InIOList.ForEach( i =>
+            //{
+            //    i.Row = i.Element.Index;
+            //    i.Col = 0;
+            //    i.Tag =  $"[{i.Element.Address}] {i.Element.Tag}";
+            //    i.IsSelected = i.Element.IsBitOn;
+            //} );
+
+            //this.IO = MPlatformSystem.Instance.IIO as EzIO;
+            //var output = IO.OutPutIOList.Where( x => x.BoardNo == this.CurrentPage ).ToArray();
+            //this.OutIOList = new SelectionList<BitBlock>( output );
+            //this.OutIOList.PropertyChanged += OutIOList_PropertyChanged;
+            //this.OutIOList.ForEach( o =>
+            //{
+            //    o.Row = o.Element.Index;
+            //    o.Col = 0;
+            //    o.Tag = $"[{o.Element.Address}] {o.Element.Tag}";
+            //    o.IsSelected = o.Element.IsBitOn;
+            //} );
+
+            //dispatcherTimer = new DispatcherTimer( TimeSpan.FromMilliseconds( 500 ), DispatcherPriority.Render, this.UpdateIO, Application.Current.Dispatcher );
+            //dispatcherTimer.Start();
+        }
+
+        private void OutIOList_PropertyChanged( object sender, System.ComponentModel.PropertyChangedEventArgs e )
+        {
+            //var s = sender as SelectionList<BitBlock>;
+            //var t = s.Where( x => x.IsSelected ).FirstOrDefault();
+
+            //this.IO.OutupOn( t.Tag );
+        }
+
+        public void ClickOutPut( object sender )
+        {
+            //var s = sender as SelectionList<BitBlock>;
+            //var t = s.Where( x => x.IsSelected ).FirstOrDefault();
+
+            //this.IO.OutupOn( t.Tag );
+        }
+
+        void UpdateIO( object senser, EventArgs args )
+        {
+            //var input = (MPlatformSystem.Instance.IIO as EzIO).InPutIOList.Where( x => x.BoardNo == this.CurrentPage ).ToList();
+            //var output = (MPlatformSystem.Instance.IIO as EzIO).OutPutIOList.Where( x => x.BoardNo == this.CurrentPage ).ToList();
+
+            //this.InIOList.ForEach( i =>
+            //{
+            //    var e = input.FirstOrDefault( x => x.Tag.Equals( i.Element.Tag ) );
+            //    if( e != null )
+            //    {
+            //        i.IsOn = e.IsBitOn; ;
+            //    }
+            //} );
+
+            //this.OutIOList.ForEach( o =>
+            //{
+            //    if( output.Contains( o.Element ) )
+            //    {
+            //        var e = output.FirstOrDefault( x => x.Tag.Equals( o.Element.Tag ) );
+            //        if( e != null )
+            //        {
+            //            o.IsOn = e.IsBitOn;
+            //        }
+            //    }
+            //} );
+        }
+
+        void ExecutePageChange( object obj )
+        {
+            int boardCount = this.allIOList.Select(x => x.BoardNo).Max();
+
+            switch( obj.ToString() )
+            {
+                case "Pre":
+                    if( this.currentPage > 1 )
+                        this.CurrentPage -= 1;
+                    break;
+
+                case "Next":
+                    if( this.CurrentPage < boardCount)
+                        this.CurrentPage += 1;
+                    break;
+
+                default:
+                    break;
+            }
+
+        }
+
+        void ExecuteOutPut( object obj )
+        {
+            BitBlock bitBlock = obj as BitBlock;
+            var oPut = this.OutIOList.Where( x => x.Element.Tag.Equals(bitBlock.Tag)).FirstOrDefault();
+            if( oPut == null )
+                return;
+
+            if( oPut.Element.IsBitOn )
+                this.IO.OutputOff( bitBlock.Tag );
+            else
+                this.IO.OutputOn( bitBlock.Tag );
+        }
+
+        public void Close()
+        {
+            if( dispatcherTimer != null )
+            {
+                dispatcherTimer.Stop();
+                dispatcherTimer = null;
+            }
+        }
+    }
+}

+ 25 - 0
Dev/OHV/OHV.Module.Monitoring/MonitoringModules.cs

@@ -0,0 +1,25 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using OHV.Module.Monitoring.Interactivity;
+using Prism.Ioc;
+using Prism.Modularity;
+using Prism.Regions;
+
+namespace OHV.Module.Monitoring
+{
+    public class MonitoringModules : IModule
+    {
+        public void OnInitialized(IContainerProvider containerProvider)
+        {
+            var regionManager = containerProvider.Resolve<IRegionManager>();
+            regionManager.RegisterViewWithRegion("IOView", typeof(InOutIOView));
+        }
+
+        public void RegisterTypes(IContainerRegistry containerRegistry)
+        {
+        }
+    }
+}

+ 99 - 0
Dev/OHV/OHV.Module.Monitoring/OHV.Module.Monitoring.csproj

@@ -0,0 +1,99 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectGuid>{CF748E61-69C2-4DEC-A9EC-755B6999077E}</ProjectGuid>
+    <OutputType>Library</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>OHV.Module.Monitoring</RootNamespace>
+    <AssemblyName>OHV.Module.Monitoring</AssemblyName>
+    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+    <Deterministic>true</Deterministic>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="CommonServiceLocator, Version=2.0.4.0, Culture=neutral, PublicKeyToken=489b6accfaf20ef0, processorArchitecture=MSIL">
+      <HintPath>..\packages\CommonServiceLocator.2.0.4\lib\net45\CommonServiceLocator.dll</HintPath>
+    </Reference>
+    <Reference Include="PresentationCore" />
+    <Reference Include="PresentationFramework" />
+    <Reference Include="Prism, Version=7.2.0.1422, Culture=neutral, PublicKeyToken=40ee6c3a2184dc59, processorArchitecture=MSIL">
+      <HintPath>..\packages\Prism.Core.7.2.0.1422\lib\net45\Prism.dll</HintPath>
+    </Reference>
+    <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="System" />
+    <Reference Include="System.Configuration" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Drawing" />
+    <Reference Include="System.ValueTuple, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
+      <HintPath>..\packages\System.ValueTuple.4.5.0\lib\netstandard1.0\System.ValueTuple.dll</HintPath>
+    </Reference>
+    <Reference Include="System.Windows.Forms" />
+    <Reference Include="System.Windows.Interactivity, Version=4.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
+      <HintPath>..\packages\Prism.Wpf.7.2.0.1422\lib\net45\System.Windows.Interactivity.dll</HintPath>
+    </Reference>
+    <Reference Include="System.Xaml" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Data.DataSetExtensions" />
+    <Reference Include="Microsoft.CSharp" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Net.Http" />
+    <Reference Include="System.Xml" />
+    <Reference Include="WindowsBase" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Interactivity\InOutIOView.xaml.cs">
+      <DependentUpon>InOutIOView.xaml</DependentUpon>
+    </Compile>
+    <Compile Include="Interactivity\InOutIOViewModel.cs">
+      <DependentUpon>InOutIOView.xaml</DependentUpon>
+    </Compile>
+    <Compile Include="MonitoringModules.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="packages.config" />
+  </ItemGroup>
+  <ItemGroup>
+    <Page Include="Interactivity\InOutIOView.xaml">
+      <Generator>MSBuild:Compile</Generator>
+      <SubType>Designer</SubType>
+    </Page>
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\..\..\..\GSG\GSG\GSG.NET.WPF\GSG.NET.WPF.csproj">
+      <Project>{6b91fca2-0a26-41d5-8959-a6f27645dacd}</Project>
+      <Name>GSG.NET.WPF</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\OHV.Common\OHV.Common.csproj">
+      <Project>{0D1F7FBC-BFB0-4EE4-852D-E2A8D62C5708}</Project>
+      <Name>OHV.Common</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\VehicleControlSystem\VehicleControlSystem.csproj">
+      <Project>{73BAB40E-FC7D-4AB5-85CA-B4CF221DFBD1}</Project>
+      <Name>VehicleControlSystem</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+</Project>

+ 3 - 3
Dev/OHV/OHV.Model/Properties/AssemblyInfo.cs

@@ -5,11 +5,11 @@ using System.Runtime.InteropServices;
 // 어셈블리에 대한 일반 정보는 다음 특성 집합을 통해 
 // 제어됩니다. 어셈블리와 관련된 정보를 수정하려면
 // 이러한 특성 값을 변경하세요.
-[assembly: AssemblyTitle("OHV.Model")]
+[assembly: AssemblyTitle("OHV.Module.Monitoring")]
 [assembly: AssemblyDescription("")]
 [assembly: AssemblyConfiguration("")]
 [assembly: AssemblyCompany("")]
-[assembly: AssemblyProduct("OHV.Model")]
+[assembly: AssemblyProduct("OHV.Module.Monitoring")]
 [assembly: AssemblyCopyright("Copyright ©  2020")]
 [assembly: AssemblyTrademark("")]
 [assembly: AssemblyCulture("")]
@@ -20,7 +20,7 @@ using System.Runtime.InteropServices;
 [assembly: ComVisible(false)]
 
 // 이 프로젝트가 COM에 노출되는 경우 다음 GUID는 typelib의 ID를 나타냅니다.
-[assembly: Guid("4d200545-043f-47fc-8da5-317ae12c3f1a")]
+[assembly: Guid("cf748e61-69c2-4dec-a9ec-755b6999077e")]
 
 // 어셈블리의 버전 정보는 다음 네 가지 값으로 구성됩니다.
 //

+ 7 - 0
Dev/OHV/OHV.Module.Monitoring/packages.config

@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+  <package id="CommonServiceLocator" version="2.0.4" targetFramework="net45" />
+  <package id="Prism.Core" version="7.2.0.1422" targetFramework="net45" />
+  <package id="Prism.Wpf" version="7.2.0.1422" targetFramework="net45" />
+  <package id="System.ValueTuple" version="4.5.0" targetFramework="net45" />
+</packages>

+ 40 - 3
Dev/OHV/OHV.SqliteDAL/OHVDbInitializer.cs

@@ -1,18 +1,55 @@
-using SQLite.CodeFirst;
+using OHV.Common.Model;
+using SQLite.CodeFirst;
+using System;
+using System.Collections.Generic;
 using System.Data.Entity;
 
 namespace OHV.SqliteDAL
 {
     public class OHVDbInitializer : SqliteDropCreateDatabaseWhenModelChanges<OHVDbContext>
     {
-        public OHVDbInitializer( DbModelBuilder modelBuilder ) : base( modelBuilder, typeof( CustomHistory ) )
+        public OHVDbInitializer(DbModelBuilder modelBuilder) : base(modelBuilder, typeof(CustomHistory))
         {
         }
 
-        protected override void Seed( OHVDbContext context )
+        protected override void Seed(OHVDbContext context)
         {
             //base.Seed( context );
             // Here you can seed your core data if you have any.
+            context.Set<Config>().AddRange(new List<Config>()
+            {
+                new Config
+                {
+                    ID = "OCSAddrIP",
+                    Name = "OCSAddrIP",
+                    Value = "127.0.0.1",
+                    Desc = "",
+                    EditTime = DateTime.Now
+                },
+                new Config
+                {
+                    ID = "OCSAddrPortNo",
+                    Name = "OCSAddrPortNo",
+                    Value = "5000",
+                    Desc = "",
+                    EditTime = DateTime.Now
+                },
+                new Config
+                {
+                    ID = "VehicleID",
+                    Name = "VehicleID",
+                    Value = "V0001",
+                    Desc = "",
+                    EditTime = DateTime.Now
+                },
+            });
+
+            context.Set<Route>().AddRange(new List<Route>()
+            { 
+                new Route
+                { 
+                },
+            });
         }
     }
 }

+ 5 - 0
Dev/OHV/OHV.Vehicle/App.xaml

@@ -5,6 +5,11 @@
                           xmlns:prism="http://prismlibrary.com/"
              Startup="Application_Startup" Exit="Application_Exit">
     <Application.Resources>
+        <ResourceDictionary>
+            <ResourceDictionary.MergedDictionaries>
+                <ResourceDictionary Source="/GSG.NET.WPF;component/ControlResources/ButtonResources.xaml"/>
+            </ResourceDictionary.MergedDictionaries>
+        </ResourceDictionary>
 
     </Application.Resources>
 </prism:PrismApplication>

+ 1 - 0
Dev/OHV/OHV.Vehicle/App.xaml.cs

@@ -84,6 +84,7 @@ namespace OHV.Vehicle
             base.ConfigureModuleCatalog(moduleCatalog);
 
             moduleCatalog.AddModule(typeof(VCSystem));
+            moduleCatalog.AddModule<OHV.Module.Monitoring.MonitoringModules>();
         }
 
     }

+ 8 - 2
Dev/OHV/OHV.Vehicle/MainWindow.xaml

@@ -7,11 +7,17 @@
         xmlns:prism="http://prismlibrary.com/"
         prism:ViewModelLocator.AutoWireViewModel="True"
         mc:Ignorable="d"
-        Title="{Binding Title}" Height="450" Width="800">
+        Title="{Binding Title}" Height="1000" Width="1280">
     <Grid>
-        <!--<ContentControl prism:RegionManager.RegionName="ContentRegion" />-->
+        <Grid.ColumnDefinitions>
+            <ColumnDefinition Width="1*"/>
+            <ColumnDefinition Width="1*"/>
+        </Grid.ColumnDefinitions>
+
         <TextBlock ><InlineUIContainer>
             </InlineUIContainer></TextBlock>
         <Button Content="Button" Height="30" Width="65" Command="{Binding TestCommand}"/>
+
+        <ContentControl Grid.Column="1" prism:RegionManager.RegionName="IOView" />
     </Grid>
 </Window>

+ 2 - 2
Dev/OHV/OHV.Vehicle/MainWindow.xaml.cs

@@ -12,7 +12,7 @@ using System.Windows.Media;
 using System.Windows.Media.Imaging;
 using System.Windows.Navigation;
 using System.Windows.Shapes;
-using GSG.NET.WPF.Extensions;
+//using GSG.NET.WPF.Extensions;
 
 namespace OHV.Vehicle
 {
@@ -40,7 +40,7 @@ namespace OHV.Vehicle
         {
             this.ViewModel.InitViewModel();
 
-            this.MaximizeToFirstMonitor();
+            //this.MaximizeToFirstMonitor();
         }
 
     }

+ 0 - 6
Dev/OHV/OHV.Vehicle/MainWindowViewModel.cs

@@ -1,18 +1,12 @@
 using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
 using System.Windows.Input;
 using CommonServiceLocator;
 using OHV.Common.Events;
 using Prism.Commands;
 using Prism.Events;
 using Prism.Mvvm;
-using Prism.Ioc;
 using VehicleControlSystem;
 using Prism.Modularity;
-using Prism.Unity;
 
 namespace OHV.Vehicle
 {

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

@@ -49,7 +49,8 @@
     <Reference Include="GSG.NET">
       <HintPath>..\Assambly\GSG.NET.dll</HintPath>
     </Reference>
-    <Reference Include="GSG.NET.WPF">
+    <Reference Include="GSG.NET.WPF, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
       <HintPath>..\Assambly\GSG.NET.WPF.dll</HintPath>
     </Reference>
     <Reference Include="log4net">
@@ -173,6 +174,10 @@
       <Project>{0d1f7fbc-bfb0-4ee4-852d-e2a8d62c5708}</Project>
       <Name>OHV.Common</Name>
     </ProjectReference>
+    <ProjectReference Include="..\OHV.Module.Monitoring\OHV.Module.Monitoring.csproj">
+      <Project>{cf748e61-69c2-4dec-a9ec-755b6999077e}</Project>
+      <Name>OHV.Module.Monitoring</Name>
+    </ProjectReference>
     <ProjectReference Include="..\VehicleControlSystem\VehicleControlSystem.csproj">
       <Project>{73BAB40E-FC7D-4AB5-85CA-B4CF221DFBD1}</Project>
       <Name>VehicleControlSystem</Name>

+ 7 - 7
Dev/OHV/OHV.sln

@@ -13,8 +13,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "PresentationLayer", "Presen
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OHV.SqliteDAL", "OHV.SqliteDAL\OHV.SqliteDAL.csproj", "{122D81C8-9AB9-4CED-80D2-9C4F2F9DEB4C}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OHV.Model", "OHV.Model\OHV.Model.csproj", "{4D200545-043F-47FC-8DA5-317AE12C3F1A}"
-EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OHV.Vehicle", "OHV.Vehicle\OHV.Vehicle.csproj", "{12D8B660-6FC6-4228-9198-63E3E455CAAF}"
 EndProject
 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "UICommon", "UICommon", "{D9E1DACB-13AC-4607-B112-706D055C9A0E}"
@@ -33,6 +31,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OHV.OCS", "OHV.OCS\OHV.OCS.
 EndProject
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VehicleControlSystem", "VehicleControlSystem\VehicleControlSystem.csproj", "{73BAB40E-FC7D-4AB5-85CA-B4CF221DFBD1}"
 EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OHV.Module.Monitoring", "OHV.Module.Monitoring\OHV.Module.Monitoring.csproj", "{CF748E61-69C2-4DEC-A9EC-755B6999077E}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
@@ -43,10 +43,6 @@ Global
 		{122D81C8-9AB9-4CED-80D2-9C4F2F9DEB4C}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{122D81C8-9AB9-4CED-80D2-9C4F2F9DEB4C}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{122D81C8-9AB9-4CED-80D2-9C4F2F9DEB4C}.Release|Any CPU.Build.0 = Release|Any CPU
-		{4D200545-043F-47FC-8DA5-317AE12C3F1A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
-		{4D200545-043F-47FC-8DA5-317AE12C3F1A}.Debug|Any CPU.Build.0 = Debug|Any CPU
-		{4D200545-043F-47FC-8DA5-317AE12C3F1A}.Release|Any CPU.ActiveCfg = Release|Any CPU
-		{4D200545-043F-47FC-8DA5-317AE12C3F1A}.Release|Any CPU.Build.0 = Release|Any CPU
 		{12D8B660-6FC6-4228-9198-63E3E455CAAF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
 		{12D8B660-6FC6-4228-9198-63E3E455CAAF}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{12D8B660-6FC6-4228-9198-63E3E455CAAF}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -75,13 +71,16 @@ Global
 		{73BAB40E-FC7D-4AB5-85CA-B4CF221DFBD1}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{73BAB40E-FC7D-4AB5-85CA-B4CF221DFBD1}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{73BAB40E-FC7D-4AB5-85CA-B4CF221DFBD1}.Release|Any CPU.Build.0 = Release|Any CPU
+		{CF748E61-69C2-4DEC-A9EC-755B6999077E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{CF748E61-69C2-4DEC-A9EC-755B6999077E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{CF748E61-69C2-4DEC-A9EC-755B6999077E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{CF748E61-69C2-4DEC-A9EC-755B6999077E}.Release|Any CPU.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
 	EndGlobalSection
 	GlobalSection(NestedProjects) = preSolution
 		{122D81C8-9AB9-4CED-80D2-9C4F2F9DEB4C} = {218BC935-22FD-42D6-BE1B-4C1B5994B2AE}
-		{4D200545-043F-47FC-8DA5-317AE12C3F1A} = {B2DE533E-C8A8-41CD-97CB-E88905233610}
 		{12D8B660-6FC6-4228-9198-63E3E455CAAF} = {EB9D988A-D44D-4EBF-8BB5-ABCE85AC4811}
 		{D9E1DACB-13AC-4607-B112-706D055C9A0E} = {EB9D988A-D44D-4EBF-8BB5-ABCE85AC4811}
 		{6C7A1445-7F2F-46C4-9AAD-AEB739F9BD2D} = {EB9D988A-D44D-4EBF-8BB5-ABCE85AC4811}
@@ -90,6 +89,7 @@ Global
 		{0D1F7FBC-BFB0-4EE4-852D-E2A8D62C5708} = {B2DE533E-C8A8-41CD-97CB-E88905233610}
 		{D045DC91-1AD5-4EBF-A062-0C6C5FE203C5} = {EB9D988A-D44D-4EBF-8BB5-ABCE85AC4811}
 		{73BAB40E-FC7D-4AB5-85CA-B4CF221DFBD1} = {E991DE17-D541-45A9-85B0-1AA1B0D50D89}
+		{CF748E61-69C2-4DEC-A9EC-755B6999077E} = {6C7A1445-7F2F-46C4-9AAD-AEB739F9BD2D}
 	EndGlobalSection
 	GlobalSection(ExtensibilityGlobals) = postSolution
 		SolutionGuid = {2222F9E2-CBEF-4156-9636-5DF54ECDDA89}

+ 1 - 0
Dev/OHV/VehicleControlSystem/ControlLayer/IO/BitBlock.cs

@@ -29,5 +29,6 @@ namespace VehicleControlSystem.ControlLayer.IO
         public string BoardType { get; set; }
 
         public bool IsBitOn { get; set; } = false;
+        public bool IsChanged { get; set; } = false;
     }
 }

+ 23 - 0
Dev/OHV/VehicleControlSystem/ControlLayer/IO/Delegates.cs

@@ -0,0 +1,23 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace VehicleControlSystem.ControlLayer.IO
+{
+    public delegate void Dlg(string ID);
+    public delegate void DlgChangedIO(BitBlock bit);
+    public delegate void DlgWriteIO(BitBlock bit);
+    public delegate void DlgLog(string id, string log);
+
+    public partial class EzIO 
+    {
+        public event Dlg OnContd;
+        public event Dlg OnDiscontd;
+        public event DlgChangedIO OnChangedIO;
+        public event DlgWriteIO OnWriteIO;
+        public event DlgLog OnLog;
+    }
+
+}

+ 195 - 105
Dev/OHV/VehicleControlSystem/ControlLayer/IO/EzIO.cs

@@ -10,9 +10,10 @@ using VehicleControlSystem.ControlLayer.Lib.EziPlusE;
 
 namespace VehicleControlSystem.ControlLayer.IO
 {
-    public class EzIO : IIO, IDisposable
+    public partial class EzIO : IIO, IDisposable
     {
 
+        #region Bit Mask
         public readonly uint[] bitOnMask =
        {
             0x00000001, 0x00000002, 0x00000004, 0x00000008,
@@ -52,6 +53,7 @@ namespace VehicleControlSystem.ControlLayer.IO
             0x00080000, 0x00100000, 0x00200000, 0x00400000,
             0x00800000
         };
+        #endregion
 
         static Logger logger = Logger.GetLogger();
 
@@ -81,48 +83,55 @@ namespace VehicleControlSystem.ControlLayer.IO
             get => this.isConnectError;
             set
             {
-                if( this.isConnectError == value )
+                if (this.isConnectError == value)
                     return;
                 this.isConnectError = value;
 
-                this.OnConnectError?.Invoke( this, value );
+                if (isConnectError)
+                    this.qQ.Enqueue(new QoDiconnected());
+                else
+                    this.qQ.Enqueue(new QoConnected());
+
             }
         }
 
-        public EventHandler<bool> OnConnectError;
+        #region Pull Thread
+        public TsQueue<QueueObject> qQ = new TsQueue<QueueObject>(512);
+        public Thread pullThread;
+        #endregion
 
         #region public Method
-        public int GetBit( uint usIOAddr, bool pbval )
+        public int GetBit(uint usIOAddr, bool pbval)
         {
             throw new NotImplementedException();
         }
 
-        public int GetBit( string strIOAddr, bool pbVal )
+        public int GetBit(string strIOAddr, bool pbVal)
         {
             throw new NotImplementedException();
         }
 
-        public int GetByte( uint usIOAddr, byte pcValue )
+        public int GetByte(uint usIOAddr, byte pcValue)
         {
             throw new NotImplementedException();
         }
 
-        public int GetByte( string strIOAddr, byte pcValue )
+        public int GetByte(string strIOAddr, byte pcValue)
         {
             throw new NotImplementedException();
         }
 
-        public int GetWord( uint usIOAddr, short pwValue )
+        public int GetWord(uint usIOAddr, short pwValue)
         {
             throw new NotImplementedException();
         }
 
-        public int GetWord( string strIOAddr, short pwValue )
+        public int GetWord(string strIOAddr, short pwValue)
         {
             throw new NotImplementedException();
         }
 
-        public int Initialize( List<EzBoard> ezBoards )
+        public int Initialize(List<EzBoard> ezBoards)
         {
             this.BoardList = ezBoards;
 
@@ -130,7 +139,7 @@ namespace VehicleControlSystem.ControlLayer.IO
             this._outcomingBuffer = new ushort[ezBoards.Count];
 
             this.IsThreadAlive = true;
-            _readThread = new Thread( this.IOThread );
+            _readThread = new Thread(this.IOThread);
             this._readThread.IsBackground = true;
             this._readThread.Start();
 
@@ -144,23 +153,23 @@ namespace VehicleControlSystem.ControlLayer.IO
             throw new NotImplementedException();
         }
 
-        public bool IsOff( uint usIOAddr )
+        public bool IsOff(uint usIOAddr)
         {
             throw new NotImplementedException();
         }
 
-        public bool IsOff( string ioTag, bool isInput = true )
+        public bool IsOff(string ioTag, bool isInput = true)
         {
             BitBlock bit = null;
-            if( isInput )
-                bit = this._inPutIOList.Where( x => ioTag.Equals( x.Tag ) ).FirstOrDefault();
+            if (isInput)
+                bit = this._inPutIOList.Where(x => ioTag.Equals(x.Tag)).FirstOrDefault();
             else
-                bit = this._outPutIOList.Where( x => ioTag.Equals( x.Tag ) ).FirstOrDefault();
+                bit = this._outPutIOList.Where(x => ioTag.Equals(x.Tag)).FirstOrDefault();
 
             return !bit.IsBitOn;
         }
 
-        public bool IsOn( uint usIOAddr )
+        public bool IsOn(uint usIOAddr)
         {
             throw new NotImplementedException();
         }
@@ -176,61 +185,61 @@ namespace VehicleControlSystem.ControlLayer.IO
         //    return 0;
         //}
 
-        public bool IsOn( string ioTag, bool isInput = true )
+        public bool IsOn(string ioTag, bool isInput = true)
         {
             BitBlock bit = null;
-            if( isInput )
-                bit = this._inPutIOList.Where( x => ioTag.Equals( x.Tag ) ).FirstOrDefault();
+            if (isInput)
+                bit = this._inPutIOList.Where(x => ioTag.Equals(x.Tag)).FirstOrDefault();
             else
-                bit = this._outPutIOList.Where( x => ioTag.Equals( x.Tag ) ).FirstOrDefault();
+                bit = this._outPutIOList.Where(x => ioTag.Equals(x.Tag)).FirstOrDefault();
 
             return bit.IsBitOn;
         }
 
-        public int LoadIOMap( string strFileName )
+        public int LoadIOMap(string strFileName)
         {
-            var bl = new ExcelMapper( strFileName ).Fetch<EzBoard>( "BOARD" ).ToList();
+            var bl = new ExcelMapper(strFileName).Fetch<EzBoard>("BOARD").ToList();
             this.BoardList = bl;
 
-            var il = new ExcelMapper( strFileName ).Fetch<BitBlock>( "IN_IO" ).ToList();
-            var inputIO = il.Where( x => !string.IsNullOrEmpty( x.Tag ) ).ToList();
+            var il = new ExcelMapper(strFileName).Fetch<BitBlock>("IN_IO").ToList();
+            var inputIO = il.Where(x => !string.IsNullOrEmpty(x.Tag)).ToList();
             this._inPutIOList = inputIO;
 
-            var ol = new ExcelMapper( strFileName ).Fetch<BitBlock>( "OUT_IO" ).ToList();
-            var outputIO = ol.Where( x => !string.IsNullOrEmpty( x.Tag ) ).ToList();
+            var ol = new ExcelMapper(strFileName).Fetch<BitBlock>("OUT_IO").ToList();
+            var outputIO = ol.Where(x => !string.IsNullOrEmpty(x.Tag)).ToList();
             this._outPutIOList = outputIO;
 
             return 0;
         }
 
-        public int OutputOff( uint usIOAddr )
+        public int OutputOff(uint usIOAddr)
         {
             throw new NotImplementedException();
         }
 
-        public int OutputOff( string strIOAddr )
+        public int OutputOff(string strIOAddr)
         {
             int result = 0;
 
-            var outIO = this._outPutIOList.Where( x => strIOAddr.Equals( x.Tag ) ).FirstOrDefault();
-            var boardType = this.BoardList.Where( x => x.BoardID == outIO.BoardNo ).FirstOrDefault().BoardType;
+            var outIO = this._outPutIOList.Where(x => strIOAddr.Equals(x.Tag)).FirstOrDefault();
+            var boardType = this.BoardList.Where(x => x.BoardID == outIO.BoardNo).FirstOrDefault().BoardType;
 
             uint bitMask = 0;
-            if( boardType == E_EzboardType.Servo )
+            if (boardType == E_EzboardType.Servo)
             {
                 bitMask = this.servoAmpOutputBitMask[outIO.Index];
-                result = EziMOTIONPlusELib.FAS_SetIOOutput( outIO.BoardNo, 0, bitMask );
+                result = EziMOTIONPlusELib.FAS_SetIOOutput(outIO.BoardNo, 0, bitMask);
             }
             else
             {
                 bitMask = bitOnMask[outIO.Index];
-                result = EziMOTIONPlusELib.FAS_SetOutput( outIO.BoardNo, 0, bitMask );
+                result = EziMOTIONPlusELib.FAS_SetOutput(outIO.BoardNo, 0, bitMask);
             }
 
             return result;
         }
 
-        public int OutputOn( uint usIOAddr )
+        public int OutputOn(uint usIOAddr)
         {
             //var outIO = this._inPutIOList.Where( x => strIOAddr.Equals( x.Tag ) ).FirstOrDefault();
 
@@ -239,23 +248,23 @@ namespace VehicleControlSystem.ControlLayer.IO
             return 0;
         }
 
-        public int OutputOn( string outputTag )
+        public int OutputOn(string outputTag)
         {
             int result = 0;
 
-            var outIO = this._outPutIOList.Where( x => outputTag.Equals( x.Tag ) ).FirstOrDefault();
-            var boardType = this.BoardList.Where( x => x.BoardID == outIO.BoardNo ).FirstOrDefault().BoardType;
+            var outIO = this._outPutIOList.Where(x => outputTag.Equals(x.Tag)).FirstOrDefault();
+            var boardType = this.BoardList.Where(x => x.BoardID == outIO.BoardNo).FirstOrDefault().BoardType;
 
             uint bitMask = 0;
-            if( boardType == E_EzboardType.Servo )
+            if (boardType == E_EzboardType.Servo)
             {
                 bitMask = this.servoAmpOutputBitMask[outIO.Index];
-                result = EziMOTIONPlusELib.FAS_SetIOOutput( outIO.BoardNo, bitMask, 0 );
+                result = EziMOTIONPlusELib.FAS_SetIOOutput(outIO.BoardNo, bitMask, 0);
             }
             else
             {
                 bitMask = bitOnMask[outIO.Index];
-                result = EziMOTIONPlusELib.FAS_SetOutput( outIO.BoardNo, bitMask, 0 );
+                result = EziMOTIONPlusELib.FAS_SetOutput(outIO.BoardNo, bitMask, 0);
             }
 
             return result;
@@ -275,72 +284,73 @@ namespace VehicleControlSystem.ControlLayer.IO
         //    return 0;
         //}
 
-        public int OutputToggle( uint usIOAddr )
+        public int OutputToggle(uint usIOAddr)
         {
             throw new NotImplementedException();
         }
 
-        public int OutputToggle( string strIOAddr )
+        public int OutputToggle(string strIOAddr)
         {
             throw new NotImplementedException();
         }
 
-        public int PutByte( uint usIOAddr, byte pcValue )
+        public int PutByte(uint usIOAddr, byte pcValue)
         {
             throw new NotImplementedException();
         }
 
-        public int PutByte( string strIOAddr, byte pcValue )
+        public int PutByte(string strIOAddr, byte pcValue)
         {
             throw new NotImplementedException();
         }
 
-        public int PutWord( uint usIOAddr, short pwValue )
+        public int PutWord(uint usIOAddr, short pwValue)
         {
             throw new NotImplementedException();
         }
 
-        public int PutWord( string strIOAddr, short pwValue )
+        public int PutWord(string strIOAddr, short pwValue)
         {
             throw new NotImplementedException();
         }
 
+        #region Thread
         public void RunIOThread()
         {
             try
             {
                 ThreadStart();
             }
-            catch( Exception )
+            catch (Exception)
             {
             }
             finally
             {
             }
         }
-
         public void ThreadStart()
         {
             this.IsThreadAlive = true;
-            this._readThread = ThreadUtils.Invoke( IOThread );
-        }
+            this._readThread = ThreadUtils.Invoke(IOThread);
 
+            this.pullThread = ThreadUtils.Invoke(PullQueueThread);
+        }
         void IOThread()
         {
             var sTime = SwUtils.CurrentTimeMillis;
 
-            while( IsThreadAlive )
+            while (IsThreadAlive)
             {
-                Thread.Sleep( 5 );
+                Thread.Sleep(5);
                 try
                 {
-                    if( !IsConnetedAllBoard() )
+                    if (!IsConnetedAllBoard())
                     {
-                        if( !ConnectAllBoard() )
+                        if (!ConnectAllBoard())
                         {
                             IsConnectError = true;
                         }
-                        Thread.Sleep( 1000 );
+                        Thread.Sleep(1000);
                         continue;
                     }
                     IsConnectError = false;
@@ -350,21 +360,21 @@ namespace VehicleControlSystem.ControlLayer.IO
                     //Console.WriteLine( $"Read Time - { SwUtils.Elapsed( sTime ) } mm" );
                     //sTime = SwUtils.CurrentTimeMillis;
                 }
-                catch( Exception ex )
+                catch (Exception ex)
                 {
-                    logger.E( $"Exception [EzIO IORead Thread] - {ex.StackTrace}" );
+                    logger.E($"Exception [EzIO IORead Thread] - {ex.StackTrace}");
                 }
             }
         }
 
         void ReadBoardIO()
         {
-            foreach( var board in this.BoardList )
+            foreach (var board in this.BoardList)
             {
-                if( !IsConnetedBoard( board.BoardID ) )
+                if (!IsConnetedBoard(board.BoardID))
                     continue;
 
-                switch( board.BoardType )
+                switch (board.BoardType)
                 {
                     case E_EzboardType.Servo:
                         {
@@ -372,14 +382,24 @@ namespace VehicleControlSystem.ControlLayer.IO
                             int cmdPos = 0, actPos = 0, posErr = 0, actVel = 0;
                             ushort posItemNo = 0;
 
-                            if( EziMOTIONPlusELib.FAS_GetAllStatus( board.BoardID, ref axisDIn, ref axisDOut, ref axisStatus,
-                                ref cmdPos, ref actPos, ref posErr, ref actVel, ref posItemNo ) == EziMOTIONPlusELib.FMM_OK )
+                            if (EziMOTIONPlusELib.FAS_GetAllStatus(board.BoardID, ref axisDIn, ref axisDOut, ref axisStatus,
+                                ref cmdPos, ref actPos, ref posErr, ref actVel, ref posItemNo) == EziMOTIONPlusELib.FMM_OK)
                             {
-                                var input = this._inPutIOList.Where( x => x.BoardNo == board.BoardID ).DefaultIfEmpty().ToList();
-                                input.ForEach( i => { i.IsBitOn = Convert.ToBoolean( axisDIn & this.servoAmpInputBitOnMask[i.Index] ) ? true : false; } );
-
-                                var output = this._outPutIOList.Where( x => x.BoardNo == board.BoardID ).DefaultIfEmpty().ToList();
-                                output.ForEach( o => { o.IsBitOn = Convert.ToBoolean( axisDOut & this.servoAmpOutputBitMask[o.Index] ) ? true : false; } );
+                                var input = this._inPutIOList.Where(x => x.BoardNo == board.BoardID).DefaultIfEmpty().ToList();
+                                input.ForEach(i =>
+                               {
+                                   var isOn = Convert.ToBoolean(axisDIn & this.servoAmpInputBitOnMask[i.Index]) ? true : false;
+                                   if (i.IsBitOn != isOn) i.IsChanged = true;
+                                   i.IsBitOn = isOn;
+                               });
+
+                                var output = this._outPutIOList.Where(x => x.BoardNo == board.BoardID).DefaultIfEmpty().ToList();
+                                output.ForEach(o =>
+                               {
+                                   var isOn = Convert.ToBoolean(axisDOut & this.servoAmpOutputBitMask[o.Index]) ? true : false;
+                                   if (o.IsBitOn != isOn) o.IsChanged = true;
+                                   o.IsBitOn = isOn;
+                               });
                             }
                         }
                         break;
@@ -388,14 +408,19 @@ namespace VehicleControlSystem.ControlLayer.IO
                         {
                             uint inValue = 0, latchValue = 0;
                             int result = EziMOTIONPlusELib.FMM_OK;
-                            result = EziMOTIONPlusELib.FAS_GetInput( board.BoardID, ref inValue, ref latchValue );
-                            if( result == EziMOTIONPlusELib.FMM_OK )
+                            result = EziMOTIONPlusELib.FAS_GetInput(board.BoardID, ref inValue, ref latchValue);
+                            if (result == EziMOTIONPlusELib.FMM_OK)
                             {
-                                var input = this._inPutIOList.Where( x => x.BoardNo == board.BoardID ).DefaultIfEmpty().ToList();
-                                input.ForEach( i => { i.IsBitOn = Convert.ToBoolean( inValue & this.bitOnMask[i.Index] ) ? true : false; } );
+                                var input = this._inPutIOList.Where(x => x.BoardNo == board.BoardID).DefaultIfEmpty().ToList();
+                                input.ForEach(i =>
+                               {
+                                   var isOn = Convert.ToBoolean(inValue & this.bitOnMask[i.Index]) ? true : false;
+                                   if (i.IsBitOn != isOn) i.IsChanged = true;
+                                   i.IsBitOn = isOn;
+                               });
                             }
                             else
-                                logger.E( $"EzIO - [{board.BoardID}] Read Fail Error Code {result}" );
+                                logger.E($"EzIO - [{board.BoardID}] Read Fail Error Code {result}");
                         }
                         break;
 
@@ -403,14 +428,19 @@ namespace VehicleControlSystem.ControlLayer.IO
                         {
                             uint outValue = 0, outStatus = 0;
                             int result = EziMOTIONPlusELib.FMM_OK;
-                            result = EziMOTIONPlusELib.FAS_GetOutput( board.BoardID, ref outValue, ref outStatus );
-                            if( result == EziMOTIONPlusELib.FMM_OK )
+                            result = EziMOTIONPlusELib.FAS_GetOutput(board.BoardID, ref outValue, ref outStatus);
+                            if (result == EziMOTIONPlusELib.FMM_OK)
                             {
-                                var output = this._outPutIOList.Where( x => x.BoardNo == board.BoardID ).DefaultIfEmpty().ToList();
-                                output.ForEach( o => { o.IsBitOn = Convert.ToBoolean( outValue & this.bitOnMask[o.Index] ) ? true : false; } );
+                                var output = this._outPutIOList.Where(x => x.BoardNo == board.BoardID).DefaultIfEmpty().ToList();
+                                output.ForEach(o =>
+                               {
+                                   var isOn = Convert.ToBoolean(outValue & this.bitOnMask[o.Index]) ? true : false;
+                                   if (o.IsBitOn != isOn) o.IsChanged = true;
+                                   o.IsBitOn = isOn;
+                               });
                             }
                             else
-                                logger.E( $"EzIO - [{board.BoardID}] Read Fail Error Code {result}" );
+                                logger.E($"EzIO - [{board.BoardID}] Read Fail Error Code {result}");
                         }
                         break;
 
@@ -418,19 +448,77 @@ namespace VehicleControlSystem.ControlLayer.IO
                         break;
                 }
             }
+
+            FireChangedIO();
         }
 
-        bool IsConnetedBoard( int boardNo )
+        void FireChangedIO()
         {
-            return EziMOTIONPlusELib.FAS_IsSlaveExist( boardNo ) == 1;
+            this.InPutIOList.ForEach(i =>
+            {
+                if (i.IsChanged)
+                {
+                    i.IsChanged = false;
+                    var clone = ObjectCopyUtils.DeepClone<BitBlock>(i);
+                    this.qQ.Enqueue(new QoChangedIO { Arg0 = clone });
+                }
+            });
+
+            this.OutPutIOList.ForEach(o =>
+            {
+                if (o.IsChanged)
+                {
+                    o.IsChanged = false;
+                    var clone = ObjectCopyUtils.DeepClone<BitBlock>(o);
+                    this.qQ.Enqueue(new QoChangedIO { Arg0 = clone });
+                }
+            });
+        }
+
+        void PullQueueThread()
+        {
+            for (; ; )
+            {
+                try
+                {
+                    var o = qQ.Dequeue();
+
+                    if (o is QoConnected)
+                        DelegateUtils.Invoke(OnContd);
+                    else if (o is QoDiconnected)
+                        DelegateUtils.Invoke(OnDiscontd);
+                    else if (o is QoChangedIO)
+                        DelegateUtils.Invoke(OnChangedIO, o.Arg0);
+                    else if (o is QoWriteIO)
+                        DelegateUtils.Invoke(OnWriteIO, o.Arg0);
+                    else if (o is QoLog)
+                        DelegateUtils.Invoke(OnLog, o.Arg0, o.Arg1);
+                    else
+                        Assert.Fail("Unk Object {0}", o);
+                }
+                catch (ThreadAbortException) { }
+                catch (Exception e)
+                {
+                    logger.E(e);
+                }
+            }
+        }
+        #endregion
+
+        bool IsConnetedBoard(int boardNo)
+        {
+            return EziMOTIONPlusELib.FAS_IsSlaveExist(boardNo) == 1;
         }
 
         bool IsConnetedAllBoard()
         {
-            foreach( var b in this.BoardList )
+            foreach (var b in this.BoardList)
             {
-                if( !IsConnetedBoard( b.BoardID ) )
+                if (!IsConnetedBoard(b.BoardID))
+                {
+                    this.qQ.Clear();//연결이 끊어지면 내용을 삭제.
                     return false;
+                }
             }
 
             return true;
@@ -438,14 +526,14 @@ namespace VehicleControlSystem.ControlLayer.IO
 
         bool ConnectAllBoard()
         {
-            foreach( var b in this.BoardList )
+            foreach (var b in this.BoardList)
             {
-                if( IsConnetedBoard( b.BoardID ) )
+                if (IsConnetedBoard(b.BoardID))
                     continue;
 
-                if( EziMOTIONPlusELib.FAS_Connect( (byte)192, (byte)168, (byte)0, (byte)b.BoardID, b.BoardID ) != EziMOTIONPlusELib.FMM_OK )
+                if (EziMOTIONPlusELib.FAS_Connect((byte)192, (byte)168, (byte)0, (byte)b.BoardID, b.BoardID) != EziMOTIONPlusELib.FMM_OK)
                 {
-                    logger.E( $"EzIO - Connect Fail {b.BoardID}" );
+                    logger.E($"EzIO - Connect Fail {b.BoardID}");
                     return false;
                 }
             }
@@ -456,16 +544,16 @@ namespace VehicleControlSystem.ControlLayer.IO
         public int Terminate()
         {
             this.IsThreadAlive = false;
-            if( this._readThread != null && this._readThread.IsAlive )
+            if (this._readThread != null && this._readThread.IsAlive)
             {
-                if( !this._readThread.Join( 3000 ) )
+                if (!this._readThread.Join(3000))
                     this._readThread.Abort();
             }
 
-            this.BoardList.ForEach( b =>
-            {
-                EziMOTIONPlusELib.FAS_Close( b.BoardID );
-            } );
+            this.BoardList.ForEach(b =>
+           {
+               EziMOTIONPlusELib.FAS_Close(b.BoardID);
+           });
 
             return 0;
         }
@@ -475,7 +563,7 @@ namespace VehicleControlSystem.ControlLayer.IO
             throw new NotImplementedException();
         }
 
-        int GetModuleAndBitNoByAddress( uint usIOAddr, out int boardNo, out int bitNo )
+        int GetModuleAndBitNoByAddress(uint usIOAddr, out int boardNo, out int bitNo)
         {
             long nOffset = 0;
             long nCount = 0;
@@ -485,14 +573,14 @@ namespace VehicleControlSystem.ControlLayer.IO
             boardNo = 0;
             bitNo = 0;
 
-            if( usIOAddr < OUTPUT_ORIGIN )
+            if (usIOAddr < OUTPUT_ORIGIN)
             {
                 nOffset = usIOAddr - INPUT_ORIGIN;
-                for( int nModNo = 0; nModNo < this.BoardList.Count; nModNo++ )
+                for (int nModNo = 0; nModNo < this.BoardList.Count; nModNo++)
                 {
                     // Get Input CH Count Using Module ID
                     //AxdInfoGetInputCount( nModNo, nCount );
-                    if( nOffset - nCount < 0 )
+                    if (nOffset - nCount < 0)
                     {
                         boardNo = nModNo;
                         bitNo = (int)nOffset;
@@ -504,11 +592,11 @@ namespace VehicleControlSystem.ControlLayer.IO
             else
             {
                 nOffset = usIOAddr - OUTPUT_ORIGIN;
-                for( int nModNo = 0; nModNo < this.BoardList.Count; nModNo++ )
+                for (int nModNo = 0; nModNo < this.BoardList.Count; nModNo++)
                 {
                     // Get Output CH Count Using Module ID
                     //AxdInfoGetOutputCount( nModNo, nCount );
-                    if( nOffset - nCount < 0 )
+                    if (nOffset - nCount < 0)
                     {
                         boardNo = nModNo;
                         bitNo = (int)nOffset;
@@ -524,23 +612,25 @@ namespace VehicleControlSystem.ControlLayer.IO
         #region IDisposable Support
         private bool disposedValue = false; // 중복 호출을 검색하려면
 
-        protected virtual void Dispose( bool disposing )
+        protected virtual void Dispose(bool disposing)
         {
-            if( !disposedValue )
+            if (!disposedValue)
             {
-                if( disposing )
+                if (disposing)
                 {
                     // TODO: 관리되는 상태(관리되는 개체)를 삭제합니다.
-                    if( this._readThread != null )
+                    if (this._readThread != null)
                     {
                         this.IsThreadAlive = false;
-                        if( !this._readThread.Join( 3000 ) && this._readThread.IsAlive )
+                        if (!this._readThread.Join(3000) && this._readThread.IsAlive)
                         {
                             this._readThread.Abort();
                         }
                         this._readThread = null;
                     }
 
+                    ThreadUtils.Kill(this.pullThread);
+
                     Terminate(); //Board Close 
                 }
 
@@ -562,7 +652,7 @@ namespace VehicleControlSystem.ControlLayer.IO
         public void Dispose()
         {
             // 이 코드를 변경하지 마세요. 위의 Dispose(bool disposing)에 정리 코드를 입력하세요.
-            Dispose( true );
+            Dispose(true);
             // TODO: 위의 종료자가 재정의된 경우 다음 코드 줄의 주석 처리를 제거합니다.
             // GC.SuppressFinalize(this);
         }

+ 20 - 0
Dev/OHV/VehicleControlSystem/ControlLayer/IO/QueueObjects.cs

@@ -0,0 +1,20 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace VehicleControlSystem.ControlLayer.IO
+{
+    public abstract class QueueObject
+    {
+        public object Arg0 { get; set; }
+        public object Arg1 { get; set; }
+    }
+
+    public class QoConnected: QueueObject { }
+    public class QoDiconnected : QueueObject { }
+    public class QoChangedIO : QueueObject { }
+    public class QoWriteIO : QueueObject { }
+    public class QoLog : QueueObject { }
+}

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

@@ -11,6 +11,9 @@ using VehicleControlSystem.ControlLayer.IO;
 
 namespace VehicleControlSystem.Managers
 {
+    /// <summary>
+    /// Vehicle 전체 상태를 관리.
+    /// </summary>
     public class AutoManager : IDisposable
     {
         static Logger logger = Logger.GetLogger();
@@ -36,8 +39,6 @@ namespace VehicleControlSystem.Managers
             set { autoModeState = value; }
         }
 
-
-
         public AutoManager( IIO io )
         {
             this.iO = io;
@@ -45,6 +46,9 @@ namespace VehicleControlSystem.Managers
 
         public void Init()
         {
+            this.OperationModeProperty = eOperatationMode.ManualMode;
+            this.AutoModeStateProperty = eAutoModeState.Stop;
+
             this.isThreadAlive = true;
             this.threadWorker = ThreadUtils.Invoke(this.ThreadWork);
         }

+ 3 - 3
Dev/OHV/VehicleControlSystem/Managers/Scheduler.cs

@@ -42,9 +42,9 @@ namespace VehicleControlSystem.Managers
         {
             this.AddCommand(obj.Command);
 
-            var m = new GUIMessageEventArgs() { MessageText = obj.MessageText, MessageKey = obj.MessageKey };
-            m.Command = ObjectCopyUtils.DeepClone(obj.Command);
-            GUIMessagePublish(m);
+            //var m = new GUIMessageEventArgs() { MessageText = obj.MessageText, MessageKey = obj.MessageKey };
+            //m.Command = ObjectCopyUtils.DeepClone(obj.Command);
+            //GUIMessagePublish(m);
         }
 
         void GUIMessagePublish(GUIMessageEventArgs args)

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

@@ -29,6 +29,9 @@ namespace VehicleControlSystem
             this.eventAggregator = ea;
 
             this.eventAggregator.GetEvent<ApplicationExitEvent>().Subscribe((o) => Dispose(), true);
+
+            this.eventAggregator.GetEvent<VCSMessagePubSubEvent>().Unsubscribe(ReceivedMessageEvent);
+            this.eventAggregator.GetEvent<VCSMessagePubSubEvent>().Subscribe(this.ReceivedMessageEvent, ThreadOption.BackgroundThread);
         }
 
         public void Init()
@@ -38,6 +41,10 @@ namespace VehicleControlSystem
             var mapPath = Path.Combine(System.Environment.CurrentDirectory) + @"\Config\IO.xlsx";
             this.IO.LoadIOMap(mapPath);
             this.IO.RunIOThread();
+            var ezIO = this.IO as EzIO;
+            ezIO.OnContd += EzIO_OnContd;
+            ezIO.OnDiscontd += EzIO_OnDiscontd;
+            ezIO.OnChangedIO += EzIO_OnChangedIO;
 
             this.scheduler = new Scheduler(eventAggregator);
             this.scheduler.Init();
@@ -48,6 +55,43 @@ namespace VehicleControlSystem
             //SqlManager.Instance.RouteDal.Add(new Route {Id=1, Name="P01", PrePoint="P10", NextPoint="P02", Form=Route.eRoadForm.Straight, Type=Route.ePointType.Charging, ScaleValue=0.005, UserPIO=false });
         }
 
+        #region EzIO Event
+        private void EzIO_OnChangedIO(BitBlock bit)
+        {
+            this.eventAggregator.GetEvent<IOChangedPubSubEvent>().Publish(new IOChangedMessageEventArgs { Args = bit });
+        }
+        private void EzIO_OnDiscontd(string ID)
+        {
+            //throw new NotImplementedException();
+        }
+        private void EzIO_OnContd(string ID)
+        {
+            //throw new NotImplementedException();
+        }
+        #endregion
+
+        void ReceivedMessageEvent(VCSMessageEventArgs msg)
+        {
+            switch (msg.Kind)
+            {
+                case VCSMessageEventArgs.eVCSMessageKind.ReqIOObject:
+                    RspIOObjectMessage();
+                    break;
+                case VCSMessageEventArgs.eVCSMessageKind.ReqIOMapList:
+                    break;
+                default:
+                    break;
+            }
+        }
+
+        #region RspMessage Method
+        void RspIOObjectMessage()
+        {
+            var rspMsg = new GUIMessageEventArgs(GUIMessageEventArgs.eGUIMessageKind.RspIOObject, this.IO );
+            this.eventAggregator.GetEvent<GUIMessagePubSubEvent>().Publish(rspMsg);
+        }
+        #endregion
+
         public void Dispose()
         {
             this.scheduler.Dispose();

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

@@ -70,12 +70,14 @@
   </ItemGroup>
   <ItemGroup>
     <Compile Include="ControlLayer\IO\BitBlock.cs" />
+    <Compile Include="ControlLayer\IO\Delegates.cs" />
     <Compile Include="ControlLayer\IO\EzBoard.cs" />
     <Compile Include="ControlLayer\IO\EzIO.cs" />
     <Compile Include="ControlLayer\IO\IIO.cs" />
     <Compile Include="ControlLayer\IO\Lib\LIB_EziMOTIONPlusE.cs" />
     <Compile Include="ControlLayer\IO\Lib\MOTION_DEFINE_PlusE.cs" />
     <Compile Include="ControlLayer\IO\Lib\MOTION_EziSERVO2_DEFINE.cs" />
+    <Compile Include="ControlLayer\IO\QueueObjects.cs" />
     <Compile Include="ControlLayer\Vehicle.cs" />
     <Compile Include="Managers\AutoManager.cs" />
     <Compile Include="Managers\Scheduler.cs" />