Administrator
2021-03-15 b290be9dde1492fa276649d4eb7acbb5c5f24e55
1.新增配置文件来修改镜头R边;
2.新增背板区分可视区和非可视区。
33个文件已添加
3个文件已修改
4091 ■■■■■ 已修改文件
Bro.Comn/AbstractFSM/State.cs 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Bro.Comn/AbstractFSM/StatesManager.cs 63 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Bro.Comn/AbstractFSM/Transition.cs 116 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Bro.Comn/Bro.Comn.csproj 128 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Bro.Comn/Except/ExceptionBase.cs 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Bro.Comn/FSM/SimpleFSM.cs 98 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Bro.Comn/Link/LinkBase.cs 106 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Bro.Comn/Link/SerialLink.cs 154 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Bro.Comn/Link/SerialPort.cs 449 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Bro.Comn/Link/TCPClient.cs 237 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Bro.Comn/Link/TCPLink.cs 126 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Bro.Comn/Link/TCPSvr.cs 321 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Bro.Comn/OEE/OEEToolKit.cs 242 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Bro.Comn/Procedure/IODataBase.cs 200 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Bro.Comn/Procedure/ProcedureBase.cs 475 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Bro.Comn/Procedure/ProcedureIO.cs 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Bro.Comn/Procedure/UnitBase.cs 140 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Bro.Comn/Properties/AssemblyInfo.cs 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Bro.Comn/Properties/Resource.Designer.cs 85 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Bro.Comn/Properties/Resource.resx 124 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Bro.Comn/PubSub/IPubSubCenter.cs 63 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Bro.Comn/PubSub/IPublisher.cs 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Bro.Comn/PubSub/ISubscriber.cs 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Bro.Comn/PubSub/PubSubCenter.cs 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Bro.Comn/PubSub/SimplePubSubCenter.cs 391 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Bro.Comn/PubSub/SimpleSubscriber.cs 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Bro.Comn/Util/ConfigHelper.cs 110 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Bro.Comn/Util/LoginConfig.cs 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Bro.Comn/packages.config 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
P066.Data.sln 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
P066.Data/Form1.cs 141 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
P066.Data/P066.Data.csproj 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
P066.Data/P066RunParam.cs 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
P066.Data/P066RunPaream.cs 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
P066XML/Jin_Mid - 副本.xml 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
P066XML/Jin_Mid.xml 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Bro.Comn/AbstractFSM/State.cs
New file
@@ -0,0 +1,32 @@
using System;
namespace Bro.Common.AbstractFSM
{
    public class StateEventArgs : EventArgs
    {
        public StateEventArgs(int id)
        {
            m_id = id;
        }
        private int m_id;
        public int Id
        {
            get { return m_id; }
        }
    }
    public class State
    {
        private String m_sState = null;
        public State(string sState)
        {
            m_sState = sState;
        }
        protected virtual void ChangeState(object sender, StateEventArgs eventArgs) {}
        public override string ToString()
        {
            return m_sState;
        }
    }
}
Bro.Comn/AbstractFSM/StatesManager.cs
New file
@@ -0,0 +1,63 @@
using System;
namespace Bro.Common.AbstractFSM
{
    public interface IStateManager : IDisposable
    {
        void ChangeState(object sender, StateEventArgs eventArgs);
        bool CheckState(object sender, StateEventArgs eventArgs);
    }
    public abstract class StatesManager : IStateManager
    {
        // Declare the delegate (if using non-generic pattern).
        public delegate void StateChangedEventHandler(object sender, StateEventArgs eventArgs);
        // Declare the event.
        public event StateChangedEventHandler StateChanged;
        public StatesManager()
        {
            //build transitions and set an initial state
            m_activeState = BuildTransitionsTable();
        }
        public virtual void Dispose()
        {
            //virtual method
        }
        State m_activeState = null;
        public State ActiveState
        {
            get { return m_activeState; }
        }
        Transitions m_transitions = new Transitions();
        public Transitions Transitions
        {
            get { return m_transitions; }
        }
        //returns initial state
        protected abstract State BuildTransitionsTable();
        //
        public virtual void ChangeState(object sender, StateEventArgs eventArgs)
        {
            Transition transition = m_transitions[m_activeState, eventArgs];
            m_activeState = transition.finalState;
            //raise 'StateChanged' event
             if (StateChanged != null)
                 StateChanged(this, eventArgs);
            if (transition.action != null)
                transition.action(this, eventArgs);
            //if the transitional is automatic - automatically go to the next state:
            if (transition.AutoMode == true && transition.AutoTransition != null)
            {
                m_activeState = transition.AutoTransition.initialState;
                ChangeState(sender, transition.AutoTransition.eventArgs);
            }
        }
        public virtual bool CheckState(object sender, StateEventArgs eventArgs)
        {
            return m_transitions.ContainsKey(Transition.GetHashCode(m_activeState, eventArgs));
        }
    }
}
Bro.Comn/AbstractFSM/Transition.cs
New file
@@ -0,0 +1,116 @@
using System;
using System.Collections.Generic;
namespace Bro.Common.AbstractFSM
{
    //actions that are performed when state changed
    public delegate void StateAction(object sender, StateEventArgs eventArgs);
    public class Transition
    {
        private State m_initialState;
        public State initialState
        {
            get { return m_initialState; }
        }
        private StateEventArgs m_eventArgs;
        public StateEventArgs eventArgs
        {
            get { return m_eventArgs; }
        }
        private State m_finalState;
        public State finalState
        {
            get { return m_finalState; }
        }
        private StateAction m_state_action;
        public StateAction action
        {
            get { return m_state_action; }
        }
        private bool m_autoMode = false;
        public bool AutoMode
        {
            get { return m_autoMode; }
        }
        private Transition m_autoTransition = null;
        public Transition AutoTransition
        {
            get { return m_autoTransition; }
        }
        public Transition(State initialState, StateEventArgs sevent, State finalState, StateAction action)
        {
            m_initialState = initialState;
            m_eventArgs = sevent;
            m_finalState = finalState;
            m_state_action = action;
        }
        public Transition(State initialState, StateEventArgs sevent, State finalState, StateAction action, bool autoMode, Transition autoTransition)
                         : this(initialState, sevent, finalState, action)
        {
            m_autoMode = autoMode;
            m_autoTransition = autoTransition;
        }
        public override int GetHashCode()
        {
            //create a unique transition key
            return GetHashCode(m_initialState, m_eventArgs);
        }
        public static int GetHashCode(State state, StateEventArgs sevent)
        {
            return (state.GetHashCode() << 8) + sevent.Id;
        }
    }
    /// <summary>
    /// Represents a collection of transition objects.
    /// </summary>
    public class Transitions : System.Collections.Generic.Dictionary <int, Transition>
    {
        /// <summary>Adds the specified transition to the collection.</summary>
        /// <param name="transition">Transition object</param>
        /// <see cref="System.Collections.Generic.Dictionary {int, Transition}"/>
        /// <exception cref="System.ArgumentNullException">Key is null</exception>
        /// <exception cref="System.ArgumentException">An transition with the same key already exists.</exception>
        public void Add(Transition transition)
        {
            // The Add method throws an exception if the new key is already in the dictionary.
            try
            {
                base.Add(transition.GetHashCode(), transition);
            }
            catch (ArgumentException)
            {
                throw new ArgumentException("A transition with the key (Initials state " +
                        transition.initialState + ", Event " +
                        transition.eventArgs + ") already exists.");
            }
        }
        //
        public Transition this[State state, StateEventArgs sevent]
        {
            get
            {
                try
                {
                    return this[Transition.GetHashCode(state, sevent)];
                }
                catch(KeyNotFoundException)
                {
                    throw new KeyNotFoundException("The given transition was not found.");
                }
            }
            set
            {
                this[Transition.GetHashCode(state, sevent)] = value;
            }
        }
        //
        public bool Remove(State state, StateEventArgs sevent)
        {
            return base.Remove(Transition.GetHashCode(state, sevent));
        }
    }
}
Bro.Comn/Bro.Comn.csproj
New file
@@ -0,0 +1,128 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" 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>{42407C78-FB75-4310-8910-DF515652A012}</ProjectGuid>
    <OutputType>Library</OutputType>
    <AppDesignerFolder>Properties</AppDesignerFolder>
    <RootNamespace>Broc.Comn</RootNamespace>
    <AssemblyName>Broc.Comn</AssemblyName>
    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
    <FileAlignment>512</FileAlignment>
  </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>
    <PlatformTarget>AnyCPU</PlatformTarget>
  </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>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
    <DebugSymbols>true</DebugSymbols>
    <OutputPath>bin\x86\Debug\</OutputPath>
    <DefineConstants>DEBUG;TRACE</DefineConstants>
    <DebugType>full</DebugType>
    <PlatformTarget>x86</PlatformTarget>
    <ErrorReport>prompt</ErrorReport>
    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
    <OutputPath>bin\x86\Release\</OutputPath>
    <DefineConstants>TRACE</DefineConstants>
    <Optimize>true</Optimize>
    <DebugType>pdbonly</DebugType>
    <PlatformTarget>x86</PlatformTarget>
    <ErrorReport>prompt</ErrorReport>
    <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
  </PropertyGroup>
  <ItemGroup>
    <Reference Include="log4net, Version=2.0.8.0, Culture=neutral, PublicKeyToken=669e0ddf0bb1aa2a, processorArchitecture=MSIL">
      <HintPath>..\packages\log4net.2.0.8\lib\net45-full\log4net.dll</HintPath>
    </Reference>
    <Reference Include="System" />
    <Reference Include="System.Configuration" />
    <Reference Include="System.Core" />
    <Reference Include="System.Drawing" />
    <Reference Include="System.Web" />
    <Reference Include="System.Windows.Forms" />
    <Reference Include="System.Xml.Linq" />
    <Reference Include="System.Data.DataSetExtensions" />
    <Reference Include="Microsoft.CSharp" />
    <Reference Include="System.Data" />
    <Reference Include="System.Xml" />
  </ItemGroup>
  <ItemGroup>
    <Compile Include="AbstractFSM\State.cs" />
    <Compile Include="AbstractFSM\StatesManager.cs" />
    <Compile Include="AbstractFSM\Transition.cs" />
    <Compile Include="Except\ExceptionBase.cs" />
    <Compile Include="FSM\SimpleFSM.cs" />
    <Compile Include="Link\LinkBase.cs" />
    <Compile Include="Link\SerialLink.cs" />
    <Compile Include="Link\SerialPort.cs" />
    <Compile Include="Link\TCPClient.cs" />
    <Compile Include="Link\TCPLink.cs" />
    <Compile Include="Link\TCPSvr.cs" />
    <Compile Include="Log\LogHelper.cs" />
    <Compile Include="Log\LogTraceListener.cs" />
    <Compile Include="OEE\OEEToolKit.cs" />
    <Compile Include="Procedure\IODataBase.cs" />
    <Compile Include="Procedure\ProcedureBase.cs" />
    <Compile Include="Procedure\ProcedureIO.cs" />
    <Compile Include="Procedure\UnitBase.cs" />
    <Compile Include="Properties\AssemblyInfo.cs" />
    <Compile Include="PubSub\IPublisher.cs" />
    <Compile Include="PubSub\ISubscriber.cs" />
    <Compile Include="PubSub\IPubSubCenter.cs" />
    <Compile Include="PubSub\PubSubCenter.cs" />
    <Compile Include="PubSub\SimplePubSubCenter.cs" />
    <Compile Include="PubSub\SimpleSubscriber.cs" />
    <Compile Include="Properties\Resource.Designer.cs">
      <AutoGen>True</AutoGen>
      <DesignTime>True</DesignTime>
      <DependentUpon>Resource.resx</DependentUpon>
    </Compile>
    <Compile Include="Util\ConfigHelper.cs" />
    <Compile Include="Util\LoginConfig.cs" />
  </ItemGroup>
  <ItemGroup>
    <EmbeddedResource Include="Properties\Resource.resx">
      <Generator>ResXFileCodeGenerator</Generator>
      <LastGenOutput>Resource.Designer.cs</LastGenOutput>
    </EmbeddedResource>
  </ItemGroup>
  <ItemGroup>
    <EmbeddedResource Include="Log\BroClog4net.xml">
      <SubType>Designer</SubType>
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </EmbeddedResource>
  </ItemGroup>
  <ItemGroup>
    <None Include="packages.config" />
  </ItemGroup>
  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
  <PropertyGroup>
    <PostBuildEvent>
    </PostBuildEvent>
  </PropertyGroup>
  <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
       Other similar extension points exist, see Microsoft.Common.targets.
  <Target Name="BeforeBuild">
  </Target>
  <Target Name="AfterBuild">
  </Target>
  -->
</Project>
Bro.Comn/Except/ExceptionBase.cs
New file
@@ -0,0 +1,11 @@
using System;
namespace Bro.Common.AbstractFSM
{
    /// <summary>
    /// å¼‚常基类
    /// </summary>
    public class ExceptionBase : Exception
    {
    }
}
Bro.Comn/FSM/SimpleFSM.cs
New file
@@ -0,0 +1,98 @@
using System.Collections.Generic;
namespace Bro.Common.FSM
{
    // çŠ¶æ€å¤„ç†ä»£ç†å®šä¹‰
    public delegate void StatHandler();
    public class SimpleFSM
    {
        // çŠ¶æ€æœºæè¿°
        public string   Desp { get;set; }
        // å½“前状态
        private int     curStat { get;set;}
        // çŠ¶æ€åŠ¨ä½œè¡¨
        private Dictionary<int, StatHandler> statTbl = new Dictionary<int,StatHandler>();
        public SimpleFSM()
        {
        }
        /// <summary>
        /// æ³¨å†ŒçŠ¶æ€å¤„ç†
        /// </summary>
        /// <param name="stat"></param>
        /// <param name="handle"></param>
        /// <returns></returns>
        public bool Regist(int stat, StatHandler handle)
        {
            if ( null == handle || statTbl.ContainsKey(stat) )
            {
                return false;
            }
            statTbl.Add(stat, handle);
            return true;
        }
        /// <summary>
        /// æ³¨å†ŒçŠ¶æ€å¤„ç†è¡¨
        /// </summary>
        /// <param name="statTbl"></param>
        /// <returns></returns>
        public bool Regist(Dictionary<int, StatHandler> statTbl)
        {
            this.statTbl = statTbl;
            return true;
        }
        /// <summary>
        /// è®¾ç½®å½“前状态
        /// </summary>
        /// <param name="stat"></param>
        public void SetStat(int stat)
        {
            this.curStat = stat;
        }
        /// <summary>
        /// èŽ·å–å½“å‰çŠ¶æ€
        /// </summary>
        /// <returns></returns>
        public int GetStat()
        {
            return curStat;
        }
        /// <summary>
        /// çŠ¶æ€åŸºè¿è¡Œ
        /// </summary>
        public void Run()
        {
            for (; ; )
            {
                foreach (var item in statTbl)
                {
                    StatHandler handle = item.Value;
                    if (null == handle)
                    {
                        continue;
                    }
                    if (curStat == item.Key)
                    {
                        handle();
                        break;
                    }
                }
            }
        }
    }
}
Bro.Comn/Link/LinkBase.cs
New file
@@ -0,0 +1,106 @@
using System;
using System.Diagnostics;
namespace Bro.Common.Link
{
    /// <summary>
    /// è®¾å¤‡çš„连接基类
    /// </summary>
    public abstract class LinkBase
    {
        // é»˜è®¤ä¿å­˜æ•°æ®ç¼“存长度
        public const int        DFT_BUFF_LEN    = 4096;
        // è¿žæŽ¥å¯¹è±¡æŽ¥æ”¶ç¼“存大小
        public const int        DFT_SEND_BUFF_LEN   = 4096;
        // è¿žæŽ¥å¯¹è±¡å‘送缓存大小
        public const int        DFT_RECV_BUFF_LEN   = 4096;
        // è¿žæŽ¥æè¿°
        public string   Desp { get;set;}
        // åˆå§‹åŒ–状态
        public bool     IsInit { get;set; }
        // è¿žæŽ¥çŠ¶æ€
        public bool     IsConn { get;set;}
        // æŽ¥æ”¶ç¼“存长度
        public int      BufferLen { get;set;}
        // æŽ¥æ”¶ç¼“存大小
        public int      SendBuffLen { get;set;}
        // å‘送缓存大小
        public int      RecvBuffLen { get;set;}
        // æŽ¥æ”¶ç¼“å­˜
        protected byte[] rcvBuf = null;
        // è¿žæŽ¥çŠ¶æ€
        public LinkBase()
        {
            Desp        = this.GetType().Name;
            IsInit      = false;
            IsConn      = false;
            SendBuffLen = DFT_SEND_BUFF_LEN;
            RecvBuffLen = DFT_RECV_BUFF_LEN;
            BufferLen   = DFT_BUFF_LEN;
        }
        /// <summary>
        /// è¿žæŽ¥åˆå§‹åŒ–
        /// </summary>
        /// <returns></returns>
        public virtual bool Init()
        {
            if ( IsInit )
            {
                return true;
            }
            try
            {
                rcvBuf = new byte[BufferLen];
                return true;
            }
            catch(Exception ex)
            {
                Trace.TraceError("Link:{0} Init fail, ex:{1}-{2}", this.Desp, ex.Message, ex.StackTrace);
            }
            return false;
        }
        /// <summary>
        /// æ‰“开连接
        /// </summary>
        /// <returns></returns>
        public abstract bool Open();
        /// <summary>
        /// å…³é—­è¿žæŽ¥
        /// </summary>
        public abstract void Close();
        /// <summary>
        /// é”€æ¯
        /// </summary>
        public abstract void Fnit();
        /// <summary>
        /// æŽ¥æ”¶æ•°æ®
        /// </summary>
        /// <param name="rcvBuf"></param>
        /// <param name="offset"></param>
        /// <returns></returns>
        public abstract int Recv(byte[] rcvBuf, int offset);
        /// <summary>
        /// å‘送数据
        /// </summary>
        /// <param name="sndBuf"></param>
        /// <returns></returns>
        public abstract bool Send(byte[] sndBuf, int offset, int len);
    }
}
Bro.Comn/Link/SerialLink.cs
New file
@@ -0,0 +1,154 @@
using System;
using System.Diagnostics;
using System.IO.Ports;
namespace Bro.Common.Link
{
    /// <summary>
    /// ä¸²å£è¿žæŽ¥
    /// </summary>
    public class SerialLink : LinkBase
    {
        // é»˜è®¤ä¸²å£å·
        public const int        DFT_PORT        = 1;
        // é»˜è®¤æ³¢ç‰¹çއ
        public const int        DFT_BAUD_RATE   = 9600;
        // ä¸²å£å·
        public int  Port { get;set;}
        // æ³¢ç‰¹çއ
        public int  BaudRate { get;set;}
        // ä¸²å£è¿žæŽ¥
        private SerialPort  SerialPort = new SerialPort();
        public SerialLink()
        {
            IsConn       = false;
            Port        = DFT_PORT;
            BaudRate    = DFT_BAUD_RATE;
        }
        /// <summary>
        /// æ‰“开串口连接
        /// </summary>
        /// <returns></returns>
        public override bool Open()
        {
            if ( SerialPort.IsOpen )
            {
                return true;
            }
            try
            {
                SerialPort.PortName         = "COM" + this.Port;
                SerialPort.BaudRate         = this.BaudRate;
                SerialPort.WriteBufferSize  = this.SendBuffLen;
                SerialPort.ReadBufferSize   = this.RecvBuffLen;
                SerialPort.Open();
                base.IsConn = true;
                return true;
            }
            catch(Exception ex)
            {
                Trace.TraceError("SerialLink:{0} Open fail, ex:{1}-{2}", this.Desp, ex.Message, ex.StackTrace);
            }
            return false;
        }
        /// <summary>
        /// å…³é—­ä¸²å£è¿žæŽ¥
        /// </summary>
        public override void Close()
        {
            try
            {
                if ( !SerialPort.IsOpen )
                {
                    return;
                }
                SerialPort.Close();
            }
            catch(Exception ex)
            {
                Trace.TraceError("SerialLink:{0} Close fail, ex:{1}-{2}", this.Desp, ex.Message, ex.StackTrace);
            }
        }
        /// <summary>
        /// é”€æ¯
        /// </summary>
        public override void Fnit()
        {
            Close();
        }
        /// <summary>
        /// æŽ¥æ”¶æ•°æ®
        /// </summary>
        /// <param name="rcvBuf"></param>
        /// <param name="bufLen"></param>
        /// <returns></returns>
        public override int Recv(byte[] rcvBuf, int offset)
        {
            int rcvLen = -1;
            if ( null == rcvBuf )
            {
                return -1;
            }
            try
            {
                var len = rcvBuf.Length - offset;
                if ( len <= 0 )
                {
                    return -1;
                }
                rcvLen = SerialPort.Read(rcvBuf, offset, len);
            }
            catch(Exception ex)
            {
                Trace.TraceError("SerialLink:{0} Recv fail, ex:{1}-{2}", this.Desp, ex.Message, ex.StackTrace);
            }
            return rcvLen;
        }
        /// <summary>
        /// å‘送数据
        /// </summary>
        /// <param name="sndBuf"></param>
        /// <param name="offset"></param>
        /// <returns></returns>
        public override bool Send(byte[] sndBuf, int offset, int len)
        {
            if ( null == sndBuf )
            {
                return false;
            }
            try
            {
                SerialPort.Write(sndBuf, offset, len);
                return true;
            }
            catch(Exception ex)
            {
                Trace.TraceError("SerialLink:{0} Send fail, ex:{1}-{2}", this.Desp, ex.Message, ex.StackTrace);
            }
            return false;
        }
    }
}
Bro.Comn/Link/SerialPort.cs
New file
@@ -0,0 +1,449 @@
using System;
using System.Text;
//using System.Threading.Tasks;
using System.IO.Ports;
using System.Windows.Forms;
using System.Diagnostics;
namespace Bro.Common.Link
{
    public class SerialComPort //: LinkBase
    {
        /// æŽ¥æ”¶äº‹ä»¶æ˜¯å¦æœ‰æ•ˆ false表示有效
        public bool ReceiveEventFlag = false;
        /// ç»“束符比特
        public byte EndByte = 0x23;//string End = "#";
        /// å®Œæ•´åè®®çš„记录处理事件
        public event DataReceivedEventHandler DataReceived;
        public event SerialErrorReceivedEventHandler Error;
        #region å˜é‡å±žæ€§
        private string _portName = "COM1";//串口号,默认COM1
        private SerialPortBaudRates _baudRate = SerialPortBaudRates.BaudRate_9600;//波特率
        private Parity _parity = Parity.None;//校验位
        private StopBits _stopBits = StopBits.One;//停止位
        private SerialPortDatabits _dataBits = SerialPortDatabits.EightBits;//数据位
        public SerialPort comPort = new SerialPort();
        /// ä¸²å£å·
        public string PortName
        {
            get { return _portName; }
            set { _portName = value; comPort.PortName = _portName; }
        }
        /// æ³¢ç‰¹çއ
        public SerialPortBaudRates BaudRate
        {
            get { return _baudRate; }
            set { _baudRate = value; comPort.BaudRate = (int)_baudRate; }
        }
        /// å¥‡å¶æ ¡éªŒä½
        public Parity Parity
        {
            get { return _parity; }
            set { _parity = value; comPort.Parity = _parity; }
        }
        /// æ•°æ®ä½
        public SerialPortDatabits DataBits
        {
            get { return _dataBits; }
            set { _dataBits = value; comPort.DataBits = (int)_dataBits; }
        }
        /// åœæ­¢ä½
        public StopBits StopBits
        {
            get { return _stopBits; }
            set { _stopBits = value; comPort.StopBits = _stopBits; }
        }
        #endregion
        #region æž„造函数
        /// å‚数构造函数(使用枚举参数构造)
        /// <param name="baud">波特率</param>
        /// <param name="par">奇偶校验位</param>
        /// <param name="sBits">停止位</param>
        /// <param name="dBits">数据位</param>
        /// <param name="name">串口号</param>
        public SerialComPort(string name, SerialPortBaudRates baud, Parity par, SerialPortDatabits dBits, StopBits sBits)
        {
            _portName = name;
            _baudRate = baud;
            _parity = par;
            _dataBits = dBits;
            _stopBits = sBits;
            comPort.DataReceived += new SerialDataReceivedEventHandler(comPort_DataReceived);
            comPort.ErrorReceived += new SerialErrorReceivedEventHandler(comPort_ErrorReceived);
        }
        /// å‚数构造函数(使用字符串参数构造)
        /// <param name="baud">波特率</param>
        /// <param name="par">奇偶校验位</param>
        /// <param name="sBits">停止位</param>
        /// <param name="dBits">数据位</param>
        /// <param name="name">串口号</param>
        public SerialComPort(string name, string baud, string par, string dBits, string sBits)
        {
            _portName = name;
            _baudRate = (SerialPortBaudRates)Enum.Parse(typeof(SerialPortBaudRates), baud);
            _parity = (Parity)Enum.Parse(typeof(Parity), par);
            _dataBits = (SerialPortDatabits)Enum.Parse(typeof(SerialPortDatabits), dBits);
            _stopBits = (StopBits)Enum.Parse(typeof(StopBits), sBits);
            comPort.DataReceived += new SerialDataReceivedEventHandler(comPort_DataReceived);
            comPort.ErrorReceived += new SerialErrorReceivedEventHandler(comPort_ErrorReceived);
        }
        /// é»˜è®¤æž„造函数
        public SerialComPort()
        {
            _portName = "COM1";
            _baudRate = SerialPortBaudRates.BaudRate_9600;
            _parity = Parity.None;
            _dataBits = SerialPortDatabits.EightBits;
            _stopBits = StopBits.One;
            comPort.DataReceived += new SerialDataReceivedEventHandler(comPort_DataReceived);
            comPort.ErrorReceived += new SerialErrorReceivedEventHandler(comPort_ErrorReceived);
        }
        #endregion
        /// ç«¯å£æ˜¯å¦å·²ç»æ‰“å¼€
        public bool IsOpen
        {
            get
            {
                return comPort.IsOpen;
            }
        }
        /// æ‰“开端口
        public void OpenPort()
        {
            if (comPort.IsOpen) comPort.Close();
            comPort.PortName = _portName;
            comPort.BaudRate = (int)_baudRate;
            comPort.Parity = _parity;
            comPort.DataBits = (int)_dataBits;
            comPort.StopBits = _stopBits;
            try
            {
                comPort.Open();
            }
            catch (System.Exception ex)
            {
                MessageBox.Show(ex.Message, "提示信息", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }
        /// å…³é—­ç«¯å£
        public void ClosePort()
        {
            if (comPort.IsOpen) comPort.Close();
        }
        /// ä¸¢å¼ƒæ¥è‡ªä¸²è¡Œé©±åŠ¨ç¨‹åºçš„æŽ¥æ”¶å’Œå‘é€ç¼“å†²åŒºçš„æ•°æ®
        public void DiscardBuffer()
        {
            comPort.DiscardInBuffer();
            comPort.DiscardOutBuffer();
        }
        /// <summary>
        /// æ•°æ®æŽ¥æ”¶å¤„理
        /// </summary>
        void comPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            byte[] receviedBuf;
            receviedBuf = new byte[comPort.BytesToRead];
            int itemp = comPort.BytesToRead;
            int rcvByteLen = 0;
            try
            {
                for (int i = 0; i < itemp; i++)
                {
                    receviedBuf[i] = Convert.ToByte(comPort.ReadByte());
                    rcvByteLen++;
                }
                if (receviedBuf != null)
                {
                    DataReceived(new DataReceivedEventArgs(Encoding.ASCII.GetString(receviedBuf)));
                }
            }
            catch (System.Exception ex)
            {
                Trace.TraceError("SerialPort receive fail,ex:{0}", ex);
            }
        }
        /// é”™è¯¯å¤„理函数
        void comPort_ErrorReceived(object sender, SerialErrorReceivedEventArgs e)
        {
            if (Error != null)
            {
                Error(sender, e);
            }
        }
        #region æ•°æ®å†™å…¥æ“ä½œ
        /// å†™å…¥æ•°æ®
        /// <param name="msg"></param>
        public void WriteData(string msg)
        {
            //if (!(comPort.IsOpen)) comPort.Open();
            try
            {
                comPort.Write(msg);
            }
            catch (System.Exception ex)
            {
                Trace.TraceError("SerialPort write data fail,ex:{0}", ex);
            }
        }
        /// <summary>
        /// å†™å…¥æ•°æ®
        /// </summary>
        /// <param name="msg">写入端口的字节数组</param>
        public void WriteData(byte[] msg)
        {
            //if (!(comPort.IsOpen)) comPort.Open();
            try
            {
                comPort.Write(msg, 0, msg.Length);
            }
            catch (System.Exception ex)
            {
                Trace.TraceError("SerialPort write data fail,ex:{0}", ex);
            }
        }
        /// <summary>
        /// å†™å…¥æ•°æ®
        /// </summary>
        /// <param name="msg">包含要写入端口的字节数组</param>
        /// <param name="offset">参数从0字节开始的字节偏移量</param>
        /// <param name="count">要写入的字节数</param>
        public void WriteData(byte[] msg, int offset, int count)
        {
            //if (!(comPort.IsOpen)) comPort.Open();
            try
            {
                comPort.Write(msg, offset, count);
            }
            catch (System.Exception ex)
            {
                Trace.TraceError("SerialPort write data fail,ex:{0}", ex);
            }
        }
        /// <summary>
        /// å‘送串口命令
        /// </summary>
        /// <param name="SendData">发送数据</param>
        /// <param name="ReceiveData">接收数据</param>
        /// <param name="Overtime">重复次数</param>
        /// <returns></returns>
        public int SendCommand(byte[] SendData, ref  byte[] ReceiveData, int Overtime)
        {
            if (!(comPort.IsOpen)) comPort.Open();
            ReceiveEventFlag = true;        //关闭接收事件
            comPort.DiscardInBuffer();      //清空接收缓冲区
            comPort.Write(SendData, 0, SendData.Length);
            int num = 0, ret = 0;
            while (num++ < Overtime)
            {
                if (comPort.BytesToRead >= ReceiveData.Length) break;
                System.Threading.Thread.Sleep(1);
            }
            if (comPort.BytesToRead >= ReceiveData.Length)
            {
                ret = comPort.Read(ReceiveData, 0, ReceiveData.Length);
            }
            ReceiveEventFlag = false;       //打开事件
            return ret;
        }
        #endregion
        #region å¸¸ç”¨çš„列表数据获取和绑定操作
        /// <summary>
        /// å°è£…获取串口号列表
        /// </summary>
        /// <returns></returns>
        public static string[] GetPortNames()
        {
            return SerialPort.GetPortNames();
        }
        /// <summary>
        /// è®¾ç½®ä¸²å£å·
        /// </summary>
        /// <param name="obj"></param>
        public static void SetPortNameValues(ComboBox obj)
        {
            obj.Items.Clear();
            foreach (string str in SerialPort.GetPortNames())
            {
                obj.Items.Add(str);
            }
        }
        /// <summary>
        /// è®¾ç½®æ³¢ç‰¹çއ
        /// </summary>
        public static void SetBauRateValues(ComboBox obj)
        {
            obj.Items.Clear();
            foreach (SerialPortBaudRates rate in Enum.GetValues(typeof(SerialPortBaudRates)))
            {
                obj.Items.Add(((int)rate).ToString());
            }
        }
        /// <summary>
        /// è®¾ç½®æ•°æ®ä½
        /// </summary>
        public static void SetDataBitsValues(ComboBox obj)
        {
            obj.Items.Clear();
            foreach (SerialPortDatabits databit in Enum.GetValues(typeof(SerialPortDatabits)))
            {
                obj.Items.Add(((int)databit).ToString());
            }
        }
        /// <summary>
        /// è®¾ç½®æ ¡éªŒä½åˆ—表
        /// </summary>
        public static  void SetParityValues(ComboBox obj)
        {
            obj.Items.Clear();
            foreach (string str in Enum.GetNames(typeof(Parity)))
            {
                obj.Items.Add(str);
            }
        }
        /// <summary>
        /// è®¾ç½®åœæ­¢ä½
        /// </summary>
        public static void SetStopBitValues(ComboBox obj)
        {
            obj.Items.Clear();
            foreach (string str in Enum.GetNames(typeof(StopBits)))
            {
                obj.Items.Add(str);
            }
        }
        #endregion
        #region æ ¼å¼è½¬æ¢
        /// <summary>
        /// è½¬æ¢åå…­è¿›åˆ¶å­—符串到字节数组
        /// </summary>
        /// <param name="msg">待转换字符串</param>
        /// <returns>字节数组</returns>
        public static byte[] HexToByte(string msg)
        {
            msg = msg.Replace(" ", "");//移除空格
            //create a byte array the length of the
            //divided by 2 (Hex is 2 characters in length)
            byte[] comBuffer = new byte[msg.Length / 2];
            for (int i = 0; i < msg.Length; i += 2)
            {
                comBuffer[i / 2] = (byte)Convert.ToByte(msg.Substring(i, 2), 16);
            }
            return comBuffer;
        }
        /// <summary>
        /// è½¬æ¢å­—节数组到十六进制字符串
        /// </summary>
        /// <param name="comByte">待转换字节数组</param>
        /// <returns>十六进制字符串</returns>
        public static string ByteToHex(byte[] comByte)
        {
            string returnStr = "";
            if (comByte != null)
            {
                for (int i = 0; i < comByte.Length; i++)
                {
                    returnStr += comByte[i].ToString("X2")+" ";
                }
            }
            return returnStr;
        }
        #endregion
        /// <summary>
        /// æ£€æŸ¥ç«¯å£åç§°æ˜¯å¦å­˜åœ¨
        /// </summary>
        /// <param name="port_name"></param>
        /// <returns></returns>
        public static bool Exists(string port_name)
        {
            foreach (string port in SerialPort.GetPortNames()) if (port == port_name) return true;
            return false;
        }
        /// <summary>
        /// æ ¼å¼åŒ–端口相关属性
        /// </summary>
        /// <param name="port"></param>
        /// <returns></returns>
        public static string Format(SerialPort port)
        {
            return String.Format("{0} ({1},{2},{3},{4},{5})",
                port.PortName, port.BaudRate, port.DataBits, port.Parity, port.StopBits, port.Handshake);
        }
    }
    public class DataReceivedEventArgs : EventArgs
    {
        public string DataReceived;
        public byte[] DataRecv;
        public DataReceivedEventArgs(string m_DataReceived)
        {
            this.DataReceived = m_DataReceived;
        }
        public DataReceivedEventArgs(byte[] m_DataRecv)
        {
            this.DataRecv = m_DataRecv;
        }
    }
    public delegate void DataReceivedEventHandler(DataReceivedEventArgs e);
    /// <summary>
    /// ä¸²å£æ•°æ®ä½åˆ—表(5,6,7,8)
    /// </summary>
    public enum SerialPortDatabits : int
    {
        FiveBits = 5,
        SixBits = 6,
        SeventBits = 7,
        EightBits = 8
    }
    /// <summary>
    /// ä¸²å£æ³¢ç‰¹çŽ‡åˆ—è¡¨ã€‚
    /// 75,110,150,300,600,1 0,2400,4800,9600,14400,19200,28800,38400,56000,57600,
    /// 115200,128000,230400,256000
    /// </summary>
    public enum SerialPortBaudRates : int
    {
        BaudRate_75 = 75,
        BaudRate_110 = 110,
        BaudRate_150 = 150,
        BaudRate_300 = 300,
        BaudRate_600 = 600,
        BaudRate_1200 = 1200,
        BaudRate_2400 = 2400,
        BaudRate_4800 = 4800,
        BaudRate_9600 = 9600,
        BaudRate_14400 = 14400,
        BaudRate_19200 = 19200,
        BaudRate_28800 = 28800,
        BaudRate_38400 = 38400,
        BaudRate_56000 = 56000,
        BaudRate_57600 = 57600,
        BaudRate_115200 = 115200,
        BaudRate_128000 = 128000,
        BaudRate_230400 = 230400,
        BaudRate_256000 = 256000
    }
}
Bro.Comn/Link/TCPClient.cs
New file
@@ -0,0 +1,237 @@
using System;
using System.Diagnostics;
using System.Net.Sockets;
using System.Threading;
namespace Bro.Common.Link
{
    public delegate void OnMessageRecv(byte[] dataBuff);
    /// <summary>
    /// TCP客户端连接
    /// </summary>
    public class TCPClient : LinkBase
    {
        private static object synObj = new object();
        // æœåŠ¡å™¨åœ°å€
        public string ServerIP { get;set;}
        // æœåС噍IP
        public int ServerPort { get;set;}
        // åˆå§‹åŒ–标示
        public bool IsInited { get;set; }
        public OnMessageRecv MessageRecv;
        // TCP客户端
        public TcpClient Client = new TcpClient();
        private Thread pollTask;
        // åœæ­¢æ ‡ç¤º
        private bool bStop = false;
        public TCPClient()
        {
            IsInited = false;
        }
        /// <summary>
        /// åˆå§‹åŒ–
        /// </summary>
        /// <returns></returns>
        public override bool Init()
        {
            Client = new TcpClient();
            // æŽ¥æ”¶å‘送缓存大小
            Client.SendBufferSize    = 4096;
            Client.ReceiveBufferSize = 4096;
            // è¯»å†™è¶…æ—¶
            Client.SendTimeout       = 2000;
            Client.ReceiveTimeout    = 100;
            IsInited = true;
            return true;
        }
        /// <summary>
        /// é”€æ¯
        /// </summary>
        public override void Fnit()
        {
            IsInited = false;
            if ( null == Client )
            {
                return;
            }
            Client.Close();
        }
        /// <summary>
        /// è¿žæŽ¥æœåС噍
        /// </summary>
        /// <returns></returns>
        public override bool Open()
        {
            try
            {
                if ( Client.Connected )
                {
                    Trace.TraceInformation("TCPClient:{0} dunpliated open", this.Desp);
                    return true;
                }
                Client.Connect(ServerIP, ServerPort);
                //pollTask = new Thread(new ThreadStart(PollThread));
                //pollTask.Start();
                return true;
            }
            catch(Exception ex)
            {
                Trace.TraceError("TCPClient:{0} Open fail, ex:{1}-{2}", this.Desp, ex.Message, ex.StackTrace);
            }
            return false;
        }
        /// <summary>
        /// å…³é—­è¿žæŽ¥
        /// </summary>
        public override void Close()
        {
            try
            {
                if ( !Client.Connected )
                {
                    return;
                }
                bStop = true;
                ClosePollTask();
                Client.Close();
            }
            catch(Exception ex)
            {
                Trace.TraceError("TCPClient:{0} Close fail, ex:{1}-{2}", this.Desp, ex.Message, ex.StackTrace);
            }
        }
        /// <summary>
        /// åˆ¤æ–­å¯¹æ–¹æ˜¯å¦åœ¨çº¿ï¼Œå¼ºåˆ¶é‡æ–°è¿žæŽ¥
        /// </summary>
        public void ReConnect()
        {
            if(!Client.IsOnline())
            {
                Close();
                Init();
                Open();
            }
        }
        /// <summary>
        /// æŽ¥æ”¶æ•°æ®
        /// </summary>
        /// <returns></returns>
        public override int Recv(byte[] rcvBuf, int offset)
        {
            int rcvLen = -1;
            if ( null == rcvBuf )
            {
                return -1;
            }
            try
            {
                var len = rcvBuf.Length - offset;
                if ( len <= 0 )
                {
                    return -1;
                }
                rcvLen = Client.GetStream().Read(rcvBuf, offset, len);
            }
            catch(Exception ex)
            {
                Trace.TraceError("TCPClient:{0} Recv fail, ex:{1}-{2}", this.Desp, ex.Message, ex.StackTrace);
                return -1;
            }
            return rcvLen;
        }
        /// <summary>
        /// å‘送数据
        /// </summary>
        /// <param name="sndBuf"></param>
        /// <param name="bufLen"></param>
        public override bool Send(byte[] sndBuf, int offset, int len)
        {
            if ( null == sndBuf )
            {
                return false;
            }
            try
            {
                Client.GetStream().Write(sndBuf, offset, len);
                return true;
            }
            catch(Exception ex)
            {
                Trace.TraceError("TCPClient:{0} Send fail, ex:{1}-{2}", this.Desp, ex.Message, ex.StackTrace);
            }
            return false;
        }
        public void ClosePollTask()
        {
            pollTask?.Abort();
        }
        public void StartPollTask()
        {
            pollTask = new Thread(new ThreadStart(PollThread));
            pollTask.Start();
        }
        /// <summary>
        /// ç›‘听线程
        /// </summary>
        private void PollThread()
        {
            for (; ; )
            {
                lock (synObj)
                {
                    if (bStop)
                        break;
                    var data = new byte[2048];
                    if (Recv(data, 0) > 0)
                    {
                        MessageRecv(data);
                    }
                }
            }
        }
    }
    public static class TcpClientEx
    {
        public static bool IsOnline(this TcpClient c)
        {
            return !((c.Client.Poll(1000, SelectMode.SelectRead) && (c.Client.Available == 0)) || !c.Client.Connected);
        }
    }
}
Bro.Comn/Link/TCPLink.cs
New file
@@ -0,0 +1,126 @@
using System;
using System.Diagnostics;
using System.Net.Sockets;
namespace Bro.Common.Link
{
    /// <summary>
    /// TCP连接
    /// </summary>
    public class TCPLink : LinkBase
    {
        // ç½‘络连接数据流
        public NetworkStream netStream      = null;
        // è¿œç«¯ä¿¡æ¯
        public string        remoteInfo {get;set;}
        // æ˜¯å¦è¿œç«¯å…³é—­
        public bool         IsRemoteDisconn {get;set;}
        public TCPLink(NetworkStream stream)
        {
            this.netStream          = stream;
            this.IsRemoteDisconn    = false;
        }
        public TCPLink()
        {
            this.IsRemoteDisconn    = false;
        }
        /// <summary>
        /// åˆå§‹åŒ–
        /// </summary>
        /// <returns></returns>
        public override bool Init()
        {
            // TODO:
            return true;
        }
        /// <summary>
        /// æ‰“å¼€TCP连接
        /// </summary>
        /// <returns></returns>
        public override bool Open()
        {
            // TODO:
            return true;
        }
        /// <summary>
        /// å…³é—­TCP连接
        /// </summary>
        public override void Close()
        {
            // TODO:
            if ( null == this.netStream )
            {
                return;
            }
            try
            {
                this.netStream.Close();
                this.netStream = null;
                this.IsRemoteDisconn = true;
            }
            catch(Exception ex)
            {
                Trace.TraceError("TCPLink:{0} Close fail, ex:{1}-{2}", this.Desp, ex.Message, ex.StackTrace);
            }
        }
        /// <summary>
        /// é”€æ¯
        /// </summary>
        public override void Fnit()
        {
            this.Close();
        }
        /// <summary>
        /// æŽ¥æ”¶æ•°æ®
        /// </summary>
        /// <returns></returns>
        public override int Recv(byte[] rcvBuf, int bufLen)
        {
            int len = -1;
            try
            {
                len = netStream.Read(rcvBuf, 0, bufLen);
            }
            catch(Exception ex)
            {
                this.IsRemoteDisconn = true;
                Trace.TraceError("TCPLink:{0} Recv fail, ex:{1}-{2}", this.Desp, ex.Message, ex.StackTrace);
            }
            return len;
        }
        /// <summary>
        /// å‘送数据
        /// </summary>
        /// <param name="sndBuf"></param>
        /// <param name="bufLen"></param>
        public override bool Send(byte[] sndBuf, int offset, int len)
        {
            try
            {
                netStream.Write(sndBuf, offset, len);
                return true;
            }
            catch(Exception ex)
            {
                this.IsRemoteDisconn = true;
                Trace.TraceError("TCPLink:{0} Send fail, ex:{1}-{2}", this.Desp, ex.Message, ex.StackTrace);
            }
            return false;
        }
    }
}
Bro.Comn/Link/TCPSvr.cs
New file
@@ -0,0 +1,321 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Net;
using System.Net.Sockets;
using System.Threading;
namespace Bro.Common.Link
{
    // å®¢æˆ·ç«¯åŠ¨ä½œä»£ç†
    public delegate void OnClientOpen(TcpClient client);
    public delegate void OnClientClose(TcpClient client);
    public delegate void OnClientRecv(TcpClient client);
    /// <summary>
    /// TCP服务器
    /// </summary>
    public class TCPSvr
    {
        private static object synObj = new object();
        public OnClientOpen       ClientOpen;
        public OnClientClose      ClientClose;
        public OnClientRecv       ClientRecv;
        // æœåŠ¡å™¨æè¿°
        public string   Desp {get;set;}
        // æœåС噍IP
        public string   ServerIP { get;set; }
        // æœåŠ¡å™¨ç«¯å£
        public int      ServerPort { get; set; }
        // æœåŠ¡å™¨ç›‘å¬
        private TcpListener tcpSvr  = null;
        // åœæ­¢æ ‡ç¤º
        private bool bStop = false;
        // ç›‘听线程
        private Thread listenThread;
        private Thread pollThread;
        private Dictionary<Socket,TcpClient> clientsMap = new Dictionary<Socket,TcpClient>();
        public TCPSvr()
        {
        }
        public TCPSvr(string ip, int port)
        {
            ServerIP    = ip;
            ServerPort = port;
        }
        /// <summary>
        /// åˆå§‹åŒ–
        /// </summary>
        /// <returns></returns>
        public bool Init()
        {
            try
            {
                var ip = IPAddress.Parse(ServerIP);
                tcpSvr = new TcpListener(ip, ServerPort);
                bStop = false;
            }
            catch(Exception ex)
            {
                Trace.TraceError("TCP server init fail,ex:{0}", ex);
                return false;
            }
            return true;
        }
        /// <summary>
        /// å¯åŠ¨ç›‘å¬
        /// </summary>
        /// <returns></returns>
        public bool Start()
        {
            try
            {
                clientsMap.Clear();
                tcpSvr.Start();
                listenThread = new Thread(new ThreadStart(DoAcceptCallBack));
                listenThread.Start();
                pollThread = new Thread(new ThreadStart(PollThread));
                pollThread.Start();
                bStop = false;
            }
            catch(Exception ex)
            {
                Trace.TraceError("TCP server start listen fail,ex:{0}", ex);
                return false;
            }
            return true;
        }
        /// <summary>
        /// åœæ­¢ç›‘听
        /// </summary>
        public void Stop()
        {
            bStop = true;
            try
            {
                tcpSvr.Stop();
                listenThread.Join();
                pollThread.Join();
            }
            catch(Exception ex)
            {
                Trace.TraceError("TCP server stop listen fail,ex:{0}", ex);
            }
            bStop = true;
        }
        /// <summary>
        /// å…³é—­å®¢æˆ·ç«¯
        /// </summary>
        /// <param name="client"></param>
        public void Close(TcpClient client)
        {
            lock(synObj)
            {
                clientsMap.Remove(client.Client);
                client.Close();
            }
        }
        /// <summary>
        /// ç§»é™¤å®¢æˆ·ç«¯ç›‘听
        /// </summary>
        /// <param name="client"></param>
        public void Remove(TcpClient client)
        {
            lock (synObj)
            {
                clientsMap.Remove(client.Client);
            }
        }
        /// <summary>
        /// ç›‘听线程
        /// </summary>
        private void PollThread()
        {
            for(;;)
            {
                if (bStop)
                {
                    CloseAllClient();
                    Trace.TraceInformation("{0} tcp server stop trigger", Desp);
                    break;
                }
                lock(synObj)
                {
                    PollRecv();
                }
            }
            Trace.TraceInformation("{0} tcp server stop finish", Desp);
        }
        /// <summary>
        /// æ–°æŽ¥å…¥å®¢æˆ·ç«¯è¿žæŽ¥
        /// </summary>
        /// <param name="ar"></param>
        private void DoAcceptCallBack()
        {
            for (; ; )
            {
                TcpClient client = null;
                try
                {
                    if (!tcpSvr.Pending())
                    {
                        Thread.Sleep(100);
                        continue;
                    }
                    client = tcpSvr.AcceptTcpClient();
                    // æŽ¥æ”¶å‘送缓存大小
                    client.ReceiveBufferSize = 2048;
                    client.SendBufferSize = 2048;
                    // è¯»å†™è¶…æ—¶
                    client.SendTimeout = 2000;
                    client.ReceiveTimeout = 200;
                    lock (synObj)
                    {
                        clientsMap.Add(client.Client, client);
                        // é€šçŸ¥å®¢æˆ·ç«¯è¿žæŽ¥è¿›å…¥
                        if (null != ClientOpen)
                        {
                            Trace.TraceInformation("DoAcceptCallBack {0} tcp server, accept client{1}", Desp, client.Client.RemoteEndPoint);
                            ClientOpen(client);
                        }
                    }
                }
                catch (Exception ex)
                {
                    client?.Close();
                    Trace.TraceInformation("DoAcceptCallBack fail, ex:{0},{1} tcp server, accept client{2}", ex.Message,
                        Desp, client?.Client.RemoteEndPoint.ToString());
                    return;
                }
            }
        }
        /// <summary>
        /// æ£€æŸ¥æ•°æ®æŽ¥æ”¶
        /// </summary>
        private void PollRecv()
        {
            var rList = new ArrayList();
            var eList = new ArrayList();
            foreach(var item in clientsMap)
            {
                var socket  = item.Key;
                rList.Add(socket);
                eList.Add(socket);
            }
            if (clientsMap.Count == 0)
            {
                Thread.Sleep(200);
                return;
            }
            try
            {
                Thread.Sleep(200);
                Socket.Select(rList, null, eList, 200);
                // å®¢æˆ·ç«¯å¼‚常则关闭
                foreach(var item in eList)
                {
                    Socket  socket = (Socket)item;
                    TcpClient client;
                    if ( clientsMap.TryGetValue(socket, out client) && null != ClientClose )
                    {
                        client.Close();
                        ClientClose(client);
                    }
                    clientsMap.Remove(socket);
                }
                // å®¢æˆ·ç«¯æ˜¯å¦æœ‰æ•°æ®
                foreach(var item in rList)
                {
                    Socket  socket = (Socket)item;
                    TcpClient client;
                    if ( clientsMap.TryGetValue(socket, out client) && null != ClientRecv )
                    {
                        ClientRecv(client);
                    }
                }
            }
            catch(Exception ex)
            {
                Trace.TraceInformation("CloseAllClient except{0}, {1} tcp server", ex.Message, Desp);
            }
        }
        /// <summary>
        /// å…³é—­æ‰€æœ‰å®¢æˆ·ç«¯è¿žæŽ¥
        /// </summary>
        private void CloseAllClient()
        {
            Trace.TraceInformation("CloseAllClient {0} tcp server, client cnt{0}", Desp, clientsMap.Count);
            foreach(var item in clientsMap)
            {
                var client  = item.Value;
                try
                {
                    client.Close();
                    if ( null != ClientClose )
                    {
                        ClientClose(client);
                    }
                }
                catch(Exception ex)
                {
                    Trace.TraceInformation("CloseAllClient except{0}, {1} tcp server, accept client{2}", ex.Message, Desp, client.Client.RemoteEndPoint);
                }
            }
            clientsMap.Clear();
        }
    }
}
Bro.Comn/OEE/OEEToolKit.cs
New file
@@ -0,0 +1,242 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
namespace BroC.Comn.OEE
{
    public class OEEToolKit
    {
        private DateTime lastClearTime = DateTime.Now;
        private int totalCount = 0;
        private int okCount = 0;
        private int ngCount = 0;
        private double ct = 0;
        private Dictionary<string, int> ngDic = new Dictionary<string, int>();
        private List<DateTime> testEndTimeList = new List<DateTime>();
        public int TotalCount
        {
            get => totalCount;
        }
        public int OKCount
        {
            get => okCount;
        }
        public int NGCount
        {
            get => ngCount;
        }
        public double CT
        {
            get => ct;
            set => ct = value;
        }
        public double Rate
        {
            get
            {
                if (totalCount == 0)
                    return 0;
                else
                    return okCount * 1.0 / totalCount;
            }
        }
        public int UPHAverage
        {
            get
            {
                var timeOffset = DateTime.Now - lastClearTime;
                var averageUPH = timeOffset.TotalSeconds == 0 ? totalCount : totalCount / (timeOffset.TotalSeconds / 3600.0);
                return Convert.ToInt32(averageUPH);
            }
        }
        public int UPHReal
        {
            get => testEndTimeList.Count;
        }
        public OEEToolKit()
        {
        }
        public void AddNgType(string type)
        {
            ngDic.Add(type, 0);
        }
        public void Update(bool isok)
        {
            var time = DateTime.Now;
            testEndTimeList.Add(time);
            int removeCount = 0;
            for (int i = 0; i < testEndTimeList.Count; i++)
            {
                if (testEndTimeList[i].CompareTo(time.AddHours(-1)) < 0)
                {
                    removeCount++;
                }
                else
                {
                    break;
                }
            }
            testEndTimeList.RemoveRange(0, removeCount);
            totalCount++;
            if (isok)
                okCount++;
            else
                ngCount++;
        }
        public void Update(string ngType)
        {
            if (ngType != "" && ngDic.ContainsKey(ngType))
            {
                ngDic[ngType]++;
            }
        }
        public int GetNgTypeCount(string ngType)
        {
            if (!ngDic.Keys.Contains(ngType))
                return -1;
            return ngDic[ngType];
        }
        public void Clear()
        {
            lastClearTime = DateTime.Now;
            totalCount = 0;
            okCount = 0;
            ngCount = 0;
            var keys = ngDic.Keys.ToArray();
            foreach (var item in keys)
            {
                ngDic[item] = 0;
            }
            testEndTimeList.Clear();
        }
        public void Record(string fileName,string tag="-", string ct = "-")
        {
            FileInfo fileInfo = new FileInfo(fileName);
            if (!fileInfo.Directory.Exists)
                fileInfo.Directory.Create();
            if (!File.Exists(fileName))
            {
                var title = "开始时间,记录时间,运行时间,标签,产量,良率,OK,NG,";
                foreach (var item in ngDic)
                {
                    title += $"{item.Key},";
                }
                title += "CT,UPH(实时),UPH(平均),";
                File.AppendAllText(fileName, title, Encoding.UTF8);
                File.AppendAllText(fileName, "\r\n", Encoding.UTF8);
            }
            var recordTime = DateTime.Now;
            var timeSpan = recordTime - lastClearTime;
            var content = $"{lastClearTime:yyyy-MM-dd-HH-mm-ss}," +
                $"{recordTime:yyyy-MM-dd-HH-mm-ss}," +
                $"{timeSpan.Minutes / 60.0:f2}," +
                $"{tag}," +
                $"{TotalCount}," +
                $"{Rate * 100:f2}," +
                $"{OKCount}," +
                $"{NGCount},";
            foreach (var item in ngDic)
            {
                content += $"{item.Value},";
            }
            content += $"{ct},{UPHReal},{UPHAverage}";
            File.AppendAllText(fileName, content, Encoding.UTF8);
            File.AppendAllText(fileName, "\r\n", Encoding.UTF8);
            Clear();
        }
        public void RecordNewLine(string fileName)
        {
            FileInfo fileInfo = new FileInfo(fileName);
            if (!fileInfo.Directory.Exists)
                fileInfo.Directory.Create();
            if (!File.Exists(fileName))
            {
                var title = "开始时间,记录时间,运行时间,标签,产量,良率,OK,NG,";
                foreach (var item in ngDic)
                {
                    title += $"{item.Key},";
                }
                title += "CT,UPH(实时),UPH(平均),";
                File.AppendAllText(fileName, title, Encoding.UTF8);
                File.AppendAllText(fileName, "\r\n", Encoding.UTF8);
            }
            var content = $"-," +
                $"-," +
                $"-," +
                $"-," +
                $"-," +
                $"-," +
                $"-," +
                $"-,";
            File.AppendAllText(fileName, content, Encoding.UTF8);
            File.AppendAllText(fileName, "\r\n", Encoding.UTF8);
        }
        public void StartAutoRecord()
        {
        }
        private void AutoRecordThread()
        {
        }
    }
}
Bro.Comn/Procedure/IODataBase.cs
New file
@@ -0,0 +1,200 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
namespace Bro.Common.Procedure
{
    /// <summary>
    /// IO数据状态
    /// </summary>
    public enum IODStat
    {
        IODSUndo,
        IODSDoing,
        IODSDone,
    }
    /// <summary>
    /// IO数据基类
    /// </summary>
    public class IODataBase
    {
        #region å¸¸é‡
        // é»˜è®¤çš„输入处理函数名称
        public const string DFT_HANDLE_METHOD_NAME  = "HandleRequest";
        #endregion
        #region å±žæ€§
        // æ¶ˆæ¯å¤„理者
        public List<object>     Handlers {get;set;}
        public IODStat          Stat { get { return curStat; }}
        // æ¶ˆæ¯æè¿°
        public string           Desp { get;set; }
        // åˆ›å»ºæ—¶é—´
        public DateTime         CreateTime { get;set; }
        // å¤„理开始时间
        public DateTime         BeginTime { get;set; }
        // å¤„理完成时间
        public DateTime         EndTime { get;set; }
        // ç”¨æˆ·æ•°æ®
        public object           Data { get;set; }
        #endregion
        #region æˆå‘˜å˜é‡
        private IODStat       curStat = IODStat.IODSUndo;
        #endregion
        #region ç»“构体
        public IODataBase()
        {
            Handlers    = null;
            curStat     = IODStat.IODSUndo;
            CreateTime  = DateTime.Now;
            BeginTime   = DateTime.MinValue;
            EndTime     = DateTime.MinValue;
            Desp        = this.GetType().ToString();
            Data        = null;
        }
        public IODataBase(List<object> handlers, string desp, object userData)
        {
            Handlers        = handlers;
            curStat         = IODStat.IODSUndo;
            CreateTime      = DateTime.Now;
            BeginTime       = DateTime.MinValue;
            EndTime         = DateTime.MinValue;
            this.Desp       = desp;
            this.Data       = userData;
        }
        #endregion
        #region æ–¹æ³•
        /// <summary>
        /// æ´¾é£å‡½æ•°ï¼Œåˆ©ç”¨åå°„机制自动派遣给输入处理者
        ///
        /// å¤„理方法
        /// 1. éåŽ†æ•°æ®å¤„ç†è€…
        /// 2. æ£€å¯Ÿå¤„理者中是否有指定名称函数
        /// 3. æ£€å¯Ÿæ­¤å‡½æ•°å‚数,与数返回值据类型一致
        /// 4. åˆ©ç”¨åå°„调用函数
        /// 5. è¿”回值为true,则处理结束
        /// </summary>
        public void Dispatch()
        {
            var paramType = this.GetType();
            var objParams = new object[1];
            objParams[0] = this;
            if ( null == Handlers )
            {
                return;
            }
            foreach(var handler in Handlers)
            {
                if ( null == handler )
                {
                    continue;
                }
                // èŽ·å–å‚æ•°ç±»åž‹
                var instType     = handler.GetType();
                do
                {
                    var instMthInfos = instType.GetMethods( BindingFlags.Instance       |
                                                            BindingFlags.DeclaredOnly   |
                                                            BindingFlags.Public         |
                                                            BindingFlags.NonPublic
                                                            );
                    var findsMthInfos = FindMethods(instMthInfos, paramType.Name);
                    foreach (var item in findsMthInfos)
                    {
                        var mth = (MethodInfo)item;
                        // è°ƒç”¨å¯¹åº”实例方法
                        var ret = (bool)mth.Invoke(handler, objParams);
                        if (ret)
                        {
                            return;
                        }
                    }
                    instType = instType.BaseType;
                } while (instType != null);
            }
        }
        private Array FindMethods(MethodInfo[] mthInfos, string paramType)
        {
            var findMethods = new ArrayList();
            foreach (var instMth in mthInfos)
            {
                var paramInfos = instMth.GetParameters();
                // é˜²æ­¢è°ƒç”¨çˆ¶ç±»å‡½æ•°
                //if ( instType != instMth.DeclaringType )
                //{
                //    continue;
                //}
                // å‚数个数检查
                if (paramInfos.Length != 1)
                {
                    continue;
                }
                // æ–¹æ³•必须是指定名称
                if (DFT_HANDLE_METHOD_NAME.CompareTo(instMth.Name) != 0)
                {
                    continue;
                }
                // å‚数类型检查
                if (paramInfos[0].ParameterType.Name.CompareTo(paramType) != 0)
                {
                    continue;
                }
                // æ–¹æ³•返回值检察
                if (instMth.ReturnType.Name.CompareTo(typeof(bool).Name) != 0)
                {
                    continue;
                }
                findMethods.Add(instMth);
            }
            return findMethods.ToArray();
        }
        #endregion
    }
}
Bro.Comn/Procedure/ProcedureBase.cs
New file
@@ -0,0 +1,475 @@
using System.Collections.Generic;
using System.Threading;
using Bro.Common.FSM;
using System.Diagnostics;
namespace Bro.Common.Procedure
{
    /// <summary>
    /// æµç¨‹çŠ¶æ€
    /// </summary>
    public enum ProcStat
    {
        PSInit = 0,         // åˆå§‹åŒ–
        PSOpen,             // æ‰“å¼€
        PSRunning,          // è¿è¡Œ
        PSReset,            // é‡ç½®,
        PSReseting,         // é‡ç½®ä¸­
        PSPause,            // æš‚停
        PSClose,            // å…³é—­
        PSFnit              // é”€æ¯
    }
    /// <summary>
    /// å¤„理流程基类
    ///
    /// è¯´æ˜Žï¼š
    ///     å·¥ç«™ï¼Œå·¥ä½ç±»éƒ½å¯ç»§æ‰¿æ­¤ç±»
    /// å®šä¹‰å¦‚下动作
    /// 1. åˆå§‹åŒ–/销毁
    /// 2. æ‰“å¼€/关闭
    /// 3. è¯»å†™
    /// 4. è®¾ç½®é€‰é¡¹
    /// 5. äº‹ä»¶è®¢é˜…/取消
    /// </summary>
    public abstract class ProcedureBase
    {
        #region ä»£ç†å®šä¹‰
        // çŠ¶æ€å˜åŒ–äº‹ä»¶
        public delegate void StatChange(ProcedureBase procedure, ProcStat srcStat, ProcStat dstStat);
        #endregion
        #region å¸¸é‡
        // çº¿ç¨‹é»˜è®¤ç­‰å¾…时间(单位:毫秒)
        protected const int         DFT_WAIT_INTERVAL = 200;
        #endregion
        #region äº‹ä»¶ä»£ç†
        // æµç¨‹çŠ¶æ€å˜åŒ–
        public StatChange StatChangeEvent;
        #endregion
        #region å±žæ€§
        // æµç¨‹æè¿°
        public string               Desp { get; set; }
        // æµç¨‹çŠ¶æ€
        public ProcStat             Stat{ get { return curStat; } }
        #endregion
        #region æˆå‘˜å˜é‡
        // æµç¨‹çŠ¶æ€æœº
        protected SimpleFSM         procFSM         = new SimpleFSM();
        // æµç¨‹çŠ¶æ€
        protected ProcStat          curStat         = ProcStat.PSInit;
        // ç”Ÿäº§å·¥åºåŒæ­¥äº‹ä»¶
        protected AutoResetEvent    waitEvent       = new AutoResetEvent(false);
        // è¾“入队列
        private Queue<IODataBase>   requestQueue    = new Queue<IODataBase>();
        // è¾“入处理者
        private List<object>        requestHandlers = new List<object>();
        #endregion
        #region ç»“构体
        public ProcedureBase()
        {
            this.Desp = this.GetType().Name;
            // è®¾ç½®é»˜è®¤çš„状态处理者
            AddRequestHandler(this);
            RegistProcFSM();
        }
        public ProcedureBase(SimpleFSM fsm)
        {
            this.Desp    = this.GetType().Name;
            this.procFSM = fsm;
            // è®¾ç½®é»˜è®¤çš„状态处理者
            AddRequestHandler(this);
            RegistProcFSM();
        }
        #endregion
        #region å¤–部接口
        /// <summary>
        /// æš‚停流程
        /// </summary>
        public virtual void Pause()
        {
            Trace.TraceInformation("{0} Pause", Desp);
            var req = new ProcStatChangeReq();
            req.TargetStat = ProcStat.PSPause;
            AddRequest(req);
        }
        /// <summary>
        /// é‡ç½®æµç¨‹
        /// </summary>
        public virtual void Reset()
        {
            Trace.TraceInformation("{0} Reset", Desp);
            var req = new ProcStatChangeReq();
            req.TargetStat = ProcStat.PSReset;
            AddRequest(req);
        }
        /// <summary>
        /// è¯·æ±‚处理
        /// </summary>
        /// <param name="input"></param>
        public void AddRequest(IODataBase req)
        {
            if (null == req)
            {
                return;
            }
            lock (requestQueue)
            {
                // è®¾ç½®è¾“入处理者
                req.Handlers = this.requestHandlers;
                requestQueue.Enqueue(req);
            }
        }
        #endregion
        #region åŸºç¡€æµç¨‹çŠ¶æ€æœº
        /// <summary>
        /// æ³¨å†ŒåŸºæœ¬çŠ¶æ€å¤„ç†
        /// </summary>
        protected virtual bool RegistProcFSM()
        {
            int iRet = 0;
            if ( null == procFSM )
            {
                return false;
            }
            iRet += procFSM.Regist((int)ProcStat.PSInit,            DoInit)     ? 0 : 1;
            iRet += procFSM.Regist((int)ProcStat.PSOpen,            DoOpen)     ? 0 : 1;
            iRet += procFSM.Regist((int)ProcStat.PSClose,           DoClose)    ? 0 : 1;
            iRet += procFSM.Regist((int)ProcStat.PSRunning,         DoRunning)  ? 0 : 1;
            iRet += procFSM.Regist((int)ProcStat.PSReset,           DoReset)    ? 0 : 1;
            iRet += procFSM.Regist((int)ProcStat.PSReseting,        DoReseting) ? 0 : 1;
            iRet += procFSM.Regist((int)ProcStat.PSPause,           DoPause)    ? 0 : 1;
            iRet += procFSM.Regist((int)ProcStat.PSFnit,            DoFnit)     ? 0 : 1;
            // è®¾ç½®åˆå§‹çŠ¶æ€
            SetState(ProcStat.PSInit);
            return (iRet == 0);
        }
        /// <summary>
        /// åˆå§‹åŒ–
        /// </summary>
       public virtual void DoInit()
        {
            Trace.TraceInformation("{0} DoInit", Desp);
            ClearIOData();
            SetState(ProcStat.PSOpen);
        }
        /// <summary>
        /// é”€æ¯
        /// </summary>
        public virtual void DoFnit()
        {
            Trace.TraceInformation("{0} DoFnit", Desp);
        }
        /// <summary>
        /// å¼€å§‹
        /// </summary>
        public virtual void DoOpen()
        {
            Trace.TraceInformation("{0} DoOpen", Desp);
            SetState(ProcStat.PSRunning);
        }
        /// <summary>
        /// åœæ­¢
        /// </summary>
        public virtual void DoClose()
        {
            Trace.TraceInformation("{0} DoClose", this.GetType().Name);
            SetState(ProcStat.PSFnit);
        }
        /// <summary>
        /// é‡ç½®
        /// </summary>
        public virtual void DoReset()
        {
            Trace.TraceInformation("{0} DoReset", this.GetType().Name);
            SetState(ProcStat.PSReseting);
        }
        /// <summary>
        /// é‡ç½®ä¸­
        /// </summary>
        public virtual void DoReseting()
        {
            Trace.TraceInformation("{0} DoReseting", this.GetType().Name);
            SetState(ProcStat.PSRunning);
        }
        /// <summary>
        /// æš‚停
        /// </summary>
        public virtual void DoPause()
        {
            // ç­‰å¾…
            waitEvent.WaitOne(DFT_WAIT_INTERVAL);
        }
        /// <summary>
        /// å°±ç»ª
        /// </summary>
        public virtual void DoRunning()
        {
            // TODO:流程就绪,主处理
        }
        #endregion
        #region è¯·æ±‚处理
        /// <summary>
        /// çŠ¶æ€è½¬å˜è¯·æ±‚
        /// </summary>
        /// <param name="req"></param>
        /// <returns></returns>
        protected bool HandleRequest(ProcStatChangeReq req)
        {
            Trace.TraceInformation("{0} HandleRequest cur stat:{1} target:{2}",
                                    Desp, GetStatDesp(Stat), GetStatDesp(req.TargetStat));
            if ( req.TargetStat == Stat )
            {
                Trace.TraceWarning("{0} HandleRequest fail, already in {1}", Desp, GetStatDesp(req.TargetStat));
                return true;
            }
            if ( ProcStat.PSRunning != this.Stat )
            {
                Trace.TraceWarning("{0} not running, can't turn to {1}", Desp, GetStatDesp(req.TargetStat));
                return true;
            }
            SetState(req.TargetStat);
            return true;
        }
        #endregion
        #region å…¶ä»–方法
        /// <summary>
        /// è¿è¡Œ
        /// </summary>
        public virtual void Run()
        {
            procFSM.Run();
            Routine();
        }
        /// <summary>
        /// æµç¨‹æ¯æ¬¡è¿è¡Œçš„例程
        /// </summary>
        protected virtual void Routine()
        {
            // å¤„理请求
            HandleRequests();
        }
        /// <summary>
        /// è®¾ç½®çŠ¶æ€
        /// </summary>
        /// <param name="stat"></param>
        protected internal void SetState(ProcStat stat)
        {
            var srcStat = GetStatDesp(curStat);
            var dstStat = GetStatDesp(stat);
            var tempStat = curStat;
            curStat = stat;
            if (null == procFSM)
            {
                return;
            }
            Trace.TraceInformation("{0} stat [{1}]-->[{2}]", Desp, srcStat, dstStat);
            procFSM.SetStat((int)stat);
            // é€šçŸ¥æµç¨‹çŠ¶æ€å˜åŒ–
            if (null != StatChangeEvent)
            {
                StatChangeEvent(this, tempStat, stat);
            }
        }
        /// <summary>
        /// è®¾ç½®è¾“入处理者
        /// </summary>
        /// <param name="handler"></param>
        public void AddRequestHandler(object handler)
        {
            requestHandlers.Add(handler);
        }
        /// <summary>
        /// å¤„理输入
        /// </summary>
        protected void HandleRequests()
        {
            var req = NextReq();
            if ( null == req )
            {
                return;
            }
            Trace.TraceInformation("[{0}] HandleRequest {1} ", Desp, req.GetType().Name);
            // è¾“入处理派遣
            req.Dispatch();
        }
        /// <summary>
        /// èŽ·å–ä¸‹ä¸ªè¾“å…¥
        /// </summary>
        /// <returns></returns>
        protected IODataBase NextReq()
        {
            return NextData(requestQueue);
        }
        /// <summary>
        /// æ·»åŠ æ•°æ®
        /// </summary>
        /// <param name="data"></param>
        /// <param name="dataQueue"></param>
        protected void AddQueue(IODataBase data, Queue<IODataBase> dataQueue)
        {
            if ( null == data || null == dataQueue )
            {
                return;
            }
            lock(dataQueue)
            {
                dataQueue.Enqueue(data);
            }
        }
        /// <summary>
        /// èŽ·å–ä¸‹ä¸ªæ•°æ®
        /// </summary>
        /// <param name="dataQueue"></param>
        /// <returns></returns>
        protected IODataBase NextData(Queue<IODataBase> dataQueue)
        {
            IODataBase ioData = null;
            lock(dataQueue)
            {
                if ( dataQueue.Count > 0 )
                {
                    ioData = dataQueue.Dequeue();
                }
            }
            return ioData;
        }
        /// <summary>
        /// æƒ…空输入数据
        /// </summary>
        protected void ClearIOData()
        {
            lock(requestQueue)
            {
                requestQueue.Clear();
            }
        }
        /// <summary>
        /// èŽ·å–çŠ¶æ€æè¿°
        /// </summary>
        /// <param name="procStat"></param>
        /// <returns></returns>
        private string GetStatDesp(ProcStat procStat)
        {
            var desp = "";
            switch (procStat)
            {
                case ProcStat.PSInit:
                    desp = "PSInit";
                    break;
                case ProcStat.PSFnit:
                    desp = "PSFnit";
                    break;
                case ProcStat.PSOpen:
                    desp = "PSOpen";
                    break;
                case ProcStat.PSClose:
                    desp = "PSClose";
                    break;
                case ProcStat.PSRunning:
                    desp = "PSRunning";
                    break;
                case ProcStat.PSPause:
                    desp = "PSPause";
                    break;
                case ProcStat.PSReset:
                    desp = "PSReset";
                    break;
                case ProcStat.PSReseting:
                    desp = "PSReseting";
                    break;
                default:
                    desp = "Unknow";
                    break;
            }
            return desp;
        }
        #endregion
    }
}
Bro.Comn/Procedure/ProcedureIO.cs
New file
@@ -0,0 +1,11 @@
namespace Bro.Common.Procedure
{
    /// <summary>
    /// å·¥åºçŠ¶æ€å˜åŒ–è¾“å…¥
    /// </summary>
    public class ProcStatChangeReq : IODataBase
    {
        // ç›®çš„状态
        public ProcStat TargetStat { get; set; }
    }
}
Bro.Comn/Procedure/UnitBase.cs
New file
@@ -0,0 +1,140 @@
namespace Bro.Common.Procedure
{
    /// <summary>
    /// åŸºç¡€å•å…ƒ
    /// </summary>
    public class UnitBase
    {
        #region æžšä¸¾
        /// <summary>
        /// å•元模块状态定义
        /// </summary>
        public enum UnitStat
        {
            DSUninit = 0,       // æœªåˆå§‹åŒ–
            DSInit,             // å·²åˆå§‹åŒ–
            DSOpen,             // å·²æ‰“å¼€
            DSClose,            // å·²å…³é—­
            DSExcept            // å¼‚常状态
        }
        #endregion
        #region å¸¸é‡å®šä¹‰
        #endregion
        #region è®¾å¤‡åŸºæœ¬å±žæ€§
        // è®¾å¤‡æè¿°
        public string Desp { get;set; }
        // è®¾å¤‡çŠ¶æ€
        public UnitStat Stat { get;set;}
        // è®¾å¤‡æ˜¯å¦åˆå§‹åŒ–
        public bool IsInit {
            get { return UnitStat.DSInit == this.Stat; }
        }
        // è®¾å¤‡æ˜¯å¦æ‰“å¼€
        public bool IsOpen {
            get { return UnitStat.DSOpen == this.Stat;}
        }
        // è®¾å¤‡ID(可用来唯一指定本设备)
        public int  Id { get;set; }
        // è®¾å¤‡å¼‚常描述
        public string  ExceptionDesp { get;set;}
        // è®¾å¤‡æºå¸¦æ•°æ®
        public object Data { get;set; }
        #endregion
        /// <summary>
        /// è®¾å¤‡æž„造函数
        ///
        /// ä½¿ç”¨äº†é»˜è®¤çš„设备id
        /// </summary>
        public UnitBase()
        {
            // é»˜è®¤æè¿°
            this.Desp = this.GetType().Name;
            // åˆå§‹çŠ¶æ€
            this.Stat = UnitStat.DSUninit;
            // é»˜è®¤å•å…ƒID
            this.Id  = this.GetHashCode();
        }
        #region åŸºæœ¬åŠ¨ä½œ
        /// <summary>
        /// è®¾å¤‡åˆå§‹åŒ–
        /// </summary>
        /// <returns></returns>
        public virtual bool Init()
        {
            Stat = UnitStat.DSInit;
            return true;
        }
        /// <summary>
        /// è®¾å¤‡é”€æ¯
        /// </summary>
        public virtual void Fnit()
        {
            Stat = UnitStat.DSUninit;
        }
        /// <summary>
        /// è®¾å¤‡æ‰“å¼€
        /// </summary>
        /// <returns></returns>
        public virtual bool Open()
        {
            Stat = UnitStat.DSOpen;
            return true;
        }
        /// <summary>
        /// è®¾å¤‡å…³é—­
        /// </summary>
        public virtual void Close()
        {
            Stat = UnitStat.DSClose;
        }
        /// <summary>
        /// æ‰“开前动作
        /// </summary>
        public virtual void OnBeforeOpen()
        {
        }
        /// <summary>
        /// æ‰“开后动作
        /// </summary>
        public virtual void OnAfterOpen()
        {
        }
        /// <summary>
        /// å…³é—­å‰åŠ¨ä½œ
        /// </summary>
        public virtual void OnBeforeClose()
        {
        }
        /// <summary>
        /// å…³é—­åŽåŠ¨ä½œ
        /// </summary>
        public virtual void OnAfterClose()
        {
        }
        #endregion
    }
}
Bro.Comn/Properties/AssemblyInfo.cs
New file
@@ -0,0 +1,35 @@
using System.Reflection;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("BroCComn")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Microsoft")]
[assembly: AssemblyProduct("BroCComn")]
[assembly: AssemblyCopyright("Copyright Â© Microsoft 2016")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components.  If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("deb0c803-888e-42bb-b29c-448e9b6e09f0")]
// Version information for an assembly consists of the following four values:
//
//      Major Version
//      Minor Version
//      Build Number
//      Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
[assembly: AssemblyVersion("1.0.*")]
//[assembly: AssemblyVersion("1.0.0.0")]
//[assembly: AssemblyFileVersion("1.0.0.0")]
Bro.Comn/Properties/Resource.Designer.cs
New file
@@ -0,0 +1,85 @@
//------------------------------------------------------------------------------
// <auto-generated>
//     æ­¤ä»£ç ç”±å·¥å…·ç”Ÿæˆã€‚
//     è¿è¡Œæ—¶ç‰ˆæœ¬:4.0.30319.42000
//
//     å¯¹æ­¤æ–‡ä»¶çš„æ›´æ”¹å¯èƒ½ä¼šå¯¼è‡´ä¸æ­£ç¡®çš„行为,并且如果
//     é‡æ–°ç”Ÿæˆä»£ç ï¼Œè¿™äº›æ›´æ”¹å°†ä¼šä¸¢å¤±ã€‚
// </auto-generated>
//------------------------------------------------------------------------------
namespace Broc.Comn.Properties {
    using System;
    /// <summary>
    ///   ä¸€ä¸ªå¼ºç±»åž‹çš„资源类,用于查找本地化的字符串等。
    /// </summary>
    // æ­¤ç±»æ˜¯ç”± StronglyTypedResourceBuilder
    // ç±»é€šè¿‡ç±»ä¼¼äºŽ ResGen æˆ– Visual Studio çš„工具自动生成的。
    // è‹¥è¦æ·»åŠ æˆ–ç§»é™¤æˆå‘˜ï¼Œè¯·ç¼–è¾‘ .ResX æ–‡ä»¶ï¼Œç„¶åŽé‡æ–°è¿è¡Œ ResGen
    // (以 /str ä½œä¸ºå‘½ä»¤é€‰é¡¹),或重新生成 VS é¡¹ç›®ã€‚
    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")]
    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
    internal class Resource {
        private static global::System.Resources.ResourceManager resourceMan;
        private static global::System.Globalization.CultureInfo resourceCulture;
        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
        internal Resource() {
        }
        /// <summary>
        ///   è¿”回此类使用的缓存的 ResourceManager å®žä¾‹ã€‚
        /// </summary>
        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
        internal static global::System.Resources.ResourceManager ResourceManager {
            get {
                if (object.ReferenceEquals(resourceMan, null)) {
                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Broc.Comn.Properties.Resource", typeof(Resource).Assembly);
                    resourceMan = temp;
                }
                return resourceMan;
            }
        }
        /// <summary>
        ///   é‡å†™å½“前线程的 CurrentUICulture å±žæ€§
        ///   é‡å†™å½“前线程的 CurrentUICulture å±žæ€§ã€‚
        /// </summary>
        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
        internal static global::System.Globalization.CultureInfo Culture {
            get {
                return resourceCulture;
            }
            set {
                resourceCulture = value;
            }
        }
        /// <summary>
        ///   æŸ¥æ‰¾ç±»ä¼¼ &lt;?xml version=&quot;1.0&quot;?&gt;
        ///&lt;configuration&gt;
        ///    &lt;configSections&gt;
        ///        &lt;section name=&quot;log4net&quot; type=&quot;log4net.Config.Log4NetConfigurationSectionHandler, log4net&quot; /&gt;
        ///    &lt;/configSections&gt;
        ///    &lt;log4net&gt;
        ///        &lt;!--Log4net Begin by Bruce  2016.06.14--&gt;
        ///        &lt;appender name=&quot;RollingFileAppender&quot; type=&quot;log4net.Appender.RollingFileAppender&quot;&gt;
        ///            &lt;file value=&quot;.\logs\&quot; /&gt;
        ///            &lt;appendToFile value=&quot;true&quot; /&gt;
        ///      &lt;!--log淇濈暀澶╂暟--&gt;
        ///      &lt;maxSizeRollBackups value= &quot;30&quot;/&gt;
        ///            &lt;rollingStyle value=&quot;Composite&quot; /&gt;
        ///            &lt;ma [字符串的其余部分被截断]&quot;; çš„æœ¬åœ°åŒ–字符串。
        /// </summary>
        internal static string BroClog4net {
            get {
                return ResourceManager.GetString("BroClog4net", resourceCulture);
            }
        }
    }
}
Bro.Comn/Properties/Resource.resx
New file
@@ -0,0 +1,124 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
  <!--
    Microsoft ResX Schema
    Version 2.0
    The primary goals of this format is to allow a simple XML format
    that is mostly human readable. The generation and parsing of the
    various data types are done through the TypeConverter classes
    associated with the data types.
    Example:
    ... ado.net/XML headers & schema ...
    <resheader name="resmimetype">text/microsoft-resx</resheader>
    <resheader name="version">2.0</resheader>
    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
        <value>[base64 mime encoded serialized .NET Framework object]</value>
    </data>
    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
        <comment>This is a comment</comment>
    </data>
    There are any number of "resheader" rows that contain simple
    name/value pairs.
    Each data row contains a name, and value. The row also contains a
    type or mimetype. Type corresponds to a .NET class that support
    text/value conversion through the TypeConverter architecture.
    Classes that don't support this are serialized and stored with the
    mimetype set.
    The mimetype is used for serialized objects, and tells the
    ResXResourceReader how to depersist the object. This is currently not
    extensible. For a given mimetype the value must be set accordingly:
    Note - application/x-microsoft.net.object.binary.base64 is the format
    that the ResXResourceWriter will generate, however the reader can
    read any of the formats listed below.
    mimetype: application/x-microsoft.net.object.binary.base64
    value   : The object must be serialized with
            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
            : and then encoded with base64 encoding.
    mimetype: application/x-microsoft.net.object.soap.base64
    value   : The object must be serialized with
            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
            : and then encoded with base64 encoding.
    mimetype: application/x-microsoft.net.object.bytearray.base64
    value   : The object must be serialized into a byte array
            : using a System.ComponentModel.TypeConverter
            : and then encoded with base64 encoding.
    -->
  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
    <xsd:element name="root" msdata:IsDataSet="true">
      <xsd:complexType>
        <xsd:choice maxOccurs="unbounded">
          <xsd:element name="metadata">
            <xsd:complexType>
              <xsd:sequence>
                <xsd:element name="value" type="xsd:string" minOccurs="0" />
              </xsd:sequence>
              <xsd:attribute name="name" use="required" type="xsd:string" />
              <xsd:attribute name="type" type="xsd:string" />
              <xsd:attribute name="mimetype" type="xsd:string" />
              <xsd:attribute ref="xml:space" />
            </xsd:complexType>
          </xsd:element>
          <xsd:element name="assembly">
            <xsd:complexType>
              <xsd:attribute name="alias" type="xsd:string" />
              <xsd:attribute name="name" type="xsd:string" />
            </xsd:complexType>
          </xsd:element>
          <xsd:element name="data">
            <xsd:complexType>
              <xsd:sequence>
                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
              </xsd:sequence>
              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
              <xsd:attribute ref="xml:space" />
            </xsd:complexType>
          </xsd:element>
          <xsd:element name="resheader">
            <xsd:complexType>
              <xsd:sequence>
                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
              </xsd:sequence>
              <xsd:attribute name="name" type="xsd:string" use="required" />
            </xsd:complexType>
          </xsd:element>
        </xsd:choice>
      </xsd:complexType>
    </xsd:element>
  </xsd:schema>
  <resheader name="resmimetype">
    <value>text/microsoft-resx</value>
  </resheader>
  <resheader name="version">
    <value>2.0</value>
  </resheader>
  <resheader name="reader">
    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
  </resheader>
  <resheader name="writer">
    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
  </resheader>
  <assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
  <data name="BroClog4net" type="System.Resources.ResXFileRef, System.Windows.Forms">
    <value>..\Log\BroClog4net.xml;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;gb2312</value>
  </data>
</root>
Bro.Comn/PubSub/IPubSubCenter.cs
New file
@@ -0,0 +1,63 @@
using System;
namespace Bro.Common.PubSub
{
    /// <summary>
    /// å‘布/订阅中心
    /// </summary>
    public interface IPubSubCenter
    {
        /// <summary>
        /// è®¢é˜…事件
        /// </summary>
        /// <param name="tag"></param>
        /// <param name="method"></param>
        /// <returns></returns>
        bool Subscribe(string tag, Func<ISubscriber, object, object, object> method);
        /// <summary>
        /// è®¢é˜…事件
        /// </summary>
        /// <param name="tag"></param>
        /// <param name="subscribe"></param>
        /// <returns></returns>
        bool Subscribe(string tag, ISubscriber subscribe);
        /// <summary>
        /// å‘布事件
        /// </summary>
        /// <param name="tag"></param>
        /// <param name="data"></param>
        void Publish(string tag, object param1, object param2);
        /// <summary>
        /// èŽ·å–æ‰€æœ‰è®¢é˜…è€…
        /// </summary>
        /// <param name="tag"></param>
        /// <returns></returns>
        Subscribers GetSubscribers(string tag);
        /// <summary>
        /// èŽ·å–æŸä¸ªè®¢é˜…è€…
        /// </summary>
        /// <param name="tag"></param>
        /// <param name="name"></param>
        /// <returns></returns>
        ISubscriber GetSubscriber(string tag, string name);
        /// <summary>
        /// ç§»é™¤æŸä¸ªè®¢é˜…者
        /// </summary>
        /// <param name="tag"></param>
        /// <param name="name"></param>
        /// <returns></returns>
        bool RemoveSubscriber(string tag, string name);
        /// <summary>
        /// ç§»é™¤æŸç±»æ‰€æœ‰è®¢é˜…者
        /// </summary>
        /// <param name="tag"></param>
        /// <returns></returns>
        bool RemoveSubscribers(string tag);
    }
}
Bro.Comn/PubSub/IPublisher.cs
New file
@@ -0,0 +1,15 @@
namespace Bro.Common.PubSub
{
    /// <summary>
    /// å‘布者
    /// </summary>
    public interface IPublisher
    {
        /// <summary>
        /// å‘布的事件
        /// </summary>
        string PublishTag { get; set; }
        object PublishData { get; set; }
    }
}
Bro.Comn/PubSub/ISubscriber.cs
New file
@@ -0,0 +1,19 @@
using System;
namespace Bro.Common.PubSub
{
    /// <summary>
    /// è®¢é˜…者
    /// </summary>
    public interface ISubscriber
    {
        /// <summary>
        /// è®¢é˜…的名称
        /// </summary>
        string SubscriberName { get; set; }
        /// <summary>
        /// å“åº”发布的方法
        /// </summary>
        Func<ISubscriber, object, object, object> SubMethod { get; set; }
    }
}
Bro.Comn/PubSub/PubSubCenter.cs
New file
@@ -0,0 +1,28 @@
namespace Bro.Common.PubSub
{
    /// <summary>
    /// E2E Core事件中心
    /// </summary>
    public class PubSubCenter : SimplePubSubCenter
    {
        private static PubSubCenter inst = null;
        /// <summary>
        /// Get Instance
        /// </summary>
        /// <returns></returns>
        public static PubSubCenter GetInstance()
        {
            if (null == inst)
            {
                inst = new PubSubCenter();
            }
            return inst;
        }
        private PubSubCenter()
        {
        }
    }
}
Bro.Comn/PubSub/SimplePubSubCenter.cs
New file
@@ -0,0 +1,391 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
namespace Bro.Common.PubSub
{
    /// <summary>
    /// ç®€å•发布/订阅中心
    /// </summary>
    public class SimplePubSubCenter : IPubSubCenter
    {
        /// <summary>
        /// è®¢é˜…主题和订阅者
        /// </summary>
        private Dictionary<string, Subscribers> subMap = new Dictionary<string, Subscribers>();
        /// <summary>
        /// è®¢é˜…事件
        /// </summary>
        /// <param name="tag"></param>
        /// <param name="method"></param>
        /// <returns></returns>
        public bool Subscribe(string tag, Func<ISubscriber, object, object, object> method)
        {
            var sub = new SimpleSubscriber();
            // é»˜è®¤ä½¿ç”¨hash值设置名称,防止重复
            sub.SubscriberName  = sub.GetHashCode().ToString();
            sub.SubMethod       = method;
            return Subscribe(tag, sub);
        }
        /// <summary>
        /// è®¢é˜…事件
        /// </summary>
        /// <param name="tag"></param>
        /// <param name="subscribe"></param>
        /// <returns></returns>
        public bool Subscribe(string tag, ISubscriber subscribe)
        {
            if ( null == tag || null == subscribe )
            {
                return false;
            }
            if ( subMap.ContainsKey(tag) )
            {
                var subs = subMap[tag];
                return subs.Add(subscribe);
            }
            else
            {
                var subs = new Subscribers();
                if ( !subs.Add(subscribe) )
                {
                    return false;
                }
                subMap.Add(tag, subs);
                return true;
            }
        }
        /// <summary>
        /// å‘布事件
        /// </summary>
        /// <param name="tag"></param>
        /// <param name="data"></param>
        public void Publish(string tag, object param1, object param2)
        {
            if ( null == tag )
            {
                return;
            }
            // èŽ·å–æ‰€æœ‰tag订阅者
            var subs = GetSubscribers(tag);
            if ( null == subs )
            {
                return;
            }
            var enmtor = subs.GetEnumerator();
            if ( null == enmtor )
            {
                return;
            }
            // é€šçŸ¥æ‰€æœ‰è®¢é˜…者事件
            while(enmtor.MoveNext())
            {
                var cur = enmtor.Current;
                if ( null == cur || null == cur.SubMethod)
                {
                    continue;
                }
                cur.SubMethod(cur, param1, param2);
            }
        }
        /// <summary>
        /// èŽ·å–æ‰€æœ‰è®¢é˜…è€…
        /// </summary>
        /// <param name="tag"></param>
        /// <returns></returns>
        public Subscribers GetSubscribers(string tag)
        {
            if ( !subMap.ContainsKey(tag) )
            {
                return null;
            }
            return subMap[tag];
        }
        /// <summary>
        /// èŽ·å–æŸä¸ªè®¢é˜…è€…
        /// </summary>
        /// <param name="tag"></param>
        /// <param name="name"></param>
        /// <returns></returns>
        public ISubscriber GetSubscriber(string tag, string name)
        {
            var subs = GetSubscribers(tag);
            if ( null == subs )
            {
                return null;
            }
            return subs.GetSubscriber(name);
        }
        /// <summary>
        /// ç§»é™¤æŸä¸ªè®¢é˜…者
        /// </summary>
        /// <param name="tag"></param>
        /// <param name="name"></param>
        /// <returns></returns>
        public bool RemoveSubscriber(string tag, string name)
        {
            var subs = GetSubscribers(tag);
            if ( null == subs )
            {
                return false;
            }
            if ( !subs.Rmv(name) )
            {
                return false;
            }
            if ( subs.GetCount() == 0 )
            {
                subMap.Remove(tag);
            }
            return true;
        }
        /// <summary>
        /// ç§»é™¤è®¢é˜…
        /// </summary>
        /// <param name="tag"></param>
        /// <param name="method"></param>
        /// <returns></returns>
        public bool RemoveSubscriber(string tag, Func<ISubscriber, object, object, object> method)
        {
            var subs = GetSubscribers(tag);
            if ( null == subs )
            {
                return false;
            }
            if ( !subs.Rmv(method) )
            {
                return false;
            }
            if ( subs.GetCount() == 0 )
            {
                subMap.Remove(tag);
            }
            return true;
        }
        /// <summary>
        /// ç§»é™¤æŸç±»æ‰€æœ‰è®¢é˜…者
        /// </summary>
        /// <param name="tag"></param>
        /// <returns></returns>
        public bool RemoveSubscribers(string tag)
        {
            var subs = GetSubscribers(tag);
            if ( null == subs )
            {
                return false;
            }
            subMap.Remove(tag);
            return true;
        }
        //IEnumerable<Object> Publish(string tag, object data);
        //IEnumerable<Object> Publish(string tag);
        //IEnumerable<Object> Publish(IPublisher publisher);
    }
    /// <summary>
    /// è®¢é˜…者集合
    /// </summary>
    public class Subscribers
    {
        /// <summary>
        /// è®¢é˜…者集合
        /// </summary>
        private Dictionary<string, ISubscriber>     subMap = new Dictionary<string,ISubscriber>();
        /// <summary>
        /// è®¢é˜…者集合
        /// </summary>
        private List<ISubscriber>  subList = new List<ISubscriber>();
        public Subscribers()
        {
        }
        /// <summary>
        /// æ–°å¢žè®¢é˜…者
        /// </summary>
        /// <param name="sub"></param>
        /// <returns></returns>
        public bool Add(ISubscriber sub)
        {
            if ( null == sub || subMap.ContainsKey(sub.SubscriberName) )
            {
                return false;
            }
            subMap.Add(sub.SubscriberName, sub);
            subList.Add(sub);
            return true;
        }
        /// <summary>
        /// ç§»é™¤è®¢é˜…者
        /// </summary>
        /// <param name="sub"></param>
        /// <returns></returns>
        public bool Rmv(ISubscriber sub)
        {
            if ( null == sub || !subMap.ContainsKey(sub.SubscriberName) )
            {
                return false;
            }
            subMap.Remove(sub.SubscriberName);
            subList.Remove(sub);
            return true;
        }
        /// <summary>
        /// ç§»é™¤è®¢é˜…者
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public bool Rmv(string name)
        {
            if ( !subMap.ContainsKey(name) )
            {
                return false;
            }
            var sub = subMap[name];
            subMap.Remove(name);
            subList.Remove(sub);
            return true;
        }
        /// <summary>
        /// ç§»é™¤è®¢é˜…者
        /// </summary>
        /// <param name="method"></param>
        /// <returns></returns>
        public bool Rmv(Func<ISubscriber, object, object, object> method)
        {
            var names   = new List<string>();
            try
            {
                foreach(var item in subMap)
                {
                    if ( null == item.Value )
                    {
                        continue;
                    }
                    // è‹¥æ˜¯ç›¸åŒå‡½æ•°ï¼Œåˆ™ç§»é™¤
                    if ( item.Value.SubMethod == method )
                    {
                        names.Add(item.Key);
                    }
                }
                for(int i = 0; i < names.Count; i++)
                {
                    subMap.Remove(names[i]);
                }
                names.Clear();
                return true;
            }
            catch(Exception ex)
            {
                Trace.TraceError("Remove subscriber fail,ex:{0}", ex);
            }
            return false;
        }
        /// <summary>
        /// æ£€å¯Ÿè®¢é˜…者是否存在
        /// </summary>
        /// <param name="sub"></param>
        /// <returns></returns>
        public bool Contains(ISubscriber sub)
        {
            if ( null == sub || !subMap.ContainsKey(sub.SubscriberName) )
            {
                return false;
            }
            return true;
        }
        /// <summary>
        /// èŽ·å–è®¢é˜…è€…
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public ISubscriber GetSubscriber(string name)
        {
            if ( !subMap.ContainsKey(name) )
            {
                return null;
            }
            return subMap[name];
        }
        /// <summary>
        /// æ¸…除所有订阅者
        /// </summary>
        public void Clear()
        {
            subMap.Clear();
            subList.Clear();
        }
        /// <summary>
        /// èŽ·å–è®¢é˜…è€…æžšä¸¾
        /// </summary>
        /// <returns></returns>
        public IEnumerator<ISubscriber> GetEnumerator()
        {
            return subList.GetEnumerator();
        }
        /// <summary>
        /// èŽ·å–è®¢é˜…è€…æ•°é‡
        /// </summary>
        /// <returns></returns>
        public int GetCount()
        {
            return subMap.Count;
        }
    }
}
Bro.Comn/PubSub/SimpleSubscriber.cs
New file
@@ -0,0 +1,19 @@
using System;
namespace Bro.Common.PubSub
{
    /// <summary>
    /// ç®€å•订阅者
    /// </summary>
    public class SimpleSubscriber :  ISubscriber
    {
        /// <summary>
        /// è®¢é˜…的名称
        /// </summary>
        public string SubscriberName { get; set; }
        /// <summary>
        /// å“åº”发布的方法
        /// </summary>
        public Func<ISubscriber, object, object, object> SubMethod { get; set; }
    }
}
Bro.Comn/Util/ConfigHelper.cs
New file
@@ -0,0 +1,110 @@
using System;
using System.Configuration;
using System.Diagnostics;
using System.IO;
using System.Xml.Serialization;
namespace Bro.Common.Util
{
    /// <summary>
    /// é…ç½®æ–‡ä»¶å¸®åŠ©ç±»
    /// </summary>
    public class ConfigHelper
    {
        private static object ioLock = new object();
        /// <summary>
        /// è½½å…¥XML配置文件
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="filePath"></param>
        /// <returns></returns>
        public static T Load<T>(string filePath)
        {
            try
            {
                lock (ioLock)
                {
                    if (!File.Exists(filePath))
                    {
                        return default(T);
                    }
                    var fs = new FileStream(filePath, FileMode.Open);
                    var xs = new XmlSerializer(typeof(T));
                    var config = (T)xs.Deserialize(fs);
                    fs.Close();
                    return config;
                }
            }
            catch(Exception ex)
            {
                Trace.TraceError("ConfigHelper load fail, filepath:{0},ex:{1}", filePath, ex);
            }
            return default(T);
        }
        /// <summary>
        /// ä¿å­˜XML配置文件
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="filePath"></param>
        /// <param name="config"></param>
        /// <returns></returns>
        public static bool Save<T>(string filePath, T config)
        {
            try
            {
                lock(ioLock)
                {
                    var fs = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.None);
                    var xs = new XmlSerializer(typeof(T));
                    xs.Serialize(fs, config);
                    fs.Close();
                }
                return true;
            }
            catch(Exception ex)
            {
                Trace.TraceError("ConfigHelper Save fail, filepath:{0},ex:{1}", filePath, ex);
            }
            return false;
        }
        /// <summary>
        /// ä¿®æ”¹AppSettings中配置
        /// </summary>
        /// <param name="key">key值</param>
        /// <param name="value">相应值</param>
        public static bool SetConfigValue(string key, string value)
        {
            try
            {
                Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
                if (config.AppSettings.Settings[key] != null)
                    config.AppSettings.Settings[key].Value = value;
                else
                    config.AppSettings.Settings.Add(key, value);
                config.Save(ConfigurationSaveMode.Modified);
                ConfigurationManager.RefreshSection("appSettings");
                return true;
            }
            catch
            {
                return false;
            }
        }
    }
}
Bro.Comn/Util/LoginConfig.cs
New file
@@ -0,0 +1,39 @@
using System.ComponentModel;
namespace Broc.Comn.Util
{
    public class LoginConfig
    {
        [Category("登录用户设置")]
        [Description("用户名")]
        public string LoginUserName { get; set; }
        [Category("登录用户设置")]
        [Description("用户密码")]
        public string LoginUserPassword { get; set; }
        [Category("登录用户设置")]
        [Description("用户登录状态")]
        public  int LoginStatus { get; set; }
        public bool CheckLogin(LoginConfig loginConfig)
        {
            if (loginConfig.LoginUserName == "操作员" && loginConfig.LoginUserPassword == "1")
            {
                loginConfig.LoginStatus = 1;
                return true;
            }
            if (loginConfig.LoginUserName == "管理员" && loginConfig.LoginUserPassword == "2")
            {
                loginConfig.LoginStatus = 2;
                return true;
            }
            if (loginConfig.LoginUserName == "工程师" && loginConfig.LoginUserPassword == "3")
            {
                loginConfig.LoginStatus = 3;
                return true;
            }
            return false;
        }
    }
}
Bro.Comn/packages.config
New file
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
  <package id="log4net" version="2.0.8" targetFramework="net45" />
</packages>
P066.Data.sln
@@ -1,20 +1,36 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.28307.1259
# Visual Studio Version 16
VisualStudioVersion = 16.0.30804.86
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "P066.Data", "P066.Data\P066.Data.csproj", "{8B8F7749-8823-48C6-B12A-54979E28C10C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Bro.Comn", "Bro.Comn\Bro.Comn.csproj", "{42407C78-FB75-4310-8910-DF515652A012}"
EndProject
Global
    GlobalSection(SolutionConfigurationPlatforms) = preSolution
        Debug|Any CPU = Debug|Any CPU
        Debug|x86 = Debug|x86
        Release|Any CPU = Release|Any CPU
        Release|x86 = Release|x86
    EndGlobalSection
    GlobalSection(ProjectConfigurationPlatforms) = postSolution
        {8B8F7749-8823-48C6-B12A-54979E28C10C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
        {8B8F7749-8823-48C6-B12A-54979E28C10C}.Debug|Any CPU.Build.0 = Debug|Any CPU
        {8B8F7749-8823-48C6-B12A-54979E28C10C}.Debug|x86.ActiveCfg = Debug|Any CPU
        {8B8F7749-8823-48C6-B12A-54979E28C10C}.Debug|x86.Build.0 = Debug|Any CPU
        {8B8F7749-8823-48C6-B12A-54979E28C10C}.Release|Any CPU.ActiveCfg = Release|Any CPU
        {8B8F7749-8823-48C6-B12A-54979E28C10C}.Release|Any CPU.Build.0 = Release|Any CPU
        {8B8F7749-8823-48C6-B12A-54979E28C10C}.Release|x86.ActiveCfg = Release|Any CPU
        {8B8F7749-8823-48C6-B12A-54979E28C10C}.Release|x86.Build.0 = Release|Any CPU
        {42407C78-FB75-4310-8910-DF515652A012}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
        {42407C78-FB75-4310-8910-DF515652A012}.Debug|Any CPU.Build.0 = Debug|Any CPU
        {42407C78-FB75-4310-8910-DF515652A012}.Debug|x86.ActiveCfg = Debug|x86
        {42407C78-FB75-4310-8910-DF515652A012}.Debug|x86.Build.0 = Debug|x86
        {42407C78-FB75-4310-8910-DF515652A012}.Release|Any CPU.ActiveCfg = Release|Any CPU
        {42407C78-FB75-4310-8910-DF515652A012}.Release|Any CPU.Build.0 = Release|Any CPU
        {42407C78-FB75-4310-8910-DF515652A012}.Release|x86.ActiveCfg = Release|x86
        {42407C78-FB75-4310-8910-DF515652A012}.Release|x86.Build.0 = Release|x86
    EndGlobalSection
    GlobalSection(SolutionProperties) = preSolution
        HideSolutionNode = FALSE
P066.Data/Form1.cs
@@ -8,6 +8,8 @@
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO;
using Bro.Common;
using Bro.Common.Util;
namespace P066.Data
{
@@ -15,10 +17,16 @@
    {
        DirectoryInfo directoryInfo1;
        DirectoryInfo directoryInfo2;
        private P066RunParam runparam = new P066RunParam();
        public Form1()
        {
            InitializeComponent();
            //ConfigHelper.Save(@"D:\P066-Data\P066XML\1.xml", runparam);
            runparam = ConfigHelper.Load<P066RunParam>(@"D:\P066-Data\P066XML\Jin_Mid.xml");
        }
        private void btnLoadData1_Click(object sender, EventArgs e)
@@ -91,9 +99,7 @@
                    JudgeListSum.AddRange(judgeList);
                }
                judgeList = GetLocation(judgeList);
                //给镜头区分位置及角度
                list = GetLocation(list);
                string currPath = "";
                #region//判断是初检文件夹还是复检文件夹
                if (fileinfos1[i].Name.Contains("初检中框"))
@@ -101,30 +107,45 @@
                    ChuNum++;
                    filenameDir = "初检中框白点";
                    filename = "初检中框白点" + ChuNum;
                    judgeList = GetMidLocation(judgeList);
                    //给镜头区分位置及角度
                    list = GetMidLocation(list);
                }
               else if (fileinfos1[i].Name.Contains("复检中框")&& fileinfos1[i].Name.Contains("白点"))
                {
                    FuNum=FuNum+1;
                    filenameDir = "复检中框白点";
                    filename = "复检中框白点" + FuNum;
                    judgeList = GetMidLocation(judgeList);
                    //给镜头区分位置及角度
                    list = GetMidLocation(list);
                }
                else if ( fileinfos1[i].Name.Contains("复检中框") &&fileinfos1[i].Name.Contains("刮白"))
                    {
                        GuaNum=GuaNum+1;
                        filenameDir = "复检中框刮白";
                        filename = "复检中框刮白" + GuaNum;
                    judgeList = GetMidLocation(judgeList);
                    //给镜头区分位置及角度
                    list = GetMidLocation(list);
                    }
               else if (fileinfos1[i].Name.Contains("初检背板"))
                {
                    ChuNum++;
                    filenameDir = "初检背板白点";
                    filename = "初检背板白点" + ChuNum;
                    judgeList = GetBkLocation(judgeList);
                    //给镜头区分位置及角度
                    list = GetBkLocation(list);
                }
                else if (fileinfos1[i].Name.Contains("复检背板") && fileinfos1[i].Name.Contains("白点"))
                {
                    FuNum = FuNum + 1;
                    filenameDir = "复检背板白点";
                    filename = "复检背板白点" + FuNum;
                    judgeList = GetBkLocation(judgeList);
                    //给镜头区分位置及角度
                    list = GetBkLocation(list);
                }
                currPath = directoryInfo1.Parent.Parent.FullName;
@@ -543,8 +564,8 @@
            return dataList;
        }
      
        private List<ResultData> GetLocation(List<ResultData> list)
        //获取中框角度和位置
        private List<ResultData> GetMidLocation(List<ResultData> list)
        {
            var group = list.GroupBy(a => a.TimeTip);
            foreach (var item in group)
@@ -561,11 +582,11 @@
                    listLensnumber1[k].angle = lenAngle;
                    var distance = GetDistance(1050, 1050, listLensnumber1[k].X, listLensnumber1[k].Y);
                    if (distance <= 298.022)
                    if (distance <= runparam.MidLens1R1)
                    {
                        listLensnumber1[k].location = "镜头";
                    }
                    else if (298.022 < distance && distance <= 521.171)
                    else if (runparam.MidLens1R1 < distance && distance <= runparam.MidLens1R2)
                    {
                        listLensnumber1[k].location = "斜面";
                    }
@@ -586,11 +607,11 @@
                    }
                    listLensnumber2[k].angle = lenAngle;
                    var distance = GetDistance(1050, 1050, listLensnumber2[k].X, listLensnumber2[k].Y);
                    if (distance <= 367.696)
                    if (distance <= runparam.MidLens2R1)
                    {
                        listLensnumber2[k].location = "镜头";
                    }
                    else if (367.696 < distance && distance <= 653.911)
                    else if (runparam.MidLens2R1 < distance && distance <= runparam.MidLens2R2)
                    {
                        listLensnumber2[k].location = "斜面";
                    }
@@ -610,11 +631,11 @@
                    }
                    listLensnumber3[k].angle = lenAngle;
                    var distance = GetDistance(1050, 1050, listLensnumber3[k].X, listLensnumber3[k].Y);
                    if (distance <= 339.246)
                    if (distance <= runparam.MidLens3R1)
                    {
                        listLensnumber3[k].location = "镜头";
                    }
                    else if (distance < 339.246 && distance <= 520.584)
                    else if ( runparam.MidLens3R1< distance && distance <= runparam.MidLens3R2)
                    {
                        listLensnumber3[k].location = "斜面";
                    }
@@ -634,11 +655,11 @@
                    }
                    listLensnumber4[k].angle = lenAngle;
                    var distance = GetDistance(1050, 1050, listLensnumber4[k].X, listLensnumber4[k].Y);
                    if (distance <= 104.895)
                    if (distance <= runparam.MidLens4R1)
                    {
                        listLensnumber4[k].location = "镜头";
                    }
                    else if (104.895 < distance && distance <= 239.48)
                    else if (runparam.MidLens4R1 < distance && distance <= runparam.MidLens4R2)
                    {
                        listLensnumber4[k].location = "斜面";
                    }
@@ -652,7 +673,101 @@
            }
            return list;
        }
        //获取背板角度和位置
        private List<ResultData> GetBkLocation(List<ResultData> list)
        {
            var group = list.GroupBy(a => a.TimeTip);
            foreach (var item in group)
            {
                //计算镜头1缺陷位置及角度
                var listLensnumber1 = list.FindAll(a => a.TimeTip == item.Key && a.Lensnumber == 1);
                for (int k = 0; k < listLensnumber1.Count; k++)
                {
                    var lenAngle = GetAngle(listLensnumber1[k].X, listLensnumber1[k].Y);
                    if (lenAngle < 0)
                    {
                        lenAngle = 360 + lenAngle;
                    }
                    listLensnumber1[k].angle = lenAngle;
                    var distance = GetDistance(1050, 1050, listLensnumber1[k].X, listLensnumber1[k].Y);
                    if (distance <= runparam.BkLens1R1)
                    {
                        listLensnumber1[k].location = "可视区";
                    }
                    else
                    {
                        listLensnumber1[k].location = "非可视区";
                    }
                }
                //计算镜头2位置及角度
                var listLensnumber2 = list.FindAll(a => a.TimeTip == item.Key && a.Lensnumber == 2);
                for (int k = 0; k < listLensnumber2.Count; k++)
                {
                    var lenAngle = GetAngle(listLensnumber2[k].X, listLensnumber2[k].Y);
                    if (lenAngle < 0)
                    {
                        lenAngle = 360 + lenAngle;
                    }
                    listLensnumber2[k].angle = lenAngle;
                    var distance = GetDistance(1050, 1050, listLensnumber2[k].X, listLensnumber2[k].Y);
                    if (distance <= runparam.BkLens2R1)
                    {
                        listLensnumber2[k].location = "可视区";
                    }
                    else
                    {
                        listLensnumber2[k].location = "非可视区";
                    }
                }
                //计算镜头3位置及角度
                var listLensnumber3 = list.FindAll(a => a.TimeTip == item.Key && a.Lensnumber == 3);
                for (int k = 0; k < listLensnumber3.Count; k++)
                {
                    var lenAngle = GetAngle(listLensnumber3[k].X, listLensnumber3[k].Y);
                    if (lenAngle < 0)
                    {
                        lenAngle = 360 + lenAngle;
                    }
                    listLensnumber3[k].angle = lenAngle;
                    var distance = GetDistance(1050, 1050, listLensnumber3[k].X, listLensnumber3[k].Y);
                    if (distance <= runparam.BkLens3R1)
                    {
                        listLensnumber3[k].location = "可视区";
                    }
                    else
                    {
                        listLensnumber3[k].location = "非可视区";
                    }
                }
                //计算镜头4位置及角度
                var listLensnumber4 = list.FindAll(a => a.TimeTip == item.Key && a.Lensnumber == 4);
                for (int k = 0; k < listLensnumber4.Count; k++)
                {
                    var lenAngle = GetAngle(listLensnumber4[k].X, listLensnumber4[k].Y);
                    if (lenAngle < 0)
                    {
                        lenAngle = 360 + lenAngle;
                    }
                    listLensnumber4[k].angle = lenAngle;
                    var distance = GetDistance(1050, 1050, listLensnumber4[k].X, listLensnumber4[k].Y);
                    if (distance <= runparam.BkLens4R1)
                    {
                        listLensnumber4[k].location = "可视区";
                    }
                    else
                    {
                        listLensnumber4[k].location = "非可视区";
                    }
                }
            }
            return list;
        }
        private void WriteJR(List<ResultData> Lens,string item,int LensNumb, string file12)
        {
P066.Data/P066.Data.csproj
@@ -52,6 +52,7 @@
    <Compile Include="Form1.Designer.cs">
      <DependentUpon>Form1.cs</DependentUpon>
    </Compile>
    <Compile Include="P066RunParam.cs" />
    <Compile Include="Program.cs" />
    <Compile Include="Properties\AssemblyInfo.cs" />
    <EmbeddedResource Include="Form1.resx">
@@ -79,5 +80,11 @@
  <ItemGroup>
    <None Include="App.config" />
  </ItemGroup>
  <ItemGroup>
    <ProjectReference Include="..\Bro.Comn\Bro.Comn.csproj">
      <Project>{42407c78-fb75-4310-8910-df515652a012}</Project>
      <Name>Bro.Comn</Name>
    </ProjectReference>
  </ItemGroup>
  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>
P066.Data/P066RunParam.cs
New file
@@ -0,0 +1,29 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace P066.Data
{
    public class P066RunParam
    {
        public double MidLens1R1;
        public double MidLens1R2;
        public double MidLens2R1;
        public double MidLens2R2;
        public double MidLens3R1;
        public double MidLens3R2;
        public double MidLens4R1;
        public double MidLens4R2;
        public double BkLens1R1;
        //public double BkLens1R2;
        public double BkLens2R1;
        //public double BkLens2R2;
        public double BkLens3R1;
        //public double BkLens3R2;
        public double BkLens4R1;
        //public double BkLens4R2;
    }
}
P066.Data/P066RunPaream.cs
New file
@@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace P066.Data
{
    class P066RunPaream
    {
        public int Lens1R1;
        public int Lens1R2;
        public int Lens2R1;
        public int Lens2R2;
        public int Lens3R1;
        public int Lens3R2;
        public int Lens4R1;
        public int Lens4R2;
    }
}
P066XML/Jin_Mid - ¸±±¾.xml
New file
@@ -0,0 +1,15 @@
<?xml version="1.0"?>
<P066RunParam xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <MidLens1R1>298.022</MidLens1R1>
  <MidLens1R2>521.171</MidLens1R2>
  <MidLens2R1>367.696</MidLens2R1>
  <MidLens2R2>653.911</MidLens2R2>
  <MidLens3R1>339.246</MidLens3R1>
  <MidLens3R2>520.584</MidLens3R2>
  <MidLens4R1>104.895</MidLens4R1>
  <MidLens4R2>239.48</MidLens4R2>
  <BkLens1R1>0</BkLens1R1>
  <BkLens2R1>0</BkLens2R1>
  <BkLens3R1>0</BkLens3R1>
  <BkLens4R1>0</BkLens4R1>
</P066RunParam>
P066XML/Jin_Mid.xml
New file
@@ -0,0 +1,15 @@
<?xml version="1.0"?>
<P066RunParam xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <MidLens1R1>298.022</MidLens1R1>
  <MidLens1R2>521.171</MidLens1R2>
  <MidLens2R1>367.696</MidLens2R1>
  <MidLens2R2>653.911</MidLens2R2>
  <MidLens3R1>339.246</MidLens3R1>
  <MidLens3R2>520.584</MidLens3R2>
  <MidLens4R1>104.895</MidLens4R1>
  <MidLens4R2>239.48</MidLens4R2>
  <BkLens1R1>573.196</BkLens1R1>
  <BkLens2R1>714.58</BkLens2R1>
  <BkLens3R1>766</BkLens3R1>
  <BkLens4R1>345</BkLens4R1>
</P066RunParam>